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

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

Issue 2798563002: Add MostVistedSites to ContentSuggestionsMediator (Closed)
Patch Set: Reviewable 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_tiles/most_visited_sites.h"
15 #include "components/ntp_tiles/ntp_tile.h"
14 #import "ios/chrome/browser/content_suggestions/content_suggestions_category_wra pper.h" 16 #import "ios/chrome/browser/content_suggestions/content_suggestions_category_wra pper.h"
15 #import "ios/chrome/browser/content_suggestions/content_suggestions_service_brid ge_observer.h" 17 #import "ios/chrome/browser/content_suggestions/content_suggestions_service_brid ge_observer.h"
16 #import "ios/chrome/browser/content_suggestions/mediator_util.h" 18 #import "ios/chrome/browser/content_suggestions/mediator_util.h"
19 #include "ios/chrome/browser/ntp_tiles/most_visited_sites_observer_bridge.h"
17 #import "ios/chrome/browser/ui/content_suggestions/content_suggestion.h" 20 #import "ios/chrome/browser/ui/content_suggestions/content_suggestion.h"
18 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_data_sink .h" 21 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_data_sink .h"
19 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_image_fet cher.h" 22 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_image_fet cher.h"
20 #import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion _identifier.h" 23 #import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion _identifier.h"
21 #import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion s_section_information.h" 24 #import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion s_section_information.h"
22 #import "ios/chrome/browser/ui/favicon/favicon_attributes_provider.h" 25 #import "ios/chrome/browser/ui/favicon/favicon_attributes_provider.h"
23 #include "ui/gfx/image/image.h" 26 #include "ui/gfx/image/image.h"
24 27
25 #if !defined(__has_feature) || !__has_feature(objc_arc) 28 #if !defined(__has_feature) || !__has_feature(objc_arc)
26 #error "This file requires ARC support." 29 #error "This file requires ARC support."
27 #endif 30 #endif
28 31
29 namespace { 32 namespace {
30 33
31 // Size of the favicon returned by the provider. 34 // Size of the favicon returned by the provider.
32 const CGFloat kDefaultFaviconSize = 16; 35 const CGFloat kDefaultFaviconSize = 16;
36 // Maximum number of most visited tiles fetched.
37 const NSInteger kMaxNumMostVisitedTiles = 8;
33 38
34 } // namespace 39 } // namespace
35 40
36 @interface ContentSuggestionsMediator ()<ContentSuggestionsImageFetcher, 41 @interface ContentSuggestionsMediator ()<ContentSuggestionsImageFetcher,
37 ContentSuggestionsServiceObserver> { 42 ContentSuggestionsServiceObserver,
43 MostVisitedSitesObserving> {
38 // Bridge for this class to become an observer of a ContentSuggestionsService. 44 // Bridge for this class to become an observer of a ContentSuggestionsService.
39 std::unique_ptr<ContentSuggestionsServiceBridge> _suggestionBridge; 45 std::unique_ptr<ContentSuggestionsServiceBridge> _suggestionBridge;
46 std::unique_ptr<ntp_tiles::MostVisitedSites> _mostVisitedSites;
47 std::unique_ptr<ntp_tiles::MostVisitedSitesObserverBridge> _mostVisitedBridge;
40 } 48 }
41 49
50 // Most visited data from the MostVisitedSites service (copied upon receiving
51 // the callback).
52 @property(nonatomic, assign) std::vector<ntp_tiles::NTPTile> mostVisitedData;
53 // Section Info for the Most Visited section.
54 @property(nonatomic, strong)
55 ContentSuggestionsSectionInformation* mostVisitedSectionInfo;
56 // Whether the page impression has been recorded.
57 @property(nonatomic, assign) BOOL recordedPageImpression;
42 @property(nonatomic, assign) 58 @property(nonatomic, assign)
lpromero 2017/04/04 11:25:20 For completeness, can you add a quick comment to t
gambard 2017/04/04 16:14:26 Done.
43 ntp_snippets::ContentSuggestionsService* contentService; 59 ntp_snippets::ContentSuggestionsService* contentService;
44 @property(nonatomic, strong, nonnull) 60 @property(nonatomic, strong, nonnull)
45 NSMutableDictionary<ContentSuggestionsCategoryWrapper*, 61 NSMutableDictionary<ContentSuggestionsCategoryWrapper*,
46 ContentSuggestionsSectionInformation*>* 62 ContentSuggestionsSectionInformation*>*
47 sectionInformationByCategory; 63 sectionInformationByCategory;
48 // FaviconAttributesProvider to fetch the favicon for the suggestions. 64 // FaviconAttributesProvider to fetch the favicon for the suggestions.
49 @property(nonatomic, nullable, strong) 65 @property(nonatomic, nullable, strong)
50 FaviconAttributesProvider* attributesProvider; 66 FaviconAttributesProvider* attributesProvider;
51 67
52 // Converts the |suggestions| from |category| to ContentSuggestion and adds them 68 // Converts the |suggestions| from |category| to ContentSuggestion and adds them
53 // to the |contentArray| if the category is available. 69 // to the |contentArray| if the category is available.
54 - (void)addSuggestions: 70 - (void)addSuggestions:
55 (const std::vector<ntp_snippets::ContentSuggestion>&)suggestions 71 (const std::vector<ntp_snippets::ContentSuggestion>&)suggestions
56 fromCategory:(ntp_snippets::Category&)category 72 fromCategory:(ntp_snippets::Category&)category
57 toArray:(NSMutableArray<ContentSuggestion*>*)contentArray; 73 toArray:(NSMutableArray<ContentSuggestion*>*)contentArray;
58 74
59 // Adds the section information for |category| in 75 // Adds the section information for |category| in
60 // self.sectionInformationByCategory. 76 // self.sectionInformationByCategory.
61 - (void)addSectionInformationForCategory:(ntp_snippets::Category)category; 77 - (void)addSectionInformationForCategory:(ntp_snippets::Category)category;
62 78
63 // Returns a CategoryWrapper acting as a key for this section info. 79 // Returns a CategoryWrapper acting as a key for this section info.
64 - (ContentSuggestionsCategoryWrapper*)categoryWrapperForSectionInfo: 80 - (ContentSuggestionsCategoryWrapper*)categoryWrapperForSectionInfo:
65 (ContentSuggestionsSectionInformation*)sectionInfo; 81 (ContentSuggestionsSectionInformation*)sectionInfo;
66 82
67 @end 83 @end
68 84
69 @implementation ContentSuggestionsMediator 85 @implementation ContentSuggestionsMediator
70 86
87 @synthesize mostVisitedData = _mostVisitedData;
88 @synthesize mostVisitedSectionInfo = _mostVisitedSectionInfo;
89 @synthesize recordedPageImpression = _recordedPageImpression;
71 @synthesize contentService = _contentService; 90 @synthesize contentService = _contentService;
72 @synthesize dataSink = _dataSink; 91 @synthesize dataSink = _dataSink;
73 @synthesize sectionInformationByCategory = _sectionInformationByCategory; 92 @synthesize sectionInformationByCategory = _sectionInformationByCategory;
74 @synthesize attributesProvider = _attributesProvider; 93 @synthesize attributesProvider = _attributesProvider;
75 94
76 #pragma mark - Public 95 #pragma mark - Public
77 96
78 - (instancetype) 97 - (instancetype)
79 initWithContentService:(ntp_snippets::ContentSuggestionsService*)contentService 98 initWithContentService:(ntp_snippets::ContentSuggestionsService*)contentService
80 largeIconService:(favicon::LargeIconService*)largeIconService { 99 largeIconService:(favicon::LargeIconService*)largeIconService
100 mostVisitedSite:
101 (std::unique_ptr<ntp_tiles::MostVisitedSites>)mostVisitedSites {
81 self = [super init]; 102 self = [super init];
82 if (self) { 103 if (self) {
83 _suggestionBridge = 104 _suggestionBridge =
84 base::MakeUnique<ContentSuggestionsServiceBridge>(self, contentService); 105 base::MakeUnique<ContentSuggestionsServiceBridge>(self, contentService);
85 _contentService = contentService; 106 _contentService = contentService;
86 _sectionInformationByCategory = [[NSMutableDictionary alloc] init]; 107 _sectionInformationByCategory = [[NSMutableDictionary alloc] init];
87 _attributesProvider = [[FaviconAttributesProvider alloc] 108 _attributesProvider = [[FaviconAttributesProvider alloc]
88 initWithFaviconSize:kDefaultFaviconSize 109 initWithFaviconSize:kDefaultFaviconSize
89 minFaviconSize:1 110 minFaviconSize:1
90 largeIconService:largeIconService]; 111 largeIconService:largeIconService];
112
113 _mostVisitedSectionInfo = MostVisitedSectionInformation();
114 _mostVisitedSites = std::move(mostVisitedSites);
115 _mostVisitedBridge =
116 base::MakeUnique<ntp_tiles::MostVisitedSitesObserverBridge>(self);
117 _mostVisitedSites->SetMostVisitedURLsObserver(_mostVisitedBridge.get(),
118 kMaxNumMostVisitedTiles);
91 } 119 }
92 return self; 120 return self;
93 } 121 }
94 122
95 - (void)dismissSuggestion:(ContentSuggestionIdentifier*)suggestionIdentifier { 123 - (void)dismissSuggestion:(ContentSuggestionIdentifier*)suggestionIdentifier {
96 ContentSuggestionsCategoryWrapper* categoryWrapper = 124 ContentSuggestionsCategoryWrapper* categoryWrapper =
97 [self categoryWrapperForSectionInfo:suggestionIdentifier.sectionInfo]; 125 [self categoryWrapperForSectionInfo:suggestionIdentifier.sectionInfo];
98 ntp_snippets::ContentSuggestion::ID suggestion_id = 126 ntp_snippets::ContentSuggestion::ID suggestion_id =
99 ntp_snippets::ContentSuggestion::ID([categoryWrapper category], 127 ntp_snippets::ContentSuggestion::ID([categoryWrapper category],
100 suggestionIdentifier.IDInSection); 128 suggestionIdentifier.IDInSection);
101 129
102 self.contentService->DismissSuggestion(suggestion_id); 130 self.contentService->DismissSuggestion(suggestion_id);
103 } 131 }
104 132
105 #pragma mark - ContentSuggestionsDataSource 133 #pragma mark - ContentSuggestionsDataSource
106 134
107 - (NSArray<ContentSuggestion*>*)allSuggestions { 135 - (NSArray<ContentSuggestion*>*)allSuggestions {
136 NSMutableArray<ContentSuggestion*>* dataHolders = [NSMutableArray array];
137
138 [self addMostVisitedToArray:dataHolders];
139
108 std::vector<ntp_snippets::Category> categories = 140 std::vector<ntp_snippets::Category> categories =
lpromero 2017/04/04 11:25:20 Should you create a new -addContentSuggestionsToAr
gambard 2017/04/04 16:14:26 Done.
109 self.contentService->GetCategories(); 141 self.contentService->GetCategories();
110 NSMutableArray<ContentSuggestion*>* dataHolders = [NSMutableArray array];
111 for (auto& category : categories) { 142 for (auto& category : categories) {
112 const std::vector<ntp_snippets::ContentSuggestion>& suggestions = 143 const std::vector<ntp_snippets::ContentSuggestion>& suggestions =
113 self.contentService->GetSuggestionsForCategory(category); 144 self.contentService->GetSuggestionsForCategory(category);
114 [self addSuggestions:suggestions fromCategory:category toArray:dataHolders]; 145 [self addSuggestions:suggestions fromCategory:category toArray:dataHolders];
115 } 146 }
116 return dataHolders; 147 return dataHolders;
117 } 148 }
118 149
119 - (NSArray<ContentSuggestion*>*)suggestionsForSection: 150 - (NSArray<ContentSuggestion*>*)suggestionsForSection:
120 (ContentSuggestionsSectionInformation*)sectionInfo { 151 (ContentSuggestionsSectionInformation*)sectionInfo {
121 ntp_snippets::Category category = 152 NSMutableArray* convertedSuggestions = [NSMutableArray array];
122 [[self categoryWrapperForSectionInfo:sectionInfo] category];
123 153
124 NSMutableArray* convertedSuggestions = [NSMutableArray array]; 154 if (sectionInfo == self.mostVisitedSectionInfo) {
125 const std::vector<ntp_snippets::ContentSuggestion>& suggestions = 155 [self addMostVisitedToArray:convertedSuggestions];
126 self.contentService->GetSuggestionsForCategory(category); 156 } else {
127 [self addSuggestions:suggestions 157 ntp_snippets::Category category =
128 fromCategory:category 158 [[self categoryWrapperForSectionInfo:sectionInfo] category];
129 toArray:convertedSuggestions]; 159
160 const std::vector<ntp_snippets::ContentSuggestion>& suggestions =
161 self.contentService->GetSuggestionsForCategory(category);
162 [self addSuggestions:suggestions
163 fromCategory:category
164 toArray:convertedSuggestions];
165 }
166
130 return convertedSuggestions; 167 return convertedSuggestions;
131 } 168 }
132 169
133 - (id<ContentSuggestionsImageFetcher>)imageFetcher { 170 - (id<ContentSuggestionsImageFetcher>)imageFetcher {
134 return self; 171 return self;
135 } 172 }
136 173
137 - (void)fetchMoreSuggestionsKnowing: 174 - (void)fetchMoreSuggestionsKnowing:
138 (NSArray<ContentSuggestionIdentifier*>*)knownSuggestions 175 (NSArray<ContentSuggestionIdentifier*>*)knownSuggestions
139 fromSectionInfo: 176 fromSectionInfo:
140 (ContentSuggestionsSectionInformation*)sectionInfo 177 (ContentSuggestionsSectionInformation*)sectionInfo
141 callback:(MoreSuggestionsFetched)callback { 178 callback:(MoreSuggestionsFetched)callback {
179 if (![self isAContentSuggestionsCategory:sectionInfo])
180 return;
181
142 std::set<std::string> known_suggestion_ids; 182 std::set<std::string> known_suggestion_ids;
143 for (ContentSuggestionIdentifier* identifier in knownSuggestions) { 183 for (ContentSuggestionIdentifier* identifier in knownSuggestions) {
144 if (identifier.sectionInfo != sectionInfo) 184 if (identifier.sectionInfo != sectionInfo)
145 continue; 185 continue;
146 known_suggestion_ids.insert(identifier.IDInSection); 186 known_suggestion_ids.insert(identifier.IDInSection);
147 } 187 }
148 188
149 ContentSuggestionsCategoryWrapper* wrapper = 189 ContentSuggestionsCategoryWrapper* wrapper =
150 [self categoryWrapperForSectionInfo:sectionInfo]; 190 [self categoryWrapperForSectionInfo:sectionInfo];
151 191
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
236 suggestionIdentifier.IDInSection), 276 suggestionIdentifier.IDInSection),
237 base::BindBlockArc(^(const gfx::Image& image) { 277 base::BindBlockArc(^(const gfx::Image& image) {
238 if (image.IsEmpty() || !callback) { 278 if (image.IsEmpty() || !callback) {
239 return; 279 return;
240 } 280 }
241 281
242 callback([image.ToUIImage() copy]); 282 callback([image.ToUIImage() copy]);
243 })); 283 }));
244 } 284 }
245 285
286 #pragma mark - MostVisitedSitesObserving
287
288 - (void)onMostVisitedURLsAvailable:
289 (const ntp_tiles::NTPTilesVector&)mostVisited {
290 self.mostVisitedData = mostVisited;
291 [self.dataSink reloadSection:self.mostVisitedSectionInfo];
292
293 if (mostVisited.size() && !self.recordedPageImpression) {
294 self.recordedPageImpression = YES;
295 RecordPageImpression(mostVisited);
296 }
297 }
298
299 - (void)onIconMadeAvailable:(const GURL&)siteURL {
300 [self.dataSink faviconAvailableForURL:siteURL];
301 }
302
246 #pragma mark - Private 303 #pragma mark - Private
247 304
248 - (void)addSuggestions: 305 - (void)addSuggestions:
249 (const std::vector<ntp_snippets::ContentSuggestion>&)suggestions 306 (const std::vector<ntp_snippets::ContentSuggestion>&)suggestions
250 fromCategory:(ntp_snippets::Category&)category 307 fromCategory:(ntp_snippets::Category&)category
251 toArray:(NSMutableArray<ContentSuggestion*>*)contentArray { 308 toArray:(NSMutableArray<ContentSuggestion*>*)contentArray {
252 if (!ntp_snippets::IsCategoryStatusAvailable( 309 if (!ntp_snippets::IsCategoryStatusAvailable(
253 self.contentService->GetCategoryStatus(category))) { 310 self.contentService->GetCategoryStatus(category))) {
254 return; 311 return;
255 } 312 }
256 313
257 ContentSuggestionsCategoryWrapper* categoryWrapper = 314 ContentSuggestionsCategoryWrapper* categoryWrapper =
258 [ContentSuggestionsCategoryWrapper wrapperWithCategory:category]; 315 [ContentSuggestionsCategoryWrapper wrapperWithCategory:category];
259 if (!self.sectionInformationByCategory[categoryWrapper]) { 316 if (!self.sectionInformationByCategory[categoryWrapper]) {
260 [self addSectionInformationForCategory:category]; 317 [self addSectionInformationForCategory:category];
261 } 318 }
262 319
263 for (auto& contentSuggestion : suggestions) { 320 for (auto& contentSuggestion : suggestions) {
264 ContentSuggestion* suggestion = ConvertContentSuggestion(contentSuggestion); 321 ContentSuggestion* suggestion = ConvertContentSuggestion(contentSuggestion);
265 322
266 suggestion.type = TypeForCategory(category); 323 suggestion.type = TypeForCategory(category);
267 324
268 suggestion.suggestionIdentifier.sectionInfo = 325 suggestion.suggestionIdentifier.sectionInfo =
269 self.sectionInformationByCategory[categoryWrapper]; 326 self.sectionInformationByCategory[categoryWrapper];
270 327
271 [contentArray addObject:suggestion]; 328 [contentArray addObject:suggestion];
272 } 329 }
273 330
274 if (suggestions.size() == 0) { 331 if (suggestions.size() == 0) {
275 ContentSuggestion* suggestion = [[ContentSuggestion alloc] init]; 332 ContentSuggestion* suggestion = EmptySuggestion();
276 suggestion.type = ContentSuggestionTypeEmpty;
277 suggestion.suggestionIdentifier =
278 [[ContentSuggestionIdentifier alloc] init];
279 suggestion.suggestionIdentifier.sectionInfo = 333 suggestion.suggestionIdentifier.sectionInfo =
280 self.sectionInformationByCategory[categoryWrapper]; 334 self.sectionInformationByCategory[categoryWrapper];
281 335
282 [contentArray addObject:suggestion]; 336 [contentArray addObject:suggestion];
283 } 337 }
284 } 338 }
285 339
286 - (void)addSectionInformationForCategory:(ntp_snippets::Category)category { 340 - (void)addSectionInformationForCategory:(ntp_snippets::Category)category {
287 base::Optional<ntp_snippets::CategoryInfo> categoryInfo = 341 base::Optional<ntp_snippets::CategoryInfo> categoryInfo =
288 self.contentService->GetCategoryInfo(category); 342 self.contentService->GetCategoryInfo(category);
(...skipping 21 matching lines...) Expand all
310 NSMutableArray<ContentSuggestion*>* contentSuggestions = 364 NSMutableArray<ContentSuggestion*>* contentSuggestions =
311 [NSMutableArray array]; 365 [NSMutableArray array];
312 ntp_snippets::Category category = suggestions[0].id().category(); 366 ntp_snippets::Category category = suggestions[0].id().category();
313 [self addSuggestions:suggestions 367 [self addSuggestions:suggestions
314 fromCategory:category 368 fromCategory:category
315 toArray:contentSuggestions]; 369 toArray:contentSuggestions];
316 callback(contentSuggestions); 370 callback(contentSuggestions);
317 } 371 }
318 } 372 }
319 373
374 // Adds all the suggestions for the |mostVisitedData| to |suggestions|.
375 - (void)addMostVisitedToArray:(NSMutableArray<ContentSuggestion*>*)suggestions {
376 if (self.mostVisitedData.empty()) {
377 ContentSuggestion* suggestion = EmptySuggestion();
378 suggestion.suggestionIdentifier.sectionInfo = self.mostVisitedSectionInfo;
379 [suggestions addObject:suggestion];
380
381 return;
382 }
383
384 for (const ntp_tiles::NTPTile& tile : self.mostVisitedData) {
385 ContentSuggestion* suggestion = ConvertNTPTile(tile);
386 suggestion.suggestionIdentifier.sectionInfo = self.mostVisitedSectionInfo;
387 [suggestions addObject:suggestion];
388 }
389 }
390
391 // Returns whether the |sectionInfo| is associated with a category from the
392 // content suggestions service.
393 - (BOOL)isAContentSuggestionsCategory:
394 (ContentSuggestionsSectionInformation*)sectionInfo {
395 return sectionInfo != self.mostVisitedSectionInfo;
lpromero 2017/04/04 11:25:20 Feels weird since mostVisitedSectionInfo is a Cont
gambard 2017/04/04 16:14:26 i have changed the name to isRelatedToContentSugge
396 }
397
320 @end 398 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698