Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(32)

Side by Side Diff: ios/chrome/browser/ui/bookmarks/bookmark_all_collection_view.mm

Issue 2774233002: Deletes unused files bookmark_all_collection_view.* As a followup to (Closed)
Patch Set: a Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ios/chrome/browser/ui/bookmarks/bookmark_all_collection_view.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #import "ios/chrome/browser/ui/bookmarks/bookmark_all_collection_view.h"
6
7 #include <memory>
8 #include <vector>
9
10 #include "base/logging.h"
11 #include "base/mac/objc_property_releaser.h"
12 #include "base/mac/scoped_nsobject.h"
13 #include "base/strings/sys_string_conversions.h"
14 #include "components/bookmarks/browser/bookmark_model.h"
15 #include "ios/chrome/browser/bookmarks/bookmarks_utils.h"
16 #import "ios/chrome/browser/ui/bookmarks/bookmark_collection_cells.h"
17 #include "ios/chrome/browser/ui/bookmarks/bookmark_promo_cell.h"
18 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
19 #include "ui/base/l10n/l10n_util.h"
20 #include "ui/base/models/tree_node_iterator.h"
21
22 using bookmarks::BookmarkNode;
23
24 namespace {
25 typedef std::vector<const BookmarkNode*> NodeVector;
26 // Each section of the collection view corresponds to a NodesSection object,
27 // sorted by creation date.
28 using bookmark_utils_ios::NodesSection;
29
30 // There is sometimes a flurry of events from the bookmark model. When this
31 // happens the data the collection view is displaying needs to be recalculated
32 // and the collection view needs to be reloaded. The recalculation of the data
33 // is expensive, so instead of doing the update over and over again the update
34 // is done once and all other updates received during the same runloop event are
35 // deferred to the next turn of the runloop (if everything is deferred this
36 // unfortunately triggers a bug in the UICollectionView sometimes).
37 // This enum tracks the state of the refresh. See -collectionViewNeedsUpdate
38 // for the state machine.
39 typedef enum { kNoUpdate = 0, kOneUpdateDone, kUpdateScheduled } UpdateState;
40 } // namespace
41
42 @interface BookmarkAllCollectionView ()<BookmarkPromoCellDelegate> {
43 // A vector of vectors. Url nodes are segregated by month of creation.
44 std::vector<std::unique_ptr<NodesSection>> _nodesSectionVector;
45 // To avoid refreshing the internal model too often.
46 UpdateState _updateScheduled;
47 base::mac::ObjCPropertyReleaser _propertyReleaser_BookmarkAllCollectionView;
48 }
49
50 // Keep a reference to the promo cell to deregister as delegate.
51 @property(nonatomic, retain) BookmarkPromoCell* promoCell;
52
53 // Triggers an update of the collection, but delayed in order to coallesce a lot
54 // of events into one update.
55 - (void)collectionViewNeedsUpdate;
56
57 @end
58
59 @implementation BookmarkAllCollectionView
60
61 @synthesize delegate = _delegate;
62 @synthesize promoCell = _promoCell;
63
64 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
65 frame:(CGRect)frame {
66 self = [super initWithBrowserState:browserState frame:frame];
67 if (self) {
68 _propertyReleaser_BookmarkAllCollectionView.Init(
69 self, [BookmarkAllCollectionView class]);
70 self.accessibilityIdentifier = @"bookmark_all_collection_view";
71 [self updateCollectionView];
72 }
73 return self;
74 }
75
76 - (void)dealloc {
77 _promoCell.delegate = nil;
78 [super dealloc];
79 }
80
81 - (void)updateCollectionView {
82 if (!self.bookmarkModel->loaded())
83 return;
84
85 // Regenerate the list of all bookmarks.
86 NodeVector allItems;
87 ui::TreeNodeIterator<const BookmarkNode> iterator(
88 self.bookmarkModel->root_node());
89
90 while (iterator.has_next()) {
91 const BookmarkNode* bookmark = iterator.Next();
92
93 if (bookmark->is_url())
94 allItems.push_back(bookmark);
95 }
96
97 // Perform segregation.
98 bookmark_utils_ios::segregateNodes(allItems, _nodesSectionVector);
99
100 [self cancelAllFaviconLoads];
101 [self.collectionView reloadData];
102 }
103
104 - (void)collectionViewNeedsUpdate {
105 switch (_updateScheduled) {
106 case kNoUpdate:
107 // If the collection view was not updated recently, update it now.
108 [self updateCollectionView];
109 _updateScheduled = kOneUpdateDone;
110 // And reset the state when going back to the main loop.
111 dispatch_async(dispatch_get_main_queue(), ^{
112 _updateScheduled = kNoUpdate;
113 });
114 break;
115 case kOneUpdateDone:
116 // An update was already done on this turn of the main loop, schedule the
117 // next update for later.
118 _updateScheduled = kUpdateScheduled;
119 dispatch_async(dispatch_get_main_queue(), ^{
120 if (_updateScheduled == kNoUpdate)
121 [self updateCollectionView];
122 });
123 break;
124 case kUpdateScheduled:
125 // Nothing to do.
126 break;
127 }
128 }
129
130 #pragma mark - BookmarkModelBridgeObserver Callbacks
131
132 - (void)bookmarkModelLoaded {
133 [self updateCollectionView];
134 }
135
136 - (void)bookmarkNodeChanged:(const BookmarkNode*)bookmarkNode {
137 if (bookmarkNode->is_folder())
138 return;
139
140 // TODO(crbug.com/603661): Ideally, we would only reload the relevant index
141 // path. However, calling reloadItemsAtIndexPaths:(0,0) immediately after
142 // reloadData results in a exception: NSInternalInconsistencyException
143 // 'request for index path for global index 2147483645 ...'
144 // One solution would be to keep track of whether we've just called
145 // reloadData, but that requires experimentation to determine how long we have
146 // to wait before we can safely call reloadItemsAtIndexPaths.
147 [self updateCollectionView];
148 }
149
150 - (void)bookmarkNodeFaviconChanged:
151 (const bookmarks::BookmarkNode*)bookmarkNode {
152 // Only urls have favicons.
153 DCHECK(bookmarkNode->is_url());
154
155 // Update image of corresponding cell.
156 NSIndexPath* indexPath = [self indexPathForNode:bookmarkNode];
157 if (!indexPath)
158 return;
159
160 // Check that this cell is visible.
161 NSArray* visiblePaths = [self.collectionView indexPathsForVisibleItems];
162 if (![visiblePaths containsObject:indexPath])
163 return;
164
165 [self loadFaviconAtIndexPath:indexPath];
166 }
167
168 - (void)bookmarkNodeChildrenChanged:(const BookmarkNode*)bookmarkNode {
169 [self collectionViewNeedsUpdate];
170 }
171
172 - (void)bookmarkNode:(const BookmarkNode*)bookmarkNode
173 movedFromParent:(const BookmarkNode*)oldParent
174 toParent:(const BookmarkNode*)newParent {
175 [self updateCollectionView];
176 }
177
178 - (void)bookmarkNodeDeleted:(const BookmarkNode*)node
179 fromFolder:(const BookmarkNode*)folder {
180 // Only remove the node from the list of all nodes. Since we also receive a
181 // 'bookmarkNodeChildrenChanged' callback, the collection view will be updated
182 // there.
183 for (const auto& nodesSection : _nodesSectionVector) {
184 NodeVector nodeVector = nodesSection->vector;
185 // If the node was in _nodesSectionVector, it is now invalid. In that case,
186 // remove it from _nodesSectionVector.
187 auto it = std::find(nodeVector.begin(), nodeVector.end(), node);
188 if (it != nodeVector.end()) {
189 nodeVector.erase(it);
190 nodesSection->vector = nodeVector;
191 break;
192 }
193 }
194 }
195
196 - (void)bookmarkModelRemovedAllNodes {
197 [self updateCollectionView];
198 }
199
200 #pragma mark - Parent class overrides that affect functionality
201
202 - (void)collectionView:(UICollectionView*)collectionView
203 willDisplayCell:(UICollectionViewCell*)cell
204 forItemAtIndexPath:(NSIndexPath*)indexPath {
205 auto node = [self nodeAtIndexPath:indexPath];
206 if (node && node->type() == bookmarks::BookmarkNode::URL) {
207 [self loadFaviconAtIndexPath:indexPath];
208 }
209 }
210
211 - (void)didAddCellForEditingAtIndexPath:(NSIndexPath*)indexPath {
212 DCHECK(![self isPromoSection:indexPath.section]);
213 const BookmarkNode* node = [self nodeAtIndexPath:indexPath];
214 UICollectionViewCell* cell =
215 [self.collectionView cellForItemAtIndexPath:indexPath];
216 [self.delegate bookmarkCollectionView:self cell:cell addNodeForEditing:node];
217 }
218
219 - (void)didRemoveCellForEditingAtIndexPath:(NSIndexPath*)indexPath {
220 DCHECK(![self isPromoSection:indexPath.section]);
221 const BookmarkNode* node = [self nodeAtIndexPath:indexPath];
222 UICollectionViewCell* cell =
223 [self.collectionView cellForItemAtIndexPath:indexPath];
224 [self.delegate bookmarkCollectionView:self
225 cell:cell
226 removeNodeForEditing:node];
227 }
228
229 - (BOOL)shouldSelectCellAtIndexPath:(NSIndexPath*)indexPath {
230 return ![self isPromoSection:indexPath.section];
231 }
232
233 - (void)didTapCellAtIndexPath:(NSIndexPath*)indexPath {
234 DCHECK(![self isPromoSection:indexPath.section]);
235 const BookmarkNode* node = [self nodeAtIndexPath:indexPath];
236 DCHECK(node);
237 RecordBookmarkLaunch(BOOKMARK_LAUNCH_LOCATION_ALL_ITEMS);
238 [self.delegate bookmarkCollectionView:self
239 selectedUrlForNavigation:node->url()];
240 }
241
242 - (void)didTapMenuButtonAtIndexPath:(NSIndexPath*)indexPath
243 onView:(UIView*)view
244 forCell:(BookmarkItemCell*)cell {
245 DCHECK(![self isPromoSection:indexPath.section]);
246 [self.delegate bookmarkCollectionView:self
247 wantsMenuForBookmark:[self nodeAtIndexPath:indexPath]
248 onView:view
249 forCell:cell];
250 }
251
252 - (bookmark_cell::ButtonType)buttonTypeForCellAtIndexPath:
253 (NSIndexPath*)indexPath {
254 DCHECK(![self isPromoSection:indexPath.section]);
255 if (self.editing)
256 return bookmark_cell::ButtonNone;
257 return bookmark_cell::ButtonMenu;
258 }
259
260 - (BOOL)allowLongPressForCellAtIndexPath:(NSIndexPath*)indexPath {
261 return [self isPromoSection:indexPath.section] ? NO : !self.editing;
262 }
263
264 - (void)didLongPressCell:(UICollectionViewCell*)cell
265 atIndexPath:(NSIndexPath*)indexPath {
266 DCHECK(![self isPromoSection:indexPath.section]);
267 [self.delegate bookmarkCollectionView:self
268 didLongPressCell:cell
269 forBookmark:[self nodeAtIndexPath:indexPath]];
270 }
271
272 - (BOOL)cellIsSelectedForEditingAtIndexPath:(NSIndexPath*)indexPath {
273 DCHECK(![self isPromoSection:indexPath.section]);
274
275 const BookmarkNode* node = [self nodeAtIndexPath:indexPath];
276 const std::set<const BookmarkNode*>& editingNodes =
277 [self.delegate nodesBeingEdited];
278 return editingNodes.find(node) != editingNodes.end();
279 }
280
281 - (const BookmarkNode*)nodeAtIndexPath:(NSIndexPath*)indexPath {
282 NSInteger section = indexPath.section;
283 if ([self isPromoSection:section])
284 return nullptr;
285
286 if ([self shouldShowPromoCell])
287 --section;
288 return _nodesSectionVector[section]->vector[indexPath.row];
289 }
290
291 - (NSIndexPath*)indexPathForNode:(const BookmarkNode*)bookmarkNode {
292 NSInteger section = 0;
293
294 // When showing promo cell, bookmarks start with section 1.
295 if ([self shouldShowPromoCell])
296 section = 1;
297
298 for (const auto& nodesSection : _nodesSectionVector) {
299 NodeVector nodeVector = nodesSection->vector;
300 NSInteger item = 0;
301 for (const BookmarkNode* node : nodeVector) {
302 if (bookmarkNode == node) {
303 return [NSIndexPath indexPathForItem:item inSection:section];
304 }
305 ++item;
306 }
307 ++section;
308 }
309
310 return nil;
311 }
312
313 #pragma mark - Parent class overrides that change UI
314
315 // Parent class override.
316 - (UIEdgeInsets)insetForSectionAtIndex:(NSInteger)section {
317 // Only return insets for non-empty sections.
318 NSInteger count = [self numberOfItemsInSection:section];
319 if (count == 0)
320 return UIEdgeInsetsZero;
321
322 // The last section needs special treatment.
323 UIEdgeInsets insets = [super insetForSectionAtIndex:section];
324 NSInteger sectionCount = [self.collectionView.dataSource
325 numberOfSectionsInCollectionView:self.collectionView];
326
327 if (section == sectionCount - 1) {
328 insets.top = 0;
329 return insets;
330 }
331
332 insets.top = 0;
333 insets.bottom = 0;
334 return insets;
335 }
336
337 // Parent class override.
338 - (UICollectionViewCell*)cellAtIndexPath:(NSIndexPath*)indexPath {
339 if ([self isPromoSection:indexPath.section]) {
340 self.promoCell = [self.collectionView
341 dequeueReusableCellWithReuseIdentifier:[BookmarkPromoCell
342 reuseIdentifier]
343 forIndexPath:indexPath];
344 self.promoCell.delegate = self;
345 return self.promoCell;
346 }
347
348 return [self cellForBookmark:[self nodeAtIndexPath:indexPath]
349 indexPath:indexPath];
350 }
351
352 // Parent class override.
353 - (CGSize)headerSizeForSection:(NSInteger)section {
354 if ([self isPromoSection:section])
355 return CGSizeZero;
356
357 return CGSizeMake(self.bounds.size.width, [BookmarkHeaderView handsetHeight]);
358 }
359
360 - (UICollectionReusableView*)headerAtIndexPath:(NSIndexPath*)indexPath {
361 NSInteger section = indexPath.section;
362 if ([self isPromoSection:section])
363 return nil;
364
365 if ([self shouldShowPromoCell])
366 --section;
367
368 BookmarkHeaderView* view = [self.collectionView
369 dequeueReusableSupplementaryViewOfKind:
370 UICollectionElementKindSectionHeader
371 withReuseIdentifier:[BookmarkHeaderView
372 reuseIdentifier]
373 forIndexPath:indexPath];
374
375 NSString* title =
376 base::SysUTF8ToNSString(_nodesSectionVector[section]->timeRepresentation);
377 [view setTitle:title];
378 return view;
379 }
380
381 - (NSInteger)numberOfItemsInSection:(NSInteger)section {
382 if ([self isPromoSection:section])
383 return 1;
384
385 if ([self shouldShowPromoCell])
386 --section;
387 return _nodesSectionVector[section]->vector.size();
388 }
389
390 - (NSInteger)numberOfSections {
391 const BOOL showPromo = [self shouldShowPromoCell];
392 const NSInteger nodeSectionsCount = _nodesSectionVector.size();
393 return showPromo ? nodeSectionsCount + 1 : nodeSectionsCount;
394 }
395
396 #pragma mark - BookmarkPromoCellDelegate
397
398 - (void)bookmarkPromoCellDidTapSignIn:(BookmarkPromoCell*)bookmarkPromoCell {
399 [self.delegate bookmarkCollectionViewShowSignIn:self];
400 }
401
402 - (void)bookmarkPromoCellDidTapDismiss:(BookmarkPromoCell*)bookmarkPromoCell {
403 [self.delegate bookmarkCollectionViewDismissPromo:self];
404 }
405
406 #pragma mark - Promo Cell
407
408 - (BOOL)isPromoActive {
409 return [self.delegate bookmarkCollectionViewShouldShowPromoCell:self];
410 }
411
412 - (BOOL)shouldShowPromoCell {
413 // The promo cell is not shown in edit mode.
414 return !self.editing && [self isPromoActive];
415 }
416
417 @end
OLDNEW
« no previous file with comments | « ios/chrome/browser/ui/bookmarks/bookmark_all_collection_view.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698