chromium/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/incognito/incognito_grid_coordinator.mm

// Copyright 2023 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/ui/tab_switcher/tab_grid/grid/incognito/incognito_grid_coordinator.h"

#import "ios/chrome/browser/incognito_reauth/ui_bundled/incognito_reauth_mediator.h"
#import "ios/chrome/browser/incognito_reauth/ui_bundled/incognito_reauth_scene_agent.h"
#import "ios/chrome/browser/policy/model/policy_util.h"
#import "ios/chrome/browser/shared/model/browser/browser.h"
#import "ios/chrome/browser/shared/model/profile/profile_ios.h"
#import "ios/chrome/browser/shared/public/commands/command_dispatcher.h"
#import "ios/chrome/browser/shared/public/commands/tab_grid_toolbar_commands.h"
#import "ios/chrome/browser/shared/public/features/features.h"
#import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/disabled_grid_view_controller.h"
#import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_container_view_controller.h"
#import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_coordinator_audience.h"
#import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_empty_state_view.h"
#import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_theme.h"
#import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/incognito/incognito_grid_mediator.h"
#import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/incognito/incognito_grid_view_controller.h"
#import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/tab_group_grid_view_controller.h"
#import "ios/chrome/browser/ui/tab_switcher/tab_grid/tab_context_menu/tab_context_menu_helper.h"
#import "ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_constants.h"
#import "ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.h"
#import "ios/chrome/browser/ui/tab_switcher/tab_grid/tab_groups/tab_group_coordinator.h"
#import "ios/chrome/browser/ui/tab_switcher/tab_grid/tab_groups/tab_group_view_controller.h"

@interface IncognitoGridCoordinator ()

// Redefined as readwrite.
@property(nonatomic, readwrite, strong)
    IncognitoGridViewController* gridViewController;

@end

@implementation IncognitoGridCoordinator {
  // Reauth scene agent.
  IncognitoReauthSceneAgent* _reauthAgent;
  // Mediator for incognito reauth.
  IncognitoReauthMediator* _incognitoAuthMediator;
  // Context Menu helper for the tabs.
  TabContextMenuHelper* _tabContextMenuHelper;
  // Whether the incognito mode is currently enabled. This is not computed as we
  // might need to refer to the previous value.
  BOOL _incognitoEnabled;
  // Pointer to the browser. Even if this coordinator super class has a readonly
  // browser property, it is also kept locally as it must be readwrite here.
  base::WeakPtr<Browser> _browser;
  // Mediator of incognito grid.
  IncognitoGridMediator* _mediator;
}

- (instancetype)initWithBaseViewController:(UIViewController*)baseViewController
                                   browser:(Browser*)browser
                           toolbarsMutator:
                               (id<GridToolbarsMutator>)toolbarsMutator
                      gridMediatorDelegate:(id<GridMediatorDelegate>)delegate {
  CHECK(baseViewController);
  CHECK(browser);
  CHECK(toolbarsMutator);
  CHECK(delegate);
  if ((self = [super initWithBaseViewController:baseViewController
                                        browser:browser
                                toolbarsMutator:toolbarsMutator
                           gridMediatorDelegate:delegate])) {
    _browser = browser->AsWeakPtr();
    _incognitoEnabled =
        !IsIncognitoModeDisabled(self.browser->GetBrowserState()
                                     ->GetOriginalChromeBrowserState()
                                     ->GetPrefs());
  }
  return self;
}

#pragma mark - Property Implementation.

- (IncognitoGridMediator*)mediator {
  CHECK(_mediator)
      << "IncognitoGridCoordinator's -start should be called before.";
  return _mediator;
}

- (IncognitoGridMediator*)incognitoGridMediator {
  CHECK(_mediator)
      << "IncognitoGridCoordinator's -start should be called before.";
  return _mediator;
}

- (Browser*)browser {
  return _browser.get();
}

- (id)gridHandler {
  CHECK(_mediator)
      << "IncognitoGridCoordinator's -start should be called before.";
  return _mediator;
}

#pragma mark - Superclass overrides

- (LegacyGridTransitionLayout*)transitionLayout {
  if (IsTabGroupInGridEnabled()) {
    if (self.tabGroupCoordinator) {
      return [self.tabGroupCoordinator.viewController
                  .gridViewController transitionLayout];
    }
  }
  return [self.gridViewController transitionLayout];
}

#pragma mark - ChromeCoordinator

