diff --git a/Riot/Modules/Application/LegacyAppDelegate.m b/Riot/Modules/Application/LegacyAppDelegate.m index a85047c69..1c74e5ede 100644 --- a/Riot/Modules/Application/LegacyAppDelegate.m +++ b/Riot/Modules/Application/LegacyAppDelegate.m @@ -2410,6 +2410,12 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni MXLogDebug(@"[AppDelegate] handleAppState: isLaunching: %@", isLaunching ? @"YES" : @"NO"); + if (self.masterTabBarController.isOnboardingInProgress) + { + MXLogDebug(@"[AppDelegate] handleAppState: Skipping LaunchLoadingView due to Onboarding."); + return; + } + if (isLaunching) { MXLogDebug(@"[AppDelegate] handleAppState: LaunchLoadingView"); diff --git a/Riot/Modules/Authentication/AuthenticationCoordinator.swift b/Riot/Modules/Authentication/AuthenticationCoordinator.swift index e2ba6ee2e..865161941 100644 --- a/Riot/Modules/Authentication/AuthenticationCoordinator.swift +++ b/Riot/Modules/Authentication/AuthenticationCoordinator.swift @@ -16,7 +16,6 @@ limitations under the License. */ -import Foundation import UIKit /// A coordinator that handles authentication, verification and setting a PIN. @@ -26,17 +25,27 @@ final class AuthenticationCoordinator: NSObject, AuthenticationCoordinatorProtoc // MARK: Private + private let navigationRouter: NavigationRouterType + private let authenticationViewController: AuthenticationViewController + private let crossSigningService = CrossSigningService() + + /// The password entered, for use when setting up cross-signing. + private var password: String? + /// The session created when successfully authenticated. + private var session: MXSession? // MARK: Public // Must be used only internally var childCoordinators: [Coordinator] = [] - var completion: ((MXKAuthenticationType) -> Void)? + var completion: ((AuthenticationCoordinatorResult) -> Void)? // MARK: - Setup - override init() { + init(parameters: AuthenticationCoordinatorParameters) { + self.navigationRouter = parameters.navigationRouter + let authenticationViewController = AuthenticationViewController() self.authenticationViewController = authenticationViewController @@ -81,11 +90,157 @@ final class AuthenticationCoordinator: NSObject, AuthenticationCoordinatorProtoc func continueSSOLogin(withToken loginToken: String, transactionID: String) -> Bool { authenticationViewController.continueSSOLogin(withToken: loginToken, txnId: transactionID) } + + // MARK: - Private + + private func showLoadingAnimation() { + let loadingViewController = LaunchLoadingViewController() + loadingViewController.modalPresentationStyle = .fullScreen + + // Replace the navigation stack with the loading animation + // as there is nothing to navigate back to. + navigationRouter.setRootModule(loadingViewController) + } + + private func presentCompleteSecurity(with session: MXSession) { + let isNewSignIn = true + let keyVerificationCoordinator = KeyVerificationCoordinator(session: session, flow: .completeSecurity(isNewSignIn)) + + keyVerificationCoordinator.delegate = self + let presentable = keyVerificationCoordinator.toPresentable() + presentable.presentationController?.delegate = self + navigationRouter.present(presentable, animated: true) + keyVerificationCoordinator.start() + add(childCoordinator: keyVerificationCoordinator) + } + + private func authenticationDidComplete() { + completion?(.didComplete(authenticationViewController.authType)) + } + + private func registerSessionStateChangeNotification(for session: MXSession) { + NotificationCenter.default.addObserver(self, selector: #selector(sessionStateDidChange), name: .mxSessionStateDidChange, object: session) + } + + private func unregisterSessionStateChangeNotification() { + NotificationCenter.default.removeObserver(self, name: .mxSessionStateDidChange, object: nil) + } + + @objc private func sessionStateDidChange(_ notification: Notification) { + guard let session = notification.object as? MXSession else { + MXLog.error("[AuthenticationCoordinator] sessionStateDidChange: Missing session in the notification") + return + } + + if session.state == .storeDataReady { + if let crypto = session.crypto, crypto.crossSigning != nil { + // Do not make key share requests while the "Complete security" is not complete. + // If the device is self-verified, the SDK will restore the existing key backup. + // Then, it will re-enable outgoing key share requests + crypto.setOutgoingKeyRequestsEnabled(false, onComplete: nil) + } + } else if session.state == .running { + unregisterSessionStateChangeNotification() + + if let crypto = session.crypto, let crossSigning = crypto.crossSigning { + crossSigning.refreshState { [weak self] stateUpdated in + guard let self = self else { return } + + MXLog.debug("[AuthenticationCoordinator] sessionStateDidChange: crossSigning.state: \(crossSigning.state)") + + switch crossSigning.state { + case .notBootstrapped: + // TODO: This is still not sure we want to disable the automatic cross-signing bootstrap + // if the admin disabled e2e by default. + // Do like riot-web for the moment + if session.vc_homeserverConfiguration().isE2EEByDefaultEnabled { + // Bootstrap cross-signing on user's account + // We do it for both registration and new login as long as cross-signing does not exist yet + if let password = self.password, !password.isEmpty { + MXLog.debug("[AuthenticationCoordinator] sessionStateDidChange: Bootstrap with password") + + crossSigning.setup(withPassword: password) { + MXLog.debug("[AuthenticationCoordinator] sessionStateDidChange: Bootstrap succeeded") + self.authenticationDidComplete() + } failure: { error in + MXLog.error("[AuthenticationCoordinator] sessionStateDidChange: Bootstrap failed. Error: \(error)") + crypto.setOutgoingKeyRequestsEnabled(true, onComplete: nil) + self.authenticationDidComplete() + } + } else { + // Try to setup cross-signing without authentication parameters in case if a grace period is enabled + self.crossSigningService.setupCrossSigningWithoutAuthentication(for: session) { + MXLog.debug("[AuthenticationCoordinator] sessionStateDidChange: Bootstrap succeeded without credentials") + self.authenticationDidComplete() + } failure: { error in + MXLog.error("[AuthenticationCoordinator] sessionStateDidChange: Do not know how to bootstrap cross-signing. Skip it.") + crypto.setOutgoingKeyRequestsEnabled(true, onComplete: nil) + self.authenticationDidComplete() + } + } + } else { + crypto.setOutgoingKeyRequestsEnabled(true, onComplete: nil) + self.authenticationDidComplete() + } + case .crossSigningExists: + MXLog.debug("[AuthenticationCoordinator] sessionStateDidChange: Complete security") + self.presentCompleteSecurity(with: session) + default: + MXLog.debug("[AuthenticationCoordinator] sessionStateDidChange: Nothing to do") + + crypto.setOutgoingKeyRequestsEnabled(true, onComplete: nil) + self.authenticationDidComplete() + } + } failure: { [weak self] error in + MXLog.error("[AuthenticationCoordinator] sessionStateDidChange: Fail to refresh crypto state with error: \(error)") + crypto.setOutgoingKeyRequestsEnabled(true, onComplete: nil) + self?.authenticationDidComplete() + } + } else { + authenticationDidComplete() + } + } + } } // MARK: - AuthenticationViewControllerDelegate extension AuthenticationCoordinator: AuthenticationViewControllerDelegate { - func authenticationViewControllerDidDismiss(_ authenticationViewController: AuthenticationViewController!) { - completion?(authenticationViewController.authType) + func authenticationViewController(_ authenticationViewController: AuthenticationViewController!, didLoginWith session: MXSession!, andPassword password: String!) { + registerSessionStateChangeNotification(for: session) + + self.session = session + self.password = password + + self.showLoadingAnimation() + completion?(.didLogin(session)) + } +} + +// MARK: - KeyVerificationCoordinatorDelegate +extension AuthenticationCoordinator: KeyVerificationCoordinatorDelegate { + func keyVerificationCoordinatorDidComplete(_ coordinator: KeyVerificationCoordinatorType, otherUserId: String, otherDeviceId: String) { + if let crypto = session?.crypto, + !crypto.backup.hasPrivateKeyInCryptoStore || !crypto.backup.enabled { + MXLog.debug("[AuthenticationCoordinator][MXKeyVerification] requestAllPrivateKeys: Request key backup private keys") + crypto.setOutgoingKeyRequestsEnabled(true, onComplete: nil) + } + + navigationRouter.dismissModule(animated: true) { [weak self] in + self?.authenticationDidComplete() + } + } + + func keyVerificationCoordinatorDidCancel(_ coordinator: KeyVerificationCoordinatorType) { + navigationRouter.dismissModule(animated: true) { [weak self] in + self?.authenticationDidComplete() + } + } +} + +// MARK: - UIAdaptivePresentationControllerDelegate +extension AuthenticationCoordinator: UIAdaptivePresentationControllerDelegate { + func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool { + // Prevent Key Verification from using swipe to dismiss + return false } } diff --git a/Riot/Modules/Authentication/AuthenticationCoordinatorProtocol.swift b/Riot/Modules/Authentication/AuthenticationCoordinatorProtocol.swift index 14a3d1186..c024cddbe 100644 --- a/Riot/Modules/Authentication/AuthenticationCoordinatorProtocol.swift +++ b/Riot/Modules/Authentication/AuthenticationCoordinatorProtocol.swift @@ -18,9 +18,21 @@ import Foundation +struct AuthenticationCoordinatorParameters { + let navigationRouter: NavigationRouterType +} + +enum AuthenticationCoordinatorResult { + /// The user has authenticated but key verification is yet to happen. The session value is + /// for a fresh session that still needs to load, sync etc before being ready. + case didLogin(MXSession) + /// All of the required authentication steps including key verification is complete. + case didComplete(MXKAuthenticationType) +} + /// `AuthenticationCoordinatorProtocol` is a protocol describing a Coordinator that handle's the authentication navigation flow. protocol AuthenticationCoordinatorProtocol: Coordinator, Presentable { - var completion: ((MXKAuthenticationType) -> Void)? { get set } + var completion: ((AuthenticationCoordinatorResult) -> Void)? { get set } /// Update the screen to display registration or login. func update(authenticationType: MXKAuthenticationType) diff --git a/Riot/Modules/Authentication/AuthenticationViewController.h b/Riot/Modules/Authentication/AuthenticationViewController.h index 6671863a2..dd76303a4 100644 --- a/Riot/Modules/Authentication/AuthenticationViewController.h +++ b/Riot/Modules/Authentication/AuthenticationViewController.h @@ -62,6 +62,8 @@ @protocol AuthenticationViewControllerDelegate -- (void)authenticationViewControllerDidDismiss:(AuthenticationViewController *)authenticationViewController; +- (void)authenticationViewController:(AuthenticationViewController *)authenticationViewController + didLoginWithSession:(MXSession *)session + andPassword:(NSString *)password; @end; diff --git a/Riot/Modules/Authentication/AuthenticationViewController.m b/Riot/Modules/Authentication/AuthenticationViewController.m index 776e23373..425fb4da6 100644 --- a/Riot/Modules/Authentication/AuthenticationViewController.m +++ b/Riot/Modules/Authentication/AuthenticationViewController.m @@ -28,7 +28,7 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; -@interface AuthenticationViewController () @@ -63,7 +63,6 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; } @property (nonatomic, readonly) BOOL isIdentityServerConfigured; -@property (nonatomic, strong) KeyVerificationCoordinatorBridgePresenter *keyVerificationCoordinatorBridgePresenter; @property (nonatomic, strong) SetPinCoordinatorBridgePresenter *setPinCoordinatorBridgePresenter; @property (nonatomic, strong) KeyboardAvoider *keyboardAvoider; @@ -78,8 +77,6 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; // Current SSO transaction id used to identify and validate the SSO authentication callback @property (nonatomic, strong) NSString *ssoCallbackTxnId; -@property (nonatomic, strong) CrossSigningService *crossSigningService; - @property (nonatomic, getter = isFirstViewAppearing) BOOL firstViewAppearing; @property (nonatomic, strong) MXKErrorAlertPresentation *errorPresenter; @@ -118,7 +115,6 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; _firstViewAppearing = YES; - self.crossSigningService = [CrossSigningService new]; self.errorPresenter = [MXKErrorAlertPresentation new]; } @@ -318,11 +314,6 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; { self.firstViewAppearing = NO; } - - if (self.keyVerificationCoordinatorBridgePresenter) - { - return; - } // Verify that the app does not show the authentication screen whereas // the user has already logged in. @@ -379,7 +370,6 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; [self.authenticationActivityIndicator removeObserver:self forKeyPath:@"hidden"]; autoDiscovery = nil; - _keyVerificationCoordinatorBridgePresenter = nil; _keyboardAvoider = nil; } @@ -557,30 +547,6 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; } } -- (void)presentCompleteSecurityWithSession:(MXSession*)session -{ - KeyVerificationCoordinatorBridgePresenter *keyVerificationCoordinatorBridgePresenter = [[KeyVerificationCoordinatorBridgePresenter alloc] initWithSession:session]; - keyVerificationCoordinatorBridgePresenter.delegate = self; - - [keyVerificationCoordinatorBridgePresenter presentCompleteSecurityFrom:self isNewSignIn:YES animated:YES]; - - self.keyVerificationCoordinatorBridgePresenter = keyVerificationCoordinatorBridgePresenter; -} - -- (void)dismiss -{ - self.userInteractionEnabled = YES; - [self.authenticationActivityIndicator stopAnimating]; - - // Dismiss (key verification) on successful login - [self.presentingViewController dismissViewControllerAnimated:YES completion:nil]; - - if (self.authVCDelegate) - { - [self.authVCDelegate authenticationViewControllerDidDismiss:self]; - } -} - - (BOOL)continueSSOLoginWithToken:(NSString*)loginToken txnId:(NSString*)txnId { // Check if transaction id is the same as expected @@ -1377,119 +1343,8 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; }]; } - // Wait for session change to present complete security screen if needed - [self registerSessionStateChangeNotificationForSession:session]; -} - -- (void)registerSessionStateChangeNotificationForSession:(MXSession*)session -{ - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sessionStateDidChangeNotification:) name:kMXSessionStateDidChangeNotification object:session]; -} - -- (void)unregisterSessionStateChangeNotification -{ - [[NSNotificationCenter defaultCenter] removeObserver:self name:kMXSessionStateDidChangeNotification object:nil]; -} - -- (void)sessionStateDidChangeNotification:(NSNotification*)notification -{ - MXSession *session = (MXSession*)notification.object; - - if (session.state == MXSessionStateStoreDataReady) - { - if (session.crypto.crossSigning) - { - // Do not make key share requests while the "Complete security" is not complete. - // If the device is self-verified, the SDK will restore the existing key backup. - // Then, it will re-enable outgoing key share requests - [session.crypto setOutgoingKeyRequestsEnabled:NO onComplete:nil]; - } - } - else if (session.state == MXSessionStateRunning) - { - [self unregisterSessionStateChangeNotification]; - - if (session.crypto.crossSigning) - { - [session.crypto.crossSigning refreshStateWithSuccess:^(BOOL stateUpdated) { - - MXLogDebug(@"[AuthenticationVC] sessionStateDidChange: crossSigning.state: %@", @(session.crypto.crossSigning.state)); - - switch (session.crypto.crossSigning.state) - { - case MXCrossSigningStateNotBootstrapped: - { - // TODO: This is still not sure we want to disable the automatic cross-signing bootstrap - // if the admin disabled e2e by default. - // Do like riot-web for the moment - if ([session vc_homeserverConfiguration].isE2EEByDefaultEnabled) - { - // Bootstrap cross-signing on user's account - // We do it for both registration and new login as long as cross-signing does not exist yet - if (self.authInputsView.password.length) - { - MXLogDebug(@"[AuthenticationVC] sessionStateDidChange: Bootstrap with password"); - - [session.crypto.crossSigning setupWithPassword:self.authInputsView.password success:^{ - MXLogDebug(@"[AuthenticationVC] sessionStateDidChange: Bootstrap succeeded"); - [self dismiss]; - } failure:^(NSError * _Nonnull error) { - MXLogDebug(@"[AuthenticationVC] sessionStateDidChange: Bootstrap failed. Error: %@", error); - [session.crypto setOutgoingKeyRequestsEnabled:YES onComplete:nil]; - [self dismiss]; - }]; - } - else - { - // Try to setup cross-signing without authentication parameters in case if a grace period is enabled - [self.crossSigningService setupCrossSigningWithoutAuthenticationFor:session success:^{ - MXLogDebug(@"[AuthenticationVC] sessionStateDidChange: Bootstrap succeeded without credentials"); - [self dismiss]; - } failure:^(NSError * _Nonnull error) { - MXLogDebug(@"[AuthenticationVC] sessionStateDidChange: Do not know how to bootstrap cross-signing. Skip it."); - [session.crypto setOutgoingKeyRequestsEnabled:YES onComplete:nil]; - [self dismiss]; - }]; - } - } - else - { - [session.crypto setOutgoingKeyRequestsEnabled:YES onComplete:nil]; - [self dismiss]; - } - break; - } - case MXCrossSigningStateCrossSigningExists: - { - MXLogDebug(@"[AuthenticationVC] sessionStateDidChange: Complete security"); - - // Ask the user to verify this session - self.userInteractionEnabled = YES; - [self.authenticationActivityIndicator stopAnimating]; - - [self presentCompleteSecurityWithSession:session]; - break; - } - - default: - MXLogDebug(@"[AuthenticationVC] sessionStateDidChange: Nothing to do"); - - [session.crypto setOutgoingKeyRequestsEnabled:YES onComplete:nil]; - [self dismiss]; - break; - } - - } failure:^(NSError * _Nonnull error) { - MXLogDebug(@"[AuthenticationVC] sessionStateDidChange: Fail to refresh crypto state with error: %@", error); - [session.crypto setOutgoingKeyRequestsEnabled:YES onComplete:nil]; - [self dismiss]; - }]; - } - else - { - [self dismiss]; - } - } + // Ask the coordinator to show the loading spinner whilst waiting. + [self.authVCDelegate authenticationViewController:self didLoginWithSession:session andPassword:self.authInputsView.password]; } #pragma mark - MXKAuthInputsViewDelegate @@ -1621,24 +1476,6 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; [self setCustomServerFieldsVisible:YES]; } -#pragma mark - KeyVerificationCoordinatorBridgePresenterDelegate - -- (void)keyVerificationCoordinatorBridgePresenterDelegateDidComplete:(KeyVerificationCoordinatorBridgePresenter * _Nonnull)coordinatorBridgePresenter otherUserId:(NSString * _Nonnull)otherUserId otherDeviceId:(NSString * _Nonnull)otherDeviceId -{ - MXCrypto *crypto = coordinatorBridgePresenter.session.crypto; - if (!crypto.backup.hasPrivateKeyInCryptoStore || !crypto.backup.enabled) - { - MXLogDebug(@"[AuthenticationVC][MXKeyVerification] requestAllPrivateKeys: Request key backup private keys"); - [crypto setOutgoingKeyRequestsEnabled:YES onComplete:nil]; - } - [self dismiss]; -} - -- (void)keyVerificationCoordinatorBridgePresenterDelegateDidCancel:(KeyVerificationCoordinatorBridgePresenter * _Nonnull)coordinatorBridgePresenter -{ - [self dismiss]; -} - #pragma mark - SetPinCoordinatorBridgePresenterDelegate - (void)setPinCoordinatorBridgePresenterDelegateDidComplete:(SetPinCoordinatorBridgePresenter *)coordinatorBridgePresenter diff --git a/Riot/Modules/LaunchLoading/LaunchLoadingViewController.swift b/Riot/Modules/LaunchLoading/LaunchLoadingViewController.swift new file mode 100644 index 000000000..bd7dba409 --- /dev/null +++ b/Riot/Modules/LaunchLoading/LaunchLoadingViewController.swift @@ -0,0 +1,38 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import UIKit +import Reusable + +class LaunchLoadingViewController: UIViewController, Reusable { + + required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } + + init() { + super.init(nibName: "LaunchLoadingViewController", bundle: nil) + + let launchLoadingView = LaunchLoadingView.instantiate() + launchLoadingView.update(theme: ThemeService.shared().theme) + view.vc_addSubViewMatchingParent(launchLoadingView) + + // The launch time isn't profiled for analytics as it's presentation length + // will be artificially changed based on other views in the flow. + } + + override func viewWillAppear(_ animated: Bool) { + navigationController?.setNavigationBarHidden(true, animated: false) + } +} diff --git a/Riot/Modules/LaunchLoading/LaunchLoadingViewController.xib b/Riot/Modules/LaunchLoading/LaunchLoadingViewController.xib new file mode 100644 index 000000000..19628372f --- /dev/null +++ b/Riot/Modules/LaunchLoading/LaunchLoadingViewController.xib @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Riot/Modules/Onboarding/OnboardingCoordinator.swift b/Riot/Modules/Onboarding/OnboardingCoordinator.swift index 571140f43..4f01eacfb 100644 --- a/Riot/Modules/Onboarding/OnboardingCoordinator.swift +++ b/Riot/Modules/Onboarding/OnboardingCoordinator.swift @@ -54,8 +54,8 @@ final class OnboardingCoordinator: NSObject, OnboardingCoordinatorProtocol { private var navigationRouter: NavigationRouterType { parameters.router } - // Keep a strong ref as we need to init authVC early to preload its view (it is *really* slow to do in realtime) - private var authenticationCoordinator: AuthenticationCoordinatorProtocol = AuthenticationCoordinator() + // Keep a strong ref as we need to init authVC early to preload its view + private let authenticationCoordinator: AuthenticationCoordinatorProtocol private var isShowingAuthentication = false // MARK: Screen results @@ -72,6 +72,11 @@ final class OnboardingCoordinator: NSObject, OnboardingCoordinatorProtocol { init(parameters: OnboardingCoordinatorParameters) { self.parameters = parameters + + // Preload the authVC (it is *really* slow to load in realtime) + let authenticationParameters = AuthenticationCoordinatorParameters(navigationRouter: parameters.router) + authenticationCoordinator = AuthenticationCoordinator(parameters: authenticationParameters) + super.init() } @@ -178,9 +183,16 @@ final class OnboardingCoordinator: NSObject, OnboardingCoordinatorProtocol { MXLog.debug("[OnboardingCoordinator] showAuthenticationScreen") let coordinator = authenticationCoordinator - coordinator.completion = { [weak self, weak coordinator] authenticationType in + coordinator.completion = { [weak self, weak coordinator] result in guard let self = self, let coordinator = coordinator else { return } - self.authenticationCoordinator(coordinator, didCompleteWith: authenticationType) + + switch result { + case .didLogin(let session): + self.authenticationCoordinator(coordinator, didLoginWith: session) + case .didComplete(let authenticationType): + self.authenticationCoordinator(coordinator, didCompleteWith: authenticationType) + } + } // Due to needing to preload the authVC, this breaks the Coordinator init/start pattern. @@ -200,7 +212,6 @@ final class OnboardingCoordinator: NSObject, OnboardingCoordinatorProtocol { coordinator.start() add(childCoordinator: coordinator) - authenticationCoordinator = coordinator if customHomeserver != nil || customIdentityServer != nil { coordinator.updateHomeserver(customHomeserver, andIdentityServer: customIdentityServer) @@ -217,6 +228,11 @@ final class OnboardingCoordinator: NSObject, OnboardingCoordinatorProtocol { isShowingAuthentication = true } + private func authenticationCoordinator(_ coordinator: AuthenticationCoordinatorProtocol, didLoginWith session: MXSession) { + // TODO: Show next screens whilst waiting for the everything to load. + // May need to move the spinner and key verification up to here in order to coordinate properly. + } + /// Displays the next view in the flow after the authentication screen. private func authenticationCoordinator(_ coordinator: AuthenticationCoordinatorProtocol, didCompleteWith authenticationType: MXKAuthenticationType) { completion?() diff --git a/Riot/Modules/TabBar/MasterTabBarController.m b/Riot/Modules/TabBar/MasterTabBarController.m index 5484b0c2f..65ed41122 100644 --- a/Riot/Modules/TabBar/MasterTabBarController.m +++ b/Riot/Modules/TabBar/MasterTabBarController.m @@ -119,9 +119,9 @@ self.delegate = self; - _isOnboardingInProgress = NO; + self.isOnboardingInProgress = NO; - // Note: UITabBarViewController shoud not be embed in a UINavigationController (https://github.com/vector-im/riot-ios/issues/3086) + // Note: UITabBarViewController should not be embed in a UINavigationController (https://github.com/vector-im/riot-ios/issues/3086) [self vc_removeBackTitle]; [self setupTitleView]; @@ -520,7 +520,7 @@ [self.onboardingCoordinatorBridgePresenter dismissWithAnimated:YES completion:nil]; self.onboardingCoordinatorBridgePresenter = nil; - self.isOnboardingInProgress = NO; + self.isOnboardingInProgress = NO; // Must be set before calling didCompleteAuthentication [self.masterTabBarDelegate masterTabBarControllerDidCompleteAuthentication:self]; }; diff --git a/changelog.d/5621.change b/changelog.d/5621.change new file mode 100644 index 000000000..fbf80128c --- /dev/null +++ b/changelog.d/5621.change @@ -0,0 +1 @@ +Onboarding: Use a different green spinner during onboarding and use the one presented by the LegacyAppDelegate only when logged in.