Index: ios/chrome/browser/ui/history/history_panel_view_controller.mm |
diff --git a/ios/chrome/browser/ui/history/history_panel_view_controller.mm b/ios/chrome/browser/ui/history/history_panel_view_controller.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..41be2faa97542d813293e05832e1e87c99454cf5 |
--- /dev/null |
+++ b/ios/chrome/browser/ui/history/history_panel_view_controller.mm |
@@ -0,0 +1,381 @@ |
+// Copyright 2016 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/history_panel_view_controller.h" |
+ |
+#include "base/ios/block_types.h" |
+#include "base/ios/ios_util.h" |
+#include "base/mac/scoped_nsobject.h" |
+#include "components/strings/grit/components_strings.h" |
+#import "ios/chrome/browser/ui/history/clear_browsing_bar.h" |
+#import "ios/chrome/browser/ui/history/history_collection_view_controller.h" |
+#import "ios/chrome/browser/ui/history/history_search_view_controller.h" |
+#import "ios/chrome/browser/ui/icons/chrome_icon.h" |
+#import "ios/chrome/browser/ui/material_components/utils.h" |
+#import "ios/chrome/browser/ui/ntp/recent_tabs/views/panel_bar_view.h" |
+#import "ios/chrome/browser/ui/show_privacy_settings_util.h" |
+#import "ios/chrome/browser/ui/uikit_ui_util.h" |
+#import "ios/chrome/browser/ui/url_loader.h" |
+#include "ios/chrome/grit/ios_strings.h" |
+#import "ios/third_party/material_components_ios/src/components/AppBar/src/MaterialAppBar.h" |
+#import "ios/third_party/material_components_ios/src/components/NavigationBar/src/MaterialNavigationBar.h" |
+#include "ui/base/l10n/l10n_util_mac.h" |
+ |
+namespace { |
+// Shadow opacity for the clear browsing button and the header when scrolling. |
+CGFloat kShadowOpacity = 0.2f; |
+} // namespace |
+ |
+@interface HistoryPanelViewController ()< |
+ HistoryCollectionViewControllerDelegate, |
+ HistorySearchViewControllerDelegate> { |
+ // Controller for collection view that displays history entries. |
+ base::scoped_nsobject<HistoryCollectionViewController> |
+ _historyCollectionController; |
+ // Bar at the bottom of the history panel the displays options for entry |
+ // deletion, including "Clear Browsing Data..." which takes the user to |
+ // Privacy settings, or "Edit" for entering a mode for deleting individual |
+ // entries. When in edit mode, the bar displays options to Delete or Cancel. |
+ base::scoped_nsobject<ClearBrowsingBar> _clearBrowsingBar; |
+ // View controller for the search bar. |
+ base::scoped_nsobject<HistorySearchViewController> _searchViewController; |
+ // Container view for history collection and clear browsing button to enable |
+ // use of autolayout in conjuction with Material App Bar. |
+ base::scoped_nsobject<UIView> _containerView; |
+ // The header view. |
+ base::scoped_nsobject<MDCAppBar> _appBar; |
+} |
+// Closes history. |
+- (void)closeHistory; |
+// Closes history, invoking completionHandler once dismissal is complete. |
+- (void)closeHistoryWithCompletion:(ProceduralBlock)completionHandler; |
+// Opens Privacy settings. |
+- (void)openPrivacySettings; |
+// Configure view for editing mode. |
+- (void)enterEditingMode; |
+// Configure view for non-editing mode. |
+- (void)exitEditingMode; |
+// Deletes selected history entries. |
+- (void)deleteSelectedItems; |
+// Displays a search bar for searching history entries. |
+- (void)enterSearchMode; |
+// Dismisses the search bar. |
+- (void)exitSearchMode; |
+// Configures navigation bar for current state of the history collection. |
+- (void)configureNavigationBar; |
+// Configures the clear browsing data bar for the current state of the history |
+// collection. |
+- (void)configureClearBrowsingBar; |
+@end |
+ |
+@implementation HistoryPanelViewController |
+ |
+- (instancetype)initWithLoader:(id<UrlLoader>)loader |
+ browserState:(ios::ChromeBrowserState*)browserState { |
+ self = [super initWithNibName:nil bundle:nil]; |
+ if (self) { |
+ _historyCollectionController.reset([[HistoryCollectionViewController alloc] |
+ initWithLoader:loader |
+ browserState:browserState |
+ delegate:self]); |
+ |
+ // Configure modal presentation. |
+ [self setModalPresentationStyle:UIModalPresentationFormSheet]; |
+ [self setModalTransitionStyle:UIModalTransitionStyleCoverVertical]; |
+ |
+ // Add and configure header. |
+ _appBar.reset([[MDCAppBar alloc] init]); |
+ [self addChildViewController:_appBar.get().headerViewController]; |
+ } |
+ return self; |
+} |
+ |
+- (instancetype)initWithNibName:(NSString*)nibNameOrNil |
+ bundle:(NSBundle*)nibBundleOrNil { |
+ NOTREACHED(); |
+ return nil; |
+} |
+ |
+- (instancetype)initWithCoder:(NSCoder*)aDecoder { |
+ NOTREACHED(); |
+ return nil; |
+} |
+ |
++ (UIViewController*)controllerToPresentForBrowserState: |
+ (ios::ChromeBrowserState*)browserState |
+ loader:(id<UrlLoader>)loader { |
+ HistoryPanelViewController* historyPanelController = |
+ [[[HistoryPanelViewController alloc] initWithLoader:loader |
+ browserState:browserState] |
+ autorelease]; |
+ return historyPanelController; |
+} |
+ |
+- (void)viewDidLoad { |
+ [super viewDidLoad]; |
+ [self setTitle:l10n_util::GetNSString(IDS_HISTORY_TITLE)]; |
+ |
+ _containerView.reset([[UIView alloc] initWithFrame:self.view.frame]); |
+ [_containerView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | |
+ UIViewAutoresizingFlexibleHeight]; |
+ [self.view addSubview:_containerView]; |
+ |
+ [[_historyCollectionController view] |
+ setTranslatesAutoresizingMaskIntoConstraints:NO]; |
+ [_historyCollectionController willMoveToParentViewController:self]; |
+ [_containerView addSubview:[_historyCollectionController view]]; |
+ [self addChildViewController:_historyCollectionController]; |
+ [_historyCollectionController didMoveToParentViewController:self]; |
+ |
+ _clearBrowsingBar.reset([[ClearBrowsingBar alloc] initWithFrame:CGRectZero]); |
+ [_clearBrowsingBar setClearBrowsingDataTarget:self |
+ action:@selector(openPrivacySettings)]; |
+ [_clearBrowsingBar setEditTarget:self action:@selector(enterEditingMode)]; |
+ [_clearBrowsingBar setCancelTarget:self action:@selector(exitEditingMode)]; |
+ [_clearBrowsingBar setDeleteTarget:self |
+ action:@selector(deleteSelectedItems)]; |
+ [_clearBrowsingBar setTranslatesAutoresizingMaskIntoConstraints:NO]; |
+ [_containerView addSubview:_clearBrowsingBar]; |
+ [self configureClearBrowsingBar]; |
+ |
+ ConfigureAppBarWithCardStyle(_appBar); |
+ [_appBar headerViewController].headerView.trackingScrollView = |
+ [_historyCollectionController collectionView]; |
+ [_appBar addSubviewsToParent]; |
+ |
+ // Add navigation bar buttons. |
+ self.navigationItem.leftBarButtonItem = |
+ [ChromeIcon templateBarButtonItemWithImage:[ChromeIcon searchIcon] |
+ target:self |
+ action:@selector(enterSearchMode)]; |
+ self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] |
+ initWithTitle:l10n_util::GetNSString(IDS_IOS_NAVIGATION_BAR_DONE_BUTTON) |
+ style:UIBarButtonItemStylePlain |
+ target:self |
+ action:@selector(closeHistory)] autorelease]; |
+ [self configureNavigationBar]; |
+} |
+ |
+- (void)updateViewConstraints { |
+ NSDictionary* views = @{ |
+ @"collectionView" : [_historyCollectionController view], |
+ @"clearBrowsingBar" : _clearBrowsingBar, |
+ }; |
+ NSArray* constraints = @[ |
+ @"V:|[collectionView][clearBrowsingBar(==48)]|", @"H:|[collectionView]|", |
+ @"H:|[clearBrowsingBar]|" |
+ ]; |
+ ApplyVisualConstraints(constraints, views); |
+ [super updateViewConstraints]; |
+} |
+ |
+- (BOOL)disablesAutomaticKeyboardDismissal { |
+ return NO; |
+} |
+ |
+#pragma mark - Status bar |
+ |
+- (BOOL)modalPresentationCapturesStatusBarAppearance { |
+ if (!base::ios::IsRunningOnIOS10OrLater()) { |
+ // TODO(crbug.com/620361): Remove the entire method override when iOS 9 is |
+ // dropped. |
+ return YES; |
+ } else { |
+ return [super modalPresentationCapturesStatusBarAppearance]; |
+ } |
+} |
+ |
+- (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection { |
+ [super traitCollectionDidChange:previousTraitCollection]; |
+ if (!base::ios::IsRunningOnIOS10OrLater()) { |
+ // TODO(crbug.com/620361): Remove the entire method override when iOS 9 is |
+ // dropped. |
+ [self setNeedsStatusBarAppearanceUpdate]; |
+ } |
+} |
+ |
+- (UIViewController*)childViewControllerForStatusBarHidden { |
+ if (!base::ios::IsRunningOnIOS10OrLater()) { |
+ // TODO(crbug.com/620361): Remove the entire method override when iOS 9 is |
+ // dropped. |
+ return nil; |
+ } else { |
+ return _appBar.get().headerViewController; |
+ } |
+} |
+ |
+- (BOOL)prefersStatusBarHidden { |
+ if (!base::ios::IsRunningOnIOS10OrLater()) { |
+ // TODO(crbug.com/620361): Remove the entire method override when iOS 9 is |
+ // dropped. |
+ return NO; |
+ } else { |
+ return [super prefersStatusBarHidden]; |
+ } |
+} |
+ |
+- (UIViewController*)childViewControllerForStatusBarStyle { |
+ if (!base::ios::IsRunningOnIOS10OrLater()) { |
+ // TODO(crbug.com/620361): Remove the entire method override when iOS 9 is |
+ // dropped. |
+ return nil; |
+ } else { |
+ return _appBar.get().headerViewController; |
+ } |
+} |
+ |
+- (UIStatusBarStyle)preferredStatusBarStyle { |
+ if (!base::ios::IsRunningOnIOS10OrLater()) { |
+ // TODO(crbug.com/620361): Remove the entire method override when iOS 9 is |
+ // dropped. |
+ if (IsIPadIdiom() && !IsCompact()) { |
+ return UIStatusBarStyleLightContent; |
+ } else { |
+ return UIStatusBarStyleDefault; |
+ } |
+ } else { |
+ return [super preferredStatusBarStyle]; |
+ } |
+} |
+ |
+#pragma mark - HistoryCollectionViewControllerDelegate |
+ |
+- (void)historyCollectionViewController: |
+ (HistoryCollectionViewController*)collectionViewcontroller |
+ shouldCloseWithCompletion:(ProceduralBlock)completionHandler { |
+ [self closeHistoryWithCompletion:completionHandler]; |
+} |
+ |
+- (void)historyCollectionViewController: |
+ (HistoryCollectionViewController*)controller |
+ didScrollToOffset:(CGPoint)offset { |
+ // Display a shadow on the header when the collection is scrolled. |
+ MDCFlexibleHeaderView* headerView = |
+ _appBar.get().headerViewController.headerView; |
+ headerView.visibleShadowOpacity = |
+ offset.y > -CGRectGetHeight(headerView.frame) ? kShadowOpacity : 0.0f; |
+} |
+ |
+- (void)historyCollectionViewControllerDidChangeEntries: |
+ (HistoryCollectionViewController*)controller { |
+ // Reconfigure the navigation and clear browsing bars to reflect currently |
+ // displayed entries. |
+ [self configureNavigationBar]; |
+ [self configureClearBrowsingBar]; |
+} |
+ |
+- (void)historyCollectionViewControllerDidChangeEntrySelection: |
+ (HistoryCollectionViewController*)controller { |
+ // Reconfigure the clear browsing bar to reflect current availability of |
+ // entries for deletion. |
+ [self configureClearBrowsingBar]; |
+} |
+ |
+#pragma mark - HistorySearchViewControllerDelegate |
+ |
+- (void)historySearchViewController: |
+ (HistorySearchViewController*)searchViewController |
+ didRequestSearchForTerm:(NSString*)searchTerm { |
+ [_historyCollectionController showHistoryMatchingQuery:searchTerm]; |
+} |
+ |
+- (void)historySearchViewControllerDidCancel: |
+ (HistorySearchViewController*)searchViewController { |
+ DCHECK([_searchViewController isEqual:searchViewController]); |
+ [self exitSearchMode]; |
+} |
+ |
+#pragma mark - Private methods |
+ |
+- (void)closeHistory { |
+ [self closeHistoryWithCompletion:nil]; |
+} |
+ |
+- (void)closeHistoryWithCompletion:(ProceduralBlock)completion { |
+ [self.presentingViewController dismissViewControllerAnimated:YES |
+ completion:completion]; |
+} |
+ |
+- (void)openPrivacySettings { |
+ [self exitSearchMode]; |
+ ShowClearBrowsingData(); |
+} |
+ |
+- (void)enterEditingMode { |
+ [_historyCollectionController setEditing:YES]; |
+ [_clearBrowsingBar setEditing:YES]; |
+ if (_historyCollectionController.get().searching) { |
+ [_searchViewController setEnabled:NO]; |
+ } |
+ DCHECK([_historyCollectionController isEditing]); |
+ [self configureNavigationBar]; |
+} |
+ |
+- (void)exitEditingMode { |
+ [_historyCollectionController setEditing:NO]; |
+ [_clearBrowsingBar setEditing:NO]; |
+ if (_historyCollectionController.get().searching) { |
+ [_searchViewController setEnabled:YES]; |
+ } |
+ DCHECK(![_historyCollectionController isEditing]); |
+ [self configureNavigationBar]; |
+} |
+ |
+- (void)deleteSelectedItems { |
+ [_historyCollectionController deleteSelectedItemsFromHistory]; |
+ [self exitEditingMode]; |
+} |
+- (void)enterSearchMode { |
+ if (!_searchViewController) { |
+ _searchViewController.reset([[HistorySearchViewController alloc] init]); |
+ [_searchViewController setDelegate:self]; |
+ } |
+ |
+ UIView* searchBarView = [_searchViewController view]; |
+ [_searchViewController willMoveToParentViewController:self]; |
+ [self.view addSubview:searchBarView]; |
+ _historyCollectionController.get().searching = YES; |
+ [_searchViewController didMoveToParentViewController:self]; |
+ |
+ // Constraints to make search bar cover header. |
+ [searchBarView setTranslatesAutoresizingMaskIntoConstraints:NO]; |
+ MDCFlexibleHeaderView* headerView = |
+ _appBar.get().headerViewController.headerView; |
+ NSArray* constraints = @[ |
+ [[searchBarView topAnchor] constraintEqualToAnchor:headerView.topAnchor], |
+ [[searchBarView leadingAnchor] |
+ constraintEqualToAnchor:headerView.leadingAnchor], |
+ [[searchBarView heightAnchor] |
+ constraintEqualToAnchor:headerView.heightAnchor], |
+ [[searchBarView widthAnchor] constraintEqualToAnchor:headerView.widthAnchor] |
+ ]; |
+ [NSLayoutConstraint activateConstraints:constraints]; |
+} |
+ |
+- (void)exitSearchMode { |
+ if (_historyCollectionController.get().searching) { |
+ [[_searchViewController view] removeFromSuperview]; |
+ [_searchViewController removeFromParentViewController]; |
+ _historyCollectionController.get().searching = NO; |
+ [_historyCollectionController showHistoryMatchingQuery:nil]; |
+ } |
+} |
+ |
+- (void)configureNavigationBar { |
+ // The search button should only be enabled if there are history entries to |
+ // search, and if history is not in edit mode. |
+ self.navigationItem.leftBarButtonItem.enabled = |
+ [_historyCollectionController hasHistoryEntries] && |
+ ![_historyCollectionController isEditing]; |
+} |
+ |
+- (void)configureClearBrowsingBar { |
+ _clearBrowsingBar.get().editing = _historyCollectionController.get().editing; |
+ _clearBrowsingBar.get().deleteButtonEnabled = |
+ [_historyCollectionController hasSelectedEntries]; |
+ _clearBrowsingBar.get().editButtonEnabled = |
+ [_historyCollectionController hasHistoryEntries]; |
+} |
+ |
+@end |