chromium/ios/chrome/browser/context_menu/ui_bundled/link_preview/link_preview_coordinator.mm

// 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/context_menu/ui_bundled/link_preview/link_preview_coordinator.h"

#import "base/metrics/field_trial_params.h"
#import "base/strings/sys_string_conversions.h"
#import "components/url_formatter/url_formatter.h"
#import "ios/chrome/browser/context_menu/ui_bundled/link_preview/link_preview_mediator.h"
#import "ios/chrome/browser/context_menu/ui_bundled/link_preview/link_preview_view_controller.h"
#import "ios/chrome/browser/history/model/history_tab_helper.h"
#import "ios/chrome/browser/ntp/ui_bundled/new_tab_page_feature.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/model/web_state_list/web_state_list.h"
#import "ios/chrome/browser/tabs/model/tab_helper_util.h"
#import "ios/web/public/navigation/navigation_manager.h"
#import "ios/web/public/web_state.h"
#import "url/gurl.h"

@interface LinkPreviewCoordinator () {
  // The WebState used for loading the preview.
  std::unique_ptr<web::WebState> _previewWebState;
}

// Mediator that updates the UI when loading the preview.
@property(nonatomic, strong) LinkPreviewMediator* mediator;

// View controller of the preview.
@property(nonatomic, strong) LinkPreviewViewController* viewController;

// URL of the preview.
@property(nonatomic, assign) GURL URL;

@end

@implementation LinkPreviewCoordinator

- (instancetype)initWithBrowser:(Browser*)browser URL:(const GURL&)URL {
  self = [super initWithBaseViewController:nil browser:browser];
  if (self) {
    _URL = URL;
  }
  return self;
}

- (void)start {
  [self configureWebState];

  // Get the origin of the preview.
  NSString* origin = base::SysUTF16ToNSString(
      url_formatter::FormatUrl(self.URL.DeprecatedGetOriginAsURL()));

  self.viewController = [[LinkPreviewViewController alloc]
      initWithView:_previewWebState->GetView()
            origin:origin];
  self.mediator =
      [[LinkPreviewMediator alloc] initWithWebState:_previewWebState.get()
                                         previewURL:self.URL
                                           referrer:self.referrer];
  self.mediator.consumer = self.viewController;
  _previewWebState->GetNavigationManager()->LoadIfNecessary();
}

- (void)stop {
  self.viewController = nil;
  _previewWebState.reset();
}

- (UIViewController*)linkPreviewViewController {
  return self.viewController;
}

- (void)handlePreviewAction {
  WebStateList* web_state_list = self.browser->GetWebStateList();
  DCHECK_NE(WebStateList::kInvalidIndex, web_state_list->active_index());
  DCHECK(_previewWebState);

  // The WebState will be converted to a proper tab. Record navigations to the
  // HistoryService.
  HistoryTabHelper::FromWebState(_previewWebState.get())
      ->SetDelayHistoryServiceNotification(false);

  // Reset auto layout for preview before expanding it to a tab.
  [self.viewController resetAutoLayoutForPreview];

  web_state_list->ReplaceWebStateAt(web_state_list->active_index(),
                                    std::move(_previewWebState));
}

#pragma mark - Private

// Configures the web state that used to load the preview.
- (void)configureWebState {
  web::WebState* activeWebState =
      self.browser->GetWebStateList()->GetActiveWebState();
  CHECK(activeWebState);

  // To avoid losing the navigation history when the user navigates to
  // the previewed tab, clone the tab that will be replaced, and start
  // the navigation in the new tab.
  _previewWebState = activeWebState->Clone();

  // Attach tab helpers to use _previewWebState as a browser tab. It ensures
  // _previewWebState has all the expected tab helpers, including the
  // history tab helper which adding the history entry of the preview.
  AttachTabHelpers(_previewWebState.get(), TabHelperFilter::kPrerender);
  _previewWebState->SetWebUsageEnabled(true);

  // Delay the history record when showing the preview. (The history entry will
  // be added when the user tapping on the preview.)
  HistoryTabHelper::FromWebState(_previewWebState.get())
      ->SetDelayHistoryServiceNotification(true);
}

@end