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 |