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

Side by Side Diff: components/ntp_snippets/remote/ntp_snippets_service.cc

Issue 2473483006: Adds a Fetch() method to the ContentSuggestionService which asks any provider to provide more conte… (Closed)
Patch Set: comments by Markus. Created 4 years, 1 month 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 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 #include "components/ntp_snippets/remote/ntp_snippets_service.h" 5 #include "components/ntp_snippets/remote/ntp_snippets_service.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <iterator> 8 #include <iterator>
9 #include <utility> 9 #include <utility>
10 10
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
150 } 150 }
151 151
152 void RemoveNullPointers(NTPSnippet::PtrVector* snippets) { 152 void RemoveNullPointers(NTPSnippet::PtrVector* snippets) {
153 snippets->erase( 153 snippets->erase(
154 std::remove_if( 154 std::remove_if(
155 snippets->begin(), snippets->end(), 155 snippets->begin(), snippets->end(),
156 [](const std::unique_ptr<NTPSnippet>& snippet) { return !snippet; }), 156 [](const std::unique_ptr<NTPSnippet>& snippet) { return !snippet; }),
157 snippets->end()); 157 snippets->end());
158 } 158 }
159 159
160 void AssignExpiryAndPublishDates(NTPSnippet::PtrVector* snippets) {
161 for (std::unique_ptr<NTPSnippet>& snippet : *snippets) {
162 if (snippet->publish_date().is_null())
163 snippet->set_publish_date(base::Time::Now());
164 if (snippet->expiry_date().is_null()) {
165 snippet->set_expiry_date(
166 snippet->publish_date() +
167 base::TimeDelta::FromMinutes(kDefaultExpiryTimeMins));
168 }
169 }
170 }
171
172 void RemoveIncompleteSnippets(NTPSnippet::PtrVector* snippets) {
173 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
174 switches::kAddIncompleteSnippets)) {
175 return;
176 }
177 int num_snippets = snippets->size();
178 // Remove snippets that do not have all the info we need to display it to
179 // the user.
180 snippets->erase(
181 std::remove_if(snippets->begin(), snippets->end(),
182 [](const std::unique_ptr<NTPSnippet>& snippet) {
183 return !snippet->is_complete();
184 }),
185 snippets->end());
186 int num_snippets_removed = num_snippets - snippets->size();
187 UMA_HISTOGRAM_BOOLEAN("NewTabPage.Snippets.IncompleteSnippetsAfterFetch",
188 num_snippets_removed > 0);
189 if (num_snippets_removed > 0) {
190 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumIncompleteSnippets",
191 num_snippets_removed);
192 }
193 }
194
195 std::vector<ContentSuggestion> ConvertToContentSuggestions(
196 Category category,
197 const NTPSnippet::PtrVector& snippets) {
198 std::vector<ContentSuggestion> result;
199 for (const std::unique_ptr<NTPSnippet>& snippet : snippets) {
200 // TODO(sfiera): if a snippet is not going to be displayed, move it
201 // directly to content.dismissed on fetch. Otherwise, we might prune
202 // other snippets to get down to kMaxSnippetCount, only to hide one of the
203 // incomplete ones we kept.
204 if (!snippet->is_complete())
205 continue;
206 ContentSuggestion suggestion(category, snippet->id(),
207 snippet->best_source().url);
208 suggestion.set_amp_url(snippet->best_source().amp_url);
209 suggestion.set_title(base::UTF8ToUTF16(snippet->title()));
210 suggestion.set_snippet_text(base::UTF8ToUTF16(snippet->snippet()));
211 suggestion.set_publish_date(snippet->publish_date());
212 suggestion.set_publisher_name(
213 base::UTF8ToUTF16(snippet->best_source().publisher_name));
214 suggestion.set_score(snippet->score());
215 result.emplace_back(std::move(suggestion));
216 }
217 return result;
218 }
219
220 void CallWithEmptyResults(
221 base::Optional<ContentSuggestionsProvider::FetchingCallback> callback) {
222 if (!callback)
223 return;
224 if (callback->is_null())
225 return;
226 callback->Run(std::vector<ContentSuggestion>());
227 }
228
160 } // namespace 229 } // namespace
161 230
162 NTPSnippetsService::NTPSnippetsService( 231 NTPSnippetsService::NTPSnippetsService(
163 Observer* observer, 232 Observer* observer,
164 CategoryFactory* category_factory, 233 CategoryFactory* category_factory,
165 PrefService* pref_service, 234 PrefService* pref_service,
166 const std::string& application_language_code, 235 const std::string& application_language_code,
167 const UserClassifier* user_classifier, 236 const UserClassifier* user_classifier,
168 NTPSnippetsScheduler* scheduler, 237 NTPSnippetsScheduler* scheduler,
169 std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher, 238 std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher,
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
236 void NTPSnippetsService::FetchSnippets(bool interactive_request) { 305 void NTPSnippetsService::FetchSnippets(bool interactive_request) {
237 if (ready()) 306 if (ready())
238 FetchSnippetsFromHosts(std::set<std::string>(), interactive_request); 307 FetchSnippetsFromHosts(std::set<std::string>(), interactive_request);
239 else 308 else
240 fetch_when_ready_ = true; 309 fetch_when_ready_ = true;
241 } 310 }
242 311
243 void NTPSnippetsService::FetchSnippetsFromHosts( 312 void NTPSnippetsService::FetchSnippetsFromHosts(
244 const std::set<std::string>& hosts, 313 const std::set<std::string>& hosts,
245 bool interactive_request) { 314 bool interactive_request) {
246 if (!ready()) 315 FetchSnippetsFromHostsImpl(hosts, interactive_request,
316 /*fetch_more=*/false, std::set<std::string>(),
Marc Treib 2016/11/07 14:28:23 /*known_suggestion_ids=*/
tschumann 2016/11/08 16:57:35 changed in the meantime.
317 base::Optional<Category>(),
318 base::Optional<FetchingCallback>());
319 }
320
321 void NTPSnippetsService::Fetch(
322 const Category& category,
323 const std::set<std::string>& known_suggestion_ids,
324 FetchingCallback callback) {
325 FetchSnippetsFromHostsImpl(std::set<std::string>(),
326 /*interactive_request=*/true,
327 /*fetch_more=*/true, known_suggestion_ids,
328 base::Optional<Category>(category),
329 base::Optional<FetchingCallback>(callback));
330 }
331
332 void NTPSnippetsService::FetchSnippetsFromHostsImpl(
333 const std::set<std::string>& hosts,
334 bool interactive_request,
335 bool fetch_more,
336 const std::set<std::string>& known_suggestion_ids,
337 base::Optional<Category> exclusive_category,
338 base::Optional<FetchingCallback> callback) {
339 if (!ready()) {
340 CallWithEmptyResults(callback);
247 return; 341 return;
342 }
248 343
249 // Empty categories are marked as loading; others are unchanged. 344 MarkEmptyCategoriesAsLoading();
345
346 NTPSnippetsFetcher::Params params;
347 params.language_code = application_language_code_;
348 params.excluded_ids = CollectIdsToExclude(fetch_more, known_suggestion_ids);
349 params.count_to_fetch = kMaxSnippetCount;
350 params.hosts = hosts;
351 params.interactive_request = interactive_request;
352 params.exclusive_category = std::move(exclusive_category);
353
354 snippets_fetcher_->FetchSnippets(
355 params, base::BindOnce(&NTPSnippetsService::OnFetchFinished,
356 base::Unretained(this), fetch_more, callback));
357 }
358
359 std::set<std::string> NTPSnippetsService::CollectIdsToExclude(
360 bool fetch_more,
361 const std::set<std::string>& additional_ids) const {
362 std::set<std::string> ids;
363 for (const auto& item : categories_) {
364 const CategoryContent& content = item.second;
365 for (const auto& snippet : content.dismissed)
366 ids.insert(snippet->id());
367 if (!fetch_more)
368 continue;
369 for (const auto& snippet : content.archived)
370 ids.insert(snippet->id());
371 }
372 ids.insert(additional_ids.begin(), additional_ids.end());
373 return ids;
374 }
375
376 void NTPSnippetsService::MarkEmptyCategoriesAsLoading() {
250 for (const auto& item : categories_) { 377 for (const auto& item : categories_) {
251 Category category = item.first; 378 Category category = item.first;
252 const CategoryContent& content = item.second; 379 const CategoryContent& content = item.second;
253 if (content.snippets.empty()) 380 if (content.snippets.empty())
254 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE_LOADING); 381 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE_LOADING);
255 } 382 }
256
257 NTPSnippetsFetcher::Params params;
258 params.language_code = application_language_code_;
259 params.count_to_fetch = kMaxSnippetCount;
260 params.hosts = hosts;
261 params.interactive_request = interactive_request;
262 for (const auto& item : categories_) {
263 const CategoryContent& content = item.second;
264 for (const auto& snippet : content.dismissed)
265 params.excluded_ids.insert(snippet->id());
266 }
267 snippets_fetcher_->FetchSnippets(params);
268 } 383 }
269 384
270 void NTPSnippetsService::RescheduleFetching(bool force) { 385 void NTPSnippetsService::RescheduleFetching(bool force) {
271 // The scheduler only exists on Android so far, it's null on other platforms. 386 // The scheduler only exists on Android so far, it's null on other platforms.
272 if (!scheduler_) 387 if (!scheduler_)
273 return; 388 return;
274 389
275 if (ready()) { 390 if (ready()) {
276 base::TimeDelta old_interval_wifi = 391 base::TimeDelta old_interval_wifi =
277 base::TimeDelta::FromInternalValue(pref_service_->GetInt64( 392 base::TimeDelta::FromInternalValue(pref_service_->GetInt64(
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after
521 ClearExpiredDismissedSnippets(); 636 ClearExpiredDismissedSnippets();
522 ClearOrphanedImages(); 637 ClearOrphanedImages();
523 FinishInitialization(); 638 FinishInitialization();
524 } 639 }
525 640
526 void NTPSnippetsService::OnDatabaseError() { 641 void NTPSnippetsService::OnDatabaseError() {
527 EnterState(State::ERROR_OCCURRED); 642 EnterState(State::ERROR_OCCURRED);
528 UpdateAllCategoryStatus(CategoryStatus::LOADING_ERROR); 643 UpdateAllCategoryStatus(CategoryStatus::LOADING_ERROR);
529 } 644 }
530 645
646 // fetching_callback
Marc Treib 2016/11/07 14:28:23 ?
tschumann 2016/11/08 16:57:35 went away in the meantime.
531 void NTPSnippetsService::OnFetchFinished( 647 void NTPSnippetsService::OnFetchFinished(
648 bool fetched_more,
649 base::Optional<FetchingCallback> fetching_callback,
532 NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories) { 650 NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories) {
533 if (!ready()) 651 if (!ready())
534 return; 652 return;
535 653
654 // TODO(fhorschig): Check which of the things here should actually happen for
655 // |fetch_more| requests. Maybe it makes sense to have two separate
656 // "Finished" methods?
657
536 // Mark all categories as not provided by the server in the latest fetch. The 658 // Mark all categories as not provided by the server in the latest fetch. The
537 // ones we got will be marked again below. 659 // ones we got will be marked again below.
538 for (auto& item : categories_) { 660 for (auto& item : categories_) {
539 CategoryContent* content = &item.second; 661 CategoryContent* content = &item.second;
540 content->provided_by_server = false; 662 content->provided_by_server = false;
541 } 663 }
542 664
543 // Clear up expired dismissed snippets before we use them to filter new ones. 665 // Clear up expired dismissed snippets before we use them to filter new ones.
544 ClearExpiredDismissedSnippets(); 666 ClearExpiredDismissedSnippets();
545 667
(...skipping 20 matching lines...) Expand all
566 categories_[category].provided_by_server = true; 688 categories_[category].provided_by_server = true;
567 689
568 // TODO(tschumann): Remove this histogram once we only talk to the content 690 // TODO(tschumann): Remove this histogram once we only talk to the content
569 // suggestions cloud backend. 691 // suggestions cloud backend.
570 if (category == articles_category_) { 692 if (category == articles_category_) {
571 UMA_HISTOGRAM_SPARSE_SLOWLY( 693 UMA_HISTOGRAM_SPARSE_SLOWLY(
572 "NewTabPage.Snippets.NumArticlesFetched", 694 "NewTabPage.Snippets.NumArticlesFetched",
573 std::min(fetched_category.snippets.size(), 695 std::min(fetched_category.snippets.size(),
574 static_cast<size_t>(kMaxSnippetCount + 1))); 696 static_cast<size_t>(kMaxSnippetCount + 1)));
575 } 697 }
576 ReplaceSnippets(category, std::move(fetched_category.snippets)); 698 IncludeSnippets(category, std::move(fetched_category.snippets),
699 /*replace_snippets=*/!fetched_more);
577 } 700 }
578 } 701 }
579 702
580 // We might have gotten new categories (or updated the titles of existing 703 // We might have gotten new categories (or updated the titles of existing
581 // ones), so update the pref. 704 // ones), so update the pref.
582 StoreCategoriesToPrefs(); 705 StoreCategoriesToPrefs();
583 706
584 for (const auto& item : categories_) { 707 for (const auto& item : categories_) {
585 Category category = item.first; 708 Category category = item.first;
586 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE); 709 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE);
587 // TODO(sfiera): notify only when a category changed above. 710 // TODO(sfiera): notify only when a category changed above.
588 NotifyNewSuggestions(category); 711 if (fetched_more)
712 NotifyMoreSuggestions(category, fetching_callback);
713 else
714 NotifyNewSuggestions(category);
589 } 715 }
590 716
591 // TODO(sfiera): equivalent metrics for non-articles. 717 // TODO(sfiera): equivalent metrics for non-articles.
592 const CategoryContent& content = categories_[articles_category_]; 718 const CategoryContent& content = categories_[articles_category_];
593 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticles", 719 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticles",
594 content.snippets.size()); 720 content.snippets.size());
595 if (content.snippets.empty() && !content.dismissed.empty()) { 721 if (content.snippets.empty() && !content.dismissed.empty()) {
596 UMA_HISTOGRAM_COUNTS("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded", 722 UMA_HISTOGRAM_COUNTS("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded",
597 content.dismissed.size()); 723 content.dismissed.size());
598 } 724 }
(...skipping 23 matching lines...) Expand all
622 if (content->archived.size() > kMaxArchivedSnippetCount) { 748 if (content->archived.size() > kMaxArchivedSnippetCount) {
623 NTPSnippet::PtrVector to_delete( 749 NTPSnippet::PtrVector to_delete(
624 std::make_move_iterator(content->archived.begin() + 750 std::make_move_iterator(content->archived.begin() +
625 kMaxArchivedSnippetCount), 751 kMaxArchivedSnippetCount),
626 std::make_move_iterator(content->archived.end())); 752 std::make_move_iterator(content->archived.end()));
627 content->archived.resize(kMaxArchivedSnippetCount); 753 content->archived.resize(kMaxArchivedSnippetCount);
628 database_->DeleteImages(GetSnippetIDVector(to_delete)); 754 database_->DeleteImages(GetSnippetIDVector(to_delete));
629 } 755 }
630 } 756 }
631 757
632 void NTPSnippetsService::ReplaceSnippets(Category category, 758 void NTPSnippetsService::IncludeSnippets(const Category& category,
633 NTPSnippet::PtrVector new_snippets) { 759 NTPSnippet::PtrVector new_snippets,
760 bool replace_snippets) {
634 DCHECK(ready()); 761 DCHECK(ready());
635 CategoryContent* content = &categories_[category]; 762 CategoryContent* content = &categories_[category];
636 763
637 // Remove new snippets that have been dismissed. 764 // Remove new snippets that have been dismissed.
638 EraseMatchingSnippets(&new_snippets, content->dismissed); 765 EraseMatchingSnippets(&new_snippets, content->dismissed);
639 766
640 // Fill in default publish/expiry dates where required. 767 AssignExpiryAndPublishDates(&new_snippets);
641 for (std::unique_ptr<NTPSnippet>& snippet : new_snippets) { 768 RemoveIncompleteSnippets(&new_snippets);
642 if (snippet->publish_date().is_null())
643 snippet->set_publish_date(base::Time::Now());
644 if (snippet->expiry_date().is_null()) {
645 snippet->set_expiry_date(
646 snippet->publish_date() +
647 base::TimeDelta::FromMinutes(kDefaultExpiryTimeMins));
648 }
649 }
650
651 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
652 switches::kAddIncompleteSnippets)) {
653 int num_new_snippets = new_snippets.size();
654 // Remove snippets that do not have all the info we need to display it to
655 // the user.
656 new_snippets.erase(
657 std::remove_if(new_snippets.begin(), new_snippets.end(),
658 [](const std::unique_ptr<NTPSnippet>& snippet) {
659 return !snippet->is_complete();
660 }),
661 new_snippets.end());
662 int num_snippets_dismissed = num_new_snippets - new_snippets.size();
663 UMA_HISTOGRAM_BOOLEAN("NewTabPage.Snippets.IncompleteSnippetsAfterFetch",
664 num_snippets_dismissed > 0);
665 if (num_snippets_dismissed > 0) {
666 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumIncompleteSnippets",
667 num_snippets_dismissed);
668 }
669 }
670 769
671 // Do not touch the current set of snippets if the newly fetched one is empty. 770 // Do not touch the current set of snippets if the newly fetched one is empty.
672 if (new_snippets.empty()) 771 if (new_snippets.empty())
673 return; 772 return;
674 773
675 // It's entirely possible that the newly fetched snippets contain articles 774 // It's entirely possible that the newly fetched snippets contain articles
676 // that have been present before. 775 // that have been present before.
677 // Since archival removes snippets from the database (indexed by 776 // Since archival removes snippets from the database (indexed by
678 // snippet->id()), we need to make sure to only archive snippets that don't 777 // snippet->id()), we need to make sure to only archive snippets that don't
679 // appear with the same ID in the new suggestions (it's fine for additional 778 // appear with the same ID in the new suggestions (it's fine for additional
680 // IDs though). 779 // IDs though).
681 EraseByPrimaryID(&content->snippets, *GetSnippetIDVector(new_snippets)); 780 EraseByPrimaryID(&content->snippets, *GetSnippetIDVector(new_snippets));
682 ArchiveSnippets(category, &content->snippets);
683 781
684 // Save new articles to the DB.
685 database_->SaveSnippets(new_snippets); 782 database_->SaveSnippets(new_snippets);
686 783
687 content->snippets = std::move(new_snippets); 784 if (replace_snippets) {
785 ArchiveSnippets(category, &content->snippets);
786 content->snippets = std::move(new_snippets);
787 } else {
788 content->snippets.insert(content->snippets.end(),
789 std::make_move_iterator(new_snippets.begin()),
790 std::make_move_iterator(new_snippets.end()));
791 }
688 } 792 }
689
690 void NTPSnippetsService::ClearExpiredDismissedSnippets() { 793 void NTPSnippetsService::ClearExpiredDismissedSnippets() {
691 std::vector<Category> categories_to_erase; 794 std::vector<Category> categories_to_erase;
692 795
693 const base::Time now = base::Time::Now(); 796 const base::Time now = base::Time::Now();
694 797
695 for (auto& item : categories_) { 798 for (auto& item : categories_) {
696 Category category = item.first; 799 Category category = item.first;
697 CategoryContent* content = &item.second; 800 CategoryContent* content = &item.second;
698 801
699 NTPSnippet::PtrVector to_delete; 802 NTPSnippet::PtrVector to_delete;
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
863 } 966 }
864 967
865 void NTPSnippetsService::FinishInitialization() { 968 void NTPSnippetsService::FinishInitialization() {
866 if (nuke_when_initialized_) { 969 if (nuke_when_initialized_) {
867 // We nuke here in addition to EnterStateReady, so that it happens even if 970 // We nuke here in addition to EnterStateReady, so that it happens even if
868 // we enter the DISABLED state below. 971 // we enter the DISABLED state below.
869 NukeAllSnippets(); 972 NukeAllSnippets();
870 nuke_when_initialized_ = false; 973 nuke_when_initialized_ = false;
871 } 974 }
872 975
873 snippets_fetcher_->SetCallback(
874 base::Bind(&NTPSnippetsService::OnFetchFinished, base::Unretained(this)));
875
876 // |image_fetcher_| can be null in tests. 976 // |image_fetcher_| can be null in tests.
877 if (image_fetcher_) { 977 if (image_fetcher_) {
878 image_fetcher_->SetImageFetcherDelegate(this); 978 image_fetcher_->SetImageFetcherDelegate(this);
879 image_fetcher_->SetDataUseServiceName( 979 image_fetcher_->SetDataUseServiceName(
880 data_use_measurement::DataUseUserData::NTP_SNIPPETS); 980 data_use_measurement::DataUseUserData::NTP_SNIPPETS);
881 } 981 }
882 982
883 // Note: Initializing the status service will run the callback right away with 983 // Note: Initializing the status service will run the callback right away with
884 // the current state. 984 // the current state.
885 snippets_status_service_->Init(base::Bind( 985 snippets_status_service_->Init(base::Bind(
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
970 1070
971 // Schedule or un-schedule background fetching after each state change. 1071 // Schedule or un-schedule background fetching after each state change.
972 RescheduleFetching(false); 1072 RescheduleFetching(false);
973 } 1073 }
974 1074
975 void NTPSnippetsService::NotifyNewSuggestions(Category category) { 1075 void NTPSnippetsService::NotifyNewSuggestions(Category category) {
976 DCHECK(base::ContainsKey(categories_, category)); 1076 DCHECK(base::ContainsKey(categories_, category));
977 const CategoryContent& content = categories_[category]; 1077 const CategoryContent& content = categories_[category];
978 DCHECK(IsCategoryStatusAvailable(content.status)); 1078 DCHECK(IsCategoryStatusAvailable(content.status));
979 1079
980 std::vector<ContentSuggestion> result; 1080 std::vector<ContentSuggestion> result =
981 for (const std::unique_ptr<NTPSnippet>& snippet : content.snippets) { 1081 ConvertToContentSuggestions(category, content.snippets);
982 // TODO(sfiera): if a snippet is not going to be displayed, move it
983 // directly to content.dismissed on fetch. Otherwise, we might prune
984 // other snippets to get down to kMaxSnippetCount, only to hide one of the
985 // incomplete ones we kept.
986 if (!snippet->is_complete())
987 continue;
988 ContentSuggestion suggestion(category, snippet->id(),
989 snippet->best_source().url);
990 suggestion.set_amp_url(snippet->best_source().amp_url);
991 suggestion.set_title(base::UTF8ToUTF16(snippet->title()));
992 suggestion.set_snippet_text(base::UTF8ToUTF16(snippet->snippet()));
993 suggestion.set_publish_date(snippet->publish_date());
994 suggestion.set_publisher_name(
995 base::UTF8ToUTF16(snippet->best_source().publisher_name));
996 suggestion.set_score(snippet->score());
997 result.emplace_back(std::move(suggestion));
998 }
999 1082
1000 DVLOG(1) << "NotifyNewSuggestions(" << category << "): " << result.size() 1083 DVLOG(1) << "NotifyNewSuggestions(): " << result.size()
1001 << " items."; 1084 << " items in category " << category;
1002 observer()->OnNewSuggestions(this, category, std::move(result)); 1085 observer()->OnNewSuggestions(this, category, std::move(result));
1003 } 1086 }
1004 1087
1088 void NTPSnippetsService::NotifyMoreSuggestions(
1089 Category category,
1090 base::Optional<FetchingCallback> callback) {
1091 DCHECK(base::ContainsKey(categories_, category));
1092 const CategoryContent& content = categories_[category];
1093 DCHECK(IsCategoryStatusAvailable(content.status));
1094
1095 std::vector<ContentSuggestion> result =
1096 ConvertToContentSuggestions(category, content.snippets);
1097
1098 DVLOG(1) << "NotifyMoreSuggestions(): " << result.size()
1099 << " items in category " << category;
1100 DCHECK(callback);
1101 DCHECK(!callback->is_null());
1102 callback->Run(std::move(result));
1103 }
1104
1005 void NTPSnippetsService::UpdateCategoryStatus(Category category, 1105 void NTPSnippetsService::UpdateCategoryStatus(Category category,
1006 CategoryStatus status) { 1106 CategoryStatus status) {
1007 DCHECK(base::ContainsKey(categories_, category)); 1107 DCHECK(base::ContainsKey(categories_, category));
1008 CategoryContent& content = categories_[category]; 1108 CategoryContent& content = categories_[category];
1009 if (status == content.status) 1109 if (status == content.status)
1010 return; 1110 return;
1011 1111
1012 DVLOG(1) << "UpdateCategoryStatus(): " << category.id() << ": " 1112 DVLOG(1) << "UpdateCategoryStatus(): " << category.id() << ": "
1013 << static_cast<int>(content.status) << " -> " 1113 << static_cast<int>(content.status) << " -> "
1014 << static_cast<int>(status); 1114 << static_cast<int>(status);
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
1112 } 1212 }
1113 1213
1114 NTPSnippetsService::CategoryContent::CategoryContent() = default; 1214 NTPSnippetsService::CategoryContent::CategoryContent() = default;
1115 NTPSnippetsService::CategoryContent::CategoryContent(CategoryContent&&) = 1215 NTPSnippetsService::CategoryContent::CategoryContent(CategoryContent&&) =
1116 default; 1216 default;
1117 NTPSnippetsService::CategoryContent::~CategoryContent() = default; 1217 NTPSnippetsService::CategoryContent::~CategoryContent() = default;
1118 NTPSnippetsService::CategoryContent& NTPSnippetsService::CategoryContent:: 1218 NTPSnippetsService::CategoryContent& NTPSnippetsService::CategoryContent::
1119 operator=(CategoryContent&&) = default; 1219 operator=(CategoryContent&&) = default;
1120 1220
1121 } // namespace ntp_snippets 1221 } // namespace ntp_snippets
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698