- (void)start {
  // TODO(crbug.com/40789579): refactor to call setIncognitoBrowser from this
  // function.
  _reauthAgent =
      [IncognitoReauthSceneAgent agentFromScene:self.browser->GetSceneState()];

  _mediator =
      [[IncognitoGridMediator alloc] initWithModeHolder:self.modeHolder];
  _mediator.incognitoDelegate = self;
  _mediator.reauthSceneAgent = _reauthAgent;

  GridContainerViewController* container =
      [[GridContainerViewController alloc] init];
  self.gridContainerViewController = container;

  _tabContextMenuHelper = [[TabContextMenuHelper alloc]
        initWithBrowserState:self.browser->GetBrowserState()
      tabContextMenuDelegate:self.tabContextMenuDelegate];

  if (_incognitoEnabled) {
    self.gridViewController = [self createGridViewController];
    container.containedViewController = self.gridViewController;
  } else {
    self.disabledViewController = [self createDisabledViewController];
    container.containedViewController = self.disabledViewController;
  }

  _incognitoAuthMediator =
      [[IncognitoReauthMediator alloc] initWithReauthAgent:_reauthAgent];
  _incognitoAuthMediator.consumer = self.gridViewController;

  [super start];
}

- (void)stop {
  _tabContextMenuHelper = nil;
  _incognitoAuthMediator = nil;
  _reauthAgent = nil;

  [super stop];
}

#pragma mark - Public

- (void)setIncognitoBrowser:(Browser*)incognitoBrowser {
  if (_browser) {
    [_browser->GetCommandDispatcher() stopDispatchingToTarget:self];
  }
  _mediator.browser = incognitoBrowser;
  _browser.reset();
  if (incognitoBrowser) {
    _browser = incognitoBrowser->AsWeakPtr();
    _tabContextMenuHelper.browserState = incognitoBrowser->GetBrowserState();
    [incognitoBrowser->GetCommandDispatcher()
        startDispatchingToTarget:self
                     forProtocol:@protocol(TabGroupsCommands)];

    _mediator.tabGroupsHandler = self;
  } else {
    _tabContextMenuHelper.browserState = nullptr;
  }
}

#pragma mark - IncognitoGridMediatorDelegate

- (void)shouldDisableIncognito:(BOOL)disable {
  if (disable && _incognitoEnabled) {
    self.disabledViewController = [self createDisabledViewController];

    // Changing the containedViewController remove the current one.
    self.gridContainerViewController.containedViewController =
        self.disabledViewController;
    self.gridViewController = nil;
  } else if (!disable && !_incognitoEnabled) {
    self.gridViewController = [self createGridViewController];

    // Changing the containedViewController remove the current one.
    self.gridContainerViewController.containedViewController =
        self.gridViewController;
    self.disabledViewController = nil;
  }

  _incognitoEnabled = !disable;

  [self.audience incognitoGridDidChange];
}

#pragma mark - Private

// Creates and returns a configured Grid. Also sets the consumer in the
// mediator.
- (IncognitoGridViewController*)createGridViewController {
  CHECK(_reauthAgent);
  CHECK(_mediator);
  CHECK(_tabContextMenuHelper);
  IncognitoGridViewController* gridViewController =
      [[IncognitoGridViewController alloc] init];
  gridViewController.reauthHandler = _reauthAgent;
  gridViewController.menuProvider = _tabContextMenuHelper;

  gridViewController.dragDropHandler = _mediator;
  gridViewController.mutator = _mediator;
  gridViewController.gridProvider = _mediator;
  // TODO(crbug.com/40273478): Move the following lines to the grid itself when
  // specific grid file will be created.
  gridViewController.view.accessibilityIdentifier = kIncognitoTabGridIdentifier;
  gridViewController.emptyStateView =
      [[TabGridEmptyStateView alloc] initWithPage:TabGridPageIncognitoTabs];
  gridViewController.emptyStateView.accessibilityIdentifier =
      kTabGridIncognitoTabsEmptyStateIdentifier;
  gridViewController.theme = GridThemeDark;

  _mediator.consumer = gridViewController;

  return gridViewController;
}

// Creates and returns a configured disabled view controller.
- (DisabledGridViewController*)createDisabledViewController {
  DisabledGridViewController* disabledViewController =
      [[DisabledGridViewController alloc]
          initWithPage:TabGridPageIncognitoTabs];
  disabledViewController.delegate = self.disabledTabViewControllerDelegate;

  return disabledViewController;
}

@end