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

Side by Side Diff: ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm

Issue 2775593002: Add a message to empty ContentSuggestions sections (Closed)
Patch Set: Change tests Created 3 years, 8 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
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 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 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/content_suggestions/content_suggestions_collectio n_updater.h" 5 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collectio n_updater.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/mac/foundation_util.h" 8 #include "base/mac/foundation_util.h"
9 #include "base/time/time.h" 9 #include "base/time/time.h"
10 #include "components/strings/grit/components_strings.h"
10 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h " 11 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h "
11 #import "ios/chrome/browser/ui/collection_view/collection_view_controller.h" 12 #import "ios/chrome/browser/ui/collection_view/collection_view_controller.h"
12 #import "ios/chrome/browser/ui/collection_view/collection_view_model.h" 13 #import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
13 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_art icle_item.h" 14 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_art icle_item.h"
14 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_but ton_item.h" 15 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_but ton_item.h"
15 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_exp andable_item.h" 16 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_exp andable_item.h"
16 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_fav icon_item.h" 17 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_fav icon_item.h"
17 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_foo ter_item.h" 18 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_foo ter_item.h"
18 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_sta ck_item.h" 19 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_sta ck_item.h"
20 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_tex t_item.h"
19 #import "ios/chrome/browser/ui/content_suggestions/content_suggestion.h" 21 #import "ios/chrome/browser/ui/content_suggestions/content_suggestion.h"
20 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_data_sink .h" 22 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_data_sink .h"
21 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_data_sour ce.h" 23 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_data_sour ce.h"
22 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_image_fet cher.h" 24 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_image_fet cher.h"
23 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_view_cont roller.h" 25 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_view_cont roller.h"
24 #import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion _identifier.h" 26 #import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion _identifier.h"
25 #import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion s_section_information.h" 27 #import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion s_section_information.h"
28 #include "ui/base/l10n/l10n_util.h"
26 #include "ui/gfx/image/image.h" 29 #include "ui/gfx/image/image.h"
27 #include "url/gurl.h" 30 #include "url/gurl.h"
28 31
29 #if !defined(__has_feature) || !__has_feature(objc_arc) 32 #if !defined(__has_feature) || !__has_feature(objc_arc)
30 #error "This file requires ARC support." 33 #error "This file requires ARC support."
31 #endif 34 #endif
32 35
33 namespace { 36 namespace {
34 37
38 using CSCollectionViewItem =
39 CollectionViewItem<ContentSuggestionIdentification>;
40 using CSCollectionViewModel = CollectionViewModel<CSCollectionViewItem*>;
41
35 // Enum defining the ItemType of this ContentSuggestionsCollectionUpdater. 42 // Enum defining the ItemType of this ContentSuggestionsCollectionUpdater.
36 typedef NS_ENUM(NSInteger, ItemType) { 43 typedef NS_ENUM(NSInteger, ItemType) {
37 ItemTypeText = kItemTypeEnumZero, 44 ItemTypeText = kItemTypeEnumZero,
38 ItemTypeArticle, 45 ItemTypeArticle,
39 ItemTypeExpand, 46 ItemTypeExpand,
40 ItemTypeStack, 47 ItemTypeStack,
41 ItemTypeFavicon, 48 ItemTypeFavicon,
42 ItemTypeFooter, 49 ItemTypeFooter,
43 ItemTypeHeader, 50 ItemTypeHeader,
51 ItemTypeEmpty,
44 }; 52 };
45 53
46 typedef NS_ENUM(NSInteger, SectionIdentifier) { 54 typedef NS_ENUM(NSInteger, SectionIdentifier) {
47 SectionIdentifierBookmarks = kSectionIdentifierEnumZero, 55 SectionIdentifierBookmarks = kSectionIdentifierEnumZero,
48 SectionIdentifierArticles, 56 SectionIdentifierArticles,
49 SectionIdentifierDefault, 57 SectionIdentifierDefault,
50 }; 58 };
51 59
52 ItemType ItemTypeForContentSuggestionType(ContentSuggestionType type) { 60 ItemType ItemTypeForContentSuggestionType(ContentSuggestionType type) {
53 switch (type) { 61 switch (type) {
54 case ContentSuggestionTypeArticle: 62 case ContentSuggestionTypeArticle:
55 return ItemTypeArticle; 63 return ItemTypeArticle;
64 case ContentSuggestionTypeEmpty:
65 return ItemTypeEmpty;
56 } 66 }
57 } 67 }
58 68
59 ContentSuggestionType ContentSuggestionTypeForItemType(NSInteger type) { 69 ContentSuggestionType ContentSuggestionTypeForItemType(NSInteger type) {
60 if (type == ItemTypeArticle) 70 if (type == ItemTypeArticle)
61 return ContentSuggestionTypeArticle; 71 return ContentSuggestionTypeArticle;
72 if (type == ItemTypeEmpty)
73 return ContentSuggestionTypeEmpty;
62 // Add new type here 74 // Add new type here
63 75
64 // Default type. 76 // Default type.
65 return ContentSuggestionTypeArticle; 77 return ContentSuggestionTypeEmpty;
66 } 78 }
67 79
68 // Returns the section identifier corresponding to the section |info|. 80 // Returns the section identifier corresponding to the section |info|.
69 SectionIdentifier SectionIdentifierForInfo( 81 SectionIdentifier SectionIdentifierForInfo(
70 ContentSuggestionsSectionInformation* info) { 82 ContentSuggestionsSectionInformation* info) {
71 switch (info.sectionID) { 83 switch (info.sectionID) {
72 case ContentSuggestionsSectionBookmarks: 84 case ContentSuggestionsSectionBookmarks:
73 return SectionIdentifierBookmarks; 85 return SectionIdentifierBookmarks;
74 86
75 case ContentSuggestionsSectionArticles: 87 case ContentSuggestionsSectionArticles:
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
117 129
118 [self reloadAllData]; 130 [self reloadAllData];
119 } 131 }
120 132
121 #pragma mark - ContentSuggestionsDataSink 133 #pragma mark - ContentSuggestionsDataSink
122 134
123 - (void)dataAvailableForSection: 135 - (void)dataAvailableForSection:
124 (ContentSuggestionsSectionInformation*)sectionInfo { 136 (ContentSuggestionsSectionInformation*)sectionInfo {
125 SectionIdentifier sectionIdentifier = SectionIdentifierForInfo(sectionInfo); 137 SectionIdentifier sectionIdentifier = SectionIdentifierForInfo(sectionInfo);
126 138
127 CollectionViewModel* model = 139 CSCollectionViewModel* model =
128 self.collectionViewController.collectionViewModel; 140 self.collectionViewController.collectionViewModel;
129 if ([model hasSectionForSectionIdentifier:sectionIdentifier] && 141 if ([model hasSectionForSectionIdentifier:sectionIdentifier] &&
130 [model itemsInSectionWithIdentifier:sectionIdentifier].count > 0) { 142 [model itemsInSectionWithIdentifier:sectionIdentifier].count > 0) {
131 // Do not dismiss the presented items. 143 // Do not dismiss the presented items.
132 return; 144 return;
133 } 145 }
134 146
135 [self.collectionViewController 147 [self.collectionViewController
136 addSuggestions:[self.dataSource suggestionsForSection:sectionInfo]]; 148 addSuggestions:[self.dataSource suggestionsForSection:sectionInfo]];
137 } 149 }
138 150
139 - (void)clearSuggestion:(ContentSuggestionIdentifier*)suggestionIdentifier { 151 - (void)clearSuggestion:(ContentSuggestionIdentifier*)suggestionIdentifier {
140 SectionIdentifier sectionIdentifier = 152 SectionIdentifier sectionIdentifier =
141 SectionIdentifierForInfo(suggestionIdentifier.sectionInfo); 153 SectionIdentifierForInfo(suggestionIdentifier.sectionInfo);
142 if (![self.collectionViewController.collectionViewModel 154 if (![self.collectionViewController.collectionViewModel
143 hasSectionForSectionIdentifier:sectionIdentifier]) { 155 hasSectionForSectionIdentifier:sectionIdentifier]) {
144 return; 156 return;
145 } 157 }
146 158
147 NSArray<CollectionViewItem<ContentSuggestionIdentification>*>* 159 NSArray<CSCollectionViewItem*>* itemsInSection =
148 itemsInSection = [self.collectionViewController.collectionViewModel 160 [self.collectionViewController.collectionViewModel
149 itemsInSectionWithIdentifier:sectionIdentifier]; 161 itemsInSectionWithIdentifier:sectionIdentifier];
150 162
151 CollectionViewItem<ContentSuggestionIdentification>* correspondingItem = nil; 163 CSCollectionViewItem* correspondingItem = nil;
152 for (CollectionViewItem<ContentSuggestionIdentification>* item in 164 for (CSCollectionViewItem* item in itemsInSection) {
153 itemsInSection) {
154 if (item.suggestionIdentifier == suggestionIdentifier) { 165 if (item.suggestionIdentifier == suggestionIdentifier) {
155 correspondingItem = item; 166 correspondingItem = item;
156 break; 167 break;
157 } 168 }
158 } 169 }
159 170
160 if (!correspondingItem) 171 if (!correspondingItem)
161 return; 172 return;
162 173
163 NSIndexPath* indexPath = [self.collectionViewController.collectionViewModel 174 NSIndexPath* indexPath = [self.collectionViewController.collectionViewModel
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
199 (CollectionViewItem*)item { 210 (CollectionViewItem*)item {
200 return ContentSuggestionTypeForItemType(item.type); 211 return ContentSuggestionTypeForItemType(item.type);
201 } 212 }
202 213
203 - (NSArray<NSIndexPath*>*)addSuggestionsToModel: 214 - (NSArray<NSIndexPath*>*)addSuggestionsToModel:
204 (NSArray<ContentSuggestion*>*)suggestions { 215 (NSArray<ContentSuggestion*>*)suggestions {
205 if (suggestions.count == 0) { 216 if (suggestions.count == 0) {
206 return [NSArray array]; 217 return [NSArray array];
207 } 218 }
208 219
209 CollectionViewModel* model =
210 self.collectionViewController.collectionViewModel;
211
212 NSMutableArray<NSIndexPath*>* indexPaths = [NSMutableArray array]; 220 NSMutableArray<NSIndexPath*>* indexPaths = [NSMutableArray array];
213 for (ContentSuggestion* suggestion in suggestions) { 221 for (ContentSuggestion* suggestion in suggestions) {
214 NSInteger sectionIdentifier = 222 ContentSuggestionsSectionInformation* sectionInfo =
215 SectionIdentifierForInfo(suggestion.suggestionIdentifier.sectionInfo); 223 suggestion.suggestionIdentifier.sectionInfo;
224 NSInteger sectionIdentifier = SectionIdentifierForInfo(sectionInfo);
225 CSCollectionViewModel* model =
226 self.collectionViewController.collectionViewModel;
216 227
217 ContentSuggestionsArticleItem* articleItem = 228 switch (suggestion.type) {
218 [[ContentSuggestionsArticleItem alloc] 229 case ContentSuggestionTypeEmpty: {
219 initWithType:ItemTypeForContentSuggestionType(suggestion.type) 230 if ([model hasSectionForSectionIdentifier:sectionIdentifier] &&
220 title:suggestion.title 231 [model numberOfItemsInSection:[model sectionForSectionIdentifier:
221 subtitle:suggestion.text 232 sectionIdentifier]] == 0) {
222 delegate:self 233 CSCollectionViewItem* item =
223 url:suggestion.url]; 234 [self emptyItemForSectionInfo:sectionInfo];
235 NSIndexPath* addedIndexPath =
236 [self addItem:item toSectionWithIdentifier:sectionIdentifier];
237 [indexPaths addObject:addedIndexPath];
238 }
239 break;
240 }
241 case ContentSuggestionTypeArticle: {
242 ContentSuggestionsArticleItem* articleItem =
243 [[ContentSuggestionsArticleItem alloc]
244 initWithType:ItemTypeForContentSuggestionType(suggestion.type)
245 title:suggestion.title
246 subtitle:suggestion.text
247 delegate:self
248 url:suggestion.url];
224 249
225 articleItem.publisher = suggestion.publisher; 250 articleItem.publisher = suggestion.publisher;
226 articleItem.publishDate = suggestion.publishDate; 251 articleItem.publishDate = suggestion.publishDate;
227 252
228 articleItem.suggestionIdentifier = suggestion.suggestionIdentifier; 253 articleItem.suggestionIdentifier = suggestion.suggestionIdentifier;
229 254
230 NSInteger section = [model sectionForSectionIdentifier:sectionIdentifier]; 255 NSIndexPath* addedIndexPath = [self addItem:articleItem
231 NSInteger itemNumber = [model numberOfItemsInSection:section]; 256 toSectionWithIdentifier:sectionIdentifier];
232 [model addItem:articleItem toSectionWithIdentifier:sectionIdentifier]; 257 [indexPaths addObject:addedIndexPath];
233 258 break;
234 [indexPaths 259 }
235 addObject:[NSIndexPath indexPathForItem:itemNumber inSection:section]]; 260 }
236 } 261 }
237 262
238 return indexPaths; 263 return indexPaths;
239 } 264 }
240 265
241 - (NSIndexSet*)addSectionsForSuggestionsToModel: 266 - (NSIndexSet*)addSectionsForSuggestionsToModel:
242 (NSArray<ContentSuggestion*>*)suggestions { 267 (NSArray<ContentSuggestion*>*)suggestions {
243 NSMutableIndexSet* indexSet = [NSMutableIndexSet indexSet]; 268 NSMutableIndexSet* indexSet = [NSMutableIndexSet indexSet];
244 269
245 CollectionViewModel* model = 270 CSCollectionViewModel* model =
246 self.collectionViewController.collectionViewModel; 271 self.collectionViewController.collectionViewModel;
247 for (ContentSuggestion* suggestion in suggestions) { 272 for (ContentSuggestion* suggestion in suggestions) {
248 ContentSuggestionsSectionInformation* sectionInfo = 273 ContentSuggestionsSectionInformation* sectionInfo =
249 suggestion.suggestionIdentifier.sectionInfo; 274 suggestion.suggestionIdentifier.sectionInfo;
250 NSInteger sectionIdentifier = SectionIdentifierForInfo(sectionInfo); 275 NSInteger sectionIdentifier = SectionIdentifierForInfo(sectionInfo);
251 276
252 if (![model hasSectionForSectionIdentifier:sectionIdentifier]) { 277 if ([model hasSectionForSectionIdentifier:sectionIdentifier] ||
253 [model addSectionWithIdentifier:sectionIdentifier]; 278 (suggestion.type == ContentSuggestionTypeEmpty &&
254 self.sectionInfoBySectionIdentifier[@(sectionIdentifier)] = sectionInfo; 279 !sectionInfo.showIfEmpty)) {
255 [indexSet addIndex:[model sectionForSectionIdentifier:sectionIdentifier]]; 280 continue;
281 }
256 282
257 [self addHeader:suggestion.suggestionIdentifier.sectionInfo]; 283 [model addSectionWithIdentifier:sectionIdentifier];
258 [self addFooterIfNeeded:suggestion.suggestionIdentifier.sectionInfo]; 284 self.sectionInfoBySectionIdentifier[@(sectionIdentifier)] = sectionInfo;
259 } 285 [indexSet addIndex:[model sectionForSectionIdentifier:sectionIdentifier]];
286
287 [self addHeader:sectionInfo];
288 [self addFooterIfNeeded:sectionInfo];
260 } 289 }
261 return indexSet; 290 return indexSet;
262 } 291 }
263 292
293 - (NSIndexPath*)addEmptyItemForSection:(NSInteger)section {
294 CSCollectionViewModel* model =
295 self.collectionViewController.collectionViewModel;
296 NSInteger sectionIdentifier = [model sectionIdentifierForSection:section];
297 ContentSuggestionsSectionInformation* sectionInfo =
298 self.sectionInfoBySectionIdentifier[@(sectionIdentifier)];
299
300 CSCollectionViewItem* item = [self emptyItemForSectionInfo:sectionInfo];
301 return [self addItem:item toSectionWithIdentifier:sectionIdentifier];
302 }
303
264 #pragma mark - ContentSuggestionsArticleItemDelegate 304 #pragma mark - ContentSuggestionsArticleItemDelegate
265 305
266 - (void)loadImageForArticleItem:(ContentSuggestionsArticleItem*)articleItem { 306 - (void)loadImageForArticleItem:(ContentSuggestionsArticleItem*)articleItem {
267 NSInteger sectionIdentifier = 307 NSInteger sectionIdentifier =
268 SectionIdentifierForInfo(articleItem.suggestionIdentifier.sectionInfo); 308 SectionIdentifierForInfo(articleItem.suggestionIdentifier.sectionInfo);
269 309
270 __weak ContentSuggestionsCollectionUpdater* weakSelf = self; 310 __weak ContentSuggestionsCollectionUpdater* weakSelf = self;
271 __weak ContentSuggestionsArticleItem* weakArticle = articleItem; 311 __weak ContentSuggestionsArticleItem* weakArticle = articleItem;
272 void (^imageFetchedCallback)(const gfx::Image&) = ^(const gfx::Image& image) { 312 void (^imageFetchedCallback)(const gfx::Image&) = ^(const gfx::Image& image) {
273 if (image.IsEmpty()) { 313 if (image.IsEmpty()) {
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 } 378 }
339 379
340 // Runs the additional action for the section identified by |sectionInfo|. 380 // Runs the additional action for the section identified by |sectionInfo|.
341 - (void)runAdditionalActionForSection: 381 - (void)runAdditionalActionForSection:
342 (ContentSuggestionsSectionInformation*)sectionInfo { 382 (ContentSuggestionsSectionInformation*)sectionInfo {
343 SectionIdentifier sectionIdentifier = SectionIdentifierForInfo(sectionInfo); 383 SectionIdentifier sectionIdentifier = SectionIdentifierForInfo(sectionInfo);
344 384
345 NSMutableArray<ContentSuggestionIdentifier*>* knownSuggestionIdentifiers = 385 NSMutableArray<ContentSuggestionIdentifier*>* knownSuggestionIdentifiers =
346 [NSMutableArray array]; 386 [NSMutableArray array];
347 387
348 NSArray<CollectionViewItem<ContentSuggestionIdentification>*>* 388 NSArray<CSCollectionViewItem*>* knownSuggestions =
349 knownSuggestions = [self.collectionViewController.collectionViewModel 389 [self.collectionViewController.collectionViewModel
350 itemsInSectionWithIdentifier:sectionIdentifier]; 390 itemsInSectionWithIdentifier:sectionIdentifier];
351 for (CollectionViewItem<ContentSuggestionIdentification>* suggestion in 391 for (CSCollectionViewItem* suggestion in knownSuggestions) {
352 knownSuggestions) { 392 if (suggestion.type != ItemTypeEmpty) {
353 [knownSuggestionIdentifiers addObject:suggestion.suggestionIdentifier]; 393 [knownSuggestionIdentifiers addObject:suggestion.suggestionIdentifier];
394 }
354 } 395 }
355 396
356 __weak ContentSuggestionsCollectionUpdater* weakSelf = self; 397 __weak ContentSuggestionsCollectionUpdater* weakSelf = self;
357 [self.dataSource 398 [self.dataSource
358 fetchMoreSuggestionsKnowing:knownSuggestionIdentifiers 399 fetchMoreSuggestionsKnowing:knownSuggestionIdentifiers
359 fromSectionInfo:sectionInfo 400 fromSectionInfo:sectionInfo
360 callback:^(NSArray<ContentSuggestion*>* suggestions) { 401 callback:^(NSArray<ContentSuggestion*>* suggestions) {
361 [weakSelf moreSuggestionsFetched:suggestions]; 402 [weakSelf moreSuggestionsFetched:suggestions];
362 }]; 403 }];
363 } 404 }
364 405
365 // Adds the |suggestions| to the collection view. All the suggestions must have 406 // Adds the |suggestions| to the collection view. All the suggestions must have
366 // the same sectionInfo. 407 // the same sectionInfo.
367 - (void)moreSuggestionsFetched:(NSArray<ContentSuggestion*>*)suggestions { 408 - (void)moreSuggestionsFetched:(NSArray<ContentSuggestion*>*)suggestions {
368 [self.collectionViewController addSuggestions:suggestions]; 409 [self.collectionViewController addSuggestions:suggestions];
369 } 410 }
370 411
412 // Returns a item to be displayed when the section identified by |sectionInfo|
413 // is empty.
414 - (CSCollectionViewItem*)emptyItemForSectionInfo:
415 (ContentSuggestionsSectionInformation*)sectionInfo {
416 ContentSuggestionsTextItem* item =
417 [[ContentSuggestionsTextItem alloc] initWithType:ItemTypeEmpty];
418 item.text = l10n_util::GetNSString(IDS_NTP_TITLE_NO_SUGGESTIONS);
419 item.detailText = sectionInfo.emptyText;
420
421 return item;
422 }
423
424 // Adds |item| to |sectionIdentifier| section of the model of the
425 // CollectionView. Returns the IndexPath of the newly added item.
426 - (NSIndexPath*)addItem:(CSCollectionViewItem*)item
427 toSectionWithIdentifier:(NSInteger)sectionIdentifier {
428 CSCollectionViewModel* model =
429 self.collectionViewController.collectionViewModel;
430 NSInteger section = [model sectionForSectionIdentifier:sectionIdentifier];
431 NSInteger itemNumber = [model numberOfItemsInSection:section];
432 [model addItem:item toSectionWithIdentifier:sectionIdentifier];
433
434 return [NSIndexPath indexPathForItem:itemNumber inSection:section];
435 }
436
371 @end 437 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698