// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/first_run/ui_bundled/first_run_coordinator.h"
#import <UIKit/UIKit.h>
#import "base/apple/foundation_util.h"
#import "base/feature_list.h"
#import "base/metrics/histogram_functions.h"
#import "base/notreached.h"
#import "base/time/time.h"
#import "components/signin/public/base/signin_metrics.h"
#import "ios/chrome/browser/docking_promo/coordinator/docking_promo_coordinator.h"
#import "ios/chrome/browser/first_run/model/first_run_metrics.h"
#import "ios/chrome/browser/first_run/ui_bundled/default_browser/default_browser_screen_coordinator.h"
#import "ios/chrome/browser/first_run/ui_bundled/first_run_screen_delegate.h"
#import "ios/chrome/browser/first_run/ui_bundled/first_run_util.h"
#import "ios/chrome/browser/first_run/ui_bundled/signin/signin_screen_coordinator.h"
#import "ios/chrome/browser/shared/model/browser/browser.h"
#import "ios/chrome/browser/shared/model/profile/profile_ios.h"
#import "ios/chrome/browser/ui/authentication/history_sync/history_sync_coordinator.h"
#import "ios/chrome/browser/ui/screen/screen_provider.h"
#import "ios/chrome/browser/ui/screen/screen_type.h"
#import "ios/chrome/browser/ui/search_engine_choice/search_engine_choice_coordinator.h"
#import "ios/public/provider/chrome/browser/signin/choice_api.h"
@interface FirstRunCoordinator () <FirstRunScreenDelegate,
HistorySyncCoordinatorDelegate>
@property(nonatomic, strong) ScreenProvider* screenProvider;
@property(nonatomic, strong) ChromeCoordinator* childCoordinator;
@property(nonatomic, strong) UINavigationController* navigationController;
@end
@implementation FirstRunCoordinator
- (instancetype)initWithBaseViewController:(UIViewController*)viewController
browser:(Browser*)browser
screenProvider:(ScreenProvider*)screenProvider {
DCHECK(!browser->GetBrowserState()->IsOffTheRecord());
self = [super initWithBaseViewController:viewController browser:browser];
if (self) {
_screenProvider = screenProvider;
_navigationController =
[[UINavigationController alloc] initWithNavigationBarClass:nil
toolbarClass:nil];
_navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
}
return self;
}
- (void)start {
[self presentScreen:[self.screenProvider nextScreenType]];
void (^completion)(void) = ^{
base::UmaHistogramEnumeration(first_run::kFirstRunStageHistogram,
first_run::kStart);
};
[self.navigationController setNavigationBarHidden:YES animated:NO];
[self.baseViewController presentViewController:self.navigationController
animated:NO
completion:completion];
}
- (void)stop {
if (self.childCoordinator) {
// If the child coordinator is not nil, then the FRE is stopped because
// Chrome is being shutdown.
InterruptibleChromeCoordinator* interruptibleChildCoordinator =
base::apple::ObjCCast<InterruptibleChromeCoordinator>(
self.childCoordinator);
[interruptibleChildCoordinator
interruptWithAction:SigninCoordinatorInterrupt::UIShutdownNoDismiss
completion:nil];
[self.childCoordinator stop];
self.childCoordinator = nil;
}
[self.baseViewController dismissViewControllerAnimated:YES completion:nil];
_navigationController = nil;
[super stop];
}
#pragma mark - FirstRunScreenDelegate
- (void)screenWillFinishPresenting {
[self.childCoordinator stop];
self.childCoordinator = nil;
[self presentScreen:[self.screenProvider nextScreenType]];
}
#pragma mark - Helper
// Presents the screen of certain `type`.
- (void)presentScreen:(ScreenType)type {
// If no more screen need to be present, call delegate to stop presenting
// screens.
if (type == kStepsCompleted) {
// The user went through all screens of the FRE.
base::UmaHistogramEnumeration(first_run::kFirstRunStageHistogram,
first_run::kComplete);
WriteFirstRunSentinel();
[self.delegate didFinishFirstRun];
return;
}
self.childCoordinator = [self createChildCoordinatorWithScreenType:type];
[self.childCoordinator start];
}
// Creates a screen coordinator according to `type`.
- (ChromeCoordinator*)createChildCoordinatorWithScreenType:(ScreenType)type {
switch (type) {
case kSignIn:
return [[SigninScreenCoordinator alloc]
initWithBaseNavigationController:self.navigationController
browser:self.browser
delegate:self
accessPoint:signin_metrics::AccessPoint::
ACCESS_POINT_START_PAGE
promoAction:signin_metrics::PromoAction::
PROMO_ACTION_NO_SIGNIN_PROMO];
case kHistorySync:
return [[HistorySyncCoordinator alloc]
initWithBaseNavigationController:self.navigationController
browser:self.browser
delegate:self
firstRun:YES
showUserEmail:NO
isOptional:YES
accessPoint:signin_metrics::AccessPoint::
ACCESS_POINT_START_PAGE];
case kDefaultBrowserPromo:
return [[DefaultBrowserScreenCoordinator alloc]
initWithBaseNavigationController:self.navigationController
browser:self.browser
delegate:self];
case kChoice:
return [[SearchEngineChoiceCoordinator alloc]
initForFirstRunWithBaseNavigationController:self.navigationController
browser:self.browser
firstRunDelegate:self];
case kDockingPromo:
return [[DockingPromoCoordinator alloc]
initWithBaseNavigationController:self.navigationController
browser:self.browser
delegate:self];
case kStepsCompleted:
NOTREACHED_IN_MIGRATION() << "Reaches kStepsCompleted unexpectedly.";
break;
}
return nil;
}
#pragma mark - HistorySyncCoordinatorDelegate
- (void)closeHistorySyncCoordinator:
(HistorySyncCoordinator*)historySyncCoordinator
declinedByUser:(BOOL)declined {
CHECK_EQ(self.childCoordinator, historySyncCoordinator);
[self screenWillFinishPresenting];
}
@end