chromium/ios/chrome/browser/ui/whats_new/whats_new_coordinator.mm

// Copyright 2022 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/whats_new/whats_new_coordinator.h"

#import "base/apple/foundation_util.h"
#import "base/check_op.h"
#import "base/metrics/histogram_functions.h"
#import "base/metrics/user_metrics.h"
#import "base/time/time.h"
#import "components/feature_engagement/public/event_constants.h"
#import "components/feature_engagement/public/tracker.h"
#import "ios/chrome/browser/feature_engagement/model/tracker_factory.h"
#import "ios/chrome/browser/shared/public/commands/application_commands.h"
#import "ios/chrome/browser/shared/public/commands/command_dispatcher.h"
#import "ios/chrome/browser/shared/public/commands/lens_commands.h"
#import "ios/chrome/browser/shared/public/commands/promos_manager_commands.h"
#import "ios/chrome/browser/shared/public/commands/settings_commands.h"
#import "ios/chrome/browser/shared/public/commands/whats_new_commands.h"
#import "ios/chrome/browser/shared/ui/table_view/table_view_navigation_controller.h"
#import "ios/chrome/browser/ui/promos_manager/promos_manager_ui_handler.h"
#import "ios/chrome/browser/ui/whats_new/whats_new_detail_coordinator.h"
#import "ios/chrome/browser/ui/whats_new/whats_new_mediator.h"
#import "ios/chrome/browser/ui/whats_new/whats_new_table_view_controller.h"
#import "ios/chrome/browser/url_loading/model/url_loading_browser_agent.h"

namespace {

NSString* const kTableViewNavigationDismissButtonId =
    @"kWhatsNewTableViewNavigationDismissButtonId";

}  // namespace

@interface WhatsNewCoordinator () <UINavigationControllerDelegate,
                                   UIAdaptivePresentationControllerDelegate>

// The mediator to display What's New data.
@property(nonatomic, strong) WhatsNewMediator* mediator;
// The navigation controller displaying WhatsNewTableViewController.
@property(nonatomic, strong) UINavigationController* navigationController;
// The view controller used to display the What's New features and chrome tips.
@property(nonatomic, strong) WhatsNewTableViewController* tableViewController;
// The coordinator used for What's New feature.
@property(nonatomic, strong)
    WhatsNewDetailCoordinator* whatsNewDetailCoordinator;
// The starting time of What's New.
@property(nonatomic, assign) base::TimeTicks whatsNewStartTime;
// Application command handler.
@property(nonatomic, readonly) id<ApplicationCommands> applicationHandler;
// Dispatcher for handling Lens promo actions.
@property(nonatomic, readonly) id<LensCommands> lensHandler;
// Whats New commands handler.
@property(nonatomic, readonly) id<WhatsNewCommands> whatsNewHandler;
// Settings command handler.
@property(nonatomic, readonly) id<SettingsCommands> settingsHandler;
// Number of clicked items in What's New
@property(nonatomic, assign) int clicksOnWhatsNewItemsCount;

@end

@implementation WhatsNewCoordinator

#pragma mark - ChromeCoordinator

- (void)start {
  feature_engagement::Tracker* tracker =
      feature_engagement::TrackerFactory::GetForBrowserState(
          self.browser->GetBrowserState());
  DCHECK(tracker);
  tracker->NotifyEvent(feature_engagement::events::kViewedWhatsNew);

  self.clicksOnWhatsNewItemsCount = 0;
  base::RecordAction(base::UserMetricsAction("WhatsNew.Started"));
  self.mediator = [[WhatsNewMediator alloc] init];
  self.mediator.urlLoadingAgent =
      UrlLoadingBrowserAgent::FromBrowser(self.browser);
  self.tableViewController = [[WhatsNewTableViewController alloc] init];
  self.tableViewController.navigationItem.rightBarButtonItem =
      [self dismissButton];

  self.tableViewController.delegate = self;
  self.tableViewController.actionHandler = self.mediator;
  self.mediator.consumer = self.tableViewController;
  self.mediator.applicationHandler = self.applicationHandler;
  self.mediator.whatsNewHandler = self.whatsNewHandler;
  self.mediator.lensHandler = self.lensHandler;
  self.mediator.settingsHandler = self.settingsHandler;

  [self.tableViewController reloadData];

  self.navigationController = [[UINavigationController alloc]
      initWithRootViewController:self.tableViewController];
  [self.navigationController
      setModalPresentationStyle:UIModalPresentationFormSheet];
  self.navigationController.delegate = self;
  self.navigationController.presentationController.delegate = self;
  self.navigationController.navigationBar.prefersLargeTitles = YES;

  [self.baseViewController presentViewController:self.navigationController
                                        animated:YES
                                      completion:nil];
  self.whatsNewStartTime = base::TimeTicks::Now();

  [super start];
}

