OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |