Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(110)

Unified Diff: ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm

Issue 2588733002: Upstream Chrome on iOS source code [9/11]. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm
diff --git a/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm b/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm
new file mode 100644
index 0000000000000000000000000000000000000000..0f19ea9722743c7e398622fe4f1de5829ac4ce05
--- /dev/null
+++ b/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm
@@ -0,0 +1,958 @@
+// Copyright 2014 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/tools_menu/tools_menu_view_controller.h"
+
+#include <stdint.h>
+
+#include "base/ios/ios_util.h"
+#import "base/ios/weak_nsobject.h"
+#include "base/logging.h"
+#include "base/mac/objc_property_releaser.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/metrics/field_trial.h"
+#include "components/reading_list/core/reading_list_switches.h"
+#include "components/strings/grit/components_strings.h"
+#include "ios/chrome/browser/experimental_flags.h"
+#import "ios/chrome/browser/ui/animation_util.h"
+#import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
+#include "ios/chrome/browser/ui/commands/ios_command_ids.h"
+#import "ios/chrome/browser/ui/reading_list/reading_list_menu_notification_delegate.h"
+#import "ios/chrome/browser/ui/reading_list/reading_list_menu_notifier.h"
+#include "ios/chrome/browser/ui/rtl_geometry.h"
+#include "ios/chrome/browser/ui/toolbar/toolbar_resource_macros.h"
+#import "ios/chrome/browser/ui/tools_menu/reading_list_menu_view_item.h"
+#import "ios/chrome/browser/ui/tools_menu/tools_menu_context.h"
+#import "ios/chrome/browser/ui/tools_menu/tools_menu_view_item.h"
+#import "ios/chrome/browser/ui/tools_menu/tools_popup_controller.h"
+#include "ios/chrome/browser/ui/ui_util.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
+#import "ios/chrome/common/material_timing.h"
+#include "ios/chrome/grit/ios_strings.h"
+#include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
+#import "ios/public/provider/chrome/browser/user_feedback/user_feedback_provider.h"
+#import "ios/third_party/material_components_ios/src/components/Ink/src/MaterialInk.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/l10n/l10n_util_mac.h"
+#include "ui/base/resource/resource_bundle.h"
+
+using ios::material::TimingFunction;
+
+NSString* const kToolsMenuNewTabId = @"kToolsMenuNewTabId";
+NSString* const kToolsMenuNewIncognitoTabId = @"kToolsMenuNewIncognitoTabId";
+NSString* const kToolsMenuCloseAllTabsId = @"kToolsMenuCloseAllTabsId";
+NSString* const kToolsMenuCloseAllIncognitoTabsId =
+ @"kToolsMenuCloseAllIncognitoTabsId";
+NSString* const kToolsMenuBookmarksId = @"kToolsMenuBookmarksId";
+NSString* const kToolsMenuReadingListId = @"kToolsMenuReadingListId";
+NSString* const kToolsMenuOtherDevicesId = @"kToolsMenuOtherDevicesId";
+NSString* const kToolsMenuHistoryId = @"kToolsMenuHistoryId";
+NSString* const kToolsMenuReportAnIssueId = @"kToolsMenuReportAnIssueId";
+NSString* const kToolsMenuFindInPageId = @"kToolsMenuFindInPageId";
+NSString* const kToolsMenuReaderMode = @"kToolsMenuReaderMode";
+NSString* const kToolsMenuRequestDesktopId = @"kToolsMenuRequestDesktopId";
+NSString* const kToolsMenuSettingsId = @"kToolsMenuSettingsId";
+NSString* const kToolsMenuHelpId = @"kToolsMenuHelpId";
+
+namespace {
+
+// Time for ink to fade into view.
+static const NSTimeInterval kMDCInkTouchDelayInterval = 0.15;
+
+static const CGFloat kMenuItemHeight = 48;
+
+static NSString* const kToolsItemCellID = @"ToolsItemCellID";
+
+// Menu items can be marked as visible or not when Incognito is enabled.
+// The following bits are used for |visibility| field in |MenuItemInfo|.
+const NSInteger kVisibleIncognitoOnly = 1 << 0;
+const NSInteger kVisibleNotIncognitoOnly = 1 << 1;
+
+// Initialization table for all possible commands to initialize the
+// tools menu at run time. Data initialized into this structure is not mutable.
+struct MenuItemInfo {
+ int title_id;
+ NSString* accessibility_id;
+ int command_id;
+ int toolbar_types;
+ // |visibility| is applied if a menu item is included for a given
+ // |toolbar_types|. A value of 0 means the menu item is always visible for
+ // the given |toolbar_types|.
+ int visibility;
+ // Custom class, if any, for the menu item, or |nil|.
+ Class item_class;
+};
+
+// Flags for different toolbar types
+typedef NS_OPTIONS(NSUInteger, kToolbarType) {
+ // clang-format off
+ kToolbarTypeNone = 0,
+ kToolbarTypeWebiPhone = 1 << 0,
+ kToolbarTypeWebiPad = 1 << 1,
+ kToolbarTypeNoTabsiPad = 1 << 2,
+ kToolbarTypeSwitcheriPhone = 1 << 3,
+ kToolbarTypeWebAll = kToolbarTypeWebiPhone | kToolbarTypeWebiPad,
+ kToolbarTypeAll = kToolbarTypeWebAll |
+ kToolbarTypeSwitcheriPhone |
+ kToolbarTypeNoTabsiPad,
+ // clang-format on
+};
+
+// Declare all the possible items.
+static MenuItemInfo itemInfoList[] = {
+ // clang-format off
+ { IDS_IOS_TOOLS_MENU_NEW_TAB, kToolsMenuNewTabId,
+ IDC_NEW_TAB, kToolbarTypeAll,
+ 0, nil },
+ { IDS_IOS_TOOLS_MENU_NEW_INCOGNITO_TAB, kToolsMenuNewIncognitoTabId,
+ IDC_NEW_INCOGNITO_TAB, kToolbarTypeAll,
+ 0, nil },
+ { IDS_IOS_TOOLS_MENU_CLOSE_ALL_TABS, kToolsMenuCloseAllTabsId,
+ IDC_CLOSE_ALL_TABS, kToolbarTypeSwitcheriPhone,
+ kVisibleNotIncognitoOnly, nil },
+ { IDS_IOS_TOOLS_MENU_CLOSE_ALL_INCOGNITO_TABS,
+ kToolsMenuCloseAllIncognitoTabsId,
+ IDC_CLOSE_ALL_INCOGNITO_TABS, kToolbarTypeSwitcheriPhone,
+ kVisibleIncognitoOnly, nil },
+ { IDS_IOS_TOOLS_MENU_BOOKMARKS, kToolsMenuBookmarksId,
+ IDC_SHOW_BOOKMARK_MANAGER, kToolbarTypeWebAll,
+ 0, nil },
+ { IDS_IOS_TOOLS_MENU_READING_LIST, kToolsMenuReadingListId,
+ IDC_SHOW_READING_LIST, kToolbarTypeWebAll,
+ 0, [ReadingListMenuViewItem class] },
+ { IDS_IOS_TOOLS_MENU_RECENT_TABS, kToolsMenuOtherDevicesId,
+ IDC_SHOW_OTHER_DEVICES, kToolbarTypeWebAll,
+ kVisibleNotIncognitoOnly, nil },
+ { IDS_HISTORY_SHOW_HISTORY, kToolsMenuHistoryId,
+ IDC_SHOW_HISTORY, kToolbarTypeWebAll,
+ 0, nil },
+ { IDS_IOS_OPTIONS_REPORT_AN_ISSUE, kToolsMenuReportAnIssueId,
+ IDC_REPORT_AN_ISSUE, kToolbarTypeAll,
+ 0, nil },
+ { IDS_IOS_TOOLS_MENU_FIND_IN_PAGE, kToolsMenuFindInPageId,
+ IDC_FIND, kToolbarTypeWebAll,
+ 0, nil },
+ { IDS_IOS_TOOLS_MENU_REQUEST_DESKTOP_SITE, kToolsMenuRequestDesktopId,
+ IDC_REQUEST_DESKTOP_SITE, kToolbarTypeWebAll,
+ 0, nil },
+ { IDS_IOS_TOOLS_MENU_READER_MODE, kToolsMenuReaderMode,
+ IDC_READER_MODE, kToolbarTypeWebAll,
+ 0, nil },
+ { IDS_IOS_TOOLS_MENU_SETTINGS, kToolsMenuSettingsId,
+ IDC_OPTIONS, kToolbarTypeAll,
+ 0, nil },
+ { IDS_IOS_TOOLS_MENU_HELP_MOBILE, kToolsMenuHelpId,
+ IDC_HELP_PAGE_VIA_MENU, kToolbarTypeWebAll,
+ 0, nil },
+ // clang-format on
+};
+
+NS_INLINE BOOL ItemShouldBeVisible(const MenuItemInfo& item,
+ BOOL incognito,
+ kToolbarType toolbarType) {
+ if (!(item.toolbar_types & toolbarType))
+ return NO;
+
+ if (incognito && (item.visibility & kVisibleNotIncognitoOnly))
+ return NO;
+
+ if (!incognito && (item.visibility & kVisibleIncognitoOnly))
+ return NO;
+
+ if (item.title_id == IDS_IOS_TOOLBAR_SHOW_TABS) {
+ if (!IsIPadIdiom() || !experimental_flags::IsTabSwitcherEnabled()) {
+ return NO;
+ }
+ }
+
+ if (item.title_id == IDS_IOS_TOOLS_MENU_READER_MODE) {
+ if (!experimental_flags::IsReaderModeEnabled()) {
+ return NO;
+ }
+ }
+
+ if (item.title_id == IDS_IOS_TOOLS_MENU_READING_LIST) {
+ if (!reading_list::switches::IsReadingListEnabled()) {
+ return NO;
+ }
+ }
+
+ if (item.title_id == IDS_IOS_OPTIONS_REPORT_AN_ISSUE) {
+ if (!ios::GetChromeBrowserProvider()
+ ->GetUserFeedbackProvider()
+ ->IsUserFeedbackEnabled()) {
+ return NO;
+ }
+ }
+
+ return YES;
+}
+
+NS_INLINE void AnimateInViews(NSArray* views,
+ CGFloat initialX,
+ CGFloat initialY) {
+ [views enumerateObjectsUsingBlock:^(UIView* view, NSUInteger index,
+ BOOL* stop) {
+ CGFloat beginTime = index * .035;
+ CABasicAnimation* transformAnimation =
+ [CABasicAnimation animationWithKeyPath:@"transform"];
+ [transformAnimation
+ setFromValue:[NSValue
+ valueWithCATransform3D:CATransform3DMakeTranslation(
+ initialX, initialY, 0)]];
+ [transformAnimation
+ setToValue:[NSValue valueWithCATransform3D:CATransform3DIdentity]];
+ [transformAnimation setDuration:ios::material::kDuration1];
+ [transformAnimation setBeginTime:beginTime];
+
+ CAAnimation* fadeAnimation = OpacityAnimationMake(0, 1);
+ [fadeAnimation setDuration:ios::material::kDuration1];
+ [fadeAnimation
+ setTimingFunction:TimingFunction(ios::material::CurveEaseOut)];
+ [fadeAnimation setBeginTime:beginTime];
+
+ [[view layer]
+ addAnimation:AnimationGroupMake(@[ transformAnimation, fadeAnimation ])
+ forKey:@"animateIn"];
+ }];
+}
+} // anonymous namespace
+
+@interface ToolsMenuButton : UIButton
+@end
+
+@implementation ToolsMenuButton
+
+@end
+
+@interface ToolsMenuCollectionView : UICollectionView
+@property(nonatomic, assign) CGPoint touchBeginPoint;
+@property(nonatomic, assign) CGPoint touchEndPoint;
+@end
+
+@implementation ToolsMenuCollectionView
+
+@synthesize touchBeginPoint = _touchBeginPoint;
+@synthesize touchEndPoint = _touchEndPoint;
+
+- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
+ _touchBeginPoint = [[touches anyObject] locationInView:self];
+ [super touchesBegan:touches withEvent:event];
+}
+
+- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
+ _touchEndPoint = [[touches anyObject] locationInView:self];
+ [super touchesEnded:touches withEvent:event];
+}
+
+@end
+
+@interface ToolsMenuViewToolsCell : UICollectionViewCell
+@property(nonatomic, retain) ToolsMenuButton* reloadButton;
+@property(nonatomic, retain) ToolsMenuButton* shareButton;
+@property(nonatomic, retain) ToolsMenuButton* starButton;
+@property(nonatomic, retain) ToolsMenuButton* starredButton;
+@property(nonatomic, retain) ToolsMenuButton* stopButton;
+@property(nonatomic, retain) ToolsMenuButton* toolsButton;
+@end
+
+@implementation ToolsMenuViewToolsCell {
+ base::mac::ObjCPropertyReleaser _propertyReleaser_ToolsMenuViewToolsCell;
+}
+
+@synthesize reloadButton = _reloadButton;
+@synthesize shareButton = _shareButton;
+@synthesize starButton = _starButton;
+@synthesize starredButton = _starredButton;
+@synthesize stopButton = _stopButton;
+@synthesize toolsButton = _toolsButton;
+
+- (instancetype)initWithCoder:(NSCoder*)aDecoder {
+ self = [super initWithCoder:aDecoder];
+ if (self)
+ [self commonInitialization];
+
+ return self;
+}
+
+- (instancetype)initWithFrame:(CGRect)frame {
+ self = [super initWithFrame:frame];
+ if (self)
+ [self commonInitialization];
+
+ return self;
+}
+
+- (void)commonInitialization {
+ _propertyReleaser_ToolsMenuViewToolsCell.Init(self,
+ [ToolsMenuViewToolsCell class]);
+
+ [self setBackgroundColor:[UIColor whiteColor]];
+ [self setOpaque:YES];
+
+ int star[2][3] = TOOLBAR_IDR_TWO_STATE(STAR);
+ _starButton = [self newButtonForImageIds:star
+ commandID:IDC_BOOKMARK_PAGE
+ accessibilityLabelID:IDS_BOOKMARK_ADD_EDITOR_TITLE
+ automationName:@"Add Bookmark"];
+
+ int star_pressed[2][3] = TOOLBAR_IDR_ONE_STATE(STAR_PRESSED);
+ _starredButton = [self newButtonForImageIds:star_pressed
+ commandID:IDC_TEMP_EDIT_BOOKMARK
+ accessibilityLabelID:IDS_IOS_TOOLS_MENU_EDIT_BOOKMARK
+ automationName:@"Edit Bookmark"];
+
+ int reload[2][3] = TOOLBAR_IDR_TWO_STATE(RELOAD);
+ _reloadButton = [self newButtonForImageIds:reload
+ commandID:IDC_RELOAD
+ accessibilityLabelID:IDS_IOS_ACCNAME_RELOAD
+ automationName:@"Reload"
+ reverseForRTL:YES];
+
+ int stop[2][3] = TOOLBAR_IDR_TWO_STATE(STOP);
+ _stopButton = [self newButtonForImageIds:stop
+ commandID:IDC_STOP
+ accessibilityLabelID:IDS_IOS_ACCNAME_STOP
+ automationName:@"Stop"];
+
+ int share[2][3] = TOOLBAR_IDR_THREE_STATE(SHARE);
+ _shareButton = [self newButtonForImageIds:share
+ commandID:IDC_SHARE_PAGE
+ accessibilityLabelID:IDS_IOS_TOOLS_MENU_SHARE
+ automationName:@"Stop"];
+ int tools[2][3] = TOOLBAR_IDR_ONE_STATE(TOOLS_PRESSED);
+ _toolsButton =
+ [self newButtonForImageIds:tools
+ commandID:IDC_SHOW_TOOLS_MENU
+ accessibilityLabelID:IDS_IOS_TOOLBAR_CLOSE_MENU
+ automationName:@"kToolbarToolsMenuButtonIdentifier"];
+
+ UIView* contentView = [self contentView];
+ [contentView setBackgroundColor:[self backgroundColor]];
+ [contentView setOpaque:YES];
+
+ [contentView addSubview:_starredButton];
+ [contentView addSubview:_starButton];
+ [contentView addSubview:_stopButton];
+ [contentView addSubview:_reloadButton];
+ [contentView addSubview:_shareButton];
+
+ [self addConstraints];
+}
+
+- (UIImage*)imageForImageId:(int)imageId reversed:(BOOL)reversed {
+ if (imageId == 0) {
+ return nil;
+ }
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ gfx::Image image = rb.GetNativeImageNamed(imageId);
+ if (reversed) {
+ return [image.ToUIImage() imageFlippedForRightToLeftLayoutDirection];
+ } else {
+ return image.ToUIImage();
+ }
+}
+
+- (ToolsMenuButton*)newButtonForImageIds:(int[2][3])imageIds
+ commandID:(int)commandID
+ accessibilityLabelID:(int)labelID
+ automationName:(NSString*)name {
+ return [self newButtonForImageIds:imageIds
+ commandID:commandID
+ accessibilityLabelID:labelID
+ automationName:name
+ reverseForRTL:NO];
+}
+
+- (ToolsMenuButton*)newButtonForImageIds:(int[2][3])imageIds
+ commandID:(int)commandID
+ accessibilityLabelID:(int)labelID
+ automationName:(NSString*)name
+ reverseForRTL:(BOOL)reverseForRTL {
+ ToolsMenuButton* button = [[ToolsMenuButton alloc] initWithFrame:CGRectZero];
+ [button setTranslatesAutoresizingMaskIntoConstraints:NO];
+ BOOL reverseImage = reverseForRTL && UseRTLLayout();
+
+ [button setImage:[self imageForImageId:imageIds[0][0] reversed:reverseImage]
+ forState:UIControlStateNormal];
+ [[button imageView] setContentMode:UIViewContentModeCenter];
+ [button setBackgroundColor:[self backgroundColor]];
+ [button setTag:commandID];
+ [button setOpaque:YES];
+
+ SetA11yLabelAndUiAutomationName(button, labelID, name);
+
+ UIImage* pressedImage =
+ [self imageForImageId:imageIds[0][1] reversed:reverseImage];
+ if (pressedImage) {
+ [button setImage:pressedImage forState:UIControlStateHighlighted];
+ }
+
+ UIImage* disabledImage =
+ [self imageForImageId:imageIds[0][2] reversed:reverseImage];
+ if (disabledImage) {
+ [button setImage:disabledImage forState:UIControlStateDisabled];
+ }
+
+ return button;
+}
+
+- (void)addConstraints {
+ UIView* contentView = [self contentView];
+
+ for (UIButton* button in [self allButtons]) {
+ NSDictionary* view = @{ @"button" : button };
+ NSArray* constraints = @[ @"V:|-(0)-[button]-(0)-|", @"H:[button(==48)]" ];
+ ApplyVisualConstraints(constraints, view, self);
+ }
+
+ NSDictionary* views = @{
+ @"share" : _shareButton,
+ @"star" : _starButton,
+ @"reload" : _reloadButton,
+ @"starred" : _starredButton,
+ @"stop" : _stopButton
+ };
+ // Leading offset is 16, minus the button image inset of 12.
+ NSDictionary* metrics = @{ @"offset" : @4, @"space" : @24 };
+ // clang-format off
+ NSArray* constraints = @[
+ @"H:|-(offset)-[share]-(space)-[star]-(space)-[reload]",
+ @"H:[share]-(space)-[starred]",
+ @"H:[star]-(space)-[stop]"
+ ];
+ // clang-format on
+ ApplyVisualConstraintsWithMetricsAndOptions(
+ constraints, views, metrics, LayoutOptionForRTLSupport(), contentView);
+}
+
+// These should be added in display order, so they are animated in display
+// order.
+- (NSArray*)allButtons {
+ NSMutableArray* allButtons = [NSMutableArray array];
+ if (_shareButton)
+ [allButtons addObject:_shareButton];
+
+ if (_starButton)
+ [allButtons addObject:_starButton];
+
+ if (_starredButton)
+ [allButtons addObject:_starredButton];
+
+ if (_reloadButton)
+ [allButtons addObject:_reloadButton];
+
+ if (_stopButton)
+ [allButtons addObject:_stopButton];
+
+ return allButtons;
+}
+
+@end
+
+// Class Extension for private methods.
+@interface ToolsMenuViewController ()<UICollectionViewDelegateFlowLayout,
+ UICollectionViewDataSource,
+ ReadingListMenuNotificationDelegate> {
+ base::mac::ObjCPropertyReleaser _propertyReleaser_ToolsMenuViewController;
+ BOOL _waitForInk;
+ // Weak pointer to ReadingListMenuNotifier, used to set the starting values
+ // for the reading list badge.
+ base::WeakNSObject<ReadingListMenuNotifier> _readingListMenuNotifier;
+}
+@property(nonatomic, retain) ToolsMenuCollectionView* menuView;
+@property(nonatomic, retain) MDCInkView* touchFeedbackView;
+@property(nonatomic, retain) NSMutableArray* menuItems;
+@property(nonatomic, assign) kToolbarType toolbarType;
+
+// Get the reading list cell.
+- (ReadingListMenuViewCell*)readingListCell;
+@end
+
+@implementation ToolsMenuViewController
+
+@synthesize menuView = _menuView;
+@synthesize isCurrentPageBookmarked = _isCurrentPageBookmarked;
+@synthesize touchFeedbackView = _touchFeedbackView;
+@synthesize isTabLoading = _isTabLoading;
+@synthesize toolbarType = _toolbarType;
+@synthesize menuItems = _menuItems;
+@synthesize delegate = _delegate;
+
+#pragma mark Public methods
+
+- (CGFloat)optimalHeight:(CGFloat)suggestedHeight {
+ NSInteger numberOfItems = [self.menuItems count];
+ if (_toolbarType == kToolbarTypeWebiPhone) {
+ // Account for the height of the first row, not included in |menuItems|.
+ numberOfItems++;
+ }
+ CGFloat maxItems = suggestedHeight / kMenuItemHeight;
+ if (maxItems >= numberOfItems) {
+ return numberOfItems * kMenuItemHeight;
+ } else {
+ const CGFloat halfHeight = kMenuItemHeight / 2;
+ return round(maxItems) * kMenuItemHeight - halfHeight;
+ }
+}
+
+- (void)setItemEnabled:(BOOL)enabled withTag:(NSInteger)tag {
+ for (ToolsMenuViewItem* item in _menuItems) {
+ if ([item tag] == tag) {
+ [item setActive:enabled];
+ break;
+ }
+ }
+
+ for (ToolsMenuViewCell* cell in [_menuView visibleCells]) {
+ if (![cell isKindOfClass:[ToolsMenuViewCell class]])
+ continue;
+
+ if ([cell tag] != tag)
+ continue;
+
+ NSIndexPath* path = [_menuView indexPathForCell:cell];
+ NSInteger itemIndex = [self dataIndexForIndexPath:path];
+ [cell configureForMenuItem:[_menuItems objectAtIndex:itemIndex]];
+ }
+}
+
+- (void)setIsCurrentPageBookmarked:(BOOL)value {
+ _isCurrentPageBookmarked = value;
+
+ ToolsMenuViewToolsCell* toolsCell = [self toolsCell];
+ [[toolsCell starButton] setHidden:_isCurrentPageBookmarked];
+ [[toolsCell starredButton] setHidden:!_isCurrentPageBookmarked];
+}
+
+- (void)setCanUseReaderMode:(BOOL)enabled {
+ [self setItemEnabled:enabled withTag:IDC_READER_MODE];
+}
+
+- (void)setCanUseDesktopUserAgent:(BOOL)enabled {
+ [self setItemEnabled:enabled withTag:IDC_REQUEST_DESKTOP_SITE];
+}
+
+- (void)setCanShowFindBar:(BOOL)enabled {
+ [self setItemEnabled:enabled withTag:IDC_FIND];
+}
+
+- (void)setCanShowShareMenu:(BOOL)enabled {
+ ToolsMenuViewToolsCell* toolsCell = [self toolsCell];
+ [[toolsCell shareButton] setEnabled:enabled];
+ [self setItemEnabled:enabled withTag:IDC_SHARE_PAGE];
+}
+
+- (UIButton*)toolsButton {
+ UIButton* toolsButton = [[self toolsCell] toolsButton];
+ [toolsButton addTarget:self
+ action:@selector(buttonPressed:)
+ forControlEvents:UIControlEventTouchUpInside];
+ [toolsButton setTranslatesAutoresizingMaskIntoConstraints:YES];
+ [toolsButton setOpaque:NO];
+ [toolsButton setBackgroundColor:[UIColor clearColor]];
+ return toolsButton;
+}
+
+- (void)setIsTabLoading:(BOOL)isTabLoading {
+ _isTabLoading = isTabLoading;
+
+ ToolsMenuViewToolsCell* toolsCell = [self toolsCell];
+ [[toolsCell stopButton] setHidden:!isTabLoading];
+ [[toolsCell reloadButton] setHidden:isTabLoading];
+}
+
+- (void)initializeMenu:(ToolsMenuContext*)context {
+ if (context.readingListMenuNotifier) {
+ _readingListMenuNotifier.reset(context.readingListMenuNotifier);
+ [context.readingListMenuNotifier setDelegate:self];
+ }
+
+ if (IsIPadIdiom()) {
+ _toolbarType = context.hasNoOpenedTabs
+ ? kToolbarTypeNoTabsiPad
+ : (!IsCompactTablet() ? kToolbarTypeWebiPad
+ : kToolbarTypeWebiPhone);
+ } else {
+ // kOptionInTabSwitcher option must be enabled on iPhone with
+ // no opened tabs.
+ DCHECK(!context.hasNoOpenedTabs || context.isInTabSwitcher);
+ _toolbarType = context.isInTabSwitcher ? kToolbarTypeSwitcheriPhone
+ : kToolbarTypeWebiPhone;
+ }
+
+ // Build the menu, adding all relevant items.
+ NSMutableArray* menu = [NSMutableArray array];
+
+ for (size_t i = 0; i < arraysize(itemInfoList); ++i) {
+ const MenuItemInfo& item = itemInfoList[i];
+ if (!ItemShouldBeVisible(item, context.isInIncognito, _toolbarType))
+ continue;
+
+ NSString* title = l10n_util::GetNSStringWithFixup(item.title_id);
+ Class itemClass =
+ item.item_class ? item.item_class : [ToolsMenuViewItem class];
+ // Sanity check that the class is a useful one.
+ DCHECK([itemClass respondsToSelector:@selector(menuItemWithTitle:
+ accessibilityIdentifier:
+ command:)]);
+ [menu addObject:[itemClass menuItemWithTitle:title
+ accessibilityIdentifier:item.accessibility_id
+ command:item.command_id]];
+ }
+
+#if !defined(NDEBUG)
+ NSUserDefaults* standardDefaults = [NSUserDefaults standardUserDefaults];
+ if ((_toolbarType & kToolbarTypeWebAll) &&
+ [standardDefaults boolForKey:@"DevViewSource"]) {
+ // Debug menu, not localized, only visible if turned on by a default.
+ [menu addObject:[self createViewSourceItem]];
+ }
+#endif // !defined(NDEBUG)
+
+ [self setMenuItems:menu];
+
+ // Disable IDC_CLOSE_ALL_TABS menu item if on phone with no tabs.
+ if (!IsIPadIdiom()) {
+ [self setItemEnabled:!context.hasNoOpenedTabs withTag:IDC_CLOSE_ALL_TABS];
+ }
+}
+
+#if !defined(NDEBUG)
+- (ToolsMenuViewItem*)createViewSourceItem {
+ return [ToolsMenuViewItem menuItemWithTitle:@"View Source"
+ accessibilityIdentifier:@"View Source"
+ command:IDC_VIEW_SOURCE];
+}
+#endif // !defined(NDEBUG)
+
+#pragma mark - Data handling utilities
+
+- (ToolsMenuViewToolsCell*)toolsCell {
+ for (ToolsMenuViewToolsCell* visibleCell in [_menuView visibleCells]) {
+ if ([visibleCell isKindOfClass:[ToolsMenuViewToolsCell class]])
+ return visibleCell;
+ }
+
+ return nil;
+}
+
+- (ReadingListMenuViewCell*)readingListCell {
+ for (ReadingListMenuViewCell* visibleCell in [_menuView visibleCells]) {
+ if ([visibleCell isKindOfClass:[ReadingListMenuViewCell class]])
+ return visibleCell;
+ }
+
+ return nil;
+}
+
+- (NSInteger)dataIndexForIndexPath:(NSIndexPath*)path {
+ NSInteger item = [path item];
+
+ if (_toolbarType == kToolbarTypeWebiPhone)
+ --item;
+
+ return item;
+}
+
+#pragma mark - UIViewController Overrides
+
+- (instancetype)initWithNibName:(NSString*)nibNameOrNil
+ bundle:(NSBundle*)nibBundleOrNil {
+ self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
+ if (self)
+ [self commonInitialization];
+
+ return self;
+}
+
+- (instancetype)initWithCoder:(NSCoder*)aDecoder {
+ self = [super initWithCoder:aDecoder];
+ if (self)
+ [self commonInitialization];
+
+ return self;
+}
+
+- (void)commonInitialization {
+ _propertyReleaser_ToolsMenuViewController.Init(
+ self, [ToolsMenuViewController class]);
+ _readingListMenuNotifier.reset();
+}
+
+- (void)loadView {
+ [super loadView];
+
+ UIView* rootView = [self view];
+ [rootView setAutoresizingMask:UIViewAutoresizingFlexibleHeight |
+ UIViewAutoresizingFlexibleWidth];
+ [rootView setBackgroundColor:[UIColor whiteColor]];
+
+ _touchFeedbackView = [[MDCInkView alloc] initWithFrame:CGRectZero];
+
+ base::scoped_nsobject<UICollectionViewFlowLayout> menuItemsLayout(
+ [[UICollectionViewFlowLayout alloc] init]);
+
+ _menuView = [[ToolsMenuCollectionView alloc] initWithFrame:[rootView bounds]
+ collectionViewLayout:menuItemsLayout];
+ [_menuView setAccessibilityLabel:l10n_util::GetNSString(IDS_IOS_TOOLS_MENU)];
+ [_menuView setAccessibilityIdentifier:kToolsMenuTableViewId];
+ [_menuView setTranslatesAutoresizingMaskIntoConstraints:NO];
+ [_menuView setBackgroundColor:[UIColor whiteColor]];
+ [_menuView setDataSource:self];
+ [_menuView setDelegate:self];
+ [_menuView setOpaque:YES];
+
+ [rootView addSubview:_menuView];
+ [self updateViewConstraints];
+}
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+ [_menuView registerClass:[ToolsMenuViewToolsCell class]
+ forCellWithReuseIdentifier:kToolsItemCellID];
+
+ [_menuView registerClass:[ToolsMenuViewItem cellClass]
+ forCellWithReuseIdentifier:[ToolsMenuViewItem cellID]];
+
+ // Register each custom class.
+ NSMutableSet* registeredClasses = [NSMutableSet set];
+ for (size_t i = 0; i < arraysize(itemInfoList); ++i) {
+ const MenuItemInfo& item = itemInfoList[i];
+ if (!item.item_class || [registeredClasses containsObject:item.item_class])
+ continue;
+ [_menuView registerClass:[item.item_class cellClass]
+ forCellWithReuseIdentifier:[item.item_class cellID]];
+ [registeredClasses addObject:item.item_class];
+ }
+}
+
+- (void)updateViewConstraints {
+ [super updateViewConstraints];
+
+ UIView* rootView = [self view];
+ NSDictionary* view = @{ @"menu" : _menuView };
+ NSArray* constraints = @[ @"V:|-(0)-[menu]-(0)-|", @"H:|-(0)-[menu]-(0)-|" ];
+ ApplyVisualConstraints(constraints, view, rootView);
+}
+
+#pragma mark - Content Animation Stuff
+
+- (void)animateContentIn {
+ // Make sure that the collection view has laid out before trying to animate
+ // the contents.
+ [_menuView layoutIfNeeded];
+
+ NSArray* visibleCells =
+ [[_menuView visibleCells] sortedArrayUsingComparator:^NSComparisonResult(
+ UIView* view1, UIView* view2) {
+ CGPoint center1 = [view1 center];
+ CGPoint center2 = [view2 center];
+
+ if (center1.y < center2.y)
+ return NSOrderedAscending;
+
+ if (center1.y > center2.y)
+ return NSOrderedDescending;
+
+ return NSOrderedSame;
+ }];
+
+ ToolsMenuViewToolsCell* toolsCell = nil;
+ if (_toolbarType == kToolbarTypeWebiPhone) {
+ toolsCell = [visibleCells firstObject];
+ if ([toolsCell isKindOfClass:[ToolsMenuViewToolsCell class]]) {
+ visibleCells = [visibleCells
+ subarrayWithRange:NSMakeRange(1, [visibleCells count] - 1)];
+ } else {
+ toolsCell = nil;
+ }
+ }
+
+ [CATransaction begin];
+ [CATransaction
+ setAnimationTimingFunction:TimingFunction(ios::material::CurveEaseInOut)];
+ [CATransaction setAnimationDuration:ios::material::kDuration5];
+ AnimateInViews([toolsCell allButtons], 10, 0);
+ AnimateInViews(visibleCells, 0, -10);
+ [CATransaction commit];
+
+ [[self readingListCell]
+ updateBadgeCount:_readingListMenuNotifier.get().readingListUnreadCount
+ animated:YES];
+ [[self readingListCell]
+ updateSeenState:_readingListMenuNotifier.get().readingListUnseenItemsExist
+ animated:YES];
+}
+
+- (void)hideContent {
+ _menuView.alpha = 0;
+
+ // Remove the target/action for touching the buttons. VoiceOver may hold on
+ // to these buttons after |self| has been released, causing a crash if a
+ // button is activated (see http://crbug.com/480974 ).
+ UIButton* toolsButton = [[self toolsCell] toolsButton];
+ [toolsButton removeTarget:self
+ action:@selector(buttonPressed:)
+ forControlEvents:UIControlEventTouchUpInside];
+ for (UIButton* button in [[self toolsCell] allButtons]) {
+ [button removeTarget:self
+ action:@selector(buttonPressed:)
+ forControlEvents:UIControlEventTouchUpInside];
+ }
+}
+
+#pragma mark - Button event handling
+
+- (IBAction)buttonPressed:(id)sender {
+ int commandId = [sender tag];
+ DCHECK(commandId);
+ // The bookmark command workaround is only needed for metrics; remap it
+ // to the real command for the dispatch. This is very hacky, but it will go
+ // away soon. See crbug/228521
+ DCHECK([sender respondsToSelector:@selector(setTag:)]);
+ if (commandId == IDC_TEMP_EDIT_BOOKMARK)
+ [sender setTag:IDC_BOOKMARK_PAGE];
+ // Do nothing when tapping the tools menu a second time.
+ if (commandId != IDC_SHOW_TOOLS_MENU) {
+ [self chromeExecuteCommand:sender];
+ }
+ if (commandId == IDC_TEMP_EDIT_BOOKMARK)
+ [sender setTag:IDC_TEMP_EDIT_BOOKMARK];
+
+ [_delegate commandWasSelected:commandId];
+}
+
+#pragma mark - UICollectionViewDelegate Implementation
+
+- (BOOL)collectionView:(ToolsMenuCollectionView*)view
+ shouldHighlightItemAtIndexPath:(NSIndexPath*)path {
+ if (view.tracking)
+ return NO;
+ NSInteger item = [self dataIndexForIndexPath:path];
+ return (item >= 0);
+}
+
+- (void)collectionView:(ToolsMenuCollectionView*)view
+ didHighlightItemAtIndexPath:(NSIndexPath*)path {
+ ToolsMenuViewCell* cell =
+ (ToolsMenuViewCell*)[view cellForItemAtIndexPath:path];
+
+ NSInteger item = [self dataIndexForIndexPath:path];
+ DCHECK_GE(item, 0);
+ ToolsMenuViewItem* menuItem = [_menuItems objectAtIndex:item];
+ DCHECK(menuItem);
+ if ([menuItem active]) {
+ [_touchFeedbackView setFrame:cell.bounds];
+ [cell addSubview:_touchFeedbackView];
+
+ CGPoint touchPoint = [view touchBeginPoint];
+ touchPoint = [view convertPoint:touchPoint toView:_touchFeedbackView];
+ [_touchFeedbackView startTouchBeganAnimationAtPoint:touchPoint
+ completion:nil];
+ }
+}
+
+- (void)collectionView:(ToolsMenuCollectionView*)view
+ didUnhighlightItemAtIndexPath:(NSIndexPath*)path {
+ CGPoint touchPoint = [view touchEndPoint];
+ touchPoint = [view convertPoint:touchPoint toView:_touchFeedbackView];
+ base::WeakNSObject<MDCInkView> inkView(_touchFeedbackView);
+ _waitForInk = YES;
+ [_touchFeedbackView startTouchEndedAnimationAtPoint:touchPoint
+ completion:^{
+ _waitForInk = NO;
+ [inkView removeFromSuperview];
+ }];
+}
+
+- (BOOL)collectionView:(UICollectionView*)view
+ shouldSelectItemAtIndexPath:(NSIndexPath*)path {
+ NSInteger item = [self dataIndexForIndexPath:path];
+ if (item < 0)
+ return NO;
+
+ return [[_menuItems objectAtIndex:item] active];
+}
+
+- (void)collectionView:(UICollectionView*)view
+ didSelectItemAtIndexPath:(NSIndexPath*)path {
+ [view deselectItemAtIndexPath:path animated:YES];
+
+ NSInteger item = [self dataIndexForIndexPath:path];
+ if (item < 0)
+ return;
+
+ dispatch_time_t delayTime = dispatch_time(
+ DISPATCH_TIME_NOW, (int64_t)(NSEC_PER_SEC * kMDCInkTouchDelayInterval));
+ dispatch_after(
+ _waitForInk ? delayTime : 0, dispatch_get_main_queue(), ^(void) {
+ ToolsMenuViewItem* menuItem = [_menuItems objectAtIndex:item];
+ DCHECK([menuItem tag]);
+ [_delegate commandWasSelected:[menuItem tag]];
+ [self chromeExecuteCommand:menuItem];
+ });
+}
+
+#pragma mark - UICollectionViewDataSource Implementation
+
+- (NSInteger)collectionView:(UICollectionView*)view
+ numberOfItemsInSection:(NSInteger)section {
+ NSInteger numberOfItems = [_menuItems count];
+ if (_toolbarType == kToolbarTypeWebiPhone)
+ ++numberOfItems;
+
+ return numberOfItems;
+}
+
+- (UICollectionViewCell*)collectionView:(UICollectionView*)view
+ cellForItemAtIndexPath:(NSIndexPath*)path {
+ NSInteger item = [self dataIndexForIndexPath:path];
+ if (item < 0) {
+ ToolsMenuViewToolsCell* cell =
+ [view dequeueReusableCellWithReuseIdentifier:kToolsItemCellID
+ forIndexPath:path];
+ for (UIButton* button in [cell allButtons]) {
+ [button addTarget:self
+ action:@selector(buttonPressed:)
+ forControlEvents:UIControlEventTouchUpInside];
+ }
+ return cell;
+ }
+
+ ToolsMenuViewItem* menuItem = [_menuItems objectAtIndex:item];
+ ToolsMenuViewCell* menuItemCell =
+ [view dequeueReusableCellWithReuseIdentifier:[[menuItem class] cellID]
+ forIndexPath:path];
+ [menuItemCell configureForMenuItem:menuItem];
+
+ return menuItemCell;
+}
+
+#pragma mark - UICollectionViewDelegateFlowLayout Implementation
+
+- (CGSize)collectionView:(UICollectionView*)view
+ layout:(UICollectionViewLayout*)collectionViewLayout
+ sizeForItemAtIndexPath:(NSIndexPath*)path {
+ return CGSizeMake(CGRectGetWidth([_menuView bounds]), kMenuItemHeight);
+}
+
+- (CGFloat)collectionView:(UICollectionView*)collectionView
+ layout:(UICollectionViewLayout*)
+ collectionViewLayout
+ minimumLineSpacingForSectionAtIndex:(NSInteger)section {
+ return 0;
+}
+
+#pragma mark - ReadingListMenuNotificationDelegate Implementation
+
+- (void)unreadCountChanged:(NSInteger)unreadCount {
+ [[self readingListCell] updateBadgeCount:unreadCount animated:YES];
+}
+
+- (void)unseenStateChanged:(BOOL)unseenItemsExist {
+ [[self readingListCell] updateSeenState:unseenItemsExist animated:YES];
+}
+
+@end
« no previous file with comments | « ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.h ('k') | ios/chrome/browser/ui/tools_menu/tools_menu_view_item.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698