chromium/ios/chrome/browser/ui/browser_container/browser_container_view_controller.mm

// Copyright 2018 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/browser_container/browser_container_view_controller.h"

#import "base/check.h"
#import "base/feature_list.h"
#import "base/notreached.h"
#import "ios/chrome/browser/link_to_text/ui_bundled/link_to_text_delegate.h"
#import "ios/chrome/browser/shared/public/features/features.h"
#import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h"
#import "ios/chrome/browser/ui/browser_container/browser_edit_menu_handler.h"
#import "ios/chrome/common/ui/util/constraints_ui_util.h"
#import "ios/chrome/grit/ios_strings.h"
#import "ui/base/l10n/l10n_util.h"

@interface BrowserContainerViewController ()
// Properties backing public setters.
@property(nonatomic, strong) UIView* contentView;
@property(nonatomic, strong) UIViewController* contentViewController;
// BrowserContainerConsumer backing properties.
@property(nonatomic, assign, getter=isContentBlocked) BOOL contentBlocked;
// The view inserted into the hierarchy when self.contentBlocked is set to YES.
@property(nonatomic, strong) UIView* contentBlockingView;
@end

@implementation BrowserContainerViewController

- (void)dealloc {
  DCHECK(![_contentView superview] || [_contentView superview] == self.view);
}

- (void)viewDidLoad {
  [super viewDidLoad];
  self.view.autoresizingMask =
      UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
#if !defined(__IPHONE_16_0) || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_16_0
  if (@available(iOS 16, *)) {
  } else {
    [self addLinkToTextInEditMenu];
  }
#endif
}

- (void)viewDidLayoutSubviews {
  [super viewDidLayoutSubviews];

  // OverlayContainerView should cover all subviews of BrowserContainerView. The
  // ScreenTime container must be above the WebContentArea overlay container.
  [self.view
      bringSubviewToFront:self.webContentsOverlayContainerViewController.view];
  [self.view bringSubviewToFront:self.screenTimeViewController.view];
}

- (void)dismissViewControllerAnimated:(BOOL)animated
                           completion:(void (^)())completion {
  if (!self.presentedViewController) {
    // TODO(crbug.com/41364311): On iOS10, UIDocumentMenuViewController and
    // WKFileUploadPanel somehow combine to call dismiss twice instead of once.
    // The second call would dismiss the BrowserContainerViewController itself,
    // so look for that case and return early.
    //
    // TODO(crbug.com/40580587): A similar bug exists on all iOS versions with
    // WKFileUploadPanel and UIDocumentPickerViewController. See also
    // https://crbug.com/811671.
    //
    // Return early whenever this method is invoked but no VC appears to be
    // presented.  These cases will always end up dismissing the
    // BrowserContainerViewController itself, which would put the app into an
    // unresponsive state.
    return;
  }
  [super dismissViewControllerAnimated:animated completion:completion];
}

- (void)buildMenuWithBuilder:(id<UIMenuBuilder>)builder {
  [super buildMenuWithBuilder:builder];

  DCHECK(self.browserEditMenuHandler);
  [self.browserEditMenuHandler buildMenuWithBuilder:builder];
}

#pragma mark - Public

- (void)setContentViewController:(UIViewController*)contentViewController {
  if (_contentViewController == contentViewController)
    return;

  [self removeOldContentViewController];
  _contentViewController = contentViewController;

  if (contentViewController) {
    [contentViewController willMoveToParentViewController:self];
    [self addChildViewController:contentViewController];
    [self.view insertSubview:contentViewController.view atIndex:0];
    if (_contentView) {
      [self.view insertSubview:contentViewController.view
                  aboveSubview:self.contentView];
    } else {
      [self.view insertSubview:contentViewController.view atIndex:0];
    }
    [contentViewController didMoveToParentViewController:self];
  }
}

- (void)setContentView:(UIView*)contentView {
  [self removeOldContentViewController];

  if (_contentView == contentView)
    return;

  [self removeOldContentView];
  _contentView = contentView;

  _contentView.clipsToBounds = YES;

  if (contentView)
    [self.view insertSubview:contentView atIndex:0];
}

- (void)setContentBlocked:(BOOL)contentBlocked {
  if (_contentBlocked == contentBlocked)
    return;
  if (_contentBlocked) {
    // If the content was previously blocked, remove the blocking view before
    // resetting to `contentBlocked`.
    [self.contentBlockingView removeFromSuperview];
    self.contentBlockingView = nil;
  }
  _contentBlocked = contentBlocked;
  if (_contentBlocked) {
    // Install the blocking view.
    self.contentBlockingView = [[UIView alloc] initWithFrame:CGRectZero];
    self.contentBlockingView.backgroundColor =
        [UIColor secondarySystemBackgroundColor];
    UIView* overlayContainerView =
        self.webContentsOverlayContainerViewController.view;
    if (overlayContainerView) {
      [self.view insertSubview:self.contentBlockingView
                  belowSubview:overlayContainerView];
    } else {
      [self.view addSubview:self.contentBlockingView];
    }
    self.contentBlockingView.translatesAutoresizingMaskIntoConstraints = NO;
    AddSameConstraints(self.contentBlockingView, self.view);
  }
}

#if !defined(__IPHONE_16_0) || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_16_0
#pragma mark - Link to Text methods

- (void)addLinkToTextInEditMenu {
  if (!base::FeatureList::IsEnabled(kSharedHighlightingIOS)) {
    return;
  }

  NSString* title = l10n_util::GetNSString(IDS_IOS_SHARE_LINK_TO_TEXT);
  UIMenuItem* menuItem =
      [[UIMenuItem alloc] initWithTitle:title action:@selector(linkToText:)];
  RegisterEditMenuItem(menuItem);
}

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
  if (@available(iOS 16, *)) {
  } else {
    if (action == @selector(linkToText:) && self.linkToTextDelegate) {
      return [self.linkToTextDelegate shouldOfferLinkToText];
    }
  }

  return [super canPerformAction:action withSender:sender];
}

- (void)linkToText:(UIMenuItem*)item {
  DCHECK(base::FeatureList::IsEnabled(kSharedHighlightingIOS));
  DCHECK(self.linkToTextDelegate);
  [self.linkToTextDelegate handleLinkToTextSelection];
}
#endif

#pragma mark - Private

// Unloads and nils any any previous content viewControllers if they exist.
- (void)removeOldContentViewController {
  if (_contentViewController) {
    [_contentViewController willMoveToParentViewController:nil];
    [_contentViewController.view removeFromSuperview];
    [_contentViewController removeFromParentViewController];
    _contentViewController = nil;
  }
}

// Unloads and nils any any previous content views if they exist.
- (void)removeOldContentView {
  if (_contentView) {
    DCHECK(![_contentView superview] || [_contentView superview] == self.view);
    [_contentView removeFromSuperview];
    _contentView = nil;
  }
}

@end