Commit 38bdfc75 authored by Gauthier Ambard's avatar Gauthier Ambard Committed by Commit Bot

[iOS] Add IdentityChooser presentation animations

This CL adds the animations for the presentation of the IdentityChooser.

Bug: 873065
Cq-Include-Trybots: luci.chromium.try:ios-simulator-full-configs;master.tryserver.chromium.mac:ios-simulator-cronet
Change-Id: Id64905a5e11fcf64ed65860aabf988a01e17d837
Reviewed-on: https://chromium-review.googlesource.com/1170774
Commit-Queue: Gauthier Ambard <gambard@chromium.org>
Reviewed-by: default avatarJérôme Lebel <jlebel@chromium.org>
Cr-Commit-Position: refs/heads/master@{#582536}
parent 46f3a042
......@@ -55,6 +55,8 @@ source_set("identity_chooser_ui") {
"//ios/chrome/browser",
"//ios/chrome/browser/ui:ui_util",
"//ios/chrome/browser/ui/colors",
"//ios/chrome/browser/ui/image_util",
"//ios/chrome/browser/ui/resources:menu_shadow",
"//ios/chrome/browser/ui/table_view/cells",
"//ios/chrome/browser/ui/util",
"//ios/chrome/common",
......
......@@ -11,8 +11,13 @@
@interface IdentityChooserAnimator
: NSObject<UIViewControllerAnimatedTransitioning>
// Whether the IdentityChooser is |appearing|.
@property(nonatomic, assign) BOOL appearing;
// Origin of the animation, in window coordinates. Only user if |appearing| is
// true. Not user if equals to CGPointZero.
@property(nonatomic, assign) CGPoint origin;
@end
#endif // IOS_CHROME_BROWSER_UI_AUTHENTICATION_UNIFIED_CONSENT_IDENTITY_CHOOSER_IDENTITY_CHOOSER_ANIMATOR_H_
......@@ -8,19 +8,21 @@
#error "This file requires ARC support."
#endif
namespace {
const CGFloat kAnimationDuration = 0.25;
const CGFloat kDamping = 0.85;
const CGFloat kScaleFactor = 0.1;
} // namespace
@implementation IdentityChooserAnimator
@synthesize appearing = _appearing;
@synthesize origin = _origin;
#pragma mark - UIViewControllerAnimatedTransitioning
- (void)animateTransition:
(id<UIViewControllerContextTransitioning>)transitionContext {
// Get views and view controllers for this transition.
// The baseView is the view on top of which the VC is presented.
UIView* baseView = [transitionContext
viewForKey:self.appearing ? UITransitionContextFromViewKey
: UITransitionContextToViewKey];
// The VC being presented/dismissed and its view.
UIViewController* presentedViewController = [transitionContext
viewControllerForKey:self.appearing
......@@ -30,22 +32,47 @@
viewForKey:self.appearing ? UITransitionContextToViewKey
: UITransitionContextFromViewKey];
// Always add the destination view to the container.
UIView* containerView = [transitionContext containerView];
if (self.appearing) {
[containerView addSubview:presentedView];
presentedView.frame =
[transitionContext finalFrameForViewController:presentedViewController];
}
CGPoint endCenter = presentedView.center;
CGAffineTransform finalTransform;
CGAffineTransform scaleDown =
CGAffineTransformMakeScale(kScaleFactor, kScaleFactor);
if (self.appearing) {
if (!CGPointEqualToPoint(self.origin, CGPointZero)) {
presentedView.center =
[containerView convertPoint:self.origin fromView:nil];
}
presentedView.alpha = 0;
presentedView.transform = scaleDown;
finalTransform = CGAffineTransformIdentity;
} else {
[containerView addSubview:baseView];
finalTransform = scaleDown;
}
presentedView.frame =
[transitionContext finalFrameForViewController:presentedViewController];
[transitionContext completeTransition:YES];
[UIView animateWithDuration:kAnimationDuration
delay:0
usingSpringWithDamping:kDamping
initialSpringVelocity:0
options:0
animations:^{
presentedView.center = endCenter;
presentedView.transform = finalTransform;
presentedView.alpha = self.appearing ? 1 : 0;
}
completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
}];
}
- (NSTimeInterval)transitionDuration:
(id<UIViewControllerContextTransitioning>)transitionContext {
return 0;
return kAnimationDuration;
}
@end
......@@ -19,6 +19,8 @@
@property(nonatomic, strong) ChromeIdentity* selectedIdentity;
// Delegate.
@property(nonatomic, weak) id<IdentityChooserCoordinatorDelegate> delegate;
// Origin of the animation for the IdentityChooser.
@property(nonatomic, assign) CGPoint origin;
@end
......
......@@ -7,6 +7,7 @@
#include "base/logging.h"
#import "ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_coordinator_delegate.h"
#import "ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_mediator.h"
#import "ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_transition_delegate.h"
#import "ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_view_controller.h"
#import "ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_view_controller_presentation_delegate.h"
......@@ -42,23 +43,38 @@ typedef NS_ENUM(NSInteger, IdentityChooserCoordinatorState) {
IdentityChooserViewController* identityChooserViewController;
// Coordinator state.
@property(nonatomic, assign) IdentityChooserCoordinatorState state;
// Transition delegate for the view controller presentation.
@property(nonatomic, strong)
IdentityChooserTransitionDelegate* transitionController;
@end
@implementation IdentityChooserCoordinator
@synthesize delegate = _delegate;
@synthesize origin = _origin;
@synthesize identityChooserMediator = _identityChooserMediator;
@synthesize identityChooserViewController = _identityChooserViewController;
@synthesize state = _state;
@synthesize transitionController = _transitionController;
- (void)start {
[super start];
DCHECK_EQ(IdentityChooserCoordinatorStateNotStarted, self.state);
self.state = IdentityChooserCoordinatorStateStarted;
// Creates the controller.
self.identityChooserViewController =
[[IdentityChooserViewController alloc] init];
self.identityChooserViewController = [[IdentityChooserViewController alloc]
initWithTableViewStyle:UITableViewStylePlain
appBarStyle:ChromeTableViewControllerStyleNoAppBar];
self.identityChooserViewController.modalPresentationStyle =
UIModalPresentationCustom;
self.transitionController = [[IdentityChooserTransitionDelegate alloc] init];
self.transitionController.origin = self.origin;
self.identityChooserViewController.transitioningDelegate =
self.transitionController;
self.identityChooserViewController.modalPresentationStyle =
UIModalPresentationCustom;
// Creates the mediator.
self.identityChooserMediator = [[IdentityChooserMediator alloc] init];
self.identityChooserMediator.identityChooserViewController =
......
......@@ -4,6 +4,7 @@
#import "ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_presentation_controller.h"
#import "ios/chrome/browser/ui/image_util/image_util.h"
#import "ios/chrome/browser/ui/uikit_ui_util.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
......@@ -13,18 +14,24 @@
namespace {
const CGFloat kMaxWidth = 350;
const CGFloat kMaxHeight = 350;
const CGFloat kMinimumMargin = 25;
const CGFloat kMinimumMarginHorizontal = 25;
const CGFloat kMinimumMarginVertical = 35;
const CGFloat kShadowMargin = 196;
const CGFloat kContainerCornerRadius = 13.0;
} // namespace
@interface IdentityChooserPresentationController ()
@property(nonatomic, strong) UIView* shieldView;
@property(nonatomic, strong) UIView* shadowContainer;
@end
@implementation IdentityChooserPresentationController
@synthesize shieldView = _shieldView;
@synthesize shadowContainer = _shadowContainer;
#pragma mark - UIPresentationController
......@@ -35,8 +42,9 @@ const CGFloat kMinimumMargin = 25;
CGFloat availableWidth = CGRectGetWidth(safeAreaFrame);
CGFloat availableHeight = CGRectGetHeight(safeAreaFrame);
CGFloat width = MIN(kMaxWidth, availableWidth - 2 * kMinimumMargin);
CGFloat height = MIN(kMaxHeight, availableHeight - 2 * kMinimumMargin);
CGFloat width = MIN(kMaxWidth, availableWidth - 2 * kMinimumMarginHorizontal);
CGFloat height =
MIN(kMaxHeight, availableHeight - 2 * kMinimumMarginVertical);
CGRect presentedViewFrame = safeAreaFrame;
presentedViewFrame.origin.x += (availableWidth - width) / 2;
......@@ -47,10 +55,12 @@ const CGFloat kMinimumMargin = 25;
return presentedViewFrame;
}
- (UIView*)presentedView {
return self.shadowContainer;
}
- (void)presentationTransitionWillBegin {
self.shieldView = [[UIView alloc] init];
// TODO(crbug.com/873065): Change this for the real shadow.
self.shieldView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.2];
self.shieldView.frame = self.containerView.bounds;
[self.containerView addSubview:self.shieldView];
[self.shieldView
......@@ -58,14 +68,40 @@ const CGFloat kMinimumMargin = 25;
initWithTarget:self
action:@selector(handleShieldTap)]];
[self.containerView addSubview:self.presentedViewController.view];
self.shadowContainer = [[UIView alloc] init];
UIView* contentClippingView = [[UIView alloc] init];
contentClippingView.layer.cornerRadius = kContainerCornerRadius;
contentClippingView.layer.masksToBounds = YES;
contentClippingView.clipsToBounds = YES;
UIImageView* shadowView =
[[UIImageView alloc] initWithImage:StretchableImageNamed(@"menu_shadow")];
shadowView.autoresizingMask =
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.presentedViewController.view.autoresizingMask =
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
contentClippingView.autoresizingMask =
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[contentClippingView addSubview:self.presentedViewController.view];
[self.shadowContainer addSubview:shadowView];
[self.shadowContainer addSubview:contentClippingView];
[self.containerView addSubview:self.shadowContainer];
self.shadowContainer.frame = [self frameOfPresentedViewInContainerView];
contentClippingView.frame = self.shadowContainer.bounds;
self.presentedViewController.view.frame = self.shadowContainer.bounds;
shadowView.frame =
CGRectInset(self.shadowContainer.bounds, -kShadowMargin, -kShadowMargin);
}
- (void)containerViewWillLayoutSubviews {
self.shieldView.frame = self.containerView.bounds;
self.presentedViewController.view.frame =
[self frameOfPresentedViewInContainerView];
self.shadowContainer.frame = [self frameOfPresentedViewInContainerView];
}
#pragma mark - Private
......
......@@ -11,6 +11,9 @@
@interface IdentityChooserTransitionDelegate
: NSObject<UIViewControllerTransitioningDelegate>
// Origin of the animation. Must be in the window coordinates.
@property(nonatomic, assign) CGPoint origin;
@end
#endif // IOS_CHROME_BROWSER_UI_AUTHENTICATION_UNIFIED_CONSENT_IDENTITY_CHOOSER_IDENTITY_CHOOSER_TRANSITION_DELEGATE_H_
......@@ -13,6 +13,8 @@
@implementation IdentityChooserTransitionDelegate
@synthesize origin = _origin;
#pragma mark - UIViewControllerTransitioningDelegate
- (UIPresentationController*)
......@@ -30,6 +32,7 @@ animationControllerForPresentedController:(UIViewController*)presented
sourceController:(UIViewController*)source {
IdentityChooserAnimator* animator = [[IdentityChooserAnimator alloc] init];
animator.appearing = YES;
animator.origin = self.origin;
return animator;
}
......
......@@ -20,15 +20,6 @@
@property(nonatomic, weak) id<IdentityChooserViewControllerPresentationDelegate>
presentationDelegate;
// Initialises IdentityChooserViewController.
- (instancetype)init NS_DESIGNATED_INITIALIZER;
// -[IdentityChooserViewController init] should be used.
- (instancetype)initWithTableViewStyle:(UITableViewStyle)style
appBarStyle:
(ChromeTableViewControllerStyle)appBarStyle
NS_UNAVAILABLE;
@end
#endif // IOS_CHROME_BROWSER_UI_AUTHENTICATION_UNIFIED_CONSENT_IDENTITY_CHOOSER_IDENTITY_CHOOSER_VIEW_CONTROLLER_H_
......@@ -7,7 +7,6 @@
#include "base/logging.h"
#include "base/mac/foundation_util.h"
#import "ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_item.h"
#import "ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_transition_delegate.h"
#import "ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_view_controller_presentation_delegate.h"
#import "ios/third_party/material_components_ios/src/components/Dialogs/src/MaterialDialogs.h"
......@@ -26,29 +25,9 @@ const CGFloat kRowHeight = 54.;
const CGFloat kFooterHeight = 17.;
} // namespace
@interface IdentityChooserViewController ()
@property(nonatomic, strong)
IdentityChooserTransitionDelegate* transitionController;
@end
@implementation IdentityChooserViewController
@synthesize presentationDelegate = _presentationDelegate;
@synthesize transitionController = _transitionController;
- (instancetype)init {
self = [super initWithTableViewStyle:UITableViewStylePlain
appBarStyle:ChromeTableViewControllerStyleNoAppBar];
if (self) {
self.modalPresentationStyle = UIModalPresentationCustom;
_transitionController = [[IdentityChooserTransitionDelegate alloc] init];
self.transitioningDelegate = _transitionController;
self.modalPresentationStyle = UIModalPresentationCustom;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
......
......@@ -89,11 +89,13 @@
}
- (void)unifiedConsentViewControllerDidTapIdentityPickerView:
(UnifiedConsentViewController*)controller {
(UnifiedConsentViewController*)controller
atPoint:(CGPoint)point {
DCHECK_EQ(self.unifiedConsentViewController, controller);
self.identityChooserCoordinator = [[IdentityChooserCoordinator alloc]
initWithBaseViewController:self.unifiedConsentViewController];
self.identityChooserCoordinator.delegate = self;
self.identityChooserCoordinator.origin = point;
[self.identityChooserCoordinator start];
self.identityChooserCoordinator.selectedIdentity = self.selectedIdentity;
}
......
......@@ -21,9 +21,11 @@ extern NSString* const kUnifiedConsentScrollViewIdentifier;
- (void)unifiedConsentViewControllerDidTapSettingsLink:
(UnifiedConsentViewController*)controller;
// Called when the user taps on the IdentityPickerView.
// Called when the user taps at |point| on the IdentityPickerView. |point| is in
// the window coordinates.
- (void)unifiedConsentViewControllerDidTapIdentityPickerView:
(UnifiedConsentViewController*)controller;
(UnifiedConsentViewController*)controller
atPoint:(CGPoint)point;
// Called when the user scrolls down to the bottom (or when the view controller
// is loaded with no scroll needed).
......
......@@ -203,7 +203,7 @@ NSString* const kSyncCompleteIconName = @"ic_sync_complete";
self.identityPickerView.canChangeIdentity = self.interactable;
self.identityPickerView.translatesAutoresizingMaskIntoConstraints = NO;
[self.identityPickerView addTarget:self
action:@selector(identityPickerAction:)
action:@selector(identityPickerAction:forEvent:)
forControlEvents:UIControlEventTouchUpInside];
[container addSubview:self.identityPickerView];
......@@ -354,8 +354,13 @@ NSString* const kSyncCompleteIconName = @"ic_sync_complete";
#pragma mark - UI actions
- (void)identityPickerAction:(id)sender {
[self.delegate unifiedConsentViewControllerDidTapIdentityPickerView:self];
- (void)identityPickerAction:(id)sender forEvent:(UIEvent*)event {
UITouch* touch = event.allTouches.anyObject;
[self.delegate
unifiedConsentViewControllerDidTapIdentityPickerView:self
atPoint:
[touch
locationInView:nil]];
}
#pragma mark - Private
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment