Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2017 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/payments/payment_request_picker_view_controller.h" | |
| 6 | |
| 7 #import "base/logging.h" | |
| 8 #import "ios/chrome/browser/payments/payment_request_picker_row.h" | |
| 9 #import "ios/third_party/material_components_ios/src/components/CollectionCells/ src/MaterialCollectionCells.h" | |
| 10 | |
| 11 #if !defined(__has_feature) || !__has_feature(objc_arc) | |
| 12 #error "This file requires ARC support." | |
| 13 #endif | |
| 14 | |
| 15 NSString* const kPaymentRequestPickerRowAccessibilityID = | |
| 16 @"kPaymentRequestPickerRowAccessibilityID"; | |
| 17 NSString* const kPaymentRequestPickerSelectedRowAccessibilityID = | |
| 18 @"kPaymentRequestPickerSelectedRowAccessibilityID"; | |
| 19 NSString* const kPaymentRequestPickerSearchBarAccessibilityID = | |
| 20 @"kPaymentRequestPickerSearchBarAccessibilityID"; | |
| 21 | |
| 22 namespace { | |
| 23 NSString* const kPaymentRequestPickerViewControllerAccessibilityID = | |
| 24 @"kPaymentRequestPickerViewControllerAccessibilityID"; | |
| 25 | |
|
lpromero
2017/03/29 11:38:15
Remove empty line.
Moe
2017/03/29 17:04:09
Done.
| |
| 26 } // namespace | |
| 27 | |
| 28 @interface PaymentRequestPickerViewController ()<UITableViewDataSource, | |
| 29 UITableViewDelegate, | |
|
lpromero
2017/03/29 11:38:15
This is already done by the base class.
Moe
2017/03/29 17:04:09
Done.
| |
| 30 UISearchResultsUpdating> | |
| 31 | |
| 32 // Search controller that contains search bar. | |
| 33 @property(nonatomic, strong) UISearchController* searchController; | |
| 34 | |
| 35 // Full data set displayed when tableView is not filtered. | |
| 36 @property(nonatomic, strong) NSArray<PickerRow*>* allRows; | |
| 37 | |
| 38 // Displayed rows in the tableView. | |
| 39 @property(nonatomic, strong) NSArray<PickerRow*>* displayedRows; | |
| 40 | |
| 41 // Selected row. | |
| 42 @property(nonatomic, strong) PickerRow* selectedRow; | |
| 43 | |
| 44 @end | |
| 45 | |
| 46 @implementation PaymentRequestPickerViewController | |
| 47 @synthesize searchController = _searchController; | |
| 48 @synthesize allRows = _allRows; | |
| 49 @synthesize displayedRows = _displayedRows; | |
| 50 @synthesize selectedRow = _selectedRow; | |
| 51 @synthesize delegate = _delegate; | |
| 52 | |
| 53 - (instancetype)initWithRows:(NSArray<PickerRow*>*)rows | |
| 54 selected:(PickerRow*)selectedRow { | |
| 55 self = [super initWithStyle:UITableViewStylePlain]; | |
| 56 if (self) { | |
| 57 self.allRows = [rows sortedArrayUsingComparator:^NSComparisonResult( | |
| 58 PickerRow* row1, PickerRow* row2) { | |
| 59 return [row1.label localizedCaseInsensitiveCompare:row2.label]; | |
| 60 }]; | |
| 61 self.selectedRow = selectedRow; | |
| 62 // Default to displaying all the rows. | |
| 63 self.displayedRows = self.allRows; | |
| 64 } | |
| 65 return self; | |
| 66 } | |
| 67 | |
| 68 #pragma mark - UIViewController | |
| 69 | |
| 70 - (void)viewDidLoad { | |
| 71 [super viewDidLoad]; | |
| 72 | |
| 73 self.tableView.rowHeight = MDCCellDefaultOneLineHeight; | |
|
lpromero
2017/03/29 11:38:15
I'd suggest just setting your own value here, not
Moe
2017/03/29 17:04:09
Done.
| |
| 74 self.tableView.accessibilityIdentifier = | |
| 75 kPaymentRequestPickerViewControllerAccessibilityID; | |
| 76 | |
| 77 self.searchController = | |
| 78 [[UISearchController alloc] initWithSearchResultsController:nil]; | |
| 79 self.searchController.searchResultsUpdater = self; | |
| 80 self.searchController.dimsBackgroundDuringPresentation = NO; | |
| 81 self.searchController.searchBar.accessibilityIdentifier = | |
| 82 kPaymentRequestPickerSearchBarAccessibilityID; | |
| 83 self.tableView.tableHeaderView = self.searchController.searchBar; | |
| 84 | |
| 85 // Presentation of searchController will walk up the view controller hierarchy | |
| 86 // until it finds the root view controller or one that defines a presentation | |
| 87 // context. Make this class the presentation context so that the search | |
| 88 // controller does not present on top of the navigation controller. | |
| 89 self.definesPresentationContext = YES; | |
| 90 } | |
| 91 | |
| 92 #pragma mark - UITableViewDataSource | |
| 93 | |
| 94 - (NSArray<NSString*>*)sectionIndexTitlesForTableView:(UITableView*)tableView { | |
| 95 return [self sectionTitles]; | |
| 96 } | |
| 97 | |
| 98 - (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView { | |
| 99 return [[self sectionTitles] count]; | |
| 100 } | |
| 101 | |
| 102 - (NSString*)tableView:(UITableView*)tableView | |
| 103 titleForHeaderInSection:(NSInteger)section { | |
| 104 return [[self sectionTitles] objectAtIndex:section]; | |
| 105 } | |
| 106 | |
| 107 - (NSInteger)tableView:(UITableView*)tableView | |
| 108 numberOfRowsInSection:(NSInteger)section { | |
| 109 return [[self rowsInSection:section] count]; | |
| 110 } | |
| 111 | |
| 112 - (UITableViewCell*)tableView:(UITableView*)tableView | |
| 113 cellForRowAtIndexPath:(NSIndexPath*)indexPath { | |
| 114 UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; | |
| 115 if (!cell) { | |
| 116 cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle | |
| 117 reuseIdentifier:@"cell"]; | |
| 118 } | |
| 119 PickerRow* row = | |
| 120 [[self rowsInSection:indexPath.section] objectAtIndex:indexPath.row]; | |
| 121 cell.textLabel.text = row.label; | |
| 122 cell.accessoryType = (row == self.selectedRow) | |
| 123 ? UITableViewCellAccessoryCheckmark | |
| 124 : UITableViewCellAccessoryNone; | |
| 125 cell.accessibilityLabel = row.label; | |
| 126 cell.accessibilityIdentifier = | |
|
lpromero
2017/03/29 11:38:15
If you remove the need for the 2 different IDs, yo
Moe
2017/03/29 17:04:09
Done.
| |
| 127 (row == self.selectedRow) | |
| 128 ? kPaymentRequestPickerSelectedRowAccessibilityID | |
| 129 : kPaymentRequestPickerRowAccessibilityID; | |
| 130 return cell; | |
| 131 } | |
| 132 | |
| 133 #pragma mark - UITableViewDelegate | |
| 134 | |
| 135 - (void)tableView:(UITableView*)tableView | |
| 136 didSelectRowAtIndexPath:(NSIndexPath*)indexPath { | |
| 137 if (self.selectedRow) { | |
| 138 NSIndexPath* oldSelectedIndexPath = [self indexPathForRow:self.selectedRow]; | |
| 139 self.selectedRow = nil; | |
| 140 // Reload the previously selected row. | |
| 141 [self.tableView reloadRowsAtIndexPaths:@[ oldSelectedIndexPath ] | |
| 142 withRowAnimation:UITableViewRowAnimationFade]; | |
| 143 } | |
| 144 | |
| 145 self.selectedRow = | |
| 146 [[self rowsInSection:indexPath.section] objectAtIndex:indexPath.row]; | |
| 147 NSIndexPath* newSelectedIndexPath = [self indexPathForRow:self.selectedRow]; | |
|
lpromero
2017/03/29 11:38:15
Isn't this equal to indexPath?
Moe
2017/03/29 17:04:09
Oops. Done.
| |
| 148 // Reload the newly selected row. | |
| 149 [self.tableView reloadRowsAtIndexPaths:@[ newSelectedIndexPath ] | |
| 150 withRowAnimation:UITableViewRowAnimationFade]; | |
| 151 | |
| 152 [_delegate paymentRequestPickerViewController:self | |
| 153 didSelectRow:self.selectedRow]; | |
| 154 } | |
| 155 | |
| 156 #pragma mark - UISearchResultsUpdating | |
| 157 | |
| 158 - (void)updateSearchResultsForSearchController: | |
| 159 (UISearchController*)searchController { | |
| 160 [self filterContentForSearchText:searchController.searchBar.text]; | |
| 161 } | |
| 162 | |
| 163 #pragma mark - Private | |
| 164 | |
| 165 // Returns the indexPath for |row| by calculating its section and its index | |
| 166 // within the section. | |
| 167 - (NSIndexPath*)indexPathForRow:(PickerRow*)row { | |
| 168 NSString* sectionTitle = [self sectionTitleForRow:row]; | |
| 169 NSInteger section = [[self sectionTitles] indexOfObject:sectionTitle]; | |
| 170 DCHECK(section != NSNotFound); | |
| 171 | |
| 172 NSInteger indexInSection = [[self rowsInSection:section] indexOfObject:row]; | |
| 173 DCHECK(indexInSection != NSNotFound); | |
| 174 | |
| 175 return [NSIndexPath indexPathForRow:indexInSection inSection:section]; | |
| 176 } | |
| 177 | |
| 178 // Returns the titles for the displayed sections in the tableView. | |
| 179 - (NSArray<NSString*>*)sectionTitles { | |
| 180 NSMutableOrderedSet<NSString*>* sectionTitles = | |
| 181 [[NSMutableOrderedSet alloc] init]; | |
| 182 [self.displayedRows | |
| 183 enumerateObjectsUsingBlock:^(PickerRow* row, NSUInteger idx, BOOL* stop) { | |
| 184 [sectionTitles addObject:[self sectionTitleForRow:row]]; | |
| 185 }]; | |
| 186 return [sectionTitles array]; | |
|
lpromero
2017/03/29 11:38:15
Should you cache this array? (You'll need to inval
Moe
2017/03/29 17:04:09
I'm now keeping a map of section titles to the sec
| |
| 187 } | |
| 188 | |
| 189 // Returns the displayed rows in the given section. | |
| 190 - (NSArray<PickerRow*>*)rowsInSection:(NSInteger)section { | |
| 191 NSArray<NSString*>* sectionTitles = [self sectionTitles]; | |
| 192 DCHECK(section >= 0 && section < static_cast<NSInteger>(sectionTitles.count)); | |
| 193 | |
| 194 NSString* sectionTitle = [sectionTitles objectAtIndex:section]; | |
| 195 | |
| 196 // Find the rows in the section with the title |sectionTitle| based on the | |
| 197 // labels of the rows. The search is case-insensitive and ignores diacritics. | |
| 198 NSPredicate* prediacate = [NSPredicate | |
|
lpromero
2017/03/29 11:38:15
*predicate
Moe
2017/03/29 17:04:09
Done.
| |
| 199 predicateWithFormat:@"label BEGINSWITH[cd] %@", sectionTitle]; | |
| 200 return [self.displayedRows filteredArrayUsingPredicate:prediacate]; | |
|
lpromero
2017/03/29 11:38:15
idem, should this be cached? It is called several
Moe
2017/03/29 17:04:09
with the map of section titles to the section rows
| |
| 201 } | |
| 202 | |
| 203 // Returns the title for the section the given row gets added to. The section | |
| 204 // title for a row is the capitalized first letter of the label for that row. | |
| 205 - (NSString*)sectionTitleForRow:(PickerRow*)row { | |
| 206 return [[row.label substringToIndex:1] uppercaseString]; | |
| 207 } | |
| 208 | |
| 209 // Filters |allRows| for |searchText| and reloads the tableView. If |searchText| | |
| 210 // is empty, tableView will be loaded with |allRows|. | |
| 211 - (void)filterContentForSearchText:(NSString*)searchText { | |
| 212 self.displayedRows = self.allRows; | |
| 213 | |
| 214 if (searchText.length != 0) { | |
| 215 // The search is case-insensitive and ignores diacritics. | |
| 216 NSPredicate* prediacate = | |
| 217 [NSPredicate predicateWithFormat:@"label CONTAINS[cd] %@", searchText]; | |
| 218 self.displayedRows = [self.allRows filteredArrayUsingPredicate:prediacate]; | |
| 219 } | |
| 220 | |
| 221 [self.tableView reloadData]; | |
|
lpromero
2017/03/29 11:38:15
Showcase handles that more nicely, as it animates
Moe
2017/03/29 17:04:09
Since we have sections here and they would have to
| |
| 222 } | |
| 223 | |
| 224 @end | |
| OLD | NEW |