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

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

Issue 2421463002: FetchMore functionality backend (Closed)
Patch Set: Introduced callback, removed strategy. Created 4 years, 2 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 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_dismissed = num_snippets - snippets->size();
187 UMA_HISTOGRAM_BOOLEAN("NewTabPage.Snippets.IncompleteSnippetsAfterFetch",
188 num_snippets_dismissed > 0);
189 if (num_snippets_dismissed > 0) {
190 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumIncompleteSnippets",
191 num_snippets_dismissed);
192 }
193 }
194
195 NTPSnippetsService::FetchedMoreCallback NullCallback() {
196 return NTPSnippetsService::FetchedMoreCallback();
Marc Treib 2016/10/20 16:51:40 Just inline this below. Also "NTPSnippetsService::
Marc Treib 2016/10/28 14:49:49 Done.
197 }
198
160 } // namespace 199 } // namespace
161 200
162 NTPSnippetsService::NTPSnippetsService( 201 NTPSnippetsService::NTPSnippetsService(
163 Observer* observer, 202 Observer* observer,
164 CategoryFactory* category_factory, 203 CategoryFactory* category_factory,
165 PrefService* pref_service, 204 PrefService* pref_service,
166 const std::string& application_language_code, 205 const std::string& application_language_code,
167 const UserClassifier* user_classifier, 206 const UserClassifier* user_classifier,
168 NTPSnippetsScheduler* scheduler, 207 NTPSnippetsScheduler* scheduler,
169 std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher, 208 std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher,
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
232 NTPSnippetsStatusService::RegisterProfilePrefs(registry); 271 NTPSnippetsStatusService::RegisterProfilePrefs(registry);
233 } 272 }
234 273
235 void NTPSnippetsService::FetchSnippets(bool interactive_request) { 274 void NTPSnippetsService::FetchSnippets(bool interactive_request) {
236 if (ready()) 275 if (ready())
237 FetchSnippetsFromHosts(std::set<std::string>(), interactive_request); 276 FetchSnippetsFromHosts(std::set<std::string>(), interactive_request);
238 else 277 else
239 fetch_when_ready_ = true; 278 fetch_when_ready_ = true;
240 } 279 }
241 280
242 void NTPSnippetsService::FetchSnippetsFromHosts( 281 void NTPSnippetsService::FetchSnippetsFromHosts(
Marc Treib 2016/10/20 16:51:40 This doesn't do anything now - might as well remov
Marc Treib 2016/10/28 14:49:49 ...buut it's public, and used by the internals pag
243 const std::set<std::string>& hosts, 282 const std::set<std::string>& hosts,
244 bool interactive_request) { 283 bool interactive_request) {
284 FetchSnippetsFromHostsImpl(hosts, interactive_request,
285 /*fetch_more=*/false, NullCallback(),
286 base::Optional<Category>());
287 }
288
289 void NTPSnippetsService::FetchMore(const Category& category,
290 FetchedMoreCallback callback) {
291 FetchSnippetsFromHostsImpl(std::set<std::string>(),
292 /*interactive_request=*/true,
293 /*fetch_more=*/true, callback,
294 base::Optional<Category>(category));
295 }
296
297 void NTPSnippetsService::FetchSnippetsFromHostsImpl(
298 const std::set<std::string>& hosts,
299 bool interactive_request,
300 bool fetch_more,
301 FetchedMoreCallback callback,
302 base::Optional<Category> exclusive_category) {
245 if (!ready()) 303 if (!ready())
246 return; 304 return;
247 305
248 // Empty categories are marked as loading; others are unchanged. 306 MarkEmptyCategoriesAsLoading();
307
308 // TODO(fhorschig): Refactor parameter to data object or management class.
309 snippets_fetcher_->FetchSnippetsFromHosts(
310 hosts, application_language_code_,
311 std::move(CollectIdsToExclude(fetch_more)), kMaxSnippetCount,
Marc Treib 2016/10/20 16:51:40 std::move isn't needed here (it's movable anyway)
Marc Treib 2016/10/28 14:49:49 Done.
312 interactive_request,
313 base::BindOnce(&NTPSnippetsService::OnFetchFinished,
314 base::Unretained(this), fetch_more, callback),
315 std::move(exclusive_category));
316 }
317
318 std::set<std::string> NTPSnippetsService::CollectIdsToExclude(bool fetch_more) {
319 std::set<std::string> ids;
320 for (const auto& item : categories_) {
321 const CategoryContent& content = item.second;
322 for (const auto& snippet : content.dismissed)
323 ids.insert(snippet->id());
324 if (!fetch_more)
325 continue;
326 for (const auto& snippet : content.archived)
327 ids.insert(snippet->id());
328 for (const auto& snippet : content.snippets)
329 ids.insert(snippet->id());
330 }
331 return ids;
332 }
333
334 void NTPSnippetsService::MarkEmptyCategoriesAsLoading() {
249 for (const auto& item : categories_) { 335 for (const auto& item : categories_) {
250 Category category = item.first; 336 Category category = item.first;
251 const CategoryContent& content = item.second; 337 const CategoryContent& content = item.second;
252 if (content.snippets.empty()) 338 if (content.snippets.empty())
253 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE_LOADING); 339 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE_LOADING);
254 } 340 }
255
256 std::set<std::string> excluded_ids;
257 for (const auto& item : categories_) {
258 const CategoryContent& content = item.second;
259 for (const auto& snippet : content.dismissed)
260 excluded_ids.insert(snippet->id());
261 }
262 snippets_fetcher_->FetchSnippetsFromHosts(hosts, application_language_code_,
263 excluded_ids, kMaxSnippetCount,
264 interactive_request);
265 } 341 }
266 342
267 void NTPSnippetsService::RescheduleFetching(bool force) { 343 void NTPSnippetsService::RescheduleFetching(bool force) {
268 // The scheduler only exists on Android so far, it's null on other platforms. 344 // The scheduler only exists on Android so far, it's null on other platforms.
269 if (!scheduler_) 345 if (!scheduler_)
270 return; 346 return;
271 347
272 if (ready()) { 348 if (ready()) {
273 base::TimeDelta old_interval_wifi = 349 base::TimeDelta old_interval_wifi =
274 base::TimeDelta::FromInternalValue(pref_service_->GetInt64( 350 base::TimeDelta::FromInternalValue(pref_service_->GetInt64(
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
372 if (!base::ContainsKey(categories_, category)) 448 if (!base::ContainsKey(categories_, category))
373 return; 449 return;
374 CategoryContent* content = &categories_[category]; 450 CategoryContent* content = &categories_[category];
375 if (content->snippets.empty()) 451 if (content->snippets.empty())
376 return; 452 return;
377 453
378 database_->DeleteSnippets(GetSnippetIDVector(content->snippets)); 454 database_->DeleteSnippets(GetSnippetIDVector(content->snippets));
379 database_->DeleteImages(GetSnippetIDVector(content->snippets)); 455 database_->DeleteImages(GetSnippetIDVector(content->snippets));
380 content->snippets.clear(); 456 content->snippets.clear();
381 457
382 NotifyNewSuggestions(); 458 NotifyNewSuggestions(/*fetched_more=*/false, NullCallback());
383 } 459 }
384 460
385 void NTPSnippetsService::GetDismissedSuggestionsForDebugging( 461 void NTPSnippetsService::GetDismissedSuggestionsForDebugging(
386 Category category, 462 Category category,
387 const DismissedSuggestionsCallback& callback) { 463 const DismissedSuggestionsCallback& callback) {
388 DCHECK(base::ContainsKey(categories_, category)); 464 DCHECK(base::ContainsKey(categories_, category));
389 465
390 std::vector<ContentSuggestion> result; 466 std::vector<ContentSuggestion> result;
391 const CategoryContent& content = categories_[category]; 467 const CategoryContent& content = categories_[category];
392 for (const std::unique_ptr<NTPSnippet>& snippet : content.dismissed) { 468 for (const std::unique_ptr<NTPSnippet>& snippet : content.dismissed) {
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
513 ClearOrphanedImages(); 589 ClearOrphanedImages();
514 FinishInitialization(); 590 FinishInitialization();
515 } 591 }
516 592
517 void NTPSnippetsService::OnDatabaseError() { 593 void NTPSnippetsService::OnDatabaseError() {
518 EnterState(State::ERROR_OCCURRED); 594 EnterState(State::ERROR_OCCURRED);
519 UpdateAllCategoryStatus(CategoryStatus::LOADING_ERROR); 595 UpdateAllCategoryStatus(CategoryStatus::LOADING_ERROR);
520 } 596 }
521 597
522 void NTPSnippetsService::OnFetchFinished( 598 void NTPSnippetsService::OnFetchFinished(
599 bool fetched_more,
600 FetchedMoreCallback fetched_more_callback,
523 NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories) { 601 NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories) {
524 if (!ready()) 602 if (!ready())
525 return; 603 return;
526 604
527 // Mark all categories as not provided by the server in the latest fetch. The 605 // Mark all categories as not provided by the server in the latest fetch. The
528 // ones we got will be marked again below. 606 // ones we got will be marked again below.
529 for (auto& item : categories_) { 607 for (auto& item : categories_) {
530 CategoryContent* content = &item.second; 608 CategoryContent* content = &item.second;
531 content->provided_by_server = false; 609 content->provided_by_server = false;
532 } 610 }
(...skipping 24 matching lines...) Expand all
557 categories_[category].provided_by_server = true; 635 categories_[category].provided_by_server = true;
558 636
559 // TODO(tschumann): Remove this histogram once we only talk to the content 637 // TODO(tschumann): Remove this histogram once we only talk to the content
560 // suggestions cloud backend. 638 // suggestions cloud backend.
561 if (category == articles_category_) { 639 if (category == articles_category_) {
562 UMA_HISTOGRAM_SPARSE_SLOWLY( 640 UMA_HISTOGRAM_SPARSE_SLOWLY(
563 "NewTabPage.Snippets.NumArticlesFetched", 641 "NewTabPage.Snippets.NumArticlesFetched",
564 std::min(fetched_category.snippets.size(), 642 std::min(fetched_category.snippets.size(),
565 static_cast<size_t>(kMaxSnippetCount + 1))); 643 static_cast<size_t>(kMaxSnippetCount + 1)));
566 } 644 }
567 ReplaceSnippets(category, std::move(fetched_category.snippets)); 645 IncludeSnippets(category, std::move(fetched_category.snippets),
646 /*replace_snippets=*/!fetched_more);
568 } 647 }
569 } 648 }
570 649
571 // We might have gotten new categories (or updated the titles of existing 650 // We might have gotten new categories (or updated the titles of existing
572 // ones), so update the pref. 651 // ones), so update the pref.
573 StoreCategoriesToPrefs(); 652 StoreCategoriesToPrefs();
574 653
575 for (const auto& item : categories_) { 654 for (const auto& item : categories_) {
576 Category category = item.first; 655 Category category = item.first;
577 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE); 656 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE);
578 } 657 }
579 658
580 // TODO(sfiera): equivalent metrics for non-articles. 659 // TODO(sfiera): equivalent metrics for non-articles.
581 const CategoryContent& content = categories_[articles_category_]; 660 const CategoryContent& content = categories_[articles_category_];
582 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticles", 661 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticles",
583 content.snippets.size()); 662 content.snippets.size());
584 if (content.snippets.empty() && !content.dismissed.empty()) { 663 if (content.snippets.empty() && !content.dismissed.empty()) {
585 UMA_HISTOGRAM_COUNTS("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded", 664 UMA_HISTOGRAM_COUNTS("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded",
586 content.dismissed.size()); 665 content.dismissed.size());
587 } 666 }
588 667
589 // TODO(sfiera): notify only when a category changed above. 668 // TODO(sfiera): notify only when a category changed above.
590 NotifyNewSuggestions(); 669 NotifyNewSuggestions(fetched_more, fetched_more_callback);
591 670
592 // Reschedule after a successful fetch. This resets all currently scheduled 671 // Reschedule after a successful fetch. This resets all currently scheduled
593 // fetches, to make sure the fallback interval triggers only if no wifi fetch 672 // fetches, to make sure the fallback interval triggers only if no wifi fetch
594 // succeeded, and also that we don't do a background fetch immediately after 673 // succeeded, and also that we don't do a background fetch immediately after
595 // a user-initiated one. 674 // a user-initiated one.
596 if (fetched_categories) 675 if (fetched_categories)
597 RescheduleFetching(true); 676 RescheduleFetching(true);
598 } 677 }
599 678
600 void NTPSnippetsService::ArchiveSnippets(Category category, 679 void NTPSnippetsService::IncludeSnippets(const Category& category,
601 NTPSnippet::PtrVector* to_archive) { 680 NTPSnippet::PtrVector new_snippets,
602 CategoryContent* content = &categories_[category]; 681 bool replace_snippets) {
603 database_->DeleteSnippets(GetSnippetIDVector(*to_archive));
604 // Do not delete the thumbnail images as they are still handy on open NTPs.
605
606 // Archive previous snippets - move them at the beginning of the list.
607 content->archived.insert(content->archived.begin(),
608 std::make_move_iterator(to_archive->begin()),
609 std::make_move_iterator(to_archive->end()));
610 RemoveNullPointers(to_archive);
611
612 // If there are more archived snippets than we want to keep, delete the
613 // oldest ones by their fetch time (which are always in the back).
614 if (content->archived.size() > kMaxArchivedSnippetCount) {
615 NTPSnippet::PtrVector to_delete(
616 std::make_move_iterator(content->archived.begin() +
617 kMaxArchivedSnippetCount),
618 std::make_move_iterator(content->archived.end()));
619 content->archived.resize(kMaxArchivedSnippetCount);
620 database_->DeleteImages(GetSnippetIDVector(to_delete));
621 }
622 }
623
624 void NTPSnippetsService::ReplaceSnippets(Category category,
625 NTPSnippet::PtrVector new_snippets) {
626 DCHECK(ready()); 682 DCHECK(ready());
627 CategoryContent* content = &categories_[category]; 683 CategoryContent* content = &categories_[category];
628 684
629 // Remove new snippets that have been dismissed. 685 // Remove new snippets that have been dismissed.
630 EraseMatchingSnippets(&new_snippets, content->dismissed); 686 EraseMatchingSnippets(&new_snippets, content->dismissed);
631 687
632 // Fill in default publish/expiry dates where required. 688 AssignExpiryAndPublishDates(&new_snippets);
633 for (std::unique_ptr<NTPSnippet>& snippet : new_snippets) { 689 RemoveIncompleteSnippets(&new_snippets);
634 if (snippet->publish_date().is_null())
635 snippet->set_publish_date(base::Time::Now());
636 if (snippet->expiry_date().is_null()) {
637 snippet->set_expiry_date(
638 snippet->publish_date() +
639 base::TimeDelta::FromMinutes(kDefaultExpiryTimeMins));
640 }
641 }
642
643 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
644 switches::kAddIncompleteSnippets)) {
645 int num_new_snippets = new_snippets.size();
646 // Remove snippets that do not have all the info we need to display it to
647 // the user.
648 new_snippets.erase(
649 std::remove_if(new_snippets.begin(), new_snippets.end(),
650 [](const std::unique_ptr<NTPSnippet>& snippet) {
651 return !snippet->is_complete();
652 }),
653 new_snippets.end());
654 int num_snippets_dismissed = num_new_snippets - new_snippets.size();
655 UMA_HISTOGRAM_BOOLEAN("NewTabPage.Snippets.IncompleteSnippetsAfterFetch",
656 num_snippets_dismissed > 0);
657 if (num_snippets_dismissed > 0) {
658 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumIncompleteSnippets",
659 num_snippets_dismissed);
660 }
661 }
662 690
663 // Do not touch the current set of snippets if the newly fetched one is empty. 691 // Do not touch the current set of snippets if the newly fetched one is empty.
664 if (new_snippets.empty()) 692 if (new_snippets.empty())
665 return; 693 return;
666 694
667 // It's entirely possible that the newly fetched snippets contain articles 695 // It's entirely possible that the newly fetched snippets contain articles
668 // that have been present before. 696 // that have been present before.
669 // Since archival removes snippets from the database (indexed by 697 // Since archival removes snippets from the database (indexed by
670 // snippet->id()), we need to make sure to only archive snippets that don't 698 // snippet->id()), we need to make sure to only archive snippets that don't
671 // appear with the same ID in the new suggestions (it's fine for additional 699 // appear with the same ID in the new suggestions (it's fine for additional
672 // IDs though). 700 // IDs though).
673 EraseByPrimaryID(&content->snippets, *GetSnippetIDVector(new_snippets)); 701 EraseByPrimaryID(&content->snippets, *GetSnippetIDVector(new_snippets));
674 ArchiveSnippets(category, &content->snippets);
675 702
676 // Save new articles to the DB. 703 SaveSnippets(category, std::move(new_snippets), replace_snippets);
704 }
705
706 void NTPSnippetsService::SaveSnippets(const Category& category,
Marc Treib 2016/10/20 16:51:40 So this is only called once, just above? Then I wo
Marc Treib 2016/10/28 14:49:49 Done.
707 NTPSnippet::PtrVector new_snippets,
708 bool replace_snippets) {
677 database_->SaveSnippets(new_snippets); 709 database_->SaveSnippets(new_snippets);
678 710
679 content->snippets = std::move(new_snippets); 711 CategoryContent* content = &categories_[category];
712
713 if (replace_snippets) {
714 ArchiveSnippets(category, &content->snippets);
715 content->snippets = std::move(new_snippets);
716 return;
717 }
718
719 content->snippets.insert(content->snippets.end(),
720 std::make_move_iterator(new_snippets.begin()),
721 std::make_move_iterator(new_snippets.end()));
680 } 722 }
681 723
724 void NTPSnippetsService::ArchiveSnippets(Category category,
Marc Treib 2016/10/20 16:51:40 Why did you move this? It makes the diff harder to
Marc Treib 2016/10/28 14:49:49 Done. (Moved back)
725 NTPSnippet::PtrVector* to_archive) {
726 CategoryContent* content = &categories_[category];
727 database_->DeleteSnippets(GetSnippetIDVector(*to_archive));
728 // Do not delete the thumbnail images as they are still handy on open NTPs.
729
730 // Archive previous snippets - move them at the beginning of the list.
731 content->archived.insert(content->archived.begin(),
732 std::make_move_iterator(to_archive->begin()),
733 std::make_move_iterator(to_archive->end()));
734 RemoveNullPointers(to_archive);
735
736 // If there are more archived snippets than we want to keep, delete the
737 // oldest ones by their fetch time (which are always in the back).
738 if (content->archived.size() > kMaxArchivedSnippetCount) {
739 NTPSnippet::PtrVector to_delete(
740 std::make_move_iterator(content->archived.begin() +
741 kMaxArchivedSnippetCount),
742 std::make_move_iterator(content->archived.end()));
743 content->archived.resize(kMaxArchivedSnippetCount);
744 database_->DeleteImages(GetSnippetIDVector(to_delete));
745 }
746 }
682 void NTPSnippetsService::ClearExpiredDismissedSnippets() { 747 void NTPSnippetsService::ClearExpiredDismissedSnippets() {
683 std::vector<Category> categories_to_erase; 748 std::vector<Category> categories_to_erase;
684 749
685 const base::Time now = base::Time::Now(); 750 const base::Time now = base::Time::Now();
686 751
687 for (auto& item : categories_) { 752 for (auto& item : categories_) {
688 Category category = item.first; 753 Category category = item.first;
689 CategoryContent* content = &item.second; 754 CategoryContent* content = &item.second;
690 755
691 NTPSnippet::PtrVector to_delete; 756 NTPSnippet::PtrVector to_delete;
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
855 } 920 }
856 921
857 void NTPSnippetsService::FinishInitialization() { 922 void NTPSnippetsService::FinishInitialization() {
858 if (nuke_when_initialized_) { 923 if (nuke_when_initialized_) {
859 // We nuke here in addition to EnterStateReady, so that it happens even if 924 // We nuke here in addition to EnterStateReady, so that it happens even if
860 // we enter the DISABLED state below. 925 // we enter the DISABLED state below.
861 NukeAllSnippets(); 926 NukeAllSnippets();
862 nuke_when_initialized_ = false; 927 nuke_when_initialized_ = false;
863 } 928 }
864 929
865 snippets_fetcher_->SetCallback(
866 base::Bind(&NTPSnippetsService::OnFetchFinished, base::Unretained(this)));
867
868 // |image_fetcher_| can be null in tests. 930 // |image_fetcher_| can be null in tests.
869 if (image_fetcher_) { 931 if (image_fetcher_) {
870 image_fetcher_->SetImageFetcherDelegate(this); 932 image_fetcher_->SetImageFetcherDelegate(this);
871 image_fetcher_->SetDataUseServiceName( 933 image_fetcher_->SetDataUseServiceName(
872 data_use_measurement::DataUseUserData::NTP_SNIPPETS); 934 data_use_measurement::DataUseUserData::NTP_SNIPPETS);
873 } 935 }
874 936
875 // Note: Initializing the status service will run the callback right away with 937 // Note: Initializing the status service will run the callback right away with
876 // the current state. 938 // the current state.
877 snippets_status_service_->Init(base::Bind( 939 snippets_status_service_->Init(base::Bind(
878 &NTPSnippetsService::OnSnippetsStatusChanged, base::Unretained(this))); 940 &NTPSnippetsService::OnSnippetsStatusChanged, base::Unretained(this)));
879 941
880 // Always notify here even if we got nothing from the database, because we 942 // Always notify here even if we got nothing from the database, because we
881 // don't know how long the fetch will take or if it will even complete. 943 // don't know how long the fetch will take or if it will even complete.
882 NotifyNewSuggestions(); 944 NotifyNewSuggestions(/*fetched_more=*/false, NullCallback());
883 } 945 }
884 946
885 void NTPSnippetsService::OnSnippetsStatusChanged( 947 void NTPSnippetsService::OnSnippetsStatusChanged(
886 SnippetsStatus old_snippets_status, 948 SnippetsStatus old_snippets_status,
887 SnippetsStatus new_snippets_status) { 949 SnippetsStatus new_snippets_status) {
888 switch (new_snippets_status) { 950 switch (new_snippets_status) {
889 case SnippetsStatus::ENABLED_AND_SIGNED_IN: 951 case SnippetsStatus::ENABLED_AND_SIGNED_IN:
890 if (old_snippets_status == SnippetsStatus::ENABLED_AND_SIGNED_OUT) { 952 if (old_snippets_status == SnippetsStatus::ENABLED_AND_SIGNED_OUT) {
891 DCHECK(state_ == State::READY); 953 DCHECK(state_ == State::READY);
892 // Clear nonpersonalized suggestions. 954 // Clear nonpersonalized suggestions.
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
954 DVLOG(1) << "Entering state: ERROR_OCCURRED"; 1016 DVLOG(1) << "Entering state: ERROR_OCCURRED";
955 state_ = State::ERROR_OCCURRED; 1017 state_ = State::ERROR_OCCURRED;
956 EnterStateError(); 1018 EnterStateError();
957 break; 1019 break;
958 } 1020 }
959 1021
960 // Schedule or un-schedule background fetching after each state change. 1022 // Schedule or un-schedule background fetching after each state change.
961 RescheduleFetching(false); 1023 RescheduleFetching(false);
962 } 1024 }
963 1025
964 void NTPSnippetsService::NotifyNewSuggestions() { 1026 void NTPSnippetsService::NotifyNewSuggestions(
Marc Treib 2016/10/20 16:51:40 Hm, this now kinda does two totally different thin
Marc Treib 2016/10/28 14:49:49 Done.
1027 bool fetched_more,
1028 FetchedMoreCallback fetched_more_callback) {
965 for (const auto& item : categories_) { 1029 for (const auto& item : categories_) {
966 Category category = item.first; 1030 Category category = item.first;
967 const CategoryContent& content = item.second; 1031 const CategoryContent& content = item.second;
968 1032
969 std::vector<ContentSuggestion> result; 1033 std::vector<ContentSuggestion> result;
970 for (const std::unique_ptr<NTPSnippet>& snippet : content.snippets) { 1034 for (const std::unique_ptr<NTPSnippet>& snippet : content.snippets) {
971 // TODO(sfiera): if a snippet is not going to be displayed, move it 1035 // TODO(sfiera): if a snippet is not going to be displayed, move it
972 // directly to content.dismissed on fetch. Otherwise, we might prune 1036 // directly to content.dismissed on fetch. Otherwise, we might prune
973 // other snippets to get down to kMaxSnippetCount, only to hide one of the 1037 // other snippets to get down to kMaxSnippetCount, only to hide one of the
974 // incomplete ones we kept. 1038 // incomplete ones we kept.
975 if (!snippet->is_complete()) 1039 if (!snippet->is_complete())
976 continue; 1040 continue;
977 ContentSuggestion suggestion(category, snippet->id(), 1041 ContentSuggestion suggestion(category, snippet->id(),
978 snippet->best_source().url); 1042 snippet->best_source().url);
979 suggestion.set_amp_url(snippet->best_source().amp_url); 1043 suggestion.set_amp_url(snippet->best_source().amp_url);
980 suggestion.set_title(base::UTF8ToUTF16(snippet->title())); 1044 suggestion.set_title(base::UTF8ToUTF16(snippet->title()));
981 suggestion.set_snippet_text(base::UTF8ToUTF16(snippet->snippet())); 1045 suggestion.set_snippet_text(base::UTF8ToUTF16(snippet->snippet()));
982 suggestion.set_publish_date(snippet->publish_date()); 1046 suggestion.set_publish_date(snippet->publish_date());
983 suggestion.set_publisher_name( 1047 suggestion.set_publisher_name(
984 base::UTF8ToUTF16(snippet->best_source().publisher_name)); 1048 base::UTF8ToUTF16(snippet->best_source().publisher_name));
985 suggestion.set_score(snippet->score()); 1049 suggestion.set_score(snippet->score());
986 result.emplace_back(std::move(suggestion)); 1050 result.emplace_back(std::move(suggestion));
987 } 1051 }
988 1052
989 DVLOG(1) << "NotifyNewSuggestions(): " << result.size() 1053 DVLOG(1) << "NotifyNewSuggestions(/*fetched_more=*/" << fetched_more
990 << " items in category " << category; 1054 << "): " << result.size() << " items in category " << category;
991 observer()->OnNewSuggestions(this, category, std::move(result)); 1055 if (fetched_more) {
1056 DCHECK(!fetched_more_callback.is_null());
1057 fetched_more_callback.Run(std::move(result));
1058 } else {
1059 observer()->OnNewSuggestions(this, category, std::move(result));
1060 }
992 } 1061 }
993 } 1062 }
994 1063
995 void NTPSnippetsService::UpdateCategoryStatus(Category category, 1064 void NTPSnippetsService::UpdateCategoryStatus(Category category,
996 CategoryStatus status) { 1065 CategoryStatus status) {
997 DCHECK(base::ContainsKey(categories_, category)); 1066 DCHECK(base::ContainsKey(categories_, category));
998 CategoryContent& content = categories_[category]; 1067 CategoryContent& content = categories_[category];
999 if (status == content.status) 1068 if (status == content.status)
1000 return; 1069 return;
1001 1070
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
1102 } 1171 }
1103 1172
1104 NTPSnippetsService::CategoryContent::CategoryContent() = default; 1173 NTPSnippetsService::CategoryContent::CategoryContent() = default;
1105 NTPSnippetsService::CategoryContent::CategoryContent(CategoryContent&&) = 1174 NTPSnippetsService::CategoryContent::CategoryContent(CategoryContent&&) =
1106 default; 1175 default;
1107 NTPSnippetsService::CategoryContent::~CategoryContent() = default; 1176 NTPSnippetsService::CategoryContent::~CategoryContent() = default;
1108 NTPSnippetsService::CategoryContent& NTPSnippetsService::CategoryContent:: 1177 NTPSnippetsService::CategoryContent& NTPSnippetsService::CategoryContent::
1109 operator=(CategoryContent&&) = default; 1178 operator=(CategoryContent&&) = default;
1110 1179
1111 } // namespace ntp_snippets 1180 } // namespace ntp_snippets
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698