1// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#import "ios/chrome/browser/ui/scanner/scanner_transitioning_delegate.h"
6
7#include "base/ios/block_types.h"
8
9#if !defined(__has_feature) || !__has_feature(objc_arc)
10#error "This file requires ARC support."
11#endif
12
13namespace {
14
15// The default animation duration.
16const NSTimeInterval kDefaultDuration = 0.25;
17
18enum ScannerTransition { PRESENT, DISMISS };
19
20}  // namespace
21
22// Animates the Scanner transition. If initialized with the |PRESENT|
23// transition, positions the Scanner view below its presenting view
24// controller's view in the container view and animates the presenting view to
25// slide up. If initialized with the |DISMISS| transition, positions the
26// presenting view controller's view above the Scanner view in the container
27// view and animates the presenting view to slide down.
28@interface ScannerTransitionAnimator
29    : NSObject <UIViewControllerAnimatedTransitioning> {
30  ScannerTransition _transition;
31}
32
33- (instancetype)initWithTransition:(ScannerTransition)transition;
34
35@end
36
37@implementation ScannerTransitionAnimator
38
39- (instancetype)initWithTransition:(ScannerTransition)transition {
40  self = [super init];
41  if (self) {
42    _transition = transition;
43  }
44  return self;
45}
46
47- (void)animateTransition:
48    (id<UIViewControllerContextTransitioning>)transitionContext {
49  UIView* containerView = [transitionContext containerView];
50  UIView* presentedView =
51      [transitionContext viewForKey:UITransitionContextToViewKey];
52  UIView* presentingView =
53      [transitionContext viewForKey:UITransitionContextFromViewKey];
54
55  // Get the final frame for the presented view.
56  UIViewController* presentedViewController = [transitionContext
57      viewControllerForKey:UITransitionContextToViewControllerKey];
58  CGRect finalFrame =
59      [transitionContext finalFrameForViewController:presentedViewController];
60
61  ProceduralBlock animations;
62
63  // Set the frame for the presented view.
64  presentedView.frame = finalFrame;
65  [presentedView layoutIfNeeded];
66
67  switch (_transition) {
68    case PRESENT: {
69      [containerView insertSubview:presentedView belowSubview:presentingView];
70      animations = ^void {
71        presentingView.transform =
72            CGAffineTransformMakeTranslation(0, -finalFrame.size.height);
73      };
74      break;
75    }
76    case DISMISS: {
77      [containerView insertSubview:presentedView aboveSubview:presentingView];
78      presentedView.transform =
79          CGAffineTransformMakeTranslation(0, -finalFrame.size.height);
80      animations = ^void {
81        presentedView.transform = CGAffineTransformIdentity;
82      };
83      break;
84    }
85  }
86
87  void (^completion)(BOOL) = ^void(BOOL finished) {
88    presentingView.transform = CGAffineTransformIdentity;
89    [transitionContext completeTransition:finished];
90  };
91
92  // Animate the transition.
93  [UIView animateWithDuration:kDefaultDuration
94                        delay:0
95                      options:UIViewAnimationOptionCurveEaseInOut
96                   animations:animations
97                   completion:completion];
98}
99
100- (void)animationEnded:(BOOL)transitionCompleted {
101  return;
102}
103
104- (NSTimeInterval)transitionDuration:
105    (id<UIViewControllerContextTransitioning>)transitionContext {
106  return kDefaultDuration;
107}
108
109@end
110
111@implementation ScannerTransitioningDelegate
112
113- (id<UIViewControllerAnimatedTransitioning>)
114    animationControllerForPresentedController:(UIViewController*)presented
115                         presentingController:(UIViewController*)presenting
116                             sourceController:(UIViewController*)source {
117  return [[ScannerTransitionAnimator alloc] initWithTransition:PRESENT];
118}
119
120- (id<UIViewControllerAnimatedTransitioning>)
121    animationControllerForDismissedController:(UIViewController*)dismissed {
122  return [[ScannerTransitionAnimator alloc] initWithTransition:DISMISS];
123}
124
125@end
126