blob: 2b2c57102a3ade92b98a1c15a09b3d698811b79e [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// 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/infobars/legacy_infobar_container_view_controller.h"
#include "base/ios/block_types.h"
#include "base/logging.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_controller.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_ui_element.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_ui_updater.h"
#import "ios/chrome/browser/ui/infobars/infobar_positioner.h"
#import "ios/chrome/browser/ui/infobars/infobar_ui_delegate.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// Duration for the alpha change animation.
const CGFloat kAlphaChangeAnimationDuration = 0.35;
} // namespace
@interface LegacyInfobarContainerViewController () <FullscreenUIElement> {
// Observer that notifies this object of fullscreen events.
std::unique_ptr<FullscreenControllerObserver> _fullscreenObserver;
}
// Whether the controller's view is currently available.
// YES from viewDidAppear to viewDidDisappear.
@property(nonatomic, assign, getter=isVisible) BOOL visible;
// Observes scrolling events in the main content area and notifies the observers
// of the current fullscreen progress value.
@property(nonatomic, assign) FullscreenController* fullscreenController;
@end
@implementation LegacyInfobarContainerViewController
- (instancetype)initWithFullscreenController:
(FullscreenController*)fullscreenController {
DCHECK(fullscreenController);
self = [super initWithNibName:nil bundle:nil];
if (self) {
_fullscreenController = fullscreenController;
}
return self;
}
#pragma mark - UIViewController
// Whenever the container or contained views are re-drawn update the layout to
// match their new size or position.
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[self updateLayoutAnimated:YES];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
self.visible = YES;
if (!_fullscreenObserver) {
_fullscreenObserver = std::make_unique<FullscreenUIUpdater>(self);
self.fullscreenController->AddObserver(_fullscreenObserver.get());
}
}
- (void)viewDidDisappear:(BOOL)animated {
if (_fullscreenObserver) {
self.fullscreenController->RemoveObserver(_fullscreenObserver.get());
_fullscreenObserver = nullptr;
}
self.visible = NO;
[super viewDidDisappear:animated];
}
#pragma mark - InfobarConsumer
- (void)addInfoBarWithDelegate:(id<InfobarUIDelegate>)infoBarDelegate
position:(NSInteger)position {
DCHECK_LE(static_cast<NSUInteger>(position), [[self.view subviews] count]);
UIView* infoBarView = infoBarDelegate.view;
[self.view insertSubview:infoBarView atIndex:position];
infoBarView.translatesAutoresizingMaskIntoConstraints = NO;
[NSLayoutConstraint activateConstraints:@[
[infoBarView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[infoBarView.trailingAnchor
constraintEqualToAnchor:self.view.trailingAnchor],
[infoBarView.topAnchor constraintEqualToAnchor:self.view.topAnchor],
[infoBarView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor]
]];
}
- (void)setUserInteractionEnabled:(BOOL)enabled {
[self.view setUserInteractionEnabled:enabled];
}
- (void)updateLayoutAnimated:(BOOL)animated {
// Update the infobarContainer height.
CGRect containerFrame = self.view.frame;
CGFloat height = [self topmostVisibleInfoBarHeight];
containerFrame.origin.y =
CGRectGetMaxY([self.positioner parentView].frame) - height;
containerFrame.size.height = height;
auto completion = ^(BOOL finished) {
if (!self.visible)
return;
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification,
self.view);
};
ProceduralBlock frameUpdates = ^{
[self.view setFrame:containerFrame];
};
if (animated) {
[UIView animateWithDuration:0.1
animations:frameUpdates
completion:completion];
} else {
frameUpdates();
completion(YES);
}
}
#pragma mark - FullscreenUIElement methods
- (void)updateForFullscreenProgress:(CGFloat)progress {
for (UIView* view in self.view.subviews) {
if ([view conformsToProtocol:@protocol(FullscreenUIElement)]) {
[(id<FullscreenUIElement>)view updateForFullscreenProgress:progress];
}
}
}
#pragma mark - Private Methods
// Animates |self.view| alpha to |alpha|.
- (void)animateInfoBarContainerToAlpha:(CGFloat)alpha {
CGFloat oldAlpha = self.view.alpha;
if (oldAlpha > 0 && alpha == 0) {
[self.view setUserInteractionEnabled:NO];
}
[UIView transitionWithView:self.view
duration:kAlphaChangeAnimationDuration
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
[self.view setAlpha:alpha];
}
completion:^(BOOL) {
if (oldAlpha == 0 && alpha > 0) {
[self.view setUserInteractionEnabled:YES];
};
}];
}
// Height of the frontmost infobar contained in |self.view| that is not hidden.
- (CGFloat)topmostVisibleInfoBarHeight {
for (UIView* view in [self.view.subviews reverseObjectEnumerator]) {
return [view sizeThatFits:self.view.frame.size].height;
}
return 0;
}
@end