- (void)stop {
  [self.whatsNewDetailCoordinator stop];
  self.whatsNewDetailCoordinator = nil;

  self.mediator = nil;
  [self.navigationController.presentingViewController
      dismissViewControllerAnimated:YES
                         completion:nil];
  self.tableViewController = nil;
  self.navigationController = nil;

  base::RecordAction(base::UserMetricsAction("WhatsNew.Dismissed"));
  UmaHistogramMediumTimes("IOS.WhatsNew.TimeSpent",
                          base::TimeTicks::Now() - self.whatsNewStartTime);
  base::UmaHistogramCounts10000("IOS.WhatsNew.ItemsClickedCount",
                                self.clicksOnWhatsNewItemsCount);

  [self.promosUIHandler promoWasDismissed];

  if (self.shouldShowBubblePromoOnDismiss) {
    [self.whatsNewHandler showWhatsNewIPH];
  }

  [super stop];
}

#pragma mark - UINavigationControllerDelegate

- (void)navigationController:(UINavigationController*)navigationController
       didShowViewController:(UIViewController*)viewController
                    animated:(BOOL)animated {
  // No-op if the previous view controller is not the detail view.
  if (!self.whatsNewDetailCoordinator) {
    return;
  }

  // Stop the detail coordinator if the next view is the table view given that
  // the previous view was the detail view..
  if (viewController == self.tableViewController) {
    [self.whatsNewDetailCoordinator stop];
    self.whatsNewDetailCoordinator = nil;
  }
}

#pragma mark - UIAdaptivePresentationControllerDelegate

- (void)presentationControllerDidDismiss:
    (UIPresentationController*)presentationController {
  [self dismiss];
}

#pragma mark - WhatsNewTableViewDelegate

- (void)detailViewController:
            (WhatsNewTableViewController*)whatsNewTableviewController
    openDetailViewControllerForItem:(WhatsNewItem*)item {
  DCHECK_EQ(self.tableViewController, whatsNewTableviewController);

  ++self.clicksOnWhatsNewItemsCount;
  self.whatsNewDetailCoordinator = [[WhatsNewDetailCoordinator alloc]
      initWithBaseNavigationController:self.navigationController
                               browser:self.browser
                                  item:item
                         actionHandler:self.mediator
                       whatsNewHandler:self.whatsNewHandler];
  [self.whatsNewDetailCoordinator start];
}

#pragma mark Private

- (id<ApplicationCommands>)applicationHandler {
  id<ApplicationCommands> handler = HandlerForProtocol(
      self.browser->GetCommandDispatcher(), ApplicationCommands);
  DCHECK(handler);

  return handler;
}

- (id<WhatsNewCommands>)whatsNewHandler {
  id<WhatsNewCommands> handler = HandlerForProtocol(
      self.browser->GetCommandDispatcher(), WhatsNewCommands);
  DCHECK(handler);

  return handler;
}

- (id<LensCommands>)lensHandler {
  id<LensCommands> handler =
      HandlerForProtocol(self.browser->GetCommandDispatcher(), LensCommands);
  DCHECK(handler);

  return handler;
}

- (id<SettingsCommands>)settingsHandler {
  id<SettingsCommands> handler = HandlerForProtocol(
      self.browser->GetCommandDispatcher(), SettingsCommands);
  DCHECK(handler);

  return handler;
}

- (UIBarButtonItem*)dismissButton {
  UIBarButtonItem* button = [[UIBarButtonItem alloc]
      initWithBarButtonSystemItem:UIBarButtonSystemItemDone
                           target:self
                           action:@selector(dismiss)];
  [button setAccessibilityIdentifier:kTableViewNavigationDismissButtonId];
  return button;
}

- (void)dismiss {
  [self.whatsNewHandler dismissWhatsNew];
}

@end