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

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

Issue 2421463002: FetchMore functionality backend (Closed)
Patch Set: ID set reference, Optional callback, ... (2466863003 comments). 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>(),
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 244 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
531 void NTPSnippetsService::OnFetchFinished( 646 void NTPSnippetsService::OnFetchFinished(
647 bool fetched_more,
648 base::Optional<FetchingCallback> fetching_callback,
532 NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories) { 649 NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories) {
533 if (!ready()) 650 if (!ready())
534 return; 651 return;
535 652
653 // TODO(fhorschig): Check which of the things here should actually happen for
654 // |fetch_more| requests. Maybe it makes sense to have two separate
655 // "Finished" methods?
656
536 // Mark all categories as not provided by the server in the latest fetch. The 657 // Mark all categories as not provided by the server in the latest fetch. The
537 // ones we got will be marked again below. 658 // ones we got will be marked again below.
538 for (auto& item : categories_) { 659 for (auto& item : categories_) {
539 CategoryContent* content = &item.second; 660 CategoryContent* content = &item.second;
540 content->provided_by_server = false; 661 content->provided_by_server = false;
541 } 662 }
542 663
543 // Clear up expired dismissed snippets before we use them to filter new ones. 664 // Clear up expired dismissed snippets before we use them to filter new ones.
544 ClearExpiredDismissedSnippets(); 665 ClearExpiredDismissedSnippets();
545 666
(...skipping 20 matching lines...) Expand all
566 categories_[category].provided_by_server = true; 687 categories_[category].provided_by_server = true;
567 688
568 // TODO(tschumann): Remove this histogram once we only talk to the content 689 // TODO(tschumann): Remove this histogram once we only talk to the content
569 // suggestions cloud backend. 690 // suggestions cloud backend.
570 if (category == articles_category_) { 691 if (category == articles_category_) {
571 UMA_HISTOGRAM_SPARSE_SLOWLY( 692 UMA_HISTOGRAM_SPARSE_SLOWLY(
572 "NewTabPage.Snippets.NumArticlesFetched", 693 "NewTabPage.Snippets.NumArticlesFetched",
573 std::min(fetched_category.snippets.size(), 694 std::min(fetched_category.snippets.size(),
574 static_cast<size_t>(kMaxSnippetCount + 1))); 695 static_cast<size_t>(kMaxSnippetCount + 1)));
575 } 696 }
576 ReplaceSnippets(category, std::move(fetched_category.snippets)); 697 IncludeSnippets(category, std::move(fetched_category.snippets),
698 /*replace_snippets=*/!fetched_more);
577 } 699 }
578 } 700 }
579 701
580 // We might have gotten new categories (or updated the titles of existing 702 // We might have gotten new categories (or updated the titles of existing
581 // ones), so update the pref. 703 // ones), so update the pref.
582 StoreCategoriesToPrefs(); 704 StoreCategoriesToPrefs();
583 705
584 for (const auto& item : categories_) { 706 for (const auto& item : categories_) {
585 Category category = item.first; 707 Category category = item.first;
586 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE); 708 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE);
587 // TODO(sfiera): notify only when a category changed above. 709 // TODO(sfiera): notify only when a category changed above.
588 NotifyNewSuggestions(category); 710 if (fetched_more)
711 NotifyMoreSuggestions(category, fetching_callback);
712 else
713 NotifyNewSuggestions(category);
589 } 714 }
590 715
591 // TODO(sfiera): equivalent metrics for non-articles. 716 // TODO(sfiera): equivalent metrics for non-articles.
592 const CategoryContent& content = categories_[articles_category_]; 717 const CategoryContent& content = categories_[articles_category_];
593 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticles", 718 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticles",
594 content.snippets.size()); 719 content.snippets.size());
595 if (content.snippets.empty() && !content.dismissed.empty()) { 720 if (content.snippets.empty() && !content.dismissed.empty()) {
596 UMA_HISTOGRAM_COUNTS("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded", 721 UMA_HISTOGRAM_COUNTS("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded",
597 content.dismissed.size()); 722 content.dismissed.size());
598 } 723 }
(...skipping 23 matching lines...) Expand all
622 if (content->archived.size() > kMaxArchivedSnippetCount) { 747 if (content->archived.size() > kMaxArchivedSnippetCount) {
623 NTPSnippet::PtrVector to_delete( 748 NTPSnippet::PtrVector to_delete(
624 std::make_move_iterator(content->archived.begin() + 749 std::make_move_iterator(content->archived.begin() +
625 kMaxArchivedSnippetCount), 750 kMaxArchivedSnippetCount),
626 std::make_move_iterator(content->archived.end())); 751 std::make_move_iterator(content->archived.end()));
627 content->archived.resize(kMaxArchivedSnippetCount); 752 content->archived.resize(kMaxArchivedSnippetCount);
628 database_->DeleteImages(GetSnippetIDVector(to_delete)); 753 database_->DeleteImages(GetSnippetIDVector(to_delete));
629 } 754 }
630 } 755 }
631 756
632 void NTPSnippetsService::ReplaceSnippets(Category category, 757 void NTPSnippetsService::IncludeSnippets(const Category& category,
633 NTPSnippet::PtrVector new_snippets) { 758 NTPSnippet::PtrVector new_snippets,
759 bool replace_snippets) {
634 DCHECK(ready()); 760 DCHECK(ready());
635 CategoryContent* content = &categories_[category]; 761 CategoryContent* content = &categories_[category];
636 762
637 // Remove new snippets that have been dismissed. 763 // Remove new snippets that have been dismissed.
638 EraseMatchingSnippets(&new_snippets, content->dismissed); 764 EraseMatchingSnippets(&new_snippets, content->dismissed);
639 765
640 // Fill in default publish/expiry dates where required. 766 AssignExpiryAndPublishDates(&new_snippets);
641 for (std::unique_ptr<NTPSnippet>& snippet : new_snippets) { 767 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 768
671 // Do not touch the current set of snippets if the newly fetched one is empty. 769 // Do not touch the current set of snippets if the newly fetched one is empty.
672 if (new_snippets.empty()) 770 if (new_snippets.empty())
673 return; 771 return;
674 772
675 // It's entirely possible that the newly fetched snippets contain articles 773 // It's entirely possible that the newly fetched snippets contain articles
676 // that have been present before. 774 // that have been present before.
677 // Since archival removes snippets from the database (indexed by 775 // Since archival removes snippets from the database (indexed by
678 // snippet->id()), we need to make sure to only archive snippets that don't 776 // 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 777 // appear with the same ID in the new suggestions (it's fine for additional
680 // IDs though). 778 // IDs though).
681 EraseByPrimaryID(&content->snippets, *GetSnippetIDVector(new_snippets)); 779 EraseByPrimaryID(&content->snippets, *GetSnippetIDVector(new_snippets));
682 ArchiveSnippets(category, &content->snippets);
683 780
684 // Save new articles to the DB.
685 database_->SaveSnippets(new_snippets); 781 database_->SaveSnippets(new_snippets);
686 782
687 content->snippets = std::move(new_snippets); 783 if (replace_snippets) {
784 ArchiveSnippets(category, &content->snippets);
785 content->snippets = std::move(new_snippets);
786 } else {
787 content->snippets.insert(content->snippets.end(),
tschumann 2016/11/03 09:20:58 what happens if I open a new NTP after hitting 'mo
788 std::make_move_iterator(new_snippets.begin()),
789 std::make_move_iterator(new_snippets.end()));
790 }
688 } 791 }
689
690 void NTPSnippetsService::ClearExpiredDismissedSnippets() { 792 void NTPSnippetsService::ClearExpiredDismissedSnippets() {
691 std::vector<Category> categories_to_erase; 793 std::vector<Category> categories_to_erase;
692 794
693 const base::Time now = base::Time::Now(); 795 const base::Time now = base::Time::Now();
694 796
695 for (auto& item : categories_) { 797 for (auto& item : categories_) {
696 Category category = item.first; 798 Category category = item.first;
697 CategoryContent* content = &item.second; 799 CategoryContent* content = &item.second;
698 800
699 NTPSnippet::PtrVector to_delete; 801 NTPSnippet::PtrVector to_delete;
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
863 } 965 }
864 966
865 void NTPSnippetsService::FinishInitialization() { 967 void NTPSnippetsService::FinishInitialization() {
866 if (nuke_when_initialized_) { 968 if (nuke_when_initialized_) {
867 // We nuke here in addition to EnterStateReady, so that it happens even if 969 // We nuke here in addition to EnterStateReady, so that it happens even if
868 // we enter the DISABLED state below. 970 // we enter the DISABLED state below.
869 NukeAllSnippets(); 971 NukeAllSnippets();
870 nuke_when_initialized_ = false; 972 nuke_when_initialized_ = false;
871 } 973 }
872 974
873 snippets_fetcher_->SetCallback(
874 base::Bind(&NTPSnippetsService::OnFetchFinished, base::Unretained(this)));
875
876 // |image_fetcher_| can be null in tests. 975 // |image_fetcher_| can be null in tests.
877 if (image_fetcher_) { 976 if (image_fetcher_) {
878 image_fetcher_->SetImageFetcherDelegate(this); 977 image_fetcher_->SetImageFetcherDelegate(this);
879 image_fetcher_->SetDataUseServiceName( 978 image_fetcher_->SetDataUseServiceName(
880 data_use_measurement::DataUseUserData::NTP_SNIPPETS); 979 data_use_measurement::DataUseUserData::NTP_SNIPPETS);
881 } 980 }
882 981
883 // Note: Initializing the status service will run the callback right away with 982 // Note: Initializing the status service will run the callback right away with
884 // the current state. 983 // the current state.
885 snippets_status_service_->Init(base::Bind( 984 snippets_status_service_->Init(base::Bind(
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
970 1069
971 // Schedule or un-schedule background fetching after each state change. 1070 // Schedule or un-schedule background fetching after each state change.
972 RescheduleFetching(false); 1071 RescheduleFetching(false);
973 } 1072 }
974 1073
975 void NTPSnippetsService::NotifyNewSuggestions(Category category) { 1074 void NTPSnippetsService::NotifyNewSuggestions(Category category) {
976 DCHECK(base::ContainsKey(categories_, category)); 1075 DCHECK(base::ContainsKey(categories_, category));
977 const CategoryContent& content = categories_[category]; 1076 const CategoryContent& content = categories_[category];
978 DCHECK(IsCategoryStatusAvailable(content.status)); 1077 DCHECK(IsCategoryStatusAvailable(content.status));
979 1078
980 std::vector<ContentSuggestion> result; 1079 std::vector<ContentSuggestion> result =
981 for (const std::unique_ptr<NTPSnippet>& snippet : content.snippets) { 1080 ConvertToContentSuggestions(category, content.snippets);
tschumann 2016/11/03 09:20:58 i believe we need to limit this to the first 10 re
dgn 2016/11/03 10:28:04 AFAICT, NotifyNewSuggestions() reports the suggest
tschumann 2016/11/03 10:35:06 Ok got it. I was a bit confused thinking we would
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 1081
1000 DVLOG(1) << "NotifyNewSuggestions(" << category << "): " << result.size() 1082 DVLOG(1) << "NotifyNewSuggestions(): " << result.size()
1001 << " items."; 1083 << " items in category " << category;
1002 observer()->OnNewSuggestions(this, category, std::move(result)); 1084 observer()->OnNewSuggestions(this, category, std::move(result));
1003 } 1085 }
1004 1086
1087 void NTPSnippetsService::NotifyMoreSuggestions(
1088 Category category,
1089 base::Optional<FetchingCallback> callback) {
1090 DCHECK(base::ContainsKey(categories_, category));
1091 const CategoryContent& content = categories_[category];
1092 DCHECK(IsCategoryStatusAvailable(content.status));
1093
1094 std::vector<ContentSuggestion> result =
1095 ConvertToContentSuggestions(category, content.snippets);
1096
1097 DVLOG(1) << "NotifyMoreSuggestions(): " << result.size()
1098 << " items in category " << category;
1099 DCHECK(callback);
1100 DCHECK(!callback->is_null());
1101 callback->Run(std::move(result));
1102 }
1103
1005 void NTPSnippetsService::UpdateCategoryStatus(Category category, 1104 void NTPSnippetsService::UpdateCategoryStatus(Category category,
1006 CategoryStatus status) { 1105 CategoryStatus status) {
1007 DCHECK(base::ContainsKey(categories_, category)); 1106 DCHECK(base::ContainsKey(categories_, category));
1008 CategoryContent& content = categories_[category]; 1107 CategoryContent& content = categories_[category];
1009 if (status == content.status) 1108 if (status == content.status)
1010 return; 1109 return;
1011 1110
1012 DVLOG(1) << "UpdateCategoryStatus(): " << category.id() << ": " 1111 DVLOG(1) << "UpdateCategoryStatus(): " << category.id() << ": "
1013 << static_cast<int>(content.status) << " -> " 1112 << static_cast<int>(content.status) << " -> "
1014 << static_cast<int>(status); 1113 << static_cast<int>(status);
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
1112 } 1211 }
1113 1212
1114 NTPSnippetsService::CategoryContent::CategoryContent() = default; 1213 NTPSnippetsService::CategoryContent::CategoryContent() = default;
1115 NTPSnippetsService::CategoryContent::CategoryContent(CategoryContent&&) = 1214 NTPSnippetsService::CategoryContent::CategoryContent(CategoryContent&&) =
1116 default; 1215 default;
1117 NTPSnippetsService::CategoryContent::~CategoryContent() = default; 1216 NTPSnippetsService::CategoryContent::~CategoryContent() = default;
1118 NTPSnippetsService::CategoryContent& NTPSnippetsService::CategoryContent:: 1217 NTPSnippetsService::CategoryContent& NTPSnippetsService::CategoryContent::
1119 operator=(CategoryContent&&) = default; 1218 operator=(CategoryContent&&) = default;
1120 1219
1121 } // namespace ntp_snippets 1220 } // namespace ntp_snippets
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698