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

Side by Side Diff: ios/chrome/browser/content_suggestions/content_suggestions_mediator.mm

Issue 2798563002: Add MostVistedSites to ContentSuggestionsMediator (Closed)
Patch Set: Rebase (different HEAD) 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 2017 The Chromium Authors. All rights reserved. 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 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/content_suggestions/content_suggestions_mediator.h" 5 #import "ios/chrome/browser/content_suggestions/content_suggestions_mediator.h"
6 6
7 #include "base/mac/bind_objc_block.h" 7 #include "base/mac/bind_objc_block.h"
8 #include "base/memory/ptr_util.h" 8 #include "base/memory/ptr_util.h"
9 #include "base/optional.h" 9 #include "base/optional.h"
10 #include "components/favicon/core/large_icon_service.h" 10 #include "components/favicon/core/large_icon_service.h"
11 #include "components/ntp_snippets/category.h" 11 #include "components/ntp_snippets/category.h"
12 #include "components/ntp_snippets/category_info.h" 12 #include "components/ntp_snippets/category_info.h"
13 #include "components/ntp_snippets/content_suggestion.h" 13 #include "components/ntp_snippets/content_suggestion.h"
14 #include "components/ntp_snippets/reading_list/reading_list_distillation_state_u til.h" 14 #include "components/ntp_snippets/reading_list/reading_list_distillation_state_u til.h"
15 #include "components/ntp_tiles/most_visited_sites.h"
16 #include "components/ntp_tiles/ntp_tile.h"
15 #import "ios/chrome/browser/content_suggestions/content_suggestions_category_wra pper.h" 17 #import "ios/chrome/browser/content_suggestions/content_suggestions_category_wra pper.h"
16 #import "ios/chrome/browser/content_suggestions/content_suggestions_service_brid ge_observer.h" 18 #import "ios/chrome/browser/content_suggestions/content_suggestions_service_brid ge_observer.h"
17 #import "ios/chrome/browser/content_suggestions/mediator_util.h" 19 #import "ios/chrome/browser/content_suggestions/mediator_util.h"
20 #include "ios/chrome/browser/ntp_tiles/most_visited_sites_observer_bridge.h"
18 #import "ios/chrome/browser/ui/content_suggestions/content_suggestion.h" 21 #import "ios/chrome/browser/ui/content_suggestions/content_suggestion.h"
19 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_commands. h" 22 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_commands. h"
20 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_data_sink .h" 23 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_data_sink .h"
21 #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"
22 #import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion _identifier.h" 25 #import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion _identifier.h"
23 #import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion s_section_information.h" 26 #import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion s_section_information.h"
24 #import "ios/chrome/browser/ui/favicon/favicon_attributes_provider.h" 27 #import "ios/chrome/browser/ui/favicon/favicon_attributes_provider.h"
25 #import "ios/chrome/browser/ui/reading_list/reading_list_collection_view_item.h" 28 #import "ios/chrome/browser/ui/reading_list/reading_list_collection_view_item.h"
26 #import "ios/chrome/browser/ui/reading_list/reading_list_utils.h" 29 #import "ios/chrome/browser/ui/reading_list/reading_list_utils.h"
27 #include "ui/gfx/image/image.h" 30 #include "ui/gfx/image/image.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
35 // Size of the favicon returned by the provider. 38 // Size of the favicon returned by the provider.
36 const CGFloat kDefaultFaviconSize = 16; 39 const CGFloat kDefaultFaviconSize = 16;
40 // Maximum number of most visited tiles fetched.
41 const NSInteger kMaxNumMostVisitedTiles = 8;
37 42
38 } // namespace 43 } // namespace
39 44
40 @interface ContentSuggestionsMediator ()<ContentSuggestionsImageFetcher, 45 @interface ContentSuggestionsMediator ()<ContentSuggestionsImageFetcher,
41 ContentSuggestionsServiceObserver> { 46 ContentSuggestionsServiceObserver,
47 MostVisitedSitesObserving> {
42 // Bridge for this class to become an observer of a ContentSuggestionsService. 48 // Bridge for this class to become an observer of a ContentSuggestionsService.
43 std::unique_ptr<ContentSuggestionsServiceBridge> _suggestionBridge; 49 std::unique_ptr<ContentSuggestionsServiceBridge> _suggestionBridge;
50 std::unique_ptr<ntp_tiles::MostVisitedSites> _mostVisitedSites;
51 std::unique_ptr<ntp_tiles::MostVisitedSitesObserverBridge> _mostVisitedBridge;
44 } 52 }
45 53
54 // Most visited data from the MostVisitedSites service (copied upon receiving
55 // the callback).
56 @property(nonatomic, assign) std::vector<ntp_tiles::NTPTile> mostVisitedData;
57 // Section Info for the Most Visited section.
58 @property(nonatomic, strong)
59 ContentSuggestionsSectionInformation* mostVisitedSectionInfo;
60 // Whether the page impression has been recorded.
61 @property(nonatomic, assign) BOOL recordedPageImpression;
62 // The ContentSuggestionsService, serving suggestions.
46 @property(nonatomic, assign) 63 @property(nonatomic, assign)
47 ntp_snippets::ContentSuggestionsService* contentService; 64 ntp_snippets::ContentSuggestionsService* contentService;
65 // Map the section information created to the relevant category.
48 @property(nonatomic, strong, nonnull) 66 @property(nonatomic, strong, nonnull)
49 NSMutableDictionary<ContentSuggestionsCategoryWrapper*, 67 NSMutableDictionary<ContentSuggestionsCategoryWrapper*,
50 ContentSuggestionsSectionInformation*>* 68 ContentSuggestionsSectionInformation*>*
51 sectionInformationByCategory; 69 sectionInformationByCategory;
52 // FaviconAttributesProvider to fetch the favicon for the suggestions. 70 // FaviconAttributesProvider to fetch the favicon for the suggestions.
53 @property(nonatomic, nullable, strong) 71 @property(nonatomic, nullable, strong)
54 FaviconAttributesProvider* attributesProvider; 72 FaviconAttributesProvider* attributesProvider;
55 73
56 // Converts the |suggestions| from |category| to ContentSuggestion and adds them 74 // Converts the |suggestions| from |category| to ContentSuggestion and adds them
57 // to the |contentArray| if the category is available. 75 // to the |contentArray| if the category is available.
58 - (void)addSuggestions: 76 - (void)addSuggestions:
59 (const std::vector<ntp_snippets::ContentSuggestion>&)suggestions 77 (const std::vector<ntp_snippets::ContentSuggestion>&)suggestions
60 fromCategory:(ntp_snippets::Category&)category 78 fromCategory:(ntp_snippets::Category&)category
61 toArray:(NSMutableArray<ContentSuggestion*>*)contentArray; 79 toArray:(NSMutableArray<ContentSuggestion*>*)contentArray;
62 80
63 // Adds the section information for |category| in 81 // Adds the section information for |category| in
64 // self.sectionInformationByCategory. 82 // self.sectionInformationByCategory.
65 - (void)addSectionInformationForCategory:(ntp_snippets::Category)category; 83 - (void)addSectionInformationForCategory:(ntp_snippets::Category)category;
66 84
67 // Returns a CategoryWrapper acting as a key for this section info. 85 // Returns a CategoryWrapper acting as a key for this section info.
68 - (ContentSuggestionsCategoryWrapper*)categoryWrapperForSectionInfo: 86 - (ContentSuggestionsCategoryWrapper*)categoryWrapperForSectionInfo:
69 (ContentSuggestionsSectionInformation*)sectionInfo; 87 (ContentSuggestionsSectionInformation*)sectionInfo;
70 88
71 @end 89 @end
72 90
73 @implementation ContentSuggestionsMediator 91 @implementation ContentSuggestionsMediator
74 92
93 @synthesize mostVisitedData = _mostVisitedData;
94 @synthesize mostVisitedSectionInfo = _mostVisitedSectionInfo;
95 @synthesize recordedPageImpression = _recordedPageImpression;
75 @synthesize contentService = _contentService; 96 @synthesize contentService = _contentService;
76 @synthesize dataSink = _dataSink; 97 @synthesize dataSink = _dataSink;
77 @synthesize sectionInformationByCategory = _sectionInformationByCategory; 98 @synthesize sectionInformationByCategory = _sectionInformationByCategory;
78 @synthesize attributesProvider = _attributesProvider; 99 @synthesize attributesProvider = _attributesProvider;
79 @synthesize commandHandler = _commandHandler; 100 @synthesize commandHandler = _commandHandler;
80 101
81 #pragma mark - Public 102 #pragma mark - Public
82 103
83 - (instancetype) 104 - (instancetype)
84 initWithContentService:(ntp_snippets::ContentSuggestionsService*)contentService 105 initWithContentService:(ntp_snippets::ContentSuggestionsService*)contentService
85 largeIconService:(favicon::LargeIconService*)largeIconService { 106 largeIconService:(favicon::LargeIconService*)largeIconService
107 mostVisitedSite:
108 (std::unique_ptr<ntp_tiles::MostVisitedSites>)mostVisitedSites {
86 self = [super init]; 109 self = [super init];
87 if (self) { 110 if (self) {
88 _suggestionBridge = 111 _suggestionBridge =
89 base::MakeUnique<ContentSuggestionsServiceBridge>(self, contentService); 112 base::MakeUnique<ContentSuggestionsServiceBridge>(self, contentService);
90 _contentService = contentService; 113 _contentService = contentService;
91 _sectionInformationByCategory = [[NSMutableDictionary alloc] init]; 114 _sectionInformationByCategory = [[NSMutableDictionary alloc] init];
92 _attributesProvider = [[FaviconAttributesProvider alloc] 115 _attributesProvider = [[FaviconAttributesProvider alloc]
93 initWithFaviconSize:kDefaultFaviconSize 116 initWithFaviconSize:kDefaultFaviconSize
94 minFaviconSize:1 117 minFaviconSize:1
95 largeIconService:largeIconService]; 118 largeIconService:largeIconService];
119
120 _mostVisitedSectionInfo = MostVisitedSectionInformation();
121 _mostVisitedSites = std::move(mostVisitedSites);
122 _mostVisitedBridge =
123 base::MakeUnique<ntp_tiles::MostVisitedSitesObserverBridge>(self);
124 _mostVisitedSites->SetMostVisitedURLsObserver(_mostVisitedBridge.get(),
125 kMaxNumMostVisitedTiles);
96 } 126 }
97 return self; 127 return self;
98 } 128 }
99 129
100 - (void)dismissSuggestion:(ContentSuggestionIdentifier*)suggestionIdentifier { 130 - (void)dismissSuggestion:(ContentSuggestionIdentifier*)suggestionIdentifier {
101 ContentSuggestionsCategoryWrapper* categoryWrapper = 131 ContentSuggestionsCategoryWrapper* categoryWrapper =
102 [self categoryWrapperForSectionInfo:suggestionIdentifier.sectionInfo]; 132 [self categoryWrapperForSectionInfo:suggestionIdentifier.sectionInfo];
103 ntp_snippets::ContentSuggestion::ID suggestion_id = 133 ntp_snippets::ContentSuggestion::ID suggestion_id =
104 ntp_snippets::ContentSuggestion::ID([categoryWrapper category], 134 ntp_snippets::ContentSuggestion::ID([categoryWrapper category],
105 suggestionIdentifier.IDInSection); 135 suggestionIdentifier.IDInSection);
106 136
107 self.contentService->DismissSuggestion(suggestion_id); 137 self.contentService->DismissSuggestion(suggestion_id);
108 } 138 }
109 139
110 #pragma mark - ContentSuggestionsDataSource 140 #pragma mark - ContentSuggestionsDataSource
111 141
112 - (NSArray<ContentSuggestion*>*)allSuggestions { 142 - (NSArray<ContentSuggestion*>*)allSuggestions {
113 std::vector<ntp_snippets::Category> categories =
114 self.contentService->GetCategories();
115 NSMutableArray<ContentSuggestion*>* dataHolders = [NSMutableArray array]; 143 NSMutableArray<ContentSuggestion*>* dataHolders = [NSMutableArray array];
116 for (auto& category : categories) { 144
117 const std::vector<ntp_snippets::ContentSuggestion>& suggestions = 145 [self addMostVisitedToArray:dataHolders];
118 self.contentService->GetSuggestionsForCategory(category); 146
119 [self addSuggestions:suggestions fromCategory:category toArray:dataHolders]; 147 [self addContentSuggestionsToArray:dataHolders];
120 } 148
121 return dataHolders; 149 return dataHolders;
122 } 150 }
123 151
124 - (NSArray<ContentSuggestion*>*)suggestionsForSection: 152 - (NSArray<ContentSuggestion*>*)suggestionsForSection:
125 (ContentSuggestionsSectionInformation*)sectionInfo { 153 (ContentSuggestionsSectionInformation*)sectionInfo {
126 ntp_snippets::Category category = 154 NSMutableArray* convertedSuggestions = [NSMutableArray array];
127 [[self categoryWrapperForSectionInfo:sectionInfo] category];
128 155
129 NSMutableArray* convertedSuggestions = [NSMutableArray array]; 156 if (sectionInfo == self.mostVisitedSectionInfo) {
130 const std::vector<ntp_snippets::ContentSuggestion>& suggestions = 157 [self addMostVisitedToArray:convertedSuggestions];
131 self.contentService->GetSuggestionsForCategory(category); 158 } else {
132 [self addSuggestions:suggestions 159 ntp_snippets::Category category =
133 fromCategory:category 160 [[self categoryWrapperForSectionInfo:sectionInfo] category];
134 toArray:convertedSuggestions]; 161
162 const std::vector<ntp_snippets::ContentSuggestion>& suggestions =
163 self.contentService->GetSuggestionsForCategory(category);
164 [self addSuggestions:suggestions
165 fromCategory:category
166 toArray:convertedSuggestions];
167 }
168
135 return convertedSuggestions; 169 return convertedSuggestions;
136 } 170 }
137 171
138 - (id<ContentSuggestionsImageFetcher>)imageFetcher { 172 - (id<ContentSuggestionsImageFetcher>)imageFetcher {
139 return self; 173 return self;
140 } 174 }
141 175
142 - (void)fetchMoreSuggestionsKnowing: 176 - (void)fetchMoreSuggestionsKnowing:
143 (NSArray<ContentSuggestionIdentifier*>*)knownSuggestions 177 (NSArray<ContentSuggestionIdentifier*>*)knownSuggestions
144 fromSectionInfo: 178 fromSectionInfo:
145 (ContentSuggestionsSectionInformation*)sectionInfo 179 (ContentSuggestionsSectionInformation*)sectionInfo
146 callback:(MoreSuggestionsFetched)callback { 180 callback:(MoreSuggestionsFetched)callback {
181 if (![self isRelatedToContentSuggestionsService:sectionInfo])
182 return;
183
147 std::set<std::string> known_suggestion_ids; 184 std::set<std::string> known_suggestion_ids;
148 for (ContentSuggestionIdentifier* identifier in knownSuggestions) { 185 for (ContentSuggestionIdentifier* identifier in knownSuggestions) {
149 if (identifier.sectionInfo != sectionInfo) 186 if (identifier.sectionInfo != sectionInfo)
150 continue; 187 continue;
151 known_suggestion_ids.insert(identifier.IDInSection); 188 known_suggestion_ids.insert(identifier.IDInSection);
152 } 189 }
153 190
154 ContentSuggestionsCategoryWrapper* wrapper = 191 ContentSuggestionsCategoryWrapper* wrapper =
155 [self categoryWrapperForSectionInfo:sectionInfo]; 192 [self categoryWrapperForSectionInfo:sectionInfo];
156 193
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
263 suggestionIdentifier.IDInSection), 300 suggestionIdentifier.IDInSection),
264 base::BindBlockArc(^(const gfx::Image& image) { 301 base::BindBlockArc(^(const gfx::Image& image) {
265 if (image.IsEmpty() || !callback) { 302 if (image.IsEmpty() || !callback) {
266 return; 303 return;
267 } 304 }
268 305
269 callback([image.ToUIImage() copy]); 306 callback([image.ToUIImage() copy]);
270 })); 307 }));
271 } 308 }
272 309
310 #pragma mark - MostVisitedSitesObserving
311
312 - (void)onMostVisitedURLsAvailable:
313 (const ntp_tiles::NTPTilesVector&)mostVisited {
314 self.mostVisitedData = mostVisited;
315 [self.dataSink reloadSection:self.mostVisitedSectionInfo];
316
317 if (mostVisited.size() && !self.recordedPageImpression) {
318 self.recordedPageImpression = YES;
319 RecordPageImpression(mostVisited);
320 }
321 }
322
323 - (void)onIconMadeAvailable:(const GURL&)siteURL {
324 [self.dataSink faviconAvailableForURL:siteURL];
325 }
326
273 #pragma mark - Private 327 #pragma mark - Private
274 328
275 - (void)addSuggestions: 329 - (void)addSuggestions:
276 (const std::vector<ntp_snippets::ContentSuggestion>&)suggestions 330 (const std::vector<ntp_snippets::ContentSuggestion>&)suggestions
277 fromCategory:(ntp_snippets::Category&)category 331 fromCategory:(ntp_snippets::Category&)category
278 toArray:(NSMutableArray<ContentSuggestion*>*)contentArray { 332 toArray:(NSMutableArray<ContentSuggestion*>*)contentArray {
279 if (!ntp_snippets::IsCategoryStatusAvailable( 333 if (!ntp_snippets::IsCategoryStatusAvailable(
280 self.contentService->GetCategoryStatus(category))) { 334 self.contentService->GetCategoryStatus(category))) {
281 return; 335 return;
282 } 336 }
(...skipping 19 matching lines...) Expand all
302 contentSuggestion.reading_list_suggestion_extra() 356 contentSuggestion.reading_list_suggestion_extra()
303 ->distilled_state)); 357 ->distilled_state));
304 suggestion.readingListExtra = [ContentSuggestionReadingListExtra 358 suggestion.readingListExtra = [ContentSuggestionReadingListExtra
305 extraWithDistillationStatus:status]; 359 extraWithDistillationStatus:status];
306 } 360 }
307 361
308 [contentArray addObject:suggestion]; 362 [contentArray addObject:suggestion];
309 } 363 }
310 364
311 if (suggestions.size() == 0) { 365 if (suggestions.size() == 0) {
312 ContentSuggestion* suggestion = [[ContentSuggestion alloc] init]; 366 ContentSuggestion* suggestion = EmptySuggestion();
313 suggestion.type = ContentSuggestionTypeEmpty;
314 suggestion.suggestionIdentifier =
315 [[ContentSuggestionIdentifier alloc] init];
316 suggestion.suggestionIdentifier.sectionInfo = 367 suggestion.suggestionIdentifier.sectionInfo =
317 self.sectionInformationByCategory[categoryWrapper]; 368 self.sectionInformationByCategory[categoryWrapper];
318 369
319 [contentArray addObject:suggestion]; 370 [contentArray addObject:suggestion];
320 } 371 }
321 } 372 }
322 373
323 - (void)addSectionInformationForCategory:(ntp_snippets::Category)category { 374 - (void)addSectionInformationForCategory:(ntp_snippets::Category)category {
324 base::Optional<ntp_snippets::CategoryInfo> categoryInfo = 375 base::Optional<ntp_snippets::CategoryInfo> categoryInfo =
325 self.contentService->GetCategoryInfo(category); 376 self.contentService->GetCategoryInfo(category);
(...skipping 21 matching lines...) Expand all
347 NSMutableArray<ContentSuggestion*>* contentSuggestions = 398 NSMutableArray<ContentSuggestion*>* contentSuggestions =
348 [NSMutableArray array]; 399 [NSMutableArray array];
349 ntp_snippets::Category category = suggestions[0].id().category(); 400 ntp_snippets::Category category = suggestions[0].id().category();
350 [self addSuggestions:suggestions 401 [self addSuggestions:suggestions
351 fromCategory:category 402 fromCategory:category
352 toArray:contentSuggestions]; 403 toArray:contentSuggestions];
353 callback(contentSuggestions); 404 callback(contentSuggestions);
354 } 405 }
355 } 406 }
356 407
408 // Adds all the suggestions from the |contentService| to |suggestions|.
409 - (void)addContentSuggestionsToArray:
410 (NSMutableArray<ContentSuggestion*>*)arrayToFill {
411 std::vector<ntp_snippets::Category> categories =
412 self.contentService->GetCategories();
413
414 for (auto& category : categories) {
415 const std::vector<ntp_snippets::ContentSuggestion>& suggestions =
416 self.contentService->GetSuggestionsForCategory(category);
417 [self addSuggestions:suggestions fromCategory:category toArray:arrayToFill];
418 }
419 }
420
421 // Adds all the suggestions for the |mostVisitedData| to |suggestions|.
422 - (void)addMostVisitedToArray:(NSMutableArray<ContentSuggestion*>*)arrayToFill {
423 if (self.mostVisitedData.empty()) {
424 ContentSuggestion* suggestion = EmptySuggestion();
425 suggestion.suggestionIdentifier.sectionInfo = self.mostVisitedSectionInfo;
426 [arrayToFill addObject:suggestion];
427
428 return;
429 }
430
431 for (const ntp_tiles::NTPTile& tile : self.mostVisitedData) {
432 ContentSuggestion* suggestion = ConvertNTPTile(tile);
433 suggestion.suggestionIdentifier.sectionInfo = self.mostVisitedSectionInfo;
434 [arrayToFill addObject:suggestion];
435 }
436 }
437
438 // Returns whether the |sectionInfo| is associated with a category from the
439 // content suggestions service.
440 - (BOOL)isRelatedToContentSuggestionsService:
441 (ContentSuggestionsSectionInformation*)sectionInfo {
442 return sectionInfo != self.mostVisitedSectionInfo;
443 }
444
357 @end 445 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698