chromium/ios/chrome/browser/ui/presenters/non_modal_view_controller_presenter.mm

// Copyright 2019 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/presenters/non_modal_view_controller_presenter.h"

#import <ostream>

#import "base/check.h"
#import "ios/chrome/browser/ui/presenters/contained_presenter_delegate.h"
#import "ios/chrome/common/ui/util/constraints_ui_util.h"

namespace {
constexpr CGFloat kAnimationInDuration = 0.15;
constexpr CGFloat kAnimationInScale = 1.3;
constexpr CGFloat kAnimationOutDuration = 0.1;
}  // namespace

@interface NonModalViewControllerPresenter ()

// The container for the presentation.
@property(nonatomic, strong, readwrite) UIView* containerView;

// The presenter animator, so if dismiss happens while presenting, it is smooth.
@property(nonatomic, strong, readwrite) UIViewPropertyAnimator* animator;

@end

@implementation NonModalViewControllerPresenter

@synthesize baseViewController, presentedViewController, delegate;

- (void)prepareForPresentation {
  DCHECK(self.baseViewController);
  DCHECK(self.presentedViewController);

  // Add child view controller.
  [self.baseViewController addChildViewController:self.presentedViewController];

  // Prepare the container view.
  self.containerView =
      [[UIView alloc] initWithFrame:self.baseViewController.view.bounds];
  self.containerView.alpha = 0.0;
  self.containerView.transform = CGAffineTransformScale(
      CGAffineTransformIdentity, kAnimationInScale, kAnimationInScale);

  // Add the presented view in the container.
  self.presentedViewController.view.translatesAutoresizingMaskIntoConstraints =
      NO;
  [self.containerView addSubview:self.presentedViewController.view];
  AddSameConstraints(self.presentedViewController.view, self.containerView);

  // Add the container to the presenting view controller.
  self.containerView.translatesAutoresizingMaskIntoConstraints = NO;
  [self.baseViewController.view addSubview:self.containerView];
  AddSameConstraints(self.containerView, self.baseViewController.view);
}

- (void)presentAnimated:(BOOL)animated {
  DCHECK(!self.animator) << "Presenting again is not supported.";
  __weak __typeof(self) weakSelf = self;
  auto animation = ^{
    weakSelf.containerView.alpha = 1.0;
    weakSelf.containerView.transform = CGAffineTransformIdentity;
  };
  auto completion = ^void(UIViewAnimatingPosition) {
    [weakSelf.presentedViewController
        didMoveToParentViewController:weakSelf.baseViewController];
    if ([weakSelf.delegate
            respondsToSelector:@selector(containedPresenterDidPresent:)]) {
      [weakSelf.delegate containedPresenterDidPresent:weakSelf];
    }
  };

  if (animated) {
    self.animator = [[UIViewPropertyAnimator alloc]
        initWithDuration:animated ? kAnimationInDuration : 0
                   curve:UIViewAnimationCurveEaseOut
              animations:animation];
    [self.animator addCompletion:completion];
    [self.animator startAnimation];
  } else {
    animation();
    completion(UIViewAnimatingPositionEnd);
  }
}

- (void)dismissAnimated:(BOOL)animated {
  if (self.animator.state == UIViewAnimatingStateActive)
    [self.animator stopAnimation:YES];

  [self.presentedViewController willMoveToParentViewController:nil];

  __weak __typeof(self) weakSelf = self;
  auto animation = ^{
    weakSelf.containerView.alpha = 0.0;
  };
  auto completion = ^void(UIViewAnimatingPosition) {
    [weakSelf.presentedViewController.view removeFromSuperview];
    [weakSelf.presentedViewController removeFromParentViewController];
    [weakSelf.containerView removeFromSuperview];
    if ([weakSelf.delegate
            respondsToSelector:@selector(containedPresenterDidDismiss:)]) {
      [weakSelf.delegate containedPresenterDidDismiss:weakSelf];
    }
  };

  if (animated) {
    UIViewPropertyAnimator* dismissAnimator = [[UIViewPropertyAnimator alloc]
        initWithDuration:animated ? kAnimationOutDuration : 0
                   curve:UIViewAnimationCurveEaseOut
              animations:animation];
    [dismissAnimator addCompletion:completion];
    [dismissAnimator startAnimation];
  } else {
    animation();
    completion(UIViewAnimatingPositionEnd);
  }
}

@end