| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #import "ios/chrome/browser/ui/history/history_panel_view_controller.h" |
| 6 |
| 7 #include "base/ios/block_types.h" |
| 8 #include "base/ios/ios_util.h" |
| 9 #include "base/mac/scoped_nsobject.h" |
| 10 #include "components/strings/grit/components_strings.h" |
| 11 #import "ios/chrome/browser/ui/history/clear_browsing_bar.h" |
| 12 #import "ios/chrome/browser/ui/history/history_collection_view_controller.h" |
| 13 #import "ios/chrome/browser/ui/history/history_search_view_controller.h" |
| 14 #import "ios/chrome/browser/ui/icons/chrome_icon.h" |
| 15 #import "ios/chrome/browser/ui/material_components/utils.h" |
| 16 #import "ios/chrome/browser/ui/ntp/recent_tabs/views/panel_bar_view.h" |
| 17 #import "ios/chrome/browser/ui/show_privacy_settings_util.h" |
| 18 #import "ios/chrome/browser/ui/uikit_ui_util.h" |
| 19 #import "ios/chrome/browser/ui/url_loader.h" |
| 20 #include "ios/chrome/grit/ios_strings.h" |
| 21 #import "ios/third_party/material_components_ios/src/components/AppBar/src/Mater
ialAppBar.h" |
| 22 #import "ios/third_party/material_components_ios/src/components/NavigationBar/sr
c/MaterialNavigationBar.h" |
| 23 #include "ui/base/l10n/l10n_util_mac.h" |
| 24 |
| 25 namespace { |
| 26 // Shadow opacity for the clear browsing button and the header when scrolling. |
| 27 CGFloat kShadowOpacity = 0.2f; |
| 28 } // namespace |
| 29 |
| 30 @interface HistoryPanelViewController ()< |
| 31 HistoryCollectionViewControllerDelegate, |
| 32 HistorySearchViewControllerDelegate> { |
| 33 // Controller for collection view that displays history entries. |
| 34 base::scoped_nsobject<HistoryCollectionViewController> |
| 35 _historyCollectionController; |
| 36 // Bar at the bottom of the history panel the displays options for entry |
| 37 // deletion, including "Clear Browsing Data..." which takes the user to |
| 38 // Privacy settings, or "Edit" for entering a mode for deleting individual |
| 39 // entries. When in edit mode, the bar displays options to Delete or Cancel. |
| 40 base::scoped_nsobject<ClearBrowsingBar> _clearBrowsingBar; |
| 41 // View controller for the search bar. |
| 42 base::scoped_nsobject<HistorySearchViewController> _searchViewController; |
| 43 // Container view for history collection and clear browsing button to enable |
| 44 // use of autolayout in conjuction with Material App Bar. |
| 45 base::scoped_nsobject<UIView> _containerView; |
| 46 // The header view. |
| 47 base::scoped_nsobject<MDCAppBar> _appBar; |
| 48 } |
| 49 // Closes history. |
| 50 - (void)closeHistory; |
| 51 // Closes history, invoking completionHandler once dismissal is complete. |
| 52 - (void)closeHistoryWithCompletion:(ProceduralBlock)completionHandler; |
| 53 // Opens Privacy settings. |
| 54 - (void)openPrivacySettings; |
| 55 // Configure view for editing mode. |
| 56 - (void)enterEditingMode; |
| 57 // Configure view for non-editing mode. |
| 58 - (void)exitEditingMode; |
| 59 // Deletes selected history entries. |
| 60 - (void)deleteSelectedItems; |
| 61 // Displays a search bar for searching history entries. |
| 62 - (void)enterSearchMode; |
| 63 // Dismisses the search bar. |
| 64 - (void)exitSearchMode; |
| 65 // Configures navigation bar for current state of the history collection. |
| 66 - (void)configureNavigationBar; |
| 67 // Configures the clear browsing data bar for the current state of the history |
| 68 // collection. |
| 69 - (void)configureClearBrowsingBar; |
| 70 @end |
| 71 |
| 72 @implementation HistoryPanelViewController |
| 73 |
| 74 - (instancetype)initWithLoader:(id<UrlLoader>)loader |
| 75 browserState:(ios::ChromeBrowserState*)browserState { |
| 76 self = [super initWithNibName:nil bundle:nil]; |
| 77 if (self) { |
| 78 _historyCollectionController.reset([[HistoryCollectionViewController alloc] |
| 79 initWithLoader:loader |
| 80 browserState:browserState |
| 81 delegate:self]); |
| 82 |
| 83 // Configure modal presentation. |
| 84 [self setModalPresentationStyle:UIModalPresentationFormSheet]; |
| 85 [self setModalTransitionStyle:UIModalTransitionStyleCoverVertical]; |
| 86 |
| 87 // Add and configure header. |
| 88 _appBar.reset([[MDCAppBar alloc] init]); |
| 89 [self addChildViewController:_appBar.get().headerViewController]; |
| 90 } |
| 91 return self; |
| 92 } |
| 93 |
| 94 - (instancetype)initWithNibName:(NSString*)nibNameOrNil |
| 95 bundle:(NSBundle*)nibBundleOrNil { |
| 96 NOTREACHED(); |
| 97 return nil; |
| 98 } |
| 99 |
| 100 - (instancetype)initWithCoder:(NSCoder*)aDecoder { |
| 101 NOTREACHED(); |
| 102 return nil; |
| 103 } |
| 104 |
| 105 + (UIViewController*)controllerToPresentForBrowserState: |
| 106 (ios::ChromeBrowserState*)browserState |
| 107 loader:(id<UrlLoader>)loader { |
| 108 HistoryPanelViewController* historyPanelController = |
| 109 [[[HistoryPanelViewController alloc] initWithLoader:loader |
| 110 browserState:browserState] |
| 111 autorelease]; |
| 112 return historyPanelController; |
| 113 } |
| 114 |
| 115 - (void)viewDidLoad { |
| 116 [super viewDidLoad]; |
| 117 [self setTitle:l10n_util::GetNSString(IDS_HISTORY_TITLE)]; |
| 118 |
| 119 _containerView.reset([[UIView alloc] initWithFrame:self.view.frame]); |
| 120 [_containerView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | |
| 121 UIViewAutoresizingFlexibleHeight]; |
| 122 [self.view addSubview:_containerView]; |
| 123 |
| 124 [[_historyCollectionController view] |
| 125 setTranslatesAutoresizingMaskIntoConstraints:NO]; |
| 126 [_historyCollectionController willMoveToParentViewController:self]; |
| 127 [_containerView addSubview:[_historyCollectionController view]]; |
| 128 [self addChildViewController:_historyCollectionController]; |
| 129 [_historyCollectionController didMoveToParentViewController:self]; |
| 130 |
| 131 _clearBrowsingBar.reset([[ClearBrowsingBar alloc] initWithFrame:CGRectZero]); |
| 132 [_clearBrowsingBar setClearBrowsingDataTarget:self |
| 133 action:@selector(openPrivacySettings)]; |
| 134 [_clearBrowsingBar setEditTarget:self action:@selector(enterEditingMode)]; |
| 135 [_clearBrowsingBar setCancelTarget:self action:@selector(exitEditingMode)]; |
| 136 [_clearBrowsingBar setDeleteTarget:self |
| 137 action:@selector(deleteSelectedItems)]; |
| 138 [_clearBrowsingBar setTranslatesAutoresizingMaskIntoConstraints:NO]; |
| 139 [_containerView addSubview:_clearBrowsingBar]; |
| 140 [self configureClearBrowsingBar]; |
| 141 |
| 142 ConfigureAppBarWithCardStyle(_appBar); |
| 143 [_appBar headerViewController].headerView.trackingScrollView = |
| 144 [_historyCollectionController collectionView]; |
| 145 [_appBar addSubviewsToParent]; |
| 146 |
| 147 // Add navigation bar buttons. |
| 148 self.navigationItem.leftBarButtonItem = |
| 149 [ChromeIcon templateBarButtonItemWithImage:[ChromeIcon searchIcon] |
| 150 target:self |
| 151 action:@selector(enterSearchMode)]; |
| 152 self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] |
| 153 initWithTitle:l10n_util::GetNSString(IDS_IOS_NAVIGATION_BAR_DONE_BUTTON) |
| 154 style:UIBarButtonItemStylePlain |
| 155 target:self |
| 156 action:@selector(closeHistory)] autorelease]; |
| 157 [self configureNavigationBar]; |
| 158 } |
| 159 |
| 160 - (void)updateViewConstraints { |
| 161 NSDictionary* views = @{ |
| 162 @"collectionView" : [_historyCollectionController view], |
| 163 @"clearBrowsingBar" : _clearBrowsingBar, |
| 164 }; |
| 165 NSArray* constraints = @[ |
| 166 @"V:|[collectionView][clearBrowsingBar(==48)]|", @"H:|[collectionView]|", |
| 167 @"H:|[clearBrowsingBar]|" |
| 168 ]; |
| 169 ApplyVisualConstraints(constraints, views); |
| 170 [super updateViewConstraints]; |
| 171 } |
| 172 |
| 173 - (BOOL)disablesAutomaticKeyboardDismissal { |
| 174 return NO; |
| 175 } |
| 176 |
| 177 #pragma mark - Status bar |
| 178 |
| 179 - (BOOL)modalPresentationCapturesStatusBarAppearance { |
| 180 if (!base::ios::IsRunningOnIOS10OrLater()) { |
| 181 // TODO(crbug.com/620361): Remove the entire method override when iOS 9 is |
| 182 // dropped. |
| 183 return YES; |
| 184 } else { |
| 185 return [super modalPresentationCapturesStatusBarAppearance]; |
| 186 } |
| 187 } |
| 188 |
| 189 - (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection { |
| 190 [super traitCollectionDidChange:previousTraitCollection]; |
| 191 if (!base::ios::IsRunningOnIOS10OrLater()) { |
| 192 // TODO(crbug.com/620361): Remove the entire method override when iOS 9 is |
| 193 // dropped. |
| 194 [self setNeedsStatusBarAppearanceUpdate]; |
| 195 } |
| 196 } |
| 197 |
| 198 - (UIViewController*)childViewControllerForStatusBarHidden { |
| 199 if (!base::ios::IsRunningOnIOS10OrLater()) { |
| 200 // TODO(crbug.com/620361): Remove the entire method override when iOS 9 is |
| 201 // dropped. |
| 202 return nil; |
| 203 } else { |
| 204 return _appBar.get().headerViewController; |
| 205 } |
| 206 } |
| 207 |
| 208 - (BOOL)prefersStatusBarHidden { |
| 209 if (!base::ios::IsRunningOnIOS10OrLater()) { |
| 210 // TODO(crbug.com/620361): Remove the entire method override when iOS 9 is |
| 211 // dropped. |
| 212 return NO; |
| 213 } else { |
| 214 return [super prefersStatusBarHidden]; |
| 215 } |
| 216 } |
| 217 |
| 218 - (UIViewController*)childViewControllerForStatusBarStyle { |
| 219 if (!base::ios::IsRunningOnIOS10OrLater()) { |
| 220 // TODO(crbug.com/620361): Remove the entire method override when iOS 9 is |
| 221 // dropped. |
| 222 return nil; |
| 223 } else { |
| 224 return _appBar.get().headerViewController; |
| 225 } |
| 226 } |
| 227 |
| 228 - (UIStatusBarStyle)preferredStatusBarStyle { |
| 229 if (!base::ios::IsRunningOnIOS10OrLater()) { |
| 230 // TODO(crbug.com/620361): Remove the entire method override when iOS 9 is |
| 231 // dropped. |
| 232 if (IsIPadIdiom() && !IsCompact()) { |
| 233 return UIStatusBarStyleLightContent; |
| 234 } else { |
| 235 return UIStatusBarStyleDefault; |
| 236 } |
| 237 } else { |
| 238 return [super preferredStatusBarStyle]; |
| 239 } |
| 240 } |
| 241 |
| 242 #pragma mark - HistoryCollectionViewControllerDelegate |
| 243 |
| 244 - (void)historyCollectionViewController: |
| 245 (HistoryCollectionViewController*)collectionViewcontroller |
| 246 shouldCloseWithCompletion:(ProceduralBlock)completionHandler { |
| 247 [self closeHistoryWithCompletion:completionHandler]; |
| 248 } |
| 249 |
| 250 - (void)historyCollectionViewController: |
| 251 (HistoryCollectionViewController*)controller |
| 252 didScrollToOffset:(CGPoint)offset { |
| 253 // Display a shadow on the header when the collection is scrolled. |
| 254 MDCFlexibleHeaderView* headerView = |
| 255 _appBar.get().headerViewController.headerView; |
| 256 headerView.visibleShadowOpacity = |
| 257 offset.y > -CGRectGetHeight(headerView.frame) ? kShadowOpacity : 0.0f; |
| 258 } |
| 259 |
| 260 - (void)historyCollectionViewControllerDidChangeEntries: |
| 261 (HistoryCollectionViewController*)controller { |
| 262 // Reconfigure the navigation and clear browsing bars to reflect currently |
| 263 // displayed entries. |
| 264 [self configureNavigationBar]; |
| 265 [self configureClearBrowsingBar]; |
| 266 } |
| 267 |
| 268 - (void)historyCollectionViewControllerDidChangeEntrySelection: |
| 269 (HistoryCollectionViewController*)controller { |
| 270 // Reconfigure the clear browsing bar to reflect current availability of |
| 271 // entries for deletion. |
| 272 [self configureClearBrowsingBar]; |
| 273 } |
| 274 |
| 275 #pragma mark - HistorySearchViewControllerDelegate |
| 276 |
| 277 - (void)historySearchViewController: |
| 278 (HistorySearchViewController*)searchViewController |
| 279 didRequestSearchForTerm:(NSString*)searchTerm { |
| 280 [_historyCollectionController showHistoryMatchingQuery:searchTerm]; |
| 281 } |
| 282 |
| 283 - (void)historySearchViewControllerDidCancel: |
| 284 (HistorySearchViewController*)searchViewController { |
| 285 DCHECK([_searchViewController isEqual:searchViewController]); |
| 286 [self exitSearchMode]; |
| 287 } |
| 288 |
| 289 #pragma mark - Private methods |
| 290 |
| 291 - (void)closeHistory { |
| 292 [self closeHistoryWithCompletion:nil]; |
| 293 } |
| 294 |
| 295 - (void)closeHistoryWithCompletion:(ProceduralBlock)completion { |
| 296 [self.presentingViewController dismissViewControllerAnimated:YES |
| 297 completion:completion]; |
| 298 } |
| 299 |
| 300 - (void)openPrivacySettings { |
| 301 [self exitSearchMode]; |
| 302 ShowClearBrowsingData(); |
| 303 } |
| 304 |
| 305 - (void)enterEditingMode { |
| 306 [_historyCollectionController setEditing:YES]; |
| 307 [_clearBrowsingBar setEditing:YES]; |
| 308 if (_historyCollectionController.get().searching) { |
| 309 [_searchViewController setEnabled:NO]; |
| 310 } |
| 311 DCHECK([_historyCollectionController isEditing]); |
| 312 [self configureNavigationBar]; |
| 313 } |
| 314 |
| 315 - (void)exitEditingMode { |
| 316 [_historyCollectionController setEditing:NO]; |
| 317 [_clearBrowsingBar setEditing:NO]; |
| 318 if (_historyCollectionController.get().searching) { |
| 319 [_searchViewController setEnabled:YES]; |
| 320 } |
| 321 DCHECK(![_historyCollectionController isEditing]); |
| 322 [self configureNavigationBar]; |
| 323 } |
| 324 |
| 325 - (void)deleteSelectedItems { |
| 326 [_historyCollectionController deleteSelectedItemsFromHistory]; |
| 327 [self exitEditingMode]; |
| 328 } |
| 329 - (void)enterSearchMode { |
| 330 if (!_searchViewController) { |
| 331 _searchViewController.reset([[HistorySearchViewController alloc] init]); |
| 332 [_searchViewController setDelegate:self]; |
| 333 } |
| 334 |
| 335 UIView* searchBarView = [_searchViewController view]; |
| 336 [_searchViewController willMoveToParentViewController:self]; |
| 337 [self.view addSubview:searchBarView]; |
| 338 _historyCollectionController.get().searching = YES; |
| 339 [_searchViewController didMoveToParentViewController:self]; |
| 340 |
| 341 // Constraints to make search bar cover header. |
| 342 [searchBarView setTranslatesAutoresizingMaskIntoConstraints:NO]; |
| 343 MDCFlexibleHeaderView* headerView = |
| 344 _appBar.get().headerViewController.headerView; |
| 345 NSArray* constraints = @[ |
| 346 [[searchBarView topAnchor] constraintEqualToAnchor:headerView.topAnchor], |
| 347 [[searchBarView leadingAnchor] |
| 348 constraintEqualToAnchor:headerView.leadingAnchor], |
| 349 [[searchBarView heightAnchor] |
| 350 constraintEqualToAnchor:headerView.heightAnchor], |
| 351 [[searchBarView widthAnchor] constraintEqualToAnchor:headerView.widthAnchor] |
| 352 ]; |
| 353 [NSLayoutConstraint activateConstraints:constraints]; |
| 354 } |
| 355 |
| 356 - (void)exitSearchMode { |
| 357 if (_historyCollectionController.get().searching) { |
| 358 [[_searchViewController view] removeFromSuperview]; |
| 359 [_searchViewController removeFromParentViewController]; |
| 360 _historyCollectionController.get().searching = NO; |
| 361 [_historyCollectionController showHistoryMatchingQuery:nil]; |
| 362 } |
| 363 } |
| 364 |
| 365 - (void)configureNavigationBar { |
| 366 // The search button should only be enabled if there are history entries to |
| 367 // search, and if history is not in edit mode. |
| 368 self.navigationItem.leftBarButtonItem.enabled = |
| 369 [_historyCollectionController hasHistoryEntries] && |
| 370 ![_historyCollectionController isEditing]; |
| 371 } |
| 372 |
| 373 - (void)configureClearBrowsingBar { |
| 374 _clearBrowsingBar.get().editing = _historyCollectionController.get().editing; |
| 375 _clearBrowsingBar.get().deleteButtonEnabled = |
| 376 [_historyCollectionController hasSelectedEntries]; |
| 377 _clearBrowsingBar.get().editButtonEnabled = |
| 378 [_historyCollectionController hasHistoryEntries]; |
| 379 } |
| 380 |
| 381 @end |
| OLD | NEW |