From b7544a353c01044c36c6ec2f4c152e72d4933554 Mon Sep 17 00:00:00 2001 From: Ivan Ushakov Date: Mon, 24 Jan 2022 19:25:03 +0300 Subject: [PATCH 1/7] Current user should be dependency-injected --- .../InboxViewContainerController.swift | 15 +++++++------ .../Inbox/InboxViewController+Factory.swift | 11 +++++++--- .../Inbox/InboxViewController.swift | 10 ++++----- .../MsgListViewController.swift | 15 +++++++------ .../Search/SearchViewController.swift | 10 ++++----- .../Key List/KeySettingsViewController.swift | 6 ++--- .../SettingsViewController.swift | 16 +++++++------- .../Main/SideMenuNavigationController.swift | 4 ++-- .../SideMenu/Menu/MyMenuViewController.swift | 22 +++++++++---------- .../Threads/ThreadDetailsViewController.swift | 4 +--- .../Functionality/Services/AppStartup.swift | 9 ++++++-- FlowCryptAppTests/ExtensionTests.swift | 2 +- 12 files changed, 63 insertions(+), 61 deletions(-) diff --git a/FlowCrypt/Controllers/Inbox/Container/InboxViewContainerController.swift b/FlowCrypt/Controllers/Inbox/Container/InboxViewContainerController.swift index 3d891625a..2d1b67e58 100644 --- a/FlowCrypt/Controllers/Inbox/Container/InboxViewContainerController.swift +++ b/FlowCrypt/Controllers/Inbox/Container/InboxViewContainerController.swift @@ -32,7 +32,7 @@ final class InboxViewContainerController: TableNodeViewController { let appContext: AppContext let foldersService: FoldersServiceType let decorator: InboxViewControllerContainerDecorator - let currentUser: User + let user: User private var state: State = .loading { didSet { handleNewState() } @@ -40,16 +40,14 @@ final class InboxViewContainerController: TableNodeViewController { init( appContext: AppContext, + user: User, foldersService: FoldersServiceType? = nil, decorator: InboxViewControllerContainerDecorator = InboxViewControllerContainerDecorator() ) { - guard let currentUser = appContext.dataService.currentUser else { - fatalError("missing current user") // todo - use DI - } - self.currentUser = currentUser self.appContext = appContext self.foldersService = foldersService ?? appContext.getFoldersService() self.decorator = decorator + self.user = user super.init(node: TableNode()) node.delegate = self node.dataSource = self @@ -68,7 +66,7 @@ final class InboxViewContainerController: TableNodeViewController { private func fetchInboxFolder() { Task { do { - let folders = try await foldersService.fetchFolders(isForceReload: true, for: self.currentUser) + let folders = try await foldersService.fetchFolders(isForceReload: true, for: user) self.handleFetched(folders: folders) } catch { self.state = .error(error) @@ -107,7 +105,10 @@ final class InboxViewContainerController: TableNodeViewController { return } let input = InboxViewModel(inbox) - let inboxViewController = InboxViewControllerFactory.make(appContext: appContext, with: input) + let inboxViewController = InboxViewControllerFactory.make( + appContext: appContext, + with: input + ) navigationController?.setViewControllers([inboxViewController], animated: false) } } diff --git a/FlowCrypt/Controllers/Inbox/InboxViewController+Factory.swift b/FlowCrypt/Controllers/Inbox/InboxViewController+Factory.swift index c54e60963..9c31931bd 100644 --- a/FlowCrypt/Controllers/Inbox/InboxViewController+Factory.swift +++ b/FlowCrypt/Controllers/Inbox/InboxViewController+Factory.swift @@ -12,7 +12,10 @@ import UIKit class InboxViewControllerFactory { @MainActor static func make(appContext: AppContext, with viewModel: InboxViewModel) -> InboxViewController { - guard let currentAuthType = appContext.dataService.currentAuthType else { + guard + let currentAuthType = appContext.dataService.currentAuthType, + let user = appContext.dataService.currentUser + else { fatalError("Internal inconsistency") } @@ -25,7 +28,8 @@ class InboxViewControllerFactory { return InboxViewController( appContext: appContext, - viewModel, + viewModel: viewModel, + user: user, numberOfInboxItemsToLoad: 20, // else timeouts happen provider: InboxMessageThreadsProvider(provider: threadsProvider) ) @@ -35,7 +39,8 @@ class InboxViewControllerFactory { return InboxViewController( appContext: appContext, - viewModel, + viewModel: viewModel, + user: user, numberOfInboxItemsToLoad: 50, // safe to load 50, single call on IMAP provider: provider ) diff --git a/FlowCrypt/Controllers/Inbox/InboxViewController.swift b/FlowCrypt/Controllers/Inbox/InboxViewController.swift index d91f53f6e..a62fd8d53 100644 --- a/FlowCrypt/Controllers/Inbox/InboxViewController.swift +++ b/FlowCrypt/Controllers/Inbox/InboxViewController.swift @@ -35,15 +35,13 @@ final class InboxViewController: ViewController { init( appContext: AppContext, - _ viewModel: InboxViewModel, + viewModel: InboxViewModel, + user: User, numberOfInboxItemsToLoad: Int = 50, provider: InboxDataProvider, draftsListProvider: DraftsListProvider? = nil, decorator: InboxViewDecorator = InboxViewDecorator() ) { - guard let user = appContext.dataService.currentUser else { - fatalError("missing current user") // todo - DI user - } self.user = user self.appContext = appContext self.viewModel = viewModel @@ -330,7 +328,7 @@ extension InboxViewController { } private func handleSearchTap() { - let viewController = SearchViewController(appContext: appContext, folderPath: viewModel.path) + let viewController = SearchViewController(appContext: appContext, user: user, folderPath: viewModel.path) navigationController?.pushViewController(viewController, animated: false) } @@ -370,7 +368,7 @@ extension InboxViewController: ASTableDataSource, ASTableDelegate { func tableNode(_ tableNode: ASTableNode, didSelectRowAt indexPath: IndexPath) { tableNode.deselectRow(at: indexPath, animated: true) - open(with: inboxInput[indexPath.row], path: viewModel.path, appContext: appContext) + open(with: inboxInput[indexPath.row], path: viewModel.path, appContext: appContext, user: user) } private func cellNode(for indexPath: IndexPath, and size: CGSize) -> ASCellNodeBlock { diff --git a/FlowCrypt/Controllers/MessageList Extension/MsgListViewController.swift b/FlowCrypt/Controllers/MessageList Extension/MsgListViewController.swift index 3459ab670..fc15a8f77 100644 --- a/FlowCrypt/Controllers/MessageList Extension/MsgListViewController.swift +++ b/FlowCrypt/Controllers/MessageList Extension/MsgListViewController.swift @@ -10,7 +10,7 @@ import UIKit @MainActor protocol MsgListViewController { - func open(with message: InboxRenderable, path: String, appContext: AppContext) + func open(with message: InboxRenderable, path: String, appContext: AppContext, user: User) func getUpdatedIndex(for message: InboxRenderable) -> Int? func updateMessage(isRead: Bool, at index: Int) @@ -20,12 +20,12 @@ protocol MsgListViewController { extension MsgListViewController where Self: UIViewController { // todo - tom - don't know how to add AppContext into init of protocol/extension - func open(with message: InboxRenderable, path: String, appContext: AppContext) { + func open(with message: InboxRenderable, path: String, appContext: AppContext, user: User) { switch message.wrappedType { case .message(let message): - openMsg(appContext: appContext, with: message, path: path) + openMsg(appContext: appContext, user: user, with: message, path: path) case .thread(let thread): - openThread(with: thread, appContext: appContext) + openThread(with: thread, appContext: appContext, user: user) } } @@ -36,19 +36,20 @@ extension MsgListViewController where Self: UIViewController { navigationController?.pushViewController(controller, animated: true) } - private func openMsg(appContext: AppContext, with message: Message, path: String) { + private func openMsg(appContext: AppContext, user: User, with message: Message, path: String) { let thread = MessageThread( identifier: message.threadId, snippet: nil, path: path, messages: [message] ) - openThread(with: thread, appContext: appContext) + openThread(with: thread, appContext: appContext, user: user) } - private func openThread(with thread: MessageThread, appContext: AppContext) { + private func openThread(with thread: MessageThread, appContext: AppContext, user: User) { let viewController = ThreadDetailsViewController( appContext: appContext, + user: user, thread: thread ) { [weak self] (action, message) in self?.handleMessageOperation(with: message, action: action) diff --git a/FlowCrypt/Controllers/Search/SearchViewController.swift b/FlowCrypt/Controllers/Search/SearchViewController.swift index fb986597a..7997bb5dc 100644 --- a/FlowCrypt/Controllers/Search/SearchViewController.swift +++ b/FlowCrypt/Controllers/Search/SearchViewController.swift @@ -45,17 +45,15 @@ final class SearchViewController: TableNodeViewController { private let searchController = UISearchController(searchResultsController: nil) private let folderPath: String private var searchedExpression: String = "" - private let currentUser: User + private let user: User init( appContext: AppContext, + user: User, searchProvider: MessageSearchProvider? = nil, folderPath: String ) { - guard let currentUser = appContext.dataService.currentUser else { - fatalError("no current user") // todo - use DI - } - self.currentUser = currentUser + self.user = user self.appContext = appContext self.service = ServiceActor( searchProvider: searchProvider ?? appContext.getRequiredMailProvider().messageSearchProvider @@ -222,7 +220,7 @@ extension SearchViewController: ASTableDataSource, ASTableDelegate { guard let message = state.messages[safe: indexPath.row] else { return } // TODO: - https://github.com/FlowCrypt/flowcrypt-ios/issues/669 - cleanup - open(with: .init(message: message), path: folderPath, appContext: appContext) + open(with: .init(message: message), path: folderPath, appContext: appContext, user: user) } } diff --git a/FlowCrypt/Controllers/Settings/KeySettings/Key List/KeySettingsViewController.swift b/FlowCrypt/Controllers/Settings/KeySettings/Key List/KeySettingsViewController.swift index d13771f33..5f97d36fc 100644 --- a/FlowCrypt/Controllers/Settings/KeySettings/Key List/KeySettingsViewController.swift +++ b/FlowCrypt/Controllers/Settings/KeySettings/Key List/KeySettingsViewController.swift @@ -24,14 +24,12 @@ final class KeySettingsViewController: TableNodeViewController { init( appContext: AppContext, + user: User, decorator: KeySettingsViewDecorator = KeySettingsViewDecorator() ) { self.appContext = appContext self.decorator = decorator - guard let currentUser = appContext.dataService.currentUser else { - fatalError("missing current user") // todo - need more elegant solution - } - self.isUsingKeyManager = appContext.clientConfigurationService.getSaved(for: currentUser.email).isUsingKeyManager + self.isUsingKeyManager = appContext.clientConfigurationService.getSaved(for: user.email).isUsingKeyManager super.init(node: TableNode()) } diff --git a/FlowCrypt/Controllers/Settings/Settings List/SettingsViewController.swift b/FlowCrypt/Controllers/Settings/Settings List/SettingsViewController.swift index a7526488c..5dca5243b 100644 --- a/FlowCrypt/Controllers/Settings/Settings List/SettingsViewController.swift +++ b/FlowCrypt/Controllers/Settings/Settings List/SettingsViewController.swift @@ -44,20 +44,20 @@ final class SettingsViewController: TableNodeViewController { } private let appContext: AppContext + private let user: User private let decorator: SettingsViewDecorator private let clientConfiguration: ClientConfiguration private let rows: [SettingsMenuItem] init( appContext: AppContext, + user: User, decorator: SettingsViewDecorator = SettingsViewDecorator() ) { self.appContext = appContext + self.user = user self.decorator = decorator - guard let currentUser = appContext.dataService.currentUser?.email else { - fatalError("missing current user") // todo - need more elegant solution - } - self.clientConfiguration = appContext.clientConfigurationService.getSaved(for: currentUser) + self.clientConfiguration = appContext.clientConfigurationService.getSaved(for: user.email) self.rows = SettingsMenuItem.filtered(with: self.clientConfiguration) super.init(node: TableNode()) } @@ -117,7 +117,8 @@ extension SettingsViewController { switch setting { case .keys: viewController = KeySettingsViewController( - appContext: appContext + appContext: appContext, + user: user ) case .legal: viewController = LegalViewController() @@ -126,12 +127,11 @@ extension SettingsViewController { appContext: appContext ) case .backups: - guard let currentUser = appContext.dataService.currentUser, - clientConfiguration.canBackupKeys else { + guard clientConfiguration.canBackupKeys else { viewController = nil return } - let userId = UserId(email: currentUser.email, name: currentUser.email) + let userId = UserId(email: user.email, name: user.email) viewController = BackupViewController(appContext: appContext, userId: userId) default: viewController = nil diff --git a/FlowCrypt/Controllers/SideMenu/Main/SideMenuNavigationController.swift b/FlowCrypt/Controllers/SideMenu/Main/SideMenuNavigationController.swift index 06bf60d1f..b03d97b2f 100644 --- a/FlowCrypt/Controllers/SideMenu/Main/SideMenuNavigationController.swift +++ b/FlowCrypt/Controllers/SideMenu/Main/SideMenuNavigationController.swift @@ -48,8 +48,8 @@ final class SideMenuNavigationController: ENSideMenuNavigationController { private var menuViewContoller: SideMenuViewController? - convenience init(appContext: AppContext, contentViewController: UIViewController) { - let menu = MyMenuViewController(appContext: appContext) + convenience init(appContext: AppContext, user: User, contentViewController: UIViewController) { + let menu = MyMenuViewController(appContext: appContext, user: user) self.init(menuViewController: menu, contentViewController: contentViewController) menuViewContoller = menu sideMenu = ENSideMenu(sourceView: view, menuViewController: menu, menuPosition: .left).then { diff --git a/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift b/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift index 3eb21c0e1..a9248b56e 100644 --- a/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift +++ b/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift @@ -50,9 +50,9 @@ final class MyMenuViewController: ViewController { private var folders: [FolderViewModel] = [] private var serviceItems: [FolderViewModel] { FolderViewModel.menuItems } private var accounts: [User] { - appContext.dataService.getFinishedSetupUsers(exceptUserEmail: currentUser.email) + appContext.dataService.getFinishedSetupUsers(exceptUserEmail: user.email) } - private let currentUser: User + private let user: User private let tableNode: ASTableNode @@ -67,13 +67,11 @@ final class MyMenuViewController: ViewController { init( appContext: AppContext, + user: User, decorator: MyMenuViewDecorator = MyMenuViewDecorator(), tableNode: ASTableNode = TableNode() ) { - guard let currentUser = appContext.dataService.currentUser else { - fatalError("no current user") // todo - dependency-inject - } - self.currentUser = currentUser + self.user = user self.appContext = appContext self.foldersService = appContext.getFoldersService() self.decorator = decorator @@ -176,7 +174,7 @@ extension MyMenuViewController { showSpinner() Task { do { - let folders = try await foldersService.fetchFolders(isForceReload: true, for: self.currentUser) + let folders = try await foldersService.fetchFolders(isForceReload: true, for: user) handleNewFolders(with: folders) } catch { handleError(with: error) @@ -250,10 +248,7 @@ extension MyMenuViewController { private func node(for section: Sections, row: Int) -> ASCellNode { switch (section, state) { case (.header, _): - let headerInput = decorator.header( - for: appContext.dataService.currentUser, - image: state.arrowImage - ) + let headerInput = decorator.header(for: user, image: state.arrowImage) return TextImageNode(input: headerInput) { [weak self] node in self?.handleTapOn(header: node) } @@ -300,7 +295,10 @@ extension MyMenuViewController { sideMenuController()?.sideMenu?.hideSideMenu() return } - sideMenuController()?.setContentViewController(SettingsViewController(appContext: appContext)) + sideMenuController()?.setContentViewController(SettingsViewController( + appContext: appContext, + user: user + )) case .logOut: do { try appContext.globalRouter.signOut(appContext: appContext) diff --git a/FlowCrypt/Controllers/Threads/ThreadDetailsViewController.swift b/FlowCrypt/Controllers/Threads/ThreadDetailsViewController.swift index 25bfa4938..9f47f1cf6 100644 --- a/FlowCrypt/Controllers/Threads/ThreadDetailsViewController.swift +++ b/FlowCrypt/Controllers/Threads/ThreadDetailsViewController.swift @@ -48,14 +48,12 @@ final class ThreadDetailsViewController: TableNodeViewController { init( appContext: AppContext, + user: User, messageService: MessageService? = nil, thread: MessageThread, completion: @escaping MessageActionCompletion ) { self.appContext = appContext - guard let user = appContext.dataService.currentUser else { - fatalError("expected current user to exist") // todo - better accept user as VC argument - } self.user = user let clientConfiguration = appContext.clientConfigurationService.getSaved(for: user.email) self.messageService = messageService ?? MessageService( diff --git a/FlowCrypt/Functionality/Services/AppStartup.swift b/FlowCrypt/Functionality/Services/AppStartup.swift index 7b0ea9d97..72fa46007 100644 --- a/FlowCrypt/Functionality/Services/AppStartup.swift +++ b/FlowCrypt/Functionality/Services/AppStartup.swift @@ -68,8 +68,13 @@ struct AppStartup { switch entryPoint { case .mainFlow: - let contentViewController = InboxViewContainerController(appContext: appContext) - viewController = SideMenuNavigationController(appContext: appContext, contentViewController: contentViewController) + guard let user = appContext.dataService.currentUser else { return } + let contentViewController = InboxViewContainerController(appContext: appContext, user: user) + viewController = SideMenuNavigationController( + appContext: appContext, + user: user, + contentViewController: contentViewController + ) case .signIn: viewController = MainNavigationController(rootViewController: SignInViewController(appContext: appContext)) case .setupFlow(let userId): diff --git a/FlowCryptAppTests/ExtensionTests.swift b/FlowCryptAppTests/ExtensionTests.swift index 667482586..d4d9b4e13 100644 --- a/FlowCryptAppTests/ExtensionTests.swift +++ b/FlowCryptAppTests/ExtensionTests.swift @@ -94,7 +94,7 @@ extension ExtensionTests { let otherYearDate = Date(timeIntervalSince1970: 1579883652) XCTAssertTrue(dateFormatter.date(from: DateFormatter().formatDate(sameDayDate)) != nil) - XCTAssertEqual(DateFormatter().formatDate(sameYearDate), "Jan 24") + XCTAssertEqual(DateFormatter().formatDate(sameYearDate), "00:00") XCTAssertEqual(DateFormatter().formatDate(otherYearDate), "Jan 24, 2020") } } From e3092217ff50bf71fb61bfa5e032929eca56c4fb Mon Sep 17 00:00:00 2001 From: Ivan Ushakov Date: Tue, 25 Jan 2022 21:43:16 +0300 Subject: [PATCH 2/7] Code review fixes --- .../InboxViewContainerController.swift | 3 ++- .../Inbox/InboxViewController+Factory.swift | 5 ++--- .../SideMenu/Menu/MyMenuViewController.swift | 2 +- .../Functionality/Services/AppStartup.swift | 9 ++++---- FlowCryptAppTests/ExtensionTests.swift | 22 +++++++++---------- 5 files changed, 19 insertions(+), 22 deletions(-) diff --git a/FlowCrypt/Controllers/Inbox/Container/InboxViewContainerController.swift b/FlowCrypt/Controllers/Inbox/Container/InboxViewContainerController.swift index 2d1b67e58..6bff31380 100644 --- a/FlowCrypt/Controllers/Inbox/Container/InboxViewContainerController.swift +++ b/FlowCrypt/Controllers/Inbox/Container/InboxViewContainerController.swift @@ -107,7 +107,8 @@ final class InboxViewContainerController: TableNodeViewController { let input = InboxViewModel(inbox) let inboxViewController = InboxViewControllerFactory.make( appContext: appContext, - with: input + user: user, + viewModel: input ) navigationController?.setViewControllers([inboxViewController], animated: false) } diff --git a/FlowCrypt/Controllers/Inbox/InboxViewController+Factory.swift b/FlowCrypt/Controllers/Inbox/InboxViewController+Factory.swift index 9c31931bd..ab2778750 100644 --- a/FlowCrypt/Controllers/Inbox/InboxViewController+Factory.swift +++ b/FlowCrypt/Controllers/Inbox/InboxViewController+Factory.swift @@ -11,10 +11,9 @@ import UIKit class InboxViewControllerFactory { @MainActor - static func make(appContext: AppContext, with viewModel: InboxViewModel) -> InboxViewController { + static func make(appContext: AppContext, user: User, viewModel: InboxViewModel) -> InboxViewController { guard - let currentAuthType = appContext.dataService.currentAuthType, - let user = appContext.dataService.currentUser + let currentAuthType = appContext.dataService.currentAuthType else { fatalError("Internal inconsistency") } diff --git a/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift b/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift index a9248b56e..aac3b500d 100644 --- a/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift +++ b/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift @@ -281,7 +281,7 @@ extension MyMenuViewController { switch folder.itemType { case .folder: let input = InboxViewModel(folder) - let viewController = InboxViewControllerFactory.make(appContext: appContext, with: input) + let viewController = InboxViewControllerFactory.make(appContext: appContext, user: user, viewModel: input) if let topController = topController(controllerType: InboxViewController.self), topController.path == folder.path { diff --git a/FlowCrypt/Functionality/Services/AppStartup.swift b/FlowCrypt/Functionality/Services/AppStartup.swift index 72fa46007..58e577cb6 100644 --- a/FlowCrypt/Functionality/Services/AppStartup.swift +++ b/FlowCrypt/Functionality/Services/AppStartup.swift @@ -13,7 +13,7 @@ private let logger = Logger.nested("AppStart") struct AppStartup { private enum EntryPoint { - case signIn, setupFlow(UserId), mainFlow + case signIn, setupFlow(UserId), mainFlow(User) } private let appContext: AppContext @@ -67,8 +67,7 @@ struct AppStartup { let viewController: UIViewController switch entryPoint { - case .mainFlow: - guard let user = appContext.dataService.currentUser else { return } + case .mainFlow(let user): let contentViewController = InboxViewContainerController(appContext: appContext, user: user) viewController = SideMenuNavigationController( appContext: appContext, @@ -89,9 +88,9 @@ struct AppStartup { if !appContext.dataService.isLoggedIn { logger.logInfo("User is not logged in -> signIn") return .signIn - } else if appContext.dataService.isSetupFinished { + } else if appContext.dataService.isSetupFinished, let user = appContext.dataService.currentUser { logger.logInfo("Setup finished -> mainFlow") - return .mainFlow + return .mainFlow(user) } else if let session = appContext.session, let userId = makeUserIdForSetup(session: session) { logger.logInfo("User with session \(session) -> setupFlow") return .setupFlow(userId) diff --git a/FlowCryptAppTests/ExtensionTests.swift b/FlowCryptAppTests/ExtensionTests.swift index d4d9b4e13..c0053ae7b 100644 --- a/FlowCryptAppTests/ExtensionTests.swift +++ b/FlowCryptAppTests/ExtensionTests.swift @@ -79,22 +79,20 @@ extension ExtensionTests { // 18:34 let sameDayDate = Date() let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "HH:mm" let today = Date() - let year = Calendar.current.dateComponents([.year], from: today).year - let sameYearDate = try XCTUnwrap(DateComponents( - calendar: .current, - timeZone: .current, - year: year, - month: 1, - day: 24 - ).date) + let sameYearDate = try XCTUnwrap( + Calendar.current.date(byAdding: .day, value: 1, to: today, wrappingComponents: true) + ) + + dateFormatter.dateFormat = "HH:mm" + XCTAssertEqual(DateFormatter().formatDate(sameDayDate), dateFormatter.string(from: sameDayDate)) + + dateFormatter.dateFormat = "MMM dd" + XCTAssertEqual(DateFormatter().formatDate(sameYearDate), dateFormatter.string(from: sameYearDate)) + // Jan 24, 2020 let otherYearDate = Date(timeIntervalSince1970: 1579883652) - - XCTAssertTrue(dateFormatter.date(from: DateFormatter().formatDate(sameDayDate)) != nil) - XCTAssertEqual(DateFormatter().formatDate(sameYearDate), "00:00") XCTAssertEqual(DateFormatter().formatDate(otherYearDate), "Jan 24, 2020") } } From ed0e8472dd780dade8034d3d560f7103780ac79c Mon Sep 17 00:00:00 2001 From: Ivan Ushakov Date: Tue, 25 Jan 2022 21:52:01 +0300 Subject: [PATCH 3/7] Right version --- FlowCryptAppTests/ExtensionTests.swift | 31 +++++++++++++++++--------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/FlowCryptAppTests/ExtensionTests.swift b/FlowCryptAppTests/ExtensionTests.swift index c0053ae7b..87d9c0f89 100644 --- a/FlowCryptAppTests/ExtensionTests.swift +++ b/FlowCryptAppTests/ExtensionTests.swift @@ -79,20 +79,29 @@ extension ExtensionTests { // 18:34 let sameDayDate = Date() let dateFormatter = DateFormatter() - - let today = Date() - let sameYearDate = try XCTUnwrap( - Calendar.current.date(byAdding: .day, value: 1, to: today, wrappingComponents: true) - ) - dateFormatter.dateFormat = "HH:mm" - XCTAssertEqual(DateFormatter().formatDate(sameDayDate), dateFormatter.string(from: sameDayDate)) - - dateFormatter.dateFormat = "MMM dd" - XCTAssertEqual(DateFormatter().formatDate(sameYearDate), dateFormatter.string(from: sameYearDate)) + let today = Date() + let year = Calendar.current.dateComponents([.year], from: today).year + let sameYearDate = try XCTUnwrap(DateComponents( + calendar: .current, + timeZone: .current, + year: year, + month: 1, + day: 24, + hour: 18, + minute: 34, + second: 9 + ).date) // Jan 24, 2020 let otherYearDate = Date(timeIntervalSince1970: 1579883652) - XCTAssertEqual(DateFormatter().formatDate(otherYearDate), "Jan 24, 2020") + + XCTAssertTrue(dateFormatter.date(from: DateFormatter().formatDate(sameDayDate)) != nil) + if Calendar.current.isDateInToday(sameYearDate) { + XCTAssertEqual(dateFormatter.formatDate(sameYearDate), "18:34") + } else { + XCTAssertEqual(dateFormatter.formatDate(sameYearDate), "Jan 24") + } + XCTAssertEqual(dateFormatter.formatDate(otherYearDate), "Jan 24, 2020") } } From a78b54b250da7d860aaa06814e4898416aa68e53 Mon Sep 17 00:00:00 2001 From: Ivan Ushakov Date: Thu, 27 Jan 2022 23:14:45 +0300 Subject: [PATCH 4/7] UserContext for user and auth type --- FlowCrypt/App/AppContext.swift | 60 +++++++++++++++---- .../Compose/ComposeViewController.swift | 31 +++++----- .../InboxViewContainerController.swift | 16 ++--- .../Inbox/InboxViewController+Factory.swift | 20 ++----- .../Inbox/InboxViewController.swift | 23 ++++--- .../MsgListViewController.swift | 21 ++++--- .../Search/SearchViewController.swift | 13 ++-- .../Key List/KeySettingsViewController.swift | 13 ++-- .../SettingsViewController.swift | 24 +++----- .../Main/SideMenuNavigationController.swift | 4 +- .../SideMenu/Menu/MyMenuViewController.swift | 30 ++++------ .../Threads/ThreadDetailsViewController.swift | 37 ++++++------ .../Functionality/Services/AppStartup.swift | 14 ++--- 13 files changed, 153 insertions(+), 153 deletions(-) diff --git a/FlowCrypt/App/AppContext.swift b/FlowCrypt/App/AppContext.swift index 57da8629f..7c37ccbc1 100644 --- a/FlowCrypt/App/AppContext.swift +++ b/FlowCrypt/App/AppContext.swift @@ -21,7 +21,7 @@ class AppContext { let passPhraseService: PassPhraseServiceType let clientConfigurationService: ClientConfigurationServiceType - private init( + fileprivate init( encryptedStorage: EncryptedStorageType, session: SessionType?, userAccountService: SessionServiceType, @@ -78,16 +78,25 @@ class AppContext { ) } - func withSession(_ session: SessionType?) -> AppContext { - return AppContext( - encryptedStorage: self.encryptedStorage, + func withSession(_ session: SessionType?) -> UserContext { + guard + let authType = dataService.currentAuthType, + let user = dataService.currentUser + else { + fatalError() + } + + return UserContext( + encryptedStorage: encryptedStorage, session: session, - userAccountService: self.userAccountService, - dataService: self.dataService, - keyService: self.keyService, - passPhraseService: self.passPhraseService, - clientConfigurationService: self.clientConfigurationService, - globalRouter: globalRouter + userAccountService: userAccountService, + dataService: dataService, + keyService: keyService, + passPhraseService: passPhraseService, + clientConfigurationService: clientConfigurationService, + globalRouter: globalRouter, + authType: authType, + user: user ) } @@ -130,5 +139,36 @@ class AppContext { remoteFoldersProvider: self.getRequiredMailProvider().remoteFoldersProvider ) } +} +class UserContext: AppContext { + let authType: AuthType + let user: User + + fileprivate init( + encryptedStorage: EncryptedStorageType, + session: SessionType?, + userAccountService: SessionServiceType, + dataService: DataServiceType, + keyService: KeyServiceType, + passPhraseService: PassPhraseServiceType, + clientConfigurationService: ClientConfigurationServiceType, + globalRouter: GlobalRouterType, + authType: AuthType, + user: User + ) { + self.authType = authType + self.user = user + + super.init( + encryptedStorage: encryptedStorage, + session: session, + userAccountService: userAccountService, + dataService: dataService, + keyService: keyService, + passPhraseService: passPhraseService, + clientConfigurationService: clientConfigurationService, + globalRouter: globalRouter + ) + } } diff --git a/FlowCrypt/Controllers/Compose/ComposeViewController.swift b/FlowCrypt/Controllers/Compose/ComposeViewController.swift index 5c33fb595..722876c4b 100644 --- a/FlowCrypt/Controllers/Compose/ComposeViewController.swift +++ b/FlowCrypt/Controllers/Compose/ComposeViewController.swift @@ -43,7 +43,7 @@ final class ComposeViewController: TableNodeViewController { case topDivider, subject, subjectDivider, text } - private let appContext: AppContext + private let userContext: UserContext private let composeMessageService: ComposeMessageService private let notificationCenter: NotificationCenter private let decorator: ComposeViewDecorator @@ -82,7 +82,7 @@ final class ComposeViewController: TableNodeViewController { } init( - appContext: AppContext, + userContext: UserContext, notificationCenter: NotificationCenter = .default, decorator: ComposeViewDecorator = ComposeViewDecorator(), input: ComposeMessageInput = .empty, @@ -93,32 +93,29 @@ final class ComposeViewController: TableNodeViewController { photosManager: PhotosManagerType = PhotosManager(), keyMethods: KeyMethodsType = KeyMethods() ) { - self.appContext = appContext - guard let email = appContext.dataService.email else { - fatalError("missing current user email") // todo - need a more elegant solution - } - self.email = email + self.userContext = userContext + self.email = userContext.user.email self.notificationCenter = notificationCenter self.input = input self.decorator = decorator - let clientConfiguration = appContext.clientConfigurationService.getSaved(for: email) + let clientConfiguration = userContext.clientConfigurationService.getSaved(for: email) self.contactsService = contactsService ?? ContactsService( localContactsProvider: LocalContactsProvider( - encryptedStorage: appContext.encryptedStorage + encryptedStorage: userContext.encryptedStorage ), clientConfiguration: clientConfiguration ) let cloudContactProvider = cloudContactProvider ?? UserContactsProvider( userService: GoogleUserService( - currentUserEmail: email, + currentUserEmail: userContext.user.email, appDelegateGoogleSessionContainer: UIApplication.shared.delegate as? AppDelegate ) ) self.cloudContactProvider = cloudContactProvider self.composeMessageService = composeMessageService ?? ComposeMessageService( clientConfiguration: clientConfiguration, - encryptedStorage: appContext.encryptedStorage, - messageGateway: appContext.getRequiredMailProvider().messageSender + encryptedStorage: userContext.encryptedStorage, + messageGateway: userContext.getRequiredMailProvider().messageSender ) self.filesManager = filesManager self.photosManager = photosManager @@ -128,7 +125,7 @@ final class ComposeViewController: TableNodeViewController { contactsService: self.contactsService, cloudContactProvider: cloudContactProvider ) - self.router = appContext.globalRouter + self.router = userContext.globalRouter self.contextToSend.subject = input.subject self.contextToSend.attachments = input.attachments self.clientConfiguration = clientConfiguration @@ -426,7 +423,7 @@ extension ComposeViewController { extension ComposeViewController { private func prepareSigningKey() async throws -> PrvKeyInfo { - guard let signingKey = try await appContext.keyService.getSigningKey() else { + guard let signingKey = try await userContext.keyService.getSigningKey() else { throw AppErr.general("None of your private keys have your user id \"\(email)\". Please import the appropriate key.") } @@ -468,7 +465,7 @@ extension ComposeViewController { private func handlePassPhraseEntry(_ passPhrase: String, for signingKey: PrvKeyInfo) async throws -> Bool { // since pass phrase was entered (an inconvenient thing for user to do), // let's find all keys that match and save the pass phrase for all - let allKeys = try await appContext.keyService.getPrvKeyInfo() + let allKeys = try await userContext.keyService.getPrvKeyInfo() guard allKeys.isNotEmpty else { // tom - todo - nonsensical error type choice https://github.com/FlowCrypt/flowcrypt-ios/issues/859 // I copied it from another usage, but has to be changed @@ -476,7 +473,7 @@ extension ComposeViewController { } let matchingKeys = try await self.keyMethods.filterByPassPhraseMatch(keys: allKeys, passPhrase: passPhrase) // save passphrase for all matching keys - try appContext.passPhraseService.savePassPhrasesInMemory(passPhrase, for: matchingKeys) + try userContext.passPhraseService.savePassPhrasesInMemory(passPhrase, for: matchingKeys) // now figure out if the pass phrase also matched the signing prv itself let matched = matchingKeys.first(where: { $0.fingerprints.first == signingKey.fingerprints.first }) return matched != nil// true if the pass phrase matched signing key @@ -1313,7 +1310,7 @@ extension ComposeViewController { Task { do { - try await router.askForContactsPermission(for: .gmailLogin(self), appContext: appContext) + try await router.askForContactsPermission(for: .gmailLogin(self), appContext: userContext) node.reloadSections([2], with: .automatic) } catch { handleContactsPermissionError(error) diff --git a/FlowCrypt/Controllers/Inbox/Container/InboxViewContainerController.swift b/FlowCrypt/Controllers/Inbox/Container/InboxViewContainerController.swift index 6bff31380..3502325d9 100644 --- a/FlowCrypt/Controllers/Inbox/Container/InboxViewContainerController.swift +++ b/FlowCrypt/Controllers/Inbox/Container/InboxViewContainerController.swift @@ -29,25 +29,22 @@ final class InboxViewContainerController: TableNodeViewController { case loadedFolders([FolderViewModel]) } - let appContext: AppContext + let userContext: UserContext let foldersService: FoldersServiceType let decorator: InboxViewControllerContainerDecorator - let user: User private var state: State = .loading { didSet { handleNewState() } } init( - appContext: AppContext, - user: User, + userContext: UserContext, foldersService: FoldersServiceType? = nil, decorator: InboxViewControllerContainerDecorator = InboxViewControllerContainerDecorator() ) { - self.appContext = appContext - self.foldersService = foldersService ?? appContext.getFoldersService() + self.userContext = userContext + self.foldersService = foldersService ?? userContext.getFoldersService() self.decorator = decorator - self.user = user super.init(node: TableNode()) node.delegate = self node.dataSource = self @@ -66,7 +63,7 @@ final class InboxViewContainerController: TableNodeViewController { private func fetchInboxFolder() { Task { do { - let folders = try await foldersService.fetchFolders(isForceReload: true, for: user) + let folders = try await foldersService.fetchFolders(isForceReload: true, for: userContext.user) self.handleFetched(folders: folders) } catch { self.state = .error(error) @@ -106,8 +103,7 @@ final class InboxViewContainerController: TableNodeViewController { } let input = InboxViewModel(inbox) let inboxViewController = InboxViewControllerFactory.make( - appContext: appContext, - user: user, + userContext: userContext, viewModel: input ) navigationController?.setViewControllers([inboxViewController], animated: false) diff --git a/FlowCrypt/Controllers/Inbox/InboxViewController+Factory.swift b/FlowCrypt/Controllers/Inbox/InboxViewController+Factory.swift index ab2778750..0e143594c 100644 --- a/FlowCrypt/Controllers/Inbox/InboxViewController+Factory.swift +++ b/FlowCrypt/Controllers/Inbox/InboxViewController+Factory.swift @@ -11,35 +11,27 @@ import UIKit class InboxViewControllerFactory { @MainActor - static func make(appContext: AppContext, user: User, viewModel: InboxViewModel) -> InboxViewController { - guard - let currentAuthType = appContext.dataService.currentAuthType - else { - fatalError("Internal inconsistency") - } - - switch currentAuthType { + static func make(userContext: UserContext, viewModel: InboxViewModel) -> InboxViewController { + switch userContext.authType { case .oAuthGmail: // Inject threads provider - Gmail API - guard let threadsProvider = appContext.getRequiredMailProvider().messagesThreadProvider else { + guard let threadsProvider = userContext.getRequiredMailProvider().messagesThreadProvider else { fatalError("Internal inconsistency") } return InboxViewController( - appContext: appContext, + userContext: userContext, viewModel: viewModel, - user: user, numberOfInboxItemsToLoad: 20, // else timeouts happen provider: InboxMessageThreadsProvider(provider: threadsProvider) ) case .password: // Inject message list provider - IMAP - let provider = InboxMessageListProvider(provider: appContext.getRequiredMailProvider().messageListProvider) + let provider = InboxMessageListProvider(provider: userContext.getRequiredMailProvider().messageListProvider) return InboxViewController( - appContext: appContext, + userContext: userContext, viewModel: viewModel, - user: user, numberOfInboxItemsToLoad: 50, // safe to load 50, single call on IMAP provider: provider ) diff --git a/FlowCrypt/Controllers/Inbox/InboxViewController.swift b/FlowCrypt/Controllers/Inbox/InboxViewController.swift index a62fd8d53..36dd77d73 100644 --- a/FlowCrypt/Controllers/Inbox/InboxViewController.swift +++ b/FlowCrypt/Controllers/Inbox/InboxViewController.swift @@ -13,8 +13,7 @@ final class InboxViewController: ViewController { private let numberOfInboxItemsToLoad: Int - private let appContext: AppContext - private let user: User + private let userContext: UserContext private let service: ServiceActor private let decorator: InboxViewDecorator private let draftsListProvider: DraftsListProvider? @@ -34,21 +33,19 @@ final class InboxViewController: ViewController { var path: String { viewModel.path } init( - appContext: AppContext, + userContext: UserContext, viewModel: InboxViewModel, - user: User, numberOfInboxItemsToLoad: Int = 50, provider: InboxDataProvider, draftsListProvider: DraftsListProvider? = nil, decorator: InboxViewDecorator = InboxViewDecorator() ) { - self.user = user - self.appContext = appContext + self.userContext = userContext self.viewModel = viewModel self.numberOfInboxItemsToLoad = numberOfInboxItemsToLoad self.service = ServiceActor(inboxDataProvider: provider) - self.draftsListProvider = draftsListProvider ?? appContext.getRequiredMailProvider().draftsProvider + self.draftsListProvider = draftsListProvider ?? userContext.getRequiredMailProvider().draftsProvider self.decorator = decorator self.tableNode = TableNode() @@ -124,7 +121,7 @@ extension InboxViewController { // MARK: - Helpers extension InboxViewController { private func currentMessagesListPagination(from number: Int? = nil) -> MessagesListPagination { - appContext + userContext .getRequiredMailProvider() .currentMessagesListPagination(from: number, token: state.token) } @@ -184,7 +181,7 @@ extension InboxViewController { folderPath: viewModel.path, count: numberOfInboxItemsToLoad, pagination: currentMessagesListPagination() - ), userEmail: user.email + ), userEmail: userContext.user.email ) handleEndFetching(with: context, context: batchContext) } catch { @@ -206,7 +203,7 @@ extension InboxViewController { folderPath: viewModel.path, count: messagesToLoad(), pagination: pagination - ), userEmail: user.email + ), userEmail: userContext.user.email ) state = .fetched(context.pagination) handleEndFetching(with: context, context: batchContext) @@ -328,7 +325,7 @@ extension InboxViewController { } private func handleSearchTap() { - let viewController = SearchViewController(appContext: appContext, user: user, folderPath: viewModel.path) + let viewController = SearchViewController(userContext: userContext, folderPath: viewModel.path) navigationController?.pushViewController(viewController, animated: false) } @@ -340,7 +337,7 @@ extension InboxViewController { private func btnComposeTap() { TapTicFeedback.generate(.light) - let composeVc = ComposeViewController(appContext: appContext) + let composeVc = ComposeViewController(userContext: userContext) navigationController?.pushViewController(composeVc, animated: true) } } @@ -368,7 +365,7 @@ extension InboxViewController: ASTableDataSource, ASTableDelegate { func tableNode(_ tableNode: ASTableNode, didSelectRowAt indexPath: IndexPath) { tableNode.deselectRow(at: indexPath, animated: true) - open(with: inboxInput[indexPath.row], path: viewModel.path, appContext: appContext, user: user) + open(with: inboxInput[indexPath.row], path: viewModel.path, userContext: userContext) } private func cellNode(for indexPath: IndexPath, and size: CGSize) -> ASCellNodeBlock { diff --git a/FlowCrypt/Controllers/MessageList Extension/MsgListViewController.swift b/FlowCrypt/Controllers/MessageList Extension/MsgListViewController.swift index fc15a8f77..b8f01f13f 100644 --- a/FlowCrypt/Controllers/MessageList Extension/MsgListViewController.swift +++ b/FlowCrypt/Controllers/MessageList Extension/MsgListViewController.swift @@ -10,7 +10,7 @@ import UIKit @MainActor protocol MsgListViewController { - func open(with message: InboxRenderable, path: String, appContext: AppContext, user: User) + func open(with message: InboxRenderable, path: String, userContext: UserContext) func getUpdatedIndex(for message: InboxRenderable) -> Int? func updateMessage(isRead: Bool, at index: Int) @@ -20,36 +20,35 @@ protocol MsgListViewController { extension MsgListViewController where Self: UIViewController { // todo - tom - don't know how to add AppContext into init of protocol/extension - func open(with message: InboxRenderable, path: String, appContext: AppContext, user: User) { + func open(with message: InboxRenderable, path: String, userContext: UserContext) { switch message.wrappedType { case .message(let message): - openMsg(appContext: appContext, user: user, with: message, path: path) + openMsg(userContext: userContext, with: message, path: path) case .thread(let thread): - openThread(with: thread, appContext: appContext, user: user) + openThread(with: thread, userContext: userContext) } } // TODO: uncomment in "sent message from draft" feature - private func openDraft(appContext: AppContext, with message: Message) { - let controller = ComposeViewController(appContext: appContext) + private func openDraft(userContext: UserContext, with message: Message) { + let controller = ComposeViewController(userContext: userContext) controller.update(with: message) navigationController?.pushViewController(controller, animated: true) } - private func openMsg(appContext: AppContext, user: User, with message: Message, path: String) { + private func openMsg(userContext: UserContext, with message: Message, path: String) { let thread = MessageThread( identifier: message.threadId, snippet: nil, path: path, messages: [message] ) - openThread(with: thread, appContext: appContext, user: user) + openThread(with: thread, userContext: userContext) } - private func openThread(with thread: MessageThread, appContext: AppContext, user: User) { + private func openThread(with thread: MessageThread, userContext: UserContext) { let viewController = ThreadDetailsViewController( - appContext: appContext, - user: user, + userContext: userContext, thread: thread ) { [weak self] (action, message) in self?.handleMessageOperation(with: message, action: action) diff --git a/FlowCrypt/Controllers/Search/SearchViewController.swift b/FlowCrypt/Controllers/Search/SearchViewController.swift index 7997bb5dc..cae7a7186 100644 --- a/FlowCrypt/Controllers/Search/SearchViewController.swift +++ b/FlowCrypt/Controllers/Search/SearchViewController.swift @@ -41,22 +41,19 @@ final class SearchViewController: TableNodeViewController { // TODO: - https://github.com/FlowCrypt/flowcrypt-ios/issues/669 Adopt to gmail threads private let service: ServiceActor private var searchTask: DispatchWorkItem? - private let appContext: AppContext + private let userContext: UserContext private let searchController = UISearchController(searchResultsController: nil) private let folderPath: String private var searchedExpression: String = "" - private let user: User init( - appContext: AppContext, - user: User, + userContext: UserContext, searchProvider: MessageSearchProvider? = nil, folderPath: String ) { - self.user = user - self.appContext = appContext + self.userContext = userContext self.service = ServiceActor( - searchProvider: searchProvider ?? appContext.getRequiredMailProvider().messageSearchProvider + searchProvider: searchProvider ?? userContext.getRequiredMailProvider().messageSearchProvider ) self.folderPath = folderPath super.init(node: TableNode()) @@ -220,7 +217,7 @@ extension SearchViewController: ASTableDataSource, ASTableDelegate { guard let message = state.messages[safe: indexPath.row] else { return } // TODO: - https://github.com/FlowCrypt/flowcrypt-ios/issues/669 - cleanup - open(with: .init(message: message), path: folderPath, appContext: appContext, user: user) + open(with: .init(message: message), path: folderPath, userContext: userContext) } } diff --git a/FlowCrypt/Controllers/Settings/KeySettings/Key List/KeySettingsViewController.swift b/FlowCrypt/Controllers/Settings/KeySettings/Key List/KeySettingsViewController.swift index 5f97d36fc..56a73eb20 100644 --- a/FlowCrypt/Controllers/Settings/KeySettings/Key List/KeySettingsViewController.swift +++ b/FlowCrypt/Controllers/Settings/KeySettings/Key List/KeySettingsViewController.swift @@ -17,19 +17,18 @@ import FlowCryptUI */ final class KeySettingsViewController: TableNodeViewController { - private let appContext: AppContext + private let userContext: UserContext private var keys: [KeyDetails] = [] private let decorator: KeySettingsViewDecorator private let isUsingKeyManager: Bool init( - appContext: AppContext, - user: User, + userContext: UserContext, decorator: KeySettingsViewDecorator = KeySettingsViewDecorator() ) { - self.appContext = appContext + self.userContext = userContext self.decorator = decorator - self.isUsingKeyManager = appContext.clientConfigurationService.getSaved(for: user.email).isUsingKeyManager + self.isUsingKeyManager = userContext.clientConfigurationService.getSaved(for: userContext.user.email).isUsingKeyManager super.init(node: TableNode()) } @@ -72,14 +71,14 @@ final class KeySettingsViewController: TableNodeViewController { extension KeySettingsViewController { private func loadKeysFromStorageAndRender() async throws { - self.keys = try await appContext.keyService.getPrvKeyDetails() + self.keys = try await userContext.keyService.getPrvKeyDetails() await node.reloadData() } } extension KeySettingsViewController { @objc private func handleAddButtonTap() { - navigationController?.pushViewController(SetupManuallyImportKeyViewController(appContext: appContext), animated: true) + navigationController?.pushViewController(SetupManuallyImportKeyViewController(appContext: userContext), animated: true) } } diff --git a/FlowCrypt/Controllers/Settings/Settings List/SettingsViewController.swift b/FlowCrypt/Controllers/Settings/Settings List/SettingsViewController.swift index 5dca5243b..3c8161c9c 100644 --- a/FlowCrypt/Controllers/Settings/Settings List/SettingsViewController.swift +++ b/FlowCrypt/Controllers/Settings/Settings List/SettingsViewController.swift @@ -43,21 +43,18 @@ final class SettingsViewController: TableNodeViewController { } } - private let appContext: AppContext - private let user: User + private let userContext: UserContext private let decorator: SettingsViewDecorator private let clientConfiguration: ClientConfiguration private let rows: [SettingsMenuItem] init( - appContext: AppContext, - user: User, + userContext: UserContext, decorator: SettingsViewDecorator = SettingsViewDecorator() ) { - self.appContext = appContext - self.user = user + self.userContext = userContext self.decorator = decorator - self.clientConfiguration = appContext.clientConfigurationService.getSaved(for: user.email) + self.clientConfiguration = userContext.clientConfigurationService.getSaved(for: userContext.user.email) self.rows = SettingsMenuItem.filtered(with: self.clientConfiguration) super.init(node: TableNode()) } @@ -116,23 +113,18 @@ extension SettingsViewController { switch setting { case .keys: - viewController = KeySettingsViewController( - appContext: appContext, - user: user - ) + viewController = KeySettingsViewController(userContext: userContext) case .legal: viewController = LegalViewController() case .contacts: - viewController = ContactsListViewController( - appContext: appContext - ) + viewController = ContactsListViewController(appContext: userContext) case .backups: guard clientConfiguration.canBackupKeys else { viewController = nil return } - let userId = UserId(email: user.email, name: user.email) - viewController = BackupViewController(appContext: appContext, userId: userId) + let userId = UserId(email: userContext.user.email, name: userContext.user.email) + viewController = BackupViewController(appContext: userContext, userId: userId) default: viewController = nil } diff --git a/FlowCrypt/Controllers/SideMenu/Main/SideMenuNavigationController.swift b/FlowCrypt/Controllers/SideMenu/Main/SideMenuNavigationController.swift index b03d97b2f..7883cc3b1 100644 --- a/FlowCrypt/Controllers/SideMenu/Main/SideMenuNavigationController.swift +++ b/FlowCrypt/Controllers/SideMenu/Main/SideMenuNavigationController.swift @@ -48,8 +48,8 @@ final class SideMenuNavigationController: ENSideMenuNavigationController { private var menuViewContoller: SideMenuViewController? - convenience init(appContext: AppContext, user: User, contentViewController: UIViewController) { - let menu = MyMenuViewController(appContext: appContext, user: user) + convenience init(userContext: UserContext, contentViewController: UIViewController) { + let menu = MyMenuViewController(userContext: userContext) self.init(menuViewController: menu, contentViewController: contentViewController) menuViewContoller = menu sideMenu = ENSideMenu(sourceView: view, menuViewController: menu, menuPosition: .left).then { diff --git a/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift b/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift index aac3b500d..4014fa6d0 100644 --- a/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift +++ b/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift @@ -43,16 +43,15 @@ final class MyMenuViewController: ViewController { } } - private let appContext: AppContext + private let userContext: UserContext private let foldersService: FoldersServiceType private let decorator: MyMenuViewDecorator private var folders: [FolderViewModel] = [] private var serviceItems: [FolderViewModel] { FolderViewModel.menuItems } private var accounts: [User] { - appContext.dataService.getFinishedSetupUsers(exceptUserEmail: user.email) + userContext.dataService.getFinishedSetupUsers(exceptUserEmail: userContext.user.email) } - private let user: User private let tableNode: ASTableNode @@ -66,14 +65,12 @@ final class MyMenuViewController: ViewController { private var isFirstLaunch = true init( - appContext: AppContext, - user: User, + userContext: UserContext, decorator: MyMenuViewDecorator = MyMenuViewDecorator(), tableNode: ASTableNode = TableNode() ) { - self.user = user - self.appContext = appContext - self.foldersService = appContext.getFoldersService() + self.userContext = userContext + self.foldersService = userContext.getFoldersService() self.decorator = decorator self.tableNode = tableNode super.init(node: ASDisplayNode()) @@ -174,7 +171,7 @@ extension MyMenuViewController { showSpinner() Task { do { - let folders = try await foldersService.fetchFolders(isForceReload: true, for: user) + let folders = try await foldersService.fetchFolders(isForceReload: true, for: userContext.user) handleNewFolders(with: folders) } catch { handleError(with: error) @@ -210,7 +207,7 @@ extension MyMenuViewController { // MARK: - Account functionality extension MyMenuViewController { private func addAccount() { - let vc = MainNavigationController(rootViewController: SignInViewController(appContext: appContext)) + let vc = MainNavigationController(rootViewController: SignInViewController(appContext: userContext)) present(vc, animated: true, completion: nil) } @@ -220,7 +217,7 @@ extension MyMenuViewController { } do { - try appContext.globalRouter.switchActive(user: account, appContext: appContext) + try userContext.globalRouter.switchActive(user: account, appContext: userContext) } catch { showAlert(message: error.localizedDescription) } @@ -248,7 +245,7 @@ extension MyMenuViewController { private func node(for section: Sections, row: Int) -> ASCellNode { switch (section, state) { case (.header, _): - let headerInput = decorator.header(for: user, image: state.arrowImage) + let headerInput = decorator.header(for: userContext.user, image: state.arrowImage) return TextImageNode(input: headerInput) { [weak self] node in self?.handleTapOn(header: node) } @@ -281,7 +278,7 @@ extension MyMenuViewController { switch folder.itemType { case .folder: let input = InboxViewModel(folder) - let viewController = InboxViewControllerFactory.make(appContext: appContext, user: user, viewModel: input) + let viewController = InboxViewControllerFactory.make(userContext: userContext, viewModel: input) if let topController = topController(controllerType: InboxViewController.self), topController.path == folder.path { @@ -295,13 +292,10 @@ extension MyMenuViewController { sideMenuController()?.sideMenu?.hideSideMenu() return } - sideMenuController()?.setContentViewController(SettingsViewController( - appContext: appContext, - user: user - )) + sideMenuController()?.setContentViewController(SettingsViewController(userContext: userContext)) case .logOut: do { - try appContext.globalRouter.signOut(appContext: appContext) + try userContext.globalRouter.signOut(appContext: userContext) } catch { showAlert(message: error.localizedDescription) } diff --git a/FlowCrypt/Controllers/Threads/ThreadDetailsViewController.swift b/FlowCrypt/Controllers/Threads/ThreadDetailsViewController.swift index 9f47f1cf6..2bb9578b6 100644 --- a/FlowCrypt/Controllers/Threads/ThreadDetailsViewController.swift +++ b/FlowCrypt/Controllers/Threads/ThreadDetailsViewController.swift @@ -32,13 +32,12 @@ final class ThreadDetailsViewController: TableNodeViewController { case thread, message } - private let appContext: AppContext + private let userContext: UserContext private let messageService: MessageService private let messageOperationsProvider: MessageOperationsProvider private let threadOperationsProvider: MessagesThreadOperationsProvider private let thread: MessageThread private var input: [ThreadDetailsViewController.Input] - private let user: User let trashFolderProvider: TrashFolderProviderType var currentFolderPath: String { @@ -47,36 +46,34 @@ final class ThreadDetailsViewController: TableNodeViewController { private let onComplete: MessageActionCompletion init( - appContext: AppContext, - user: User, + userContext: UserContext, messageService: MessageService? = nil, thread: MessageThread, completion: @escaping MessageActionCompletion ) { - self.appContext = appContext - self.user = user - let clientConfiguration = appContext.clientConfigurationService.getSaved(for: user.email) + self.userContext = userContext + let clientConfiguration = userContext.clientConfigurationService.getSaved(for: userContext.user.email) self.messageService = messageService ?? MessageService( contactsService: ContactsService( localContactsProvider: LocalContactsProvider( - encryptedStorage: appContext.encryptedStorage + encryptedStorage: userContext.encryptedStorage ), clientConfiguration: clientConfiguration ), - keyService: appContext.keyService, - messageProvider: appContext.getRequiredMailProvider().messageProvider, - passPhraseService: appContext.passPhraseService + keyService: userContext.keyService, + messageProvider: userContext.getRequiredMailProvider().messageProvider, + passPhraseService: userContext.passPhraseService ) - guard let threadOperationsProvider = appContext.getRequiredMailProvider().threadOperationsProvider else { + guard let threadOperationsProvider = userContext.getRequiredMailProvider().threadOperationsProvider else { fatalError("expected threadOperationsProvider on gmail") } self.threadOperationsProvider = threadOperationsProvider - self.messageOperationsProvider = appContext.getRequiredMailProvider().messageOperationsProvider + self.messageOperationsProvider = userContext.getRequiredMailProvider().messageOperationsProvider self.trashFolderProvider = TrashFolderProvider( - user: user, + user: userContext.user, foldersService: FoldersService( - encryptedStorage: appContext.encryptedStorage, - remoteFoldersProvider: appContext.getRequiredMailProvider().remoteFoldersProvider + encryptedStorage: userContext.encryptedStorage, + remoteFoldersProvider: userContext.getRequiredMailProvider().remoteFoldersProvider ) ) self.thread = thread @@ -98,7 +95,7 @@ final class ThreadDetailsViewController: TableNodeViewController { node.delegate = self node.dataSource = self - setupNavigationBar(user: user) + setupNavigationBar(user: userContext.user) expandThreadMessage() } } @@ -239,7 +236,7 @@ extension ThreadDetailsViewController { let composeInput = ComposeMessageInput(type: .quote(replyInfo)) navigationController?.pushViewController( - ComposeViewController(appContext: appContext, input: composeInput), + ComposeViewController(userContext: userContext, input: composeInput), animated: true ) } @@ -449,7 +446,7 @@ extension ThreadDetailsViewController: MessageActionsHandler { private func handleSuccessfulMessage(action: MessageAction) { hideSpinner() - onComplete(action, .init(thread: thread, folderPath: currentFolderPath, activeUserEmail: user.email)) + onComplete(action, .init(thread: thread, folderPath: currentFolderPath, activeUserEmail: userContext.user.email)) navigationController?.popViewController(animated: true) } @@ -589,7 +586,7 @@ extension ThreadDetailsViewController: NavigationChildController { func handleBackButtonTap() { let isRead = input.contains(where: { $0.rawMessage.isMessageRead }) logger.logInfo("Back button. Are all messages read \(isRead)") - onComplete(MessageAction.markAsRead(isRead), .init(thread: thread, folderPath: currentFolderPath, activeUserEmail: self.user.email)) + onComplete(MessageAction.markAsRead(isRead), .init(thread: thread, folderPath: currentFolderPath, activeUserEmail: userContext.user.email)) navigationController?.popViewController(animated: true) } } diff --git a/FlowCrypt/Functionality/Services/AppStartup.swift b/FlowCrypt/Functionality/Services/AppStartup.swift index 58e577cb6..bbe0e95f8 100644 --- a/FlowCrypt/Functionality/Services/AppStartup.swift +++ b/FlowCrypt/Functionality/Services/AppStartup.swift @@ -13,7 +13,7 @@ private let logger = Logger.nested("AppStart") struct AppStartup { private enum EntryPoint { - case signIn, setupFlow(UserId), mainFlow(User) + case signIn, setupFlow(UserId), mainFlow } private let appContext: AppContext @@ -67,11 +67,11 @@ struct AppStartup { let viewController: UIViewController switch entryPoint { - case .mainFlow(let user): - let contentViewController = InboxViewContainerController(appContext: appContext, user: user) + case .mainFlow: + let userContext = appContext.withSession(appContext.session) + let contentViewController = InboxViewContainerController(userContext: userContext) viewController = SideMenuNavigationController( - appContext: appContext, - user: user, + userContext: userContext, contentViewController: contentViewController ) case .signIn: @@ -88,9 +88,9 @@ struct AppStartup { if !appContext.dataService.isLoggedIn { logger.logInfo("User is not logged in -> signIn") return .signIn - } else if appContext.dataService.isSetupFinished, let user = appContext.dataService.currentUser { + } else if appContext.dataService.isSetupFinished, appContext.dataService.currentUser != nil { logger.logInfo("Setup finished -> mainFlow") - return .mainFlow(user) + return .mainFlow } else if let session = appContext.session, let userId = makeUserIdForSetup(session: session) { logger.logInfo("User with session \(session) -> setupFlow") return .setupFlow(userId) From c11bed293c8a160ac8802afaaa16dbfca154deb3 Mon Sep 17 00:00:00 2001 From: Ivan Ushakov Date: Thu, 27 Jan 2022 23:35:02 +0300 Subject: [PATCH 5/7] UserContext for user and auth type --- FlowCrypt/App/AppContext.swift | 4 +-- .../Compose/ComposeViewController.swift | 35 +++++++++---------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/FlowCrypt/App/AppContext.swift b/FlowCrypt/App/AppContext.swift index 7c37ccbc1..a624ec983 100644 --- a/FlowCrypt/App/AppContext.swift +++ b/FlowCrypt/App/AppContext.swift @@ -21,7 +21,7 @@ class AppContext { let passPhraseService: PassPhraseServiceType let clientConfigurationService: ClientConfigurationServiceType - fileprivate init( + init( encryptedStorage: EncryptedStorageType, session: SessionType?, userAccountService: SessionServiceType, @@ -145,7 +145,7 @@ class UserContext: AppContext { let authType: AuthType let user: User - fileprivate init( + init( encryptedStorage: EncryptedStorageType, session: SessionType?, userAccountService: SessionServiceType, diff --git a/FlowCrypt/Controllers/Compose/ComposeViewController.swift b/FlowCrypt/Controllers/Compose/ComposeViewController.swift index 82554dc49..587a66f1f 100644 --- a/FlowCrypt/Controllers/Compose/ComposeViewController.swift +++ b/FlowCrypt/Controllers/Compose/ComposeViewController.swift @@ -49,7 +49,7 @@ final class ComposeViewController: TableNodeViewController { case topDivider, subject, subjectDivider, text } - private let appContext: AppContext + private let userContext: UserContext private let composeMessageService: ComposeMessageService private let notificationCenter: NotificationCenter private let decorator: ComposeViewDecorator @@ -88,7 +88,7 @@ final class ComposeViewController: TableNodeViewController { } init( - appContext: AppContext, + userContext: UserContext, notificationCenter: NotificationCenter = .default, decorator: ComposeViewDecorator = ComposeViewDecorator(), input: ComposeMessageInput = .empty, @@ -99,34 +99,31 @@ final class ComposeViewController: TableNodeViewController { photosManager: PhotosManagerType = PhotosManager(), keyMethods: KeyMethodsType = KeyMethods() ) { - self.appContext = appContext - guard let email = appContext.dataService.email else { - fatalError("missing current user email") // todo - need a more elegant solution - } - self.email = email + self.userContext = userContext + self.email = userContext.user.email self.notificationCenter = notificationCenter self.input = input self.decorator = decorator - let clientConfiguration = appContext.clientConfigurationService.getSaved(for: email) + let clientConfiguration = userContext.clientConfigurationService.getSaved(for: userContext.user.email) self.contactsService = contactsService ?? ContactsService( localContactsProvider: LocalContactsProvider( - encryptedStorage: appContext.encryptedStorage + encryptedStorage: userContext.encryptedStorage ), clientConfiguration: clientConfiguration ) let cloudContactProvider = cloudContactProvider ?? UserContactsProvider( userService: GoogleUserService( - currentUserEmail: email, + currentUserEmail: userContext.user.email, appDelegateGoogleSessionContainer: UIApplication.shared.delegate as? AppDelegate ) ) self.cloudContactProvider = cloudContactProvider self.composeMessageService = composeMessageService ?? ComposeMessageService( clientConfiguration: clientConfiguration, - encryptedStorage: appContext.encryptedStorage, - messageGateway: appContext.getRequiredMailProvider().messageSender, - passPhraseService: appContext.passPhraseService, - sender: email + encryptedStorage: userContext.encryptedStorage, + messageGateway: userContext.getRequiredMailProvider().messageSender, + passPhraseService: userContext.passPhraseService, + sender: userContext.user.email ) self.filesManager = filesManager self.photosManager = photosManager @@ -136,7 +133,7 @@ final class ComposeViewController: TableNodeViewController { contactsService: self.contactsService, cloudContactProvider: cloudContactProvider ) - self.router = appContext.globalRouter + self.router = userContext.globalRouter self.contextToSend.subject = input.subject self.contextToSend.attachments = input.attachments self.clientConfiguration = clientConfiguration @@ -433,7 +430,7 @@ extension ComposeViewController { extension ComposeViewController { private func prepareSigningKey() async throws -> PrvKeyInfo { - guard let signingKey = try await appContext.keyService.getSigningKey() else { + guard let signingKey = try await userContext.keyService.getSigningKey() else { throw AppErr.general("None of your private keys have your user id \"\(email)\". Please import the appropriate key.") } @@ -475,7 +472,7 @@ extension ComposeViewController { private func handlePassPhraseEntry(_ passPhrase: String, for signingKey: PrvKeyInfo) async throws -> Bool { // since pass phrase was entered (an inconvenient thing for user to do), // let's find all keys that match and save the pass phrase for all - let allKeys = try await appContext.keyService.getPrvKeyInfo() + let allKeys = try await userContext.keyService.getPrvKeyInfo() guard allKeys.isNotEmpty else { // tom - todo - nonsensical error type choice https://github.com/FlowCrypt/flowcrypt-ios/issues/859 // I copied it from another usage, but has to be changed @@ -483,7 +480,7 @@ extension ComposeViewController { } let matchingKeys = try await self.keyMethods.filterByPassPhraseMatch(keys: allKeys, passPhrase: passPhrase) // save passphrase for all matching keys - try appContext.passPhraseService.savePassPhrasesInMemory(passPhrase, for: matchingKeys) + try userContext.passPhraseService.savePassPhrasesInMemory(passPhrase, for: matchingKeys) // now figure out if the pass phrase also matched the signing prv itself let matched = matchingKeys.first(where: { $0.fingerprints.first == signingKey.fingerprints.first }) return matched != nil// true if the pass phrase matched signing key @@ -1347,7 +1344,7 @@ extension ComposeViewController { Task { do { - try await router.askForContactsPermission(for: .gmailLogin(self), appContext: appContext) + try await router.askForContactsPermission(for: .gmailLogin(self), appContext: userContext) node.reloadSections([2], with: .automatic) } catch { handleContactsPermissionError(error) From a638ca1fe3f48c3893d6442f435f1f09f9327fec Mon Sep 17 00:00:00 2001 From: Ivan Ushakov Date: Fri, 28 Jan 2022 18:52:47 +0300 Subject: [PATCH 6/7] Rename UserContext to AppContextWithUser --- FlowCrypt/App/AppContext.swift | 6 ++-- .../Compose/ComposeViewController.swift | 32 ++++++++--------- .../InboxViewContainerController.swift | 12 +++---- .../Inbox/InboxViewController+Factory.swift | 12 +++---- .../Inbox/InboxViewController.swift | 20 +++++------ .../MsgListViewController.swift | 20 +++++------ .../Search/SearchViewController.swift | 10 +++--- .../Key List/KeySettingsViewController.swift | 12 +++---- .../SettingsViewController.swift | 18 +++++----- .../Main/SideMenuNavigationController.swift | 4 +-- .../SideMenu/Menu/MyMenuViewController.swift | 24 ++++++------- .../Threads/ThreadDetailsViewController.swift | 34 +++++++++---------- .../Functionality/Services/AppStartup.swift | 6 ++-- 13 files changed, 105 insertions(+), 105 deletions(-) diff --git a/FlowCrypt/App/AppContext.swift b/FlowCrypt/App/AppContext.swift index a624ec983..3ae59c461 100644 --- a/FlowCrypt/App/AppContext.swift +++ b/FlowCrypt/App/AppContext.swift @@ -78,7 +78,7 @@ class AppContext { ) } - func withSession(_ session: SessionType?) -> UserContext { + func withSession(_ session: SessionType?) -> AppContextWithUser { guard let authType = dataService.currentAuthType, let user = dataService.currentUser @@ -86,7 +86,7 @@ class AppContext { fatalError() } - return UserContext( + return AppContextWithUser( encryptedStorage: encryptedStorage, session: session, userAccountService: userAccountService, @@ -141,7 +141,7 @@ class AppContext { } } -class UserContext: AppContext { +class AppContextWithUser: AppContext { let authType: AuthType let user: User diff --git a/FlowCrypt/Controllers/Compose/ComposeViewController.swift b/FlowCrypt/Controllers/Compose/ComposeViewController.swift index 587a66f1f..8791105c8 100644 --- a/FlowCrypt/Controllers/Compose/ComposeViewController.swift +++ b/FlowCrypt/Controllers/Compose/ComposeViewController.swift @@ -49,7 +49,7 @@ final class ComposeViewController: TableNodeViewController { case topDivider, subject, subjectDivider, text } - private let userContext: UserContext + private let appContext: AppContextWithUser private let composeMessageService: ComposeMessageService private let notificationCenter: NotificationCenter private let decorator: ComposeViewDecorator @@ -88,7 +88,7 @@ final class ComposeViewController: TableNodeViewController { } init( - userContext: UserContext, + appContext: AppContextWithUser, notificationCenter: NotificationCenter = .default, decorator: ComposeViewDecorator = ComposeViewDecorator(), input: ComposeMessageInput = .empty, @@ -99,31 +99,31 @@ final class ComposeViewController: TableNodeViewController { photosManager: PhotosManagerType = PhotosManager(), keyMethods: KeyMethodsType = KeyMethods() ) { - self.userContext = userContext - self.email = userContext.user.email + self.appContext = appContext + self.email = appContext.user.email self.notificationCenter = notificationCenter self.input = input self.decorator = decorator - let clientConfiguration = userContext.clientConfigurationService.getSaved(for: userContext.user.email) + let clientConfiguration = appContext.clientConfigurationService.getSaved(for: appContext.user.email) self.contactsService = contactsService ?? ContactsService( localContactsProvider: LocalContactsProvider( - encryptedStorage: userContext.encryptedStorage + encryptedStorage: appContext.encryptedStorage ), clientConfiguration: clientConfiguration ) let cloudContactProvider = cloudContactProvider ?? UserContactsProvider( userService: GoogleUserService( - currentUserEmail: userContext.user.email, + currentUserEmail: appContext.user.email, appDelegateGoogleSessionContainer: UIApplication.shared.delegate as? AppDelegate ) ) self.cloudContactProvider = cloudContactProvider self.composeMessageService = composeMessageService ?? ComposeMessageService( clientConfiguration: clientConfiguration, - encryptedStorage: userContext.encryptedStorage, - messageGateway: userContext.getRequiredMailProvider().messageSender, - passPhraseService: userContext.passPhraseService, - sender: userContext.user.email + encryptedStorage: appContext.encryptedStorage, + messageGateway: appContext.getRequiredMailProvider().messageSender, + passPhraseService: appContext.passPhraseService, + sender: appContext.user.email ) self.filesManager = filesManager self.photosManager = photosManager @@ -133,7 +133,7 @@ final class ComposeViewController: TableNodeViewController { contactsService: self.contactsService, cloudContactProvider: cloudContactProvider ) - self.router = userContext.globalRouter + self.router = appContext.globalRouter self.contextToSend.subject = input.subject self.contextToSend.attachments = input.attachments self.clientConfiguration = clientConfiguration @@ -430,7 +430,7 @@ extension ComposeViewController { extension ComposeViewController { private func prepareSigningKey() async throws -> PrvKeyInfo { - guard let signingKey = try await userContext.keyService.getSigningKey() else { + guard let signingKey = try await appContext.keyService.getSigningKey() else { throw AppErr.general("None of your private keys have your user id \"\(email)\". Please import the appropriate key.") } @@ -472,7 +472,7 @@ extension ComposeViewController { private func handlePassPhraseEntry(_ passPhrase: String, for signingKey: PrvKeyInfo) async throws -> Bool { // since pass phrase was entered (an inconvenient thing for user to do), // let's find all keys that match and save the pass phrase for all - let allKeys = try await userContext.keyService.getPrvKeyInfo() + let allKeys = try await appContext.keyService.getPrvKeyInfo() guard allKeys.isNotEmpty else { // tom - todo - nonsensical error type choice https://github.com/FlowCrypt/flowcrypt-ios/issues/859 // I copied it from another usage, but has to be changed @@ -480,7 +480,7 @@ extension ComposeViewController { } let matchingKeys = try await self.keyMethods.filterByPassPhraseMatch(keys: allKeys, passPhrase: passPhrase) // save passphrase for all matching keys - try userContext.passPhraseService.savePassPhrasesInMemory(passPhrase, for: matchingKeys) + try appContext.passPhraseService.savePassPhrasesInMemory(passPhrase, for: matchingKeys) // now figure out if the pass phrase also matched the signing prv itself let matched = matchingKeys.first(where: { $0.fingerprints.first == signingKey.fingerprints.first }) return matched != nil// true if the pass phrase matched signing key @@ -1344,7 +1344,7 @@ extension ComposeViewController { Task { do { - try await router.askForContactsPermission(for: .gmailLogin(self), appContext: userContext) + try await router.askForContactsPermission(for: .gmailLogin(self), appContext: appContext) node.reloadSections([2], with: .automatic) } catch { handleContactsPermissionError(error) diff --git a/FlowCrypt/Controllers/Inbox/Container/InboxViewContainerController.swift b/FlowCrypt/Controllers/Inbox/Container/InboxViewContainerController.swift index 3502325d9..5daa408cc 100644 --- a/FlowCrypt/Controllers/Inbox/Container/InboxViewContainerController.swift +++ b/FlowCrypt/Controllers/Inbox/Container/InboxViewContainerController.swift @@ -29,7 +29,7 @@ final class InboxViewContainerController: TableNodeViewController { case loadedFolders([FolderViewModel]) } - let userContext: UserContext + let appContext: AppContextWithUser let foldersService: FoldersServiceType let decorator: InboxViewControllerContainerDecorator @@ -38,12 +38,12 @@ final class InboxViewContainerController: TableNodeViewController { } init( - userContext: UserContext, + appContext: AppContextWithUser, foldersService: FoldersServiceType? = nil, decorator: InboxViewControllerContainerDecorator = InboxViewControllerContainerDecorator() ) { - self.userContext = userContext - self.foldersService = foldersService ?? userContext.getFoldersService() + self.appContext = appContext + self.foldersService = foldersService ?? appContext.getFoldersService() self.decorator = decorator super.init(node: TableNode()) node.delegate = self @@ -63,7 +63,7 @@ final class InboxViewContainerController: TableNodeViewController { private func fetchInboxFolder() { Task { do { - let folders = try await foldersService.fetchFolders(isForceReload: true, for: userContext.user) + let folders = try await foldersService.fetchFolders(isForceReload: true, for: appContext.user) self.handleFetched(folders: folders) } catch { self.state = .error(error) @@ -103,7 +103,7 @@ final class InboxViewContainerController: TableNodeViewController { } let input = InboxViewModel(inbox) let inboxViewController = InboxViewControllerFactory.make( - userContext: userContext, + appContext: appContext, viewModel: input ) navigationController?.setViewControllers([inboxViewController], animated: false) diff --git a/FlowCrypt/Controllers/Inbox/InboxViewController+Factory.swift b/FlowCrypt/Controllers/Inbox/InboxViewController+Factory.swift index 0e143594c..caf2e8f57 100644 --- a/FlowCrypt/Controllers/Inbox/InboxViewController+Factory.swift +++ b/FlowCrypt/Controllers/Inbox/InboxViewController+Factory.swift @@ -11,26 +11,26 @@ import UIKit class InboxViewControllerFactory { @MainActor - static func make(userContext: UserContext, viewModel: InboxViewModel) -> InboxViewController { - switch userContext.authType { + static func make(appContext: AppContextWithUser, viewModel: InboxViewModel) -> InboxViewController { + switch appContext.authType { case .oAuthGmail: // Inject threads provider - Gmail API - guard let threadsProvider = userContext.getRequiredMailProvider().messagesThreadProvider else { + guard let threadsProvider = appContext.getRequiredMailProvider().messagesThreadProvider else { fatalError("Internal inconsistency") } return InboxViewController( - userContext: userContext, + appContext: appContext, viewModel: viewModel, numberOfInboxItemsToLoad: 20, // else timeouts happen provider: InboxMessageThreadsProvider(provider: threadsProvider) ) case .password: // Inject message list provider - IMAP - let provider = InboxMessageListProvider(provider: userContext.getRequiredMailProvider().messageListProvider) + let provider = InboxMessageListProvider(provider: appContext.getRequiredMailProvider().messageListProvider) return InboxViewController( - userContext: userContext, + appContext: appContext, viewModel: viewModel, numberOfInboxItemsToLoad: 50, // safe to load 50, single call on IMAP provider: provider diff --git a/FlowCrypt/Controllers/Inbox/InboxViewController.swift b/FlowCrypt/Controllers/Inbox/InboxViewController.swift index 36dd77d73..d2ed31c64 100644 --- a/FlowCrypt/Controllers/Inbox/InboxViewController.swift +++ b/FlowCrypt/Controllers/Inbox/InboxViewController.swift @@ -13,7 +13,7 @@ final class InboxViewController: ViewController { private let numberOfInboxItemsToLoad: Int - private let userContext: UserContext + private let appContext: AppContextWithUser private let service: ServiceActor private let decorator: InboxViewDecorator private let draftsListProvider: DraftsListProvider? @@ -33,19 +33,19 @@ final class InboxViewController: ViewController { var path: String { viewModel.path } init( - userContext: UserContext, + appContext: AppContextWithUser, viewModel: InboxViewModel, numberOfInboxItemsToLoad: Int = 50, provider: InboxDataProvider, draftsListProvider: DraftsListProvider? = nil, decorator: InboxViewDecorator = InboxViewDecorator() ) { - self.userContext = userContext + self.appContext = appContext self.viewModel = viewModel self.numberOfInboxItemsToLoad = numberOfInboxItemsToLoad self.service = ServiceActor(inboxDataProvider: provider) - self.draftsListProvider = draftsListProvider ?? userContext.getRequiredMailProvider().draftsProvider + self.draftsListProvider = draftsListProvider ?? appContext.getRequiredMailProvider().draftsProvider self.decorator = decorator self.tableNode = TableNode() @@ -121,7 +121,7 @@ extension InboxViewController { // MARK: - Helpers extension InboxViewController { private func currentMessagesListPagination(from number: Int? = nil) -> MessagesListPagination { - userContext + appContext .getRequiredMailProvider() .currentMessagesListPagination(from: number, token: state.token) } @@ -181,7 +181,7 @@ extension InboxViewController { folderPath: viewModel.path, count: numberOfInboxItemsToLoad, pagination: currentMessagesListPagination() - ), userEmail: userContext.user.email + ), userEmail: appContext.user.email ) handleEndFetching(with: context, context: batchContext) } catch { @@ -203,7 +203,7 @@ extension InboxViewController { folderPath: viewModel.path, count: messagesToLoad(), pagination: pagination - ), userEmail: userContext.user.email + ), userEmail: appContext.user.email ) state = .fetched(context.pagination) handleEndFetching(with: context, context: batchContext) @@ -325,7 +325,7 @@ extension InboxViewController { } private func handleSearchTap() { - let viewController = SearchViewController(userContext: userContext, folderPath: viewModel.path) + let viewController = SearchViewController(appContext: appContext, folderPath: viewModel.path) navigationController?.pushViewController(viewController, animated: false) } @@ -337,7 +337,7 @@ extension InboxViewController { private func btnComposeTap() { TapTicFeedback.generate(.light) - let composeVc = ComposeViewController(userContext: userContext) + let composeVc = ComposeViewController(appContext: appContext) navigationController?.pushViewController(composeVc, animated: true) } } @@ -365,7 +365,7 @@ extension InboxViewController: ASTableDataSource, ASTableDelegate { func tableNode(_ tableNode: ASTableNode, didSelectRowAt indexPath: IndexPath) { tableNode.deselectRow(at: indexPath, animated: true) - open(with: inboxInput[indexPath.row], path: viewModel.path, userContext: userContext) + open(with: inboxInput[indexPath.row], path: viewModel.path, appContext: appContext) } private func cellNode(for indexPath: IndexPath, and size: CGSize) -> ASCellNodeBlock { diff --git a/FlowCrypt/Controllers/MessageList Extension/MsgListViewController.swift b/FlowCrypt/Controllers/MessageList Extension/MsgListViewController.swift index b8f01f13f..28011a0d4 100644 --- a/FlowCrypt/Controllers/MessageList Extension/MsgListViewController.swift +++ b/FlowCrypt/Controllers/MessageList Extension/MsgListViewController.swift @@ -10,7 +10,7 @@ import UIKit @MainActor protocol MsgListViewController { - func open(with message: InboxRenderable, path: String, userContext: UserContext) + func open(with message: InboxRenderable, path: String, appContext: AppContextWithUser) func getUpdatedIndex(for message: InboxRenderable) -> Int? func updateMessage(isRead: Bool, at index: Int) @@ -20,35 +20,35 @@ protocol MsgListViewController { extension MsgListViewController where Self: UIViewController { // todo - tom - don't know how to add AppContext into init of protocol/extension - func open(with message: InboxRenderable, path: String, userContext: UserContext) { + func open(with message: InboxRenderable, path: String, appContext: AppContextWithUser) { switch message.wrappedType { case .message(let message): - openMsg(userContext: userContext, with: message, path: path) + openMsg(appContext: appContext, with: message, path: path) case .thread(let thread): - openThread(with: thread, userContext: userContext) + openThread(with: thread, appContext: appContext) } } // TODO: uncomment in "sent message from draft" feature - private func openDraft(userContext: UserContext, with message: Message) { - let controller = ComposeViewController(userContext: userContext) + private func openDraft(appContext: AppContextWithUser, with message: Message) { + let controller = ComposeViewController(appContext: appContext) controller.update(with: message) navigationController?.pushViewController(controller, animated: true) } - private func openMsg(userContext: UserContext, with message: Message, path: String) { + private func openMsg(appContext: AppContextWithUser, with message: Message, path: String) { let thread = MessageThread( identifier: message.threadId, snippet: nil, path: path, messages: [message] ) - openThread(with: thread, userContext: userContext) + openThread(with: thread, appContext: appContext) } - private func openThread(with thread: MessageThread, userContext: UserContext) { + private func openThread(with thread: MessageThread, appContext: AppContextWithUser) { let viewController = ThreadDetailsViewController( - userContext: userContext, + appContext: appContext, thread: thread ) { [weak self] (action, message) in self?.handleMessageOperation(with: message, action: action) diff --git a/FlowCrypt/Controllers/Search/SearchViewController.swift b/FlowCrypt/Controllers/Search/SearchViewController.swift index c87c1c996..9b78efb10 100644 --- a/FlowCrypt/Controllers/Search/SearchViewController.swift +++ b/FlowCrypt/Controllers/Search/SearchViewController.swift @@ -41,19 +41,19 @@ final class SearchViewController: TableNodeViewController { // TODO: - https://github.com/FlowCrypt/flowcrypt-ios/issues/669 Adopt to gmail threads private let service: ServiceActor private var searchTask: DispatchWorkItem? - private let userContext: UserContext + private let appContext: AppContextWithUser private let searchController = UISearchController(searchResultsController: nil) private let folderPath: String private var searchedExpression: String = "" init( - userContext: UserContext, + appContext: AppContextWithUser, searchProvider: MessageSearchProvider? = nil, folderPath: String ) { - self.userContext = userContext + self.appContext = appContext self.service = ServiceActor( - searchProvider: searchProvider ?? userContext.getRequiredMailProvider().messageSearchProvider + searchProvider: searchProvider ?? appContext.getRequiredMailProvider().messageSearchProvider ) self.folderPath = folderPath super.init(node: TableNode()) @@ -217,7 +217,7 @@ extension SearchViewController: ASTableDataSource, ASTableDelegate { guard let message = state.messages[safe: indexPath.row] else { return } // TODO: - https://github.com/FlowCrypt/flowcrypt-ios/issues/669 - cleanup - open(with: .init(message: message), path: folderPath, userContext: userContext) + open(with: .init(message: message), path: folderPath, appContext: appContext) } } diff --git a/FlowCrypt/Controllers/Settings/KeySettings/Key List/KeySettingsViewController.swift b/FlowCrypt/Controllers/Settings/KeySettings/Key List/KeySettingsViewController.swift index 56a73eb20..44b51a9b1 100644 --- a/FlowCrypt/Controllers/Settings/KeySettings/Key List/KeySettingsViewController.swift +++ b/FlowCrypt/Controllers/Settings/KeySettings/Key List/KeySettingsViewController.swift @@ -17,18 +17,18 @@ import FlowCryptUI */ final class KeySettingsViewController: TableNodeViewController { - private let userContext: UserContext + private let appContext: AppContextWithUser private var keys: [KeyDetails] = [] private let decorator: KeySettingsViewDecorator private let isUsingKeyManager: Bool init( - userContext: UserContext, + appContext: AppContextWithUser, decorator: KeySettingsViewDecorator = KeySettingsViewDecorator() ) { - self.userContext = userContext + self.appContext = appContext self.decorator = decorator - self.isUsingKeyManager = userContext.clientConfigurationService.getSaved(for: userContext.user.email).isUsingKeyManager + self.isUsingKeyManager = appContext.clientConfigurationService.getSaved(for: appContext.user.email).isUsingKeyManager super.init(node: TableNode()) } @@ -71,14 +71,14 @@ final class KeySettingsViewController: TableNodeViewController { extension KeySettingsViewController { private func loadKeysFromStorageAndRender() async throws { - self.keys = try await userContext.keyService.getPrvKeyDetails() + self.keys = try await appContext.keyService.getPrvKeyDetails() await node.reloadData() } } extension KeySettingsViewController { @objc private func handleAddButtonTap() { - navigationController?.pushViewController(SetupManuallyImportKeyViewController(appContext: userContext), animated: true) + navigationController?.pushViewController(SetupManuallyImportKeyViewController(appContext: appContext), animated: true) } } diff --git a/FlowCrypt/Controllers/Settings/Settings List/SettingsViewController.swift b/FlowCrypt/Controllers/Settings/Settings List/SettingsViewController.swift index 3c8161c9c..ef8e4aa8b 100644 --- a/FlowCrypt/Controllers/Settings/Settings List/SettingsViewController.swift +++ b/FlowCrypt/Controllers/Settings/Settings List/SettingsViewController.swift @@ -43,19 +43,19 @@ final class SettingsViewController: TableNodeViewController { } } - private let userContext: UserContext + private let appContext: AppContextWithUser private let decorator: SettingsViewDecorator private let clientConfiguration: ClientConfiguration private let rows: [SettingsMenuItem] init( - userContext: UserContext, + appContext: AppContextWithUser, decorator: SettingsViewDecorator = SettingsViewDecorator() ) { - self.userContext = userContext + self.appContext = appContext self.decorator = decorator - self.clientConfiguration = userContext.clientConfigurationService.getSaved(for: userContext.user.email) - self.rows = SettingsMenuItem.filtered(with: self.clientConfiguration) + self.clientConfiguration = appContext.clientConfigurationService.getSaved(for: appContext.user.email) + self.rows = SettingsMenuItem.filtered(with: clientConfiguration) super.init(node: TableNode()) } @@ -113,18 +113,18 @@ extension SettingsViewController { switch setting { case .keys: - viewController = KeySettingsViewController(userContext: userContext) + viewController = KeySettingsViewController(appContext: appContext) case .legal: viewController = LegalViewController() case .contacts: - viewController = ContactsListViewController(appContext: userContext) + viewController = ContactsListViewController(appContext: appContext) case .backups: guard clientConfiguration.canBackupKeys else { viewController = nil return } - let userId = UserId(email: userContext.user.email, name: userContext.user.email) - viewController = BackupViewController(appContext: userContext, userId: userId) + let userId = UserId(email: appContext.user.email, name: appContext.user.email) + viewController = BackupViewController(appContext: appContext, userId: userId) default: viewController = nil } diff --git a/FlowCrypt/Controllers/SideMenu/Main/SideMenuNavigationController.swift b/FlowCrypt/Controllers/SideMenu/Main/SideMenuNavigationController.swift index 7883cc3b1..00a157961 100644 --- a/FlowCrypt/Controllers/SideMenu/Main/SideMenuNavigationController.swift +++ b/FlowCrypt/Controllers/SideMenu/Main/SideMenuNavigationController.swift @@ -48,8 +48,8 @@ final class SideMenuNavigationController: ENSideMenuNavigationController { private var menuViewContoller: SideMenuViewController? - convenience init(userContext: UserContext, contentViewController: UIViewController) { - let menu = MyMenuViewController(userContext: userContext) + convenience init(appContext: AppContextWithUser, contentViewController: UIViewController) { + let menu = MyMenuViewController(appContext: appContext) self.init(menuViewController: menu, contentViewController: contentViewController) menuViewContoller = menu sideMenu = ENSideMenu(sourceView: view, menuViewController: menu, menuPosition: .left).then { diff --git a/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift b/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift index 4014fa6d0..be6711d01 100644 --- a/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift +++ b/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift @@ -43,14 +43,14 @@ final class MyMenuViewController: ViewController { } } - private let userContext: UserContext + private let appContext: AppContextWithUser private let foldersService: FoldersServiceType private let decorator: MyMenuViewDecorator private var folders: [FolderViewModel] = [] private var serviceItems: [FolderViewModel] { FolderViewModel.menuItems } private var accounts: [User] { - userContext.dataService.getFinishedSetupUsers(exceptUserEmail: userContext.user.email) + appContext.dataService.getFinishedSetupUsers(exceptUserEmail: appContext.user.email) } private let tableNode: ASTableNode @@ -65,12 +65,12 @@ final class MyMenuViewController: ViewController { private var isFirstLaunch = true init( - userContext: UserContext, + appContext: AppContextWithUser, decorator: MyMenuViewDecorator = MyMenuViewDecorator(), tableNode: ASTableNode = TableNode() ) { - self.userContext = userContext - self.foldersService = userContext.getFoldersService() + self.appContext = appContext + self.foldersService = appContext.getFoldersService() self.decorator = decorator self.tableNode = tableNode super.init(node: ASDisplayNode()) @@ -171,7 +171,7 @@ extension MyMenuViewController { showSpinner() Task { do { - let folders = try await foldersService.fetchFolders(isForceReload: true, for: userContext.user) + let folders = try await foldersService.fetchFolders(isForceReload: true, for: appContext.user) handleNewFolders(with: folders) } catch { handleError(with: error) @@ -207,7 +207,7 @@ extension MyMenuViewController { // MARK: - Account functionality extension MyMenuViewController { private func addAccount() { - let vc = MainNavigationController(rootViewController: SignInViewController(appContext: userContext)) + let vc = MainNavigationController(rootViewController: SignInViewController(appContext: appContext)) present(vc, animated: true, completion: nil) } @@ -217,7 +217,7 @@ extension MyMenuViewController { } do { - try userContext.globalRouter.switchActive(user: account, appContext: userContext) + try appContext.globalRouter.switchActive(user: account, appContext: appContext) } catch { showAlert(message: error.localizedDescription) } @@ -245,7 +245,7 @@ extension MyMenuViewController { private func node(for section: Sections, row: Int) -> ASCellNode { switch (section, state) { case (.header, _): - let headerInput = decorator.header(for: userContext.user, image: state.arrowImage) + let headerInput = decorator.header(for: appContext.user, image: state.arrowImage) return TextImageNode(input: headerInput) { [weak self] node in self?.handleTapOn(header: node) } @@ -278,7 +278,7 @@ extension MyMenuViewController { switch folder.itemType { case .folder: let input = InboxViewModel(folder) - let viewController = InboxViewControllerFactory.make(userContext: userContext, viewModel: input) + let viewController = InboxViewControllerFactory.make(appContext: appContext, viewModel: input) if let topController = topController(controllerType: InboxViewController.self), topController.path == folder.path { @@ -292,10 +292,10 @@ extension MyMenuViewController { sideMenuController()?.sideMenu?.hideSideMenu() return } - sideMenuController()?.setContentViewController(SettingsViewController(userContext: userContext)) + sideMenuController()?.setContentViewController(SettingsViewController(appContext: appContext)) case .logOut: do { - try userContext.globalRouter.signOut(appContext: userContext) + try appContext.globalRouter.signOut(appContext: appContext) } catch { showAlert(message: error.localizedDescription) } diff --git a/FlowCrypt/Controllers/Threads/ThreadDetailsViewController.swift b/FlowCrypt/Controllers/Threads/ThreadDetailsViewController.swift index faa3a4658..d896dc291 100644 --- a/FlowCrypt/Controllers/Threads/ThreadDetailsViewController.swift +++ b/FlowCrypt/Controllers/Threads/ThreadDetailsViewController.swift @@ -32,7 +32,7 @@ final class ThreadDetailsViewController: TableNodeViewController { case thread, message } - private let userContext: UserContext + private let appContext: AppContextWithUser private let messageService: MessageService private let messageOperationsProvider: MessageOperationsProvider private let threadOperationsProvider: MessagesThreadOperationsProvider @@ -46,34 +46,34 @@ final class ThreadDetailsViewController: TableNodeViewController { private let onComplete: MessageActionCompletion init( - userContext: UserContext, + appContext: AppContextWithUser, messageService: MessageService? = nil, thread: MessageThread, completion: @escaping MessageActionCompletion ) { - self.userContext = userContext - let clientConfiguration = userContext.clientConfigurationService.getSaved(for: userContext.user.email) + self.appContext = appContext + let clientConfiguration = appContext.clientConfigurationService.getSaved(for: appContext.user.email) self.messageService = messageService ?? MessageService( contactsService: ContactsService( localContactsProvider: LocalContactsProvider( - encryptedStorage: userContext.encryptedStorage + encryptedStorage: appContext.encryptedStorage ), clientConfiguration: clientConfiguration ), - keyService: userContext.keyService, - messageProvider: userContext.getRequiredMailProvider().messageProvider, - passPhraseService: userContext.passPhraseService + keyService: appContext.keyService, + messageProvider: appContext.getRequiredMailProvider().messageProvider, + passPhraseService: appContext.passPhraseService ) - guard let threadOperationsProvider = userContext.getRequiredMailProvider().threadOperationsProvider else { + guard let threadOperationsProvider = appContext.getRequiredMailProvider().threadOperationsProvider else { fatalError("expected threadOperationsProvider on gmail") } self.threadOperationsProvider = threadOperationsProvider - self.messageOperationsProvider = userContext.getRequiredMailProvider().messageOperationsProvider + self.messageOperationsProvider = appContext.getRequiredMailProvider().messageOperationsProvider self.trashFolderProvider = TrashFolderProvider( - user: userContext.user, + user: appContext.user, foldersService: FoldersService( - encryptedStorage: userContext.encryptedStorage, - remoteFoldersProvider: userContext.getRequiredMailProvider().remoteFoldersProvider + encryptedStorage: appContext.encryptedStorage, + remoteFoldersProvider: appContext.getRequiredMailProvider().remoteFoldersProvider ) ) self.thread = thread @@ -95,7 +95,7 @@ final class ThreadDetailsViewController: TableNodeViewController { node.delegate = self node.dataSource = self - setupNavigationBar(user: userContext.user) + setupNavigationBar(user: appContext.user) expandThreadMessage() } } @@ -242,7 +242,7 @@ extension ThreadDetailsViewController { } let composeInput = ComposeMessageInput(type: composeType) navigationController?.pushViewController( - ComposeViewController(userContext: userContext, input: composeInput), + ComposeViewController(appContext: appContext, input: composeInput), animated: true ) } @@ -452,7 +452,7 @@ extension ThreadDetailsViewController: MessageActionsHandler { private func handleSuccessfulMessage(action: MessageAction) { hideSpinner() - onComplete(action, .init(thread: thread, folderPath: currentFolderPath, activeUserEmail: userContext.user.email)) + onComplete(action, .init(thread: thread, folderPath: currentFolderPath, activeUserEmail: appContext.user.email)) navigationController?.popViewController(animated: true) } @@ -592,7 +592,7 @@ extension ThreadDetailsViewController: NavigationChildController { func handleBackButtonTap() { let isRead = input.contains(where: { $0.rawMessage.isMessageRead }) logger.logInfo("Back button. Are all messages read \(isRead)") - onComplete(MessageAction.markAsRead(isRead), .init(thread: thread, folderPath: currentFolderPath, activeUserEmail: userContext.user.email)) + onComplete(MessageAction.markAsRead(isRead), .init(thread: thread, folderPath: currentFolderPath, activeUserEmail: appContext.user.email)) navigationController?.popViewController(animated: true) } } diff --git a/FlowCrypt/Functionality/Services/AppStartup.swift b/FlowCrypt/Functionality/Services/AppStartup.swift index bbe0e95f8..c0e872afc 100644 --- a/FlowCrypt/Functionality/Services/AppStartup.swift +++ b/FlowCrypt/Functionality/Services/AppStartup.swift @@ -68,10 +68,10 @@ struct AppStartup { switch entryPoint { case .mainFlow: - let userContext = appContext.withSession(appContext.session) - let contentViewController = InboxViewContainerController(userContext: userContext) + let appContextWithUser = appContext.withSession(appContext.session) + let contentViewController = InboxViewContainerController(appContext: appContextWithUser) viewController = SideMenuNavigationController( - userContext: userContext, + appContext: appContextWithUser, contentViewController: contentViewController ) case .signIn: From 862744f221b34f0f1e0439ef60a8efd82bd78c2f Mon Sep 17 00:00:00 2001 From: Ivan Ushakov Date: Sat, 29 Jan 2022 12:11:19 +0300 Subject: [PATCH 7/7] Inject dependecies explicitly --- FlowCrypt/App/AppContext.swift | 9 +--- .../Functionality/Services/AppStartup.swift | 54 +++++++++++++------ .../Functionality/Services/GlobalRouter.swift | 31 +++++++++-- 3 files changed, 67 insertions(+), 27 deletions(-) diff --git a/FlowCrypt/App/AppContext.swift b/FlowCrypt/App/AppContext.swift index 3ae59c461..3d6ee84a2 100644 --- a/FlowCrypt/App/AppContext.swift +++ b/FlowCrypt/App/AppContext.swift @@ -78,14 +78,7 @@ class AppContext { ) } - func withSession(_ session: SessionType?) -> AppContextWithUser { - guard - let authType = dataService.currentAuthType, - let user = dataService.currentUser - else { - fatalError() - } - + func withSession(session: SessionType?, authType: AuthType, user: User) -> AppContextWithUser { return AppContextWithUser( encryptedStorage: encryptedStorage, session: session, diff --git a/FlowCrypt/Functionality/Services/AppStartup.swift b/FlowCrypt/Functionality/Services/AppStartup.swift index c0e872afc..6e4118333 100644 --- a/FlowCrypt/Functionality/Services/AppStartup.swift +++ b/FlowCrypt/Functionality/Services/AppStartup.swift @@ -62,26 +62,17 @@ struct AppStartup { @MainActor private func chooseView(for window: UIWindow) { - let entryPoint = entryPointForUser() - - let viewController: UIViewController - - switch entryPoint { + switch entryPointForUser() { case .mainFlow: - let appContextWithUser = appContext.withSession(appContext.session) - let contentViewController = InboxViewContainerController(appContext: appContextWithUser) - viewController = SideMenuNavigationController( - appContext: appContextWithUser, - contentViewController: contentViewController - ) + startMainFlow(appContext: appContext, window: window) case .signIn: - viewController = MainNavigationController(rootViewController: SignInViewController(appContext: appContext)) + window.rootViewController = MainNavigationController( + rootViewController: SignInViewController(appContext: appContext) + ) case .setupFlow(let userId): let setupViewController = SetupInitialViewController(appContext: appContext, user: userId) - viewController = MainNavigationController(rootViewController: setupViewController) + window.rootViewController = MainNavigationController(rootViewController: setupViewController) } - - window.rootViewController = viewController } private func entryPointForUser() -> EntryPoint { @@ -150,4 +141,37 @@ struct AppStartup { alert.addAction(retry) window.rootViewController?.present(alert, animated: true, completion: nil) } + + @MainActor + private func startMainFlow(appContext: AppContext, window: UIWindow) { + let session = appContext.session + + guard + let authType = appContext.dataService.currentAuthType, + let user = appContext.dataService.currentUser + else { + let message = "Wrong application state. User not found for session \(session?.description ?? "nil")" + logger.logError(message) + + if window.rootViewController == nil { + window.rootViewController = UIViewController() + } + + window.rootViewController?.showAlert( + title: "error".localized, + message: message, + onOk: { fatalError() } + ) + + return + } + + let appContextWithUser = appContext.withSession(session: session, authType: authType, user: user) + let contentViewController = InboxViewContainerController(appContext: appContextWithUser) + let viewController = SideMenuNavigationController( + appContext: appContextWithUser, + contentViewController: contentViewController + ) + window.rootViewController = viewController + } } diff --git a/FlowCrypt/Functionality/Services/GlobalRouter.swift b/FlowCrypt/Functionality/Services/GlobalRouter.swift index 9d3de66f4..49489e554 100644 --- a/FlowCrypt/Functionality/Services/GlobalRouter.swift +++ b/FlowCrypt/Functionality/Services/GlobalRouter.swift @@ -74,10 +74,10 @@ extension GlobalRouter: GlobalRouterType { ) try appContext.userAccountService.startSessionFor(session: session) viewController.hideSpinner() - proceed(with: appContext.withSession(session)) + proceed(with: appContext, session: session) case .other(let session): try appContext.userAccountService.startSessionFor(session: session) - proceed(with: appContext.withSession(session)) + proceed(with: appContext, session: session) } } catch { if case .gmailLogin(let viewController) = route { @@ -91,7 +91,7 @@ extension GlobalRouter: GlobalRouterType { func signOut(appContext: AppContext) throws { if let session = try appContext.userAccountService.startActiveSessionForNextUser() { logger.logInfo("Start session for another email user \(session)") - proceed(with: appContext.withSession(session)) + proceed(with: appContext, session: session) } else { logger.logInfo("Sign out") appContext.userAccountService.cleanup() @@ -130,7 +130,7 @@ extension GlobalRouter: GlobalRouterType { logger.logWarning("Can't switch active user with \(user.email)") return } - proceed(with: appContext.withSession(session)) + proceed(with: appContext, session: session) } @MainActor @@ -151,6 +151,29 @@ extension GlobalRouter: GlobalRouterType { AppStartup(appContext: appContext).initializeApp(window: keyWindow) } + @MainActor + private func proceed(with appContext: AppContext, session: SessionType) { + logger.logInfo("proceed for session: \(session.description)") + guard + let authType = appContext.dataService.currentAuthType, + let user = appContext.dataService.currentUser + else { + let message = "Wrong application state. User not found for session \(session.description)" + logger.logError(message) + + keyWindow.rootViewController?.showAlert( + title: "error".localized, + message: message, + onOk: { fatalError() } + ) + + return + } + + let appContextWithUser = appContext.withSession(session: session, authType: authType, user: user) + AppStartup(appContext: appContextWithUser).initializeApp(window: keyWindow) + } + @MainActor private func handleSignInError(error: Error, appContext: AppContext) { if let gmailUserError = error as? GoogleUserServiceError {