OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "ios/chrome/browser/ui/bookmarks/bookmark_folder_view_controller.h" | 5 #import "ios/chrome/browser/ui/bookmarks/bookmark_folder_view_controller.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
| 10 #import "base/ios/weak_nsobject.h" |
10 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/mac/objc_property_releaser.h" |
| 13 #include "base/mac/scoped_nsobject.h" |
11 #include "base/strings/sys_string_conversions.h" | 14 #include "base/strings/sys_string_conversions.h" |
12 #include "components/bookmarks/browser/bookmark_model.h" | 15 #include "components/bookmarks/browser/bookmark_model.h" |
13 #import "ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.
h" | 16 #import "ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.
h" |
14 #import "ios/chrome/browser/ui/bookmarks/bookmark_folder_table_view_cell.h" | 17 #import "ios/chrome/browser/ui/bookmarks/bookmark_folder_table_view_cell.h" |
15 #import "ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h" | 18 #import "ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h" |
16 #import "ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller.h" | 19 #import "ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller.h" |
17 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h" | 20 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h" |
18 #import "ios/chrome/browser/ui/icons/chrome_icon.h" | 21 #import "ios/chrome/browser/ui/icons/chrome_icon.h" |
19 #import "ios/chrome/browser/ui/material_components/utils.h" | 22 #import "ios/chrome/browser/ui/material_components/utils.h" |
20 #include "ios/chrome/grit/ios_strings.h" | 23 #include "ios/chrome/grit/ios_strings.h" |
21 #import "ios/third_party/material_components_ios/src/components/AppBar/src/Mater
ialAppBar.h" | 24 #import "ios/third_party/material_components_ios/src/components/AppBar/src/Mater
ialAppBar.h" |
22 #include "ui/base/l10n/l10n_util_mac.h" | 25 #include "ui/base/l10n/l10n_util_mac.h" |
23 | 26 |
24 #if !defined(__has_feature) || !__has_feature(objc_arc) | |
25 #error "This file requires ARC support." | |
26 #endif | |
27 | |
28 using bookmarks::BookmarkNode; | 27 using bookmarks::BookmarkNode; |
29 | 28 |
30 namespace { | 29 namespace { |
31 | 30 |
32 // The height of every folder cell. | 31 // The height of every folder cell. |
33 const CGFloat kFolderCellHeight = 48.0; | 32 const CGFloat kFolderCellHeight = 48.0; |
34 | 33 |
35 // Height of section headers/footers. | 34 // Height of section headers/footers. |
36 const CGFloat kSectionHeaderHeight = 8.0; | 35 const CGFloat kSectionHeaderHeight = 8.0; |
37 const CGFloat kSectionFooterHeight = 8.0; | 36 const CGFloat kSectionFooterHeight = 8.0; |
(...skipping 10 matching lines...) Expand all Loading... |
48 } // namespace | 47 } // namespace |
49 | 48 |
50 @interface BookmarkFolderViewController ()< | 49 @interface BookmarkFolderViewController ()< |
51 BookmarkFolderEditorViewControllerDelegate, | 50 BookmarkFolderEditorViewControllerDelegate, |
52 BookmarkModelBridgeObserver, | 51 BookmarkModelBridgeObserver, |
53 UITableViewDataSource, | 52 UITableViewDataSource, |
54 UITableViewDelegate> { | 53 UITableViewDelegate> { |
55 std::set<const BookmarkNode*> _editedNodes; | 54 std::set<const BookmarkNode*> _editedNodes; |
56 std::vector<const BookmarkNode*> _folders; | 55 std::vector<const BookmarkNode*> _folders; |
57 std::unique_ptr<bookmarks::BookmarkModelBridge> _modelBridge; | 56 std::unique_ptr<bookmarks::BookmarkModelBridge> _modelBridge; |
58 MDCAppBar* _appBar; | 57 base::scoped_nsobject<MDCAppBar> _appBar; |
| 58 base::mac::ObjCPropertyReleaser |
| 59 _propertyReleaser_BookmarkFolderViewController; |
59 } | 60 } |
60 | 61 |
61 // Should the controller setup Cancel and Done buttons instead of a back button. | 62 // Should the controller setup Cancel and Done buttons instead of a back button. |
62 @property(nonatomic, assign) BOOL allowsCancel; | 63 @property(nonatomic, assign) BOOL allowsCancel; |
63 | 64 |
64 // Should the controller setup a new-folder button. | 65 // Should the controller setup a new-folder button. |
65 @property(nonatomic, assign) BOOL allowsNewFolders; | 66 @property(nonatomic, assign) BOOL allowsNewFolders; |
66 | 67 |
67 // Reference to the main bookmark model. | 68 // Reference to the main bookmark model. |
68 @property(nonatomic, assign) bookmarks::BookmarkModel* bookmarkModel; | 69 @property(nonatomic, assign) bookmarks::BookmarkModel* bookmarkModel; |
69 | 70 |
70 // The currently selected folder. | 71 // The currently selected folder. |
71 @property(nonatomic, readonly) const BookmarkNode* selectedFolder; | 72 @property(nonatomic, readonly) const BookmarkNode* selectedFolder; |
72 | 73 |
73 // The view controller to present when creating a new folder. | 74 // The view controller to present when creating a new folder. |
74 @property(nonatomic, strong) | 75 @property(nonatomic, retain) |
75 BookmarkFolderEditorViewController* folderAddController; | 76 BookmarkFolderEditorViewController* folderAddController; |
76 | 77 |
77 // A linear list of folders. | 78 // A linear list of folders. |
78 @property(nonatomic, assign, readonly) | 79 @property(nonatomic, assign, readonly) |
79 const std::vector<const BookmarkNode*>& folders; | 80 const std::vector<const BookmarkNode*>& folders; |
80 | 81 |
81 // The table view that displays the options and folders. | 82 // The table view that displays the options and folders. |
82 @property(nonatomic, strong) UITableView* tableView; | 83 @property(nonatomic, retain) UITableView* tableView; |
83 | 84 |
84 // Returns the cell for the default section and the given |row|. | 85 // Returns the cell for the default section and the given |row|. |
85 - (BookmarkFolderTableViewCell*)defaultSectionCellForRow:(NSInteger)row; | 86 - (BookmarkFolderTableViewCell*)defaultSectionCellForRow:(NSInteger)row; |
86 | 87 |
87 // Returns a folder cell for the folder at |row| in |self.folders|. | 88 // Returns a folder cell for the folder at |row| in |self.folders|. |
88 - (BookmarkFolderTableViewCell*)folderSectionCellForRow:(NSInteger)row; | 89 - (BookmarkFolderTableViewCell*)folderSectionCellForRow:(NSInteger)row; |
89 | 90 |
90 // Reloads the folder list. | 91 // Reloads the folder list. |
91 - (void)reloadFolders; | 92 - (void)reloadFolders; |
92 | 93 |
(...skipping 25 matching lines...) Expand all Loading... |
118 allowsNewFolders:(BOOL)allowsNewFolders | 119 allowsNewFolders:(BOOL)allowsNewFolders |
119 editedNodes: | 120 editedNodes: |
120 (const std::set<const BookmarkNode*>&)nodes | 121 (const std::set<const BookmarkNode*>&)nodes |
121 allowsCancel:(BOOL)allowsCancel | 122 allowsCancel:(BOOL)allowsCancel |
122 selectedFolder:(const BookmarkNode*)selectedFolder { | 123 selectedFolder:(const BookmarkNode*)selectedFolder { |
123 DCHECK(bookmarkModel); | 124 DCHECK(bookmarkModel); |
124 DCHECK(bookmarkModel->loaded()); | 125 DCHECK(bookmarkModel->loaded()); |
125 DCHECK(selectedFolder == NULL || selectedFolder->is_folder()); | 126 DCHECK(selectedFolder == NULL || selectedFolder->is_folder()); |
126 self = [super initWithNibName:nil bundle:nil]; | 127 self = [super initWithNibName:nil bundle:nil]; |
127 if (self) { | 128 if (self) { |
| 129 _propertyReleaser_BookmarkFolderViewController.Init( |
| 130 self, [BookmarkFolderViewController class]); |
128 _allowsCancel = allowsCancel; | 131 _allowsCancel = allowsCancel; |
129 _allowsNewFolders = allowsNewFolders; | 132 _allowsNewFolders = allowsNewFolders; |
130 _bookmarkModel = bookmarkModel; | 133 _bookmarkModel = bookmarkModel; |
131 _editedNodes = nodes; | 134 _editedNodes = nodes; |
132 _selectedFolder = selectedFolder; | 135 _selectedFolder = selectedFolder; |
133 | 136 |
134 // Set up the bookmark model oberver. | 137 // Set up the bookmark model oberver. |
135 _modelBridge.reset( | 138 _modelBridge.reset( |
136 new bookmarks::BookmarkModelBridge(self, _bookmarkModel)); | 139 new bookmarks::BookmarkModelBridge(self, _bookmarkModel)); |
137 | 140 |
138 _appBar = [[MDCAppBar alloc] init]; | 141 _appBar.reset([[MDCAppBar alloc] init]); |
139 [self addChildViewController:[_appBar headerViewController]]; | 142 [self addChildViewController:[_appBar headerViewController]]; |
140 } | 143 } |
141 return self; | 144 return self; |
142 } | 145 } |
143 | 146 |
144 - (void)changeSelectedFolder:(const BookmarkNode*)selectedFolder { | 147 - (void)changeSelectedFolder:(const BookmarkNode*)selectedFolder { |
145 DCHECK(selectedFolder); | 148 DCHECK(selectedFolder); |
146 DCHECK(selectedFolder->is_folder()); | 149 DCHECK(selectedFolder->is_folder()); |
147 _selectedFolder = selectedFolder; | 150 _selectedFolder = selectedFolder; |
148 [self.tableView reloadData]; | 151 [self.tableView reloadData]; |
149 } | 152 } |
150 | 153 |
151 - (void)dealloc { | 154 - (void)dealloc { |
152 _tableView.dataSource = nil; | 155 _tableView.dataSource = nil; |
153 _tableView.delegate = nil; | 156 _tableView.delegate = nil; |
154 _folderAddController.delegate = nil; | 157 _folderAddController.delegate = nil; |
| 158 [super dealloc]; |
155 } | 159 } |
156 | 160 |
157 - (UIStatusBarStyle)preferredStatusBarStyle { | 161 - (UIStatusBarStyle)preferredStatusBarStyle { |
158 return UIStatusBarStyleDefault; | 162 return UIStatusBarStyleDefault; |
159 } | 163 } |
160 | 164 |
161 #pragma mark - View lifecycle | 165 #pragma mark - View lifecycle |
162 | 166 |
163 - (void)viewDidLoad { | 167 - (void)viewDidLoad { |
164 [super viewDidLoad]; | 168 [super viewDidLoad]; |
165 if ([self respondsToSelector:@selector(setEdgesForExtendedLayout:)]) { | 169 if ([self respondsToSelector:@selector(setEdgesForExtendedLayout:)]) { |
166 [self setEdgesForExtendedLayout:UIRectEdgeNone]; | 170 [self setEdgesForExtendedLayout:UIRectEdgeNone]; |
167 } | 171 } |
168 self.view.backgroundColor = [UIColor whiteColor]; | 172 self.view.backgroundColor = [UIColor whiteColor]; |
169 self.view.accessibilityIdentifier = @"Folder Picker"; | 173 self.view.accessibilityIdentifier = @"Folder Picker"; |
170 | 174 |
171 self.title = l10n_util::GetNSString(IDS_IOS_BOOKMARK_CHOOSE_GROUP_BUTTON); | 175 self.title = l10n_util::GetNSString(IDS_IOS_BOOKMARK_CHOOSE_GROUP_BUTTON); |
172 | 176 |
173 UIBarButtonItem* doneItem = [[UIBarButtonItem alloc] | 177 base::scoped_nsobject<UIBarButtonItem> doneItem([[UIBarButtonItem alloc] |
174 initWithTitle:l10n_util::GetNSString( | 178 initWithTitle:l10n_util::GetNSString( |
175 IDS_IOS_BOOKMARK_EDIT_MODE_EXIT_MOBILE) | 179 IDS_IOS_BOOKMARK_EDIT_MODE_EXIT_MOBILE) |
176 style:UIBarButtonItemStylePlain | 180 style:UIBarButtonItemStylePlain |
177 target:self | 181 target:self |
178 action:@selector(done:)]; | 182 action:@selector(done:)]); |
179 doneItem.accessibilityIdentifier = @"Done"; | 183 doneItem.get().accessibilityIdentifier = @"Done"; |
180 self.navigationItem.rightBarButtonItem = doneItem; | 184 self.navigationItem.rightBarButtonItem = doneItem; |
181 | 185 |
182 if (self.allowsCancel) { | 186 if (self.allowsCancel) { |
183 UIBarButtonItem* cancelItem = | 187 UIBarButtonItem* cancelItem = |
184 [ChromeIcon templateBarButtonItemWithImage:[ChromeIcon closeIcon] | 188 [ChromeIcon templateBarButtonItemWithImage:[ChromeIcon closeIcon] |
185 target:self | 189 target:self |
186 action:@selector(cancel:)]; | 190 action:@selector(cancel:)]; |
187 cancelItem.accessibilityLabel = | 191 cancelItem.accessibilityLabel = |
188 l10n_util::GetNSString(IDS_IOS_BOOKMARK_NEW_CANCEL_BUTTON_LABEL); | 192 l10n_util::GetNSString(IDS_IOS_BOOKMARK_NEW_CANCEL_BUTTON_LABEL); |
189 cancelItem.accessibilityIdentifier = @"Cancel"; | 193 cancelItem.accessibilityIdentifier = @"Cancel"; |
190 self.navigationItem.leftBarButtonItem = cancelItem; | 194 self.navigationItem.leftBarButtonItem = cancelItem; |
191 } else { | 195 } else { |
192 UIBarButtonItem* backItem = | 196 UIBarButtonItem* backItem = |
193 [ChromeIcon templateBarButtonItemWithImage:[ChromeIcon backIcon] | 197 [ChromeIcon templateBarButtonItemWithImage:[ChromeIcon backIcon] |
194 target:self | 198 target:self |
195 action:@selector(back:)]; | 199 action:@selector(back:)]; |
196 backItem.accessibilityLabel = | 200 backItem.accessibilityLabel = |
197 l10n_util::GetNSString(IDS_IOS_BOOKMARK_NEW_BACK_LABEL); | 201 l10n_util::GetNSString(IDS_IOS_BOOKMARK_NEW_BACK_LABEL); |
198 backItem.accessibilityIdentifier = @"Back"; | 202 backItem.accessibilityIdentifier = @"Back"; |
199 self.navigationItem.leftBarButtonItem = backItem; | 203 self.navigationItem.leftBarButtonItem = backItem; |
200 } | 204 } |
201 | 205 |
202 // The table view. | 206 // The table view. |
203 UITableView* tableView = | 207 base::scoped_nsobject<UITableView> tableView([[UITableView alloc] |
204 [[UITableView alloc] initWithFrame:self.view.bounds | 208 initWithFrame:self.view.bounds |
205 style:UITableViewStylePlain]; | 209 style:UITableViewStylePlain]); |
206 tableView.dataSource = self; | 210 tableView.get().dataSource = self; |
207 tableView.delegate = self; | 211 tableView.get().delegate = self; |
208 tableView.autoresizingMask = | 212 tableView.get().autoresizingMask = |
209 UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; | 213 UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; |
210 tableView.separatorStyle = UITableViewCellSeparatorStyleNone; | 214 tableView.get().separatorStyle = UITableViewCellSeparatorStyleNone; |
211 [self.view addSubview:tableView]; | 215 [self.view addSubview:tableView]; |
212 [self.view sendSubviewToBack:tableView]; | 216 [self.view sendSubviewToBack:tableView]; |
213 self.tableView = tableView; | 217 self.tableView = tableView; |
214 | 218 |
215 // Add the app bar to the view hierarchy. This must be done last, so that the | 219 // Add the app bar to the view hierarchy. This must be done last, so that the |
216 // app bar's views are the frontmost. | 220 // app bar's views are the frontmost. |
217 ConfigureAppBarWithCardStyle(_appBar); | 221 ConfigureAppBarWithCardStyle(_appBar); |
218 [_appBar headerViewController].headerView.trackingScrollView = self.tableView; | 222 [_appBar headerViewController].headerView.trackingScrollView = self.tableView; |
219 [_appBar addSubviewsToParent]; | 223 [_appBar addSubviewsToParent]; |
220 } | 224 } |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
326 } | 330 } |
327 NOTREACHED(); | 331 NOTREACHED(); |
328 return 0; | 332 return 0; |
329 } | 333 } |
330 | 334 |
331 - (UIView*)tableView:(UITableView*)tableView | 335 - (UIView*)tableView:(UITableView*)tableView |
332 viewForHeaderInSection:(NSInteger)section { | 336 viewForHeaderInSection:(NSInteger)section { |
333 CGRect headerViewFrame = | 337 CGRect headerViewFrame = |
334 CGRectMake(0, 0, CGRectGetWidth(tableView.frame), | 338 CGRectMake(0, 0, CGRectGetWidth(tableView.frame), |
335 [self tableView:tableView heightForHeaderInSection:section]); | 339 [self tableView:tableView heightForHeaderInSection:section]); |
336 UIView* headerView = [[UIView alloc] initWithFrame:headerViewFrame]; | 340 UIView* headerView = |
| 341 [[[UIView alloc] initWithFrame:headerViewFrame] autorelease]; |
337 if (section == BookmarkFolderSectionFolders && | 342 if (section == BookmarkFolderSectionFolders && |
338 [self shouldShowDefaultSection]) { | 343 [self shouldShowDefaultSection]) { |
339 CGRect separatorFrame = | 344 CGRect separatorFrame = |
340 CGRectMake(0, 0, CGRectGetWidth(headerView.bounds), | 345 CGRectMake(0, 0, CGRectGetWidth(headerView.bounds), |
341 1.0 / [[UIScreen mainScreen] scale]); // 1-pixel divider. | 346 1.0 / [[UIScreen mainScreen] scale]); // 1-pixel divider. |
342 UIView* separator = [[UIView alloc] initWithFrame:separatorFrame]; | 347 base::scoped_nsobject<UIView> separator( |
343 separator.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | | 348 [[UIView alloc] initWithFrame:separatorFrame]); |
344 UIViewAutoresizingFlexibleWidth; | 349 separator.get().autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | |
345 separator.backgroundColor = bookmark_utils_ios::separatorColor(); | 350 UIViewAutoresizingFlexibleWidth; |
| 351 separator.get().backgroundColor = bookmark_utils_ios::separatorColor(); |
346 [headerView addSubview:separator]; | 352 [headerView addSubview:separator]; |
347 } | 353 } |
348 return headerView; | 354 return headerView; |
349 } | 355 } |
350 | 356 |
351 - (CGFloat)tableView:(UITableView*)tableView | 357 - (CGFloat)tableView:(UITableView*)tableView |
352 heightForFooterInSection:(NSInteger)section { | 358 heightForFooterInSection:(NSInteger)section { |
353 switch (static_cast<BookmarkFolderSection>(section)) { | 359 switch (static_cast<BookmarkFolderSection>(section)) { |
354 case BookmarkFolderSectionDefault: | 360 case BookmarkFolderSectionDefault: |
355 return [self shouldShowDefaultSection] ? kSectionFooterHeight : 0; | 361 return [self shouldShowDefaultSection] ? kSectionFooterHeight : 0; |
356 | 362 |
357 case BookmarkFolderSectionFolders: | 363 case BookmarkFolderSectionFolders: |
358 return kSectionFooterHeight; | 364 return kSectionFooterHeight; |
359 } | 365 } |
360 NOTREACHED(); | 366 NOTREACHED(); |
361 return 0; | 367 return 0; |
362 } | 368 } |
363 | 369 |
364 - (UIView*)tableView:(UITableView*)tableView | 370 - (UIView*)tableView:(UITableView*)tableView |
365 viewForFooterInSection:(NSInteger)section { | 371 viewForFooterInSection:(NSInteger)section { |
366 return [[UIView alloc] init]; | 372 return [[[UIView alloc] init] autorelease]; |
367 } | 373 } |
368 | 374 |
369 - (void)tableView:(UITableView*)tableView | 375 - (void)tableView:(UITableView*)tableView |
370 didSelectRowAtIndexPath:(NSIndexPath*)indexPath { | 376 didSelectRowAtIndexPath:(NSIndexPath*)indexPath { |
371 [tableView deselectRowAtIndexPath:indexPath animated:YES]; | 377 [tableView deselectRowAtIndexPath:indexPath animated:YES]; |
372 switch (static_cast<BookmarkFolderSection>(indexPath.section)) { | 378 switch (static_cast<BookmarkFolderSection>(indexPath.section)) { |
373 case BookmarkFolderSectionDefault: | 379 case BookmarkFolderSectionDefault: |
374 [self pushFolderAddViewController]; | 380 [self pushFolderAddViewController]; |
375 break; | 381 break; |
376 | 382 |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
525 [BookmarkFolderEditorViewController | 531 [BookmarkFolderEditorViewController |
526 folderCreatorWithBookmarkModel:self.bookmarkModel | 532 folderCreatorWithBookmarkModel:self.bookmarkModel |
527 parentFolder:self.selectedFolder]; | 533 parentFolder:self.selectedFolder]; |
528 folderCreator.delegate = self; | 534 folderCreator.delegate = self; |
529 [self.navigationController pushViewController:folderCreator animated:YES]; | 535 [self.navigationController pushViewController:folderCreator animated:YES]; |
530 self.folderAddController = folderCreator; | 536 self.folderAddController = folderCreator; |
531 } | 537 } |
532 | 538 |
533 - (void)delayedNotifyDelegateOfSelection { | 539 - (void)delayedNotifyDelegateOfSelection { |
534 self.view.userInteractionEnabled = NO; | 540 self.view.userInteractionEnabled = NO; |
535 __weak BookmarkFolderViewController* weakSelf = self; | 541 base::WeakNSObject<BookmarkFolderViewController> weakSelf(self); |
536 dispatch_after( | 542 dispatch_after( |
537 dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), | 543 dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), |
538 dispatch_get_main_queue(), ^{ | 544 dispatch_get_main_queue(), ^{ |
539 BookmarkFolderViewController* strongSelf = weakSelf; | 545 base::scoped_nsobject<BookmarkFolderViewController> strongSelf( |
| 546 [weakSelf retain]); |
540 // Early return if the controller has been deallocated. | 547 // Early return if the controller has been deallocated. |
541 if (!strongSelf) | 548 if (!strongSelf) |
542 return; | 549 return; |
543 strongSelf.view.userInteractionEnabled = YES; | 550 strongSelf.get().view.userInteractionEnabled = YES; |
544 [strongSelf done:nil]; | 551 [strongSelf done:nil]; |
545 }); | 552 }); |
546 } | 553 } |
547 | 554 |
548 @end | 555 @end |
OLD | NEW |