blob: 832de03afada7c2b7e8a4fcdb927d90f924e01d3 [file] [log] [blame]
// Copyright 2012 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/history/tab_history_popup_controller.h"
#import <QuartzCore/QuartzCore.h>
#include "base/logging.h"
#include "base/mac/bundle_locations.h"
#include "base/strings/sys_string_conversions.h"
#import "ios/chrome/browser/ui/history/tab_history_view_controller.h"
#import "ios/chrome/browser/ui/popup_menu/popup_menu_view.h"
#include "ios/chrome/browser/ui/rtl_geometry.h"
#include "ios/chrome/browser/ui/ui_util.h"
#import "ios/chrome/common/material_timing.h"
#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
#import "ios/web/navigation/crw_session_entry.h"
#include "ios/web/public/navigation_item.h"
#import "ui/gfx/ios/NSString+CrStringDrawing.h"
#include "ui/gfx/ios/uikit_util.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
static const CGFloat kTabHistoryMinWidth = 250.0;
static const CGFloat kTabHistoryMaxWidthLandscapePhone = 350.0;
// x coordinate for the textLabel in a default table cell with an image.
static const CGFloat kCellTextXCoordinate = 60.0;
// Inset for the shadows of the contained views.
NS_INLINE UIEdgeInsets TabHistoryPopupMenuInsets() {
return UIEdgeInsetsMakeDirected(9, 11, 12, 11);
}
// Layout for popup: shift twelve pixels towards the leading edge.
LayoutOffset kHistoryPopupLeadingOffset = -12;
CGFloat kHistoryPopupYOffset = 3;
// Occupation of the Tools Container as a percentage of the parent height.
static const CGFloat kHeightPercentage = 0.85;
} // anonymous namespace
@interface TabHistoryPopupController () {
// TableViewController for the table displaying tab history entries.
TabHistoryViewController* tabHistoryTableViewController_;
// Container view of the history entries table.
UIView* tabHistoryTableViewContainer_;
}
// Determines the width for the popup depending on the device, orientation, and
// CRWSessionEntrys to display.
- (CGFloat)calculatePopupWidth:(NSArray*)entries;
@property(nonatomic, strong)
TabHistoryViewController* tabHistoryTableViewController;
@property(nonatomic, strong) UIView* tabHistoryTableViewContainer;
@end
@implementation TabHistoryPopupController
@synthesize tabHistoryTableViewController = tabHistoryTableViewController_;
@synthesize tabHistoryTableViewContainer = tabHistoryTableViewContainer_;
- (id)initWithOrigin:(CGPoint)origin
parentView:(UIView*)parent
entries:(NSArray*)entries {
DCHECK(parent);
self = [super initWithParentView:parent];
if (self) {
tabHistoryTableViewController_ = [[TabHistoryViewController alloc] init];
[tabHistoryTableViewController_ setSessionEntries:entries];
UICollectionView* collectionView =
[tabHistoryTableViewController_ collectionView];
[collectionView setAccessibilityIdentifier:@"Tab History"];
tabHistoryTableViewContainer_ = [[UIView alloc] initWithFrame:CGRectZero];
[tabHistoryTableViewContainer_ layer].cornerRadius = 2;
[tabHistoryTableViewContainer_ layer].masksToBounds = YES;
[tabHistoryTableViewContainer_ addSubview:collectionView];
LayoutOffset originOffset =
kHistoryPopupLeadingOffset - TabHistoryPopupMenuInsets().left;
CGPoint newOrigin = CGPointLayoutOffset(origin, originOffset);
newOrigin.y += kHistoryPopupYOffset;
CGFloat availableHeight =
(CGRectGetHeight([parent bounds]) - origin.y) * kHeightPercentage;
CGFloat optimalHeight =
[tabHistoryTableViewController_ optimalHeight:availableHeight];
CGFloat popupWidth = [self calculatePopupWidth:entries];
[self setOptimalSize:CGSizeMake(popupWidth, optimalHeight)
atOrigin:newOrigin];
CGRect bounds = [[self popupContainer] bounds];
CGRect frame = UIEdgeInsetsInsetRect(bounds, TabHistoryPopupMenuInsets());
[tabHistoryTableViewContainer_ setFrame:frame];
[collectionView setFrame:[tabHistoryTableViewContainer_ bounds]];
[[self popupContainer] addSubview:tabHistoryTableViewContainer_];
CGRect containerFrame = [[self popupContainer] frame];
CGPoint destination = CGPointMake(CGRectGetLeadingEdge(containerFrame),
CGRectGetMinY(containerFrame));
[self fadeInPopupFromSource:origin toDestination:destination];
}
return self;
}
- (void)fadeInPopupFromSource:(CGPoint)source
toDestination:(CGPoint)destination {
[tabHistoryTableViewContainer_ setAlpha:0];
[UIView animateWithDuration:ios::material::kDuration1
animations:^{
[tabHistoryTableViewContainer_ setAlpha:1];
}];
[super fadeInPopupFromSource:source toDestination:destination];
}
- (void)dismissAnimatedWithCompletion:(void (^)(void))completion {
[tabHistoryTableViewContainer_ setAlpha:0];
[super dismissAnimatedWithCompletion:completion];
}
- (CGFloat)calculatePopupWidth:(NSArray*)entries {
CGFloat maxWidth;
// Determine the maximum width for the device and orientation.
if (!IsIPadIdiom()) {
UIInterfaceOrientation orientation =
[[UIApplication sharedApplication] statusBarOrientation];
// Phone in portrait has constant width.
if (UIInterfaceOrientationIsPortrait(orientation))
return kTabHistoryMinWidth;
maxWidth = kTabHistoryMaxWidthLandscapePhone;
} else {
// On iPad use 85% of the available width.
maxWidth = ui::AlignValueToUpperPixel(
[UIApplication sharedApplication].keyWindow.frame.size.width * .85);
}
// Increase the width to fit the text to display but don't exceed maxWidth.
CGFloat cellWidth = kTabHistoryMinWidth;
UIFont* font = [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:16];
for (CRWSessionEntry* sessionEntry in entries) {
web::NavigationItem* item = sessionEntry.navigationItem;
// TODO(rohitrao): Can this be replaced with GetTitleForDisplay()?
NSString* cellText = item->GetTitle().empty()
? base::SysUTF8ToNSString(item->GetURL().spec())
: base::SysUTF16ToNSString(item->GetTitle());
CGFloat contentWidth = [cellText cr_pixelAlignedSizeWithFont:font].width +
kCellTextXCoordinate;
// If contentWidth is larger than maxWidth, return maxWidth instead of
// checking the rest of the entries.
if (contentWidth > maxWidth)
return maxWidth;
if (contentWidth > cellWidth)
cellWidth = contentWidth;
}
return cellWidth;
}
- (void)dealloc {
[tabHistoryTableViewContainer_ removeFromSuperview];
}
@end