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

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

Issue 2395273003: [NTP Snippets] Persist remote categories in prefs (Closed)
Patch Set: tschumann review 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 175 matching lines...) Expand 10 before | Expand all | Expand 10 after
186 snippets_fetcher_(std::move(snippets_fetcher)), 186 snippets_fetcher_(std::move(snippets_fetcher)),
187 image_fetcher_(std::move(image_fetcher)), 187 image_fetcher_(std::move(image_fetcher)),
188 image_decoder_(std::move(image_decoder)), 188 image_decoder_(std::move(image_decoder)),
189 database_(std::move(database)), 189 database_(std::move(database)),
190 snippets_status_service_(std::move(status_service)), 190 snippets_status_service_(std::move(status_service)),
191 fetch_when_ready_(false), 191 fetch_when_ready_(false),
192 nuke_when_initialized_(false), 192 nuke_when_initialized_(false),
193 thumbnail_requests_throttler_( 193 thumbnail_requests_throttler_(
194 pref_service, 194 pref_service,
195 RequestThrottler::RequestType::CONTENT_SUGGESTION_THUMBNAIL) { 195 RequestThrottler::RequestType::CONTENT_SUGGESTION_THUMBNAIL) {
196 // Articles category always exists; others will be added as needed. 196 RestoreCategoriesFromPrefs();
197 categories_[articles_category_] = CategoryContent(); 197 // The articles category always exists. Add it if we didn't get it from prefs.
198 categories_[articles_category_].localized_title = 198 // TODO(treib): Rethink this.
199 l10n_util::GetStringUTF16(IDS_NTP_ARTICLE_SUGGESTIONS_SECTION_HEADER); 199 if (!base::ContainsKey(categories_, articles_category_)) {
200 observer->OnCategoryStatusChanged(this, articles_category_, 200 categories_[articles_category_] = CategoryContent();
201 categories_[articles_category_].status); 201 categories_[articles_category_].localized_title =
202 l10n_util::GetStringUTF16(IDS_NTP_ARTICLE_SUGGESTIONS_SECTION_HEADER);
203 }
204 // Tell the observer about all the categories.
205 for (const auto& entry : categories_) {
206 observer->OnCategoryStatusChanged(this, entry.first, entry.second.status);
207 }
208
202 if (database_->IsErrorState()) { 209 if (database_->IsErrorState()) {
203 EnterState(State::ERROR_OCCURRED); 210 EnterState(State::ERROR_OCCURRED);
204 UpdateAllCategoryStatus(CategoryStatus::LOADING_ERROR); 211 UpdateAllCategoryStatus(CategoryStatus::LOADING_ERROR);
205 return; 212 return;
206 } 213 }
207 214
208 database_->SetErrorCallback(base::Bind(&NTPSnippetsService::OnDatabaseError, 215 database_->SetErrorCallback(base::Bind(&NTPSnippetsService::OnDatabaseError,
209 base::Unretained(this))); 216 base::Unretained(this)));
210 217
211 // We transition to other states while finalizing the initialization, when the 218 // We transition to other states while finalizing the initialization, when the
212 // database is done loading. 219 // database is done loading.
213 database_->LoadSnippets(base::Bind(&NTPSnippetsService::OnDatabaseLoaded, 220 database_->LoadSnippets(base::Bind(&NTPSnippetsService::OnDatabaseLoaded,
214 base::Unretained(this))); 221 base::Unretained(this)));
215 } 222 }
216 223
217 NTPSnippetsService::~NTPSnippetsService() = default; 224 NTPSnippetsService::~NTPSnippetsService() = default;
218 225
219 // static 226 // static
220 void NTPSnippetsService::RegisterProfilePrefs(PrefRegistrySimple* registry) { 227 void NTPSnippetsService::RegisterProfilePrefs(PrefRegistrySimple* registry) {
221 registry->RegisterListPref(prefs::kSnippetHosts); //TODO remove 228 // TODO(treib): Add cleanup logic for prefs::kSnippetHosts, then remove it
229 // completely after M56.
230 registry->RegisterListPref(prefs::kSnippetHosts);
231 registry->RegisterListPref(prefs::kRemoteSuggestionCategories);
222 registry->RegisterInt64Pref(prefs::kSnippetBackgroundFetchingIntervalWifi, 0); 232 registry->RegisterInt64Pref(prefs::kSnippetBackgroundFetchingIntervalWifi, 0);
223 registry->RegisterInt64Pref(prefs::kSnippetBackgroundFetchingIntervalFallback, 233 registry->RegisterInt64Pref(prefs::kSnippetBackgroundFetchingIntervalFallback,
224 0); 234 0);
225 235
226 NTPSnippetsStatusService::RegisterProfilePrefs(registry); 236 NTPSnippetsStatusService::RegisterProfilePrefs(registry);
227 } 237 }
228 238
229 void NTPSnippetsService::FetchSnippets(bool interactive_request) { 239 void NTPSnippetsService::FetchSnippets(bool interactive_request) {
230 if (ready()) 240 if (ready())
231 FetchSnippetsFromHosts(std::set<std::string>(), interactive_request); 241 FetchSnippetsFromHosts(std::set<std::string>(), interactive_request);
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
292 if (state_ != State::NOT_INITED || force) { 302 if (state_ != State::NOT_INITED || force) {
293 scheduler_->Unschedule(); 303 scheduler_->Unschedule();
294 pref_service_->ClearPref(prefs::kSnippetBackgroundFetchingIntervalWifi); 304 pref_service_->ClearPref(prefs::kSnippetBackgroundFetchingIntervalWifi);
295 pref_service_->ClearPref( 305 pref_service_->ClearPref(
296 prefs::kSnippetBackgroundFetchingIntervalFallback); 306 prefs::kSnippetBackgroundFetchingIntervalFallback);
297 } 307 }
298 } 308 }
299 } 309 }
300 310
301 CategoryStatus NTPSnippetsService::GetCategoryStatus(Category category) { 311 CategoryStatus NTPSnippetsService::GetCategoryStatus(Category category) {
302 DCHECK(categories_.find(category) != categories_.end()); 312 DCHECK(base::ContainsKey(categories_, category));
303 return categories_[category].status; 313 return categories_[category].status;
304 } 314 }
305 315
306 CategoryInfo NTPSnippetsService::GetCategoryInfo(Category category) { 316 CategoryInfo NTPSnippetsService::GetCategoryInfo(Category category) {
307 DCHECK(categories_.find(category) != categories_.end()); 317 DCHECK(base::ContainsKey(categories_, category));
308 const CategoryContent& content = categories_[category]; 318 const CategoryContent& content = categories_[category];
309 return CategoryInfo(content.localized_title, 319 return CategoryInfo(content.localized_title,
310 ContentSuggestionsCardLayout::FULL_CARD, 320 ContentSuggestionsCardLayout::FULL_CARD,
311 /* has_more_button */ false, 321 /* has_more_button */ false,
312 /* show_if_empty */ true); 322 /* show_if_empty */ true);
313 } 323 }
314 324
315 void NTPSnippetsService::DismissSuggestion( 325 void NTPSnippetsService::DismissSuggestion(
316 const ContentSuggestion::ID& suggestion_id) { 326 const ContentSuggestion::ID& suggestion_id) {
317 if (!ready()) 327 if (!ready())
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
356 if (!ready()) 366 if (!ready())
357 nuke_when_initialized_ = true; 367 nuke_when_initialized_ = true;
358 else 368 else
359 NukeAllSnippets(); 369 NukeAllSnippets();
360 } 370 }
361 371
362 void NTPSnippetsService::ClearCachedSuggestions(Category category) { 372 void NTPSnippetsService::ClearCachedSuggestions(Category category) {
363 if (!initialized()) 373 if (!initialized())
364 return; 374 return;
365 375
366 if (categories_.find(category) == categories_.end()) 376 if (!base::ContainsKey(categories_, category))
367 return; 377 return;
368 CategoryContent* content = &categories_[category]; 378 CategoryContent* content = &categories_[category];
369 if (content->snippets.empty()) 379 if (content->snippets.empty())
370 return; 380 return;
371 381
372 if (category == articles_category_) { 382 if (category == articles_category_) {
373 database_->DeleteSnippets(GetSnippetIDVector(content->snippets)); 383 database_->DeleteSnippets(GetSnippetIDVector(content->snippets));
374 database_->DeleteImages(GetSnippetIDVector(content->snippets)); 384 database_->DeleteImages(GetSnippetIDVector(content->snippets));
375 } 385 }
376 content->snippets.clear(); 386 content->snippets.clear();
377 387
378 NotifyNewSuggestions(); 388 NotifyNewSuggestions();
379 } 389 }
380 390
381 void NTPSnippetsService::GetDismissedSuggestionsForDebugging( 391 void NTPSnippetsService::GetDismissedSuggestionsForDebugging(
382 Category category, 392 Category category,
383 const DismissedSuggestionsCallback& callback) { 393 const DismissedSuggestionsCallback& callback) {
384 DCHECK(categories_.find(category) != categories_.end()); 394 DCHECK(base::ContainsKey(categories_, category));
385 395
386 std::vector<ContentSuggestion> result; 396 std::vector<ContentSuggestion> result;
387 const CategoryContent& content = categories_[category]; 397 const CategoryContent& content = categories_[category];
388 for (const std::unique_ptr<NTPSnippet>& snippet : content.dismissed) { 398 for (const std::unique_ptr<NTPSnippet>& snippet : content.dismissed) {
389 if (!snippet->is_complete()) 399 if (!snippet->is_complete())
390 continue; 400 continue;
391 ContentSuggestion suggestion(category, snippet->id(), 401 ContentSuggestion suggestion(category, snippet->id(),
392 snippet->best_source().url); 402 snippet->best_source().url);
393 suggestion.set_amp_url(snippet->best_source().amp_url); 403 suggestion.set_amp_url(snippet->best_source().amp_url);
394 suggestion.set_title(base::UTF8ToUTF16(snippet->title())); 404 suggestion.set_title(base::UTF8ToUTF16(snippet->title()));
395 suggestion.set_snippet_text(base::UTF8ToUTF16(snippet->snippet())); 405 suggestion.set_snippet_text(base::UTF8ToUTF16(snippet->snippet()));
396 suggestion.set_publish_date(snippet->publish_date()); 406 suggestion.set_publish_date(snippet->publish_date());
397 suggestion.set_publisher_name( 407 suggestion.set_publisher_name(
398 base::UTF8ToUTF16(snippet->best_source().publisher_name)); 408 base::UTF8ToUTF16(snippet->best_source().publisher_name));
399 suggestion.set_score(snippet->score()); 409 suggestion.set_score(snippet->score());
400 result.emplace_back(std::move(suggestion)); 410 result.emplace_back(std::move(suggestion));
401 } 411 }
402 callback.Run(std::move(result)); 412 callback.Run(std::move(result));
403 } 413 }
404 414
405 void NTPSnippetsService::ClearDismissedSuggestionsForDebugging( 415 void NTPSnippetsService::ClearDismissedSuggestionsForDebugging(
406 Category category) { 416 Category category) {
407 DCHECK(categories_.find(category) != categories_.end()); 417 DCHECK(base::ContainsKey(categories_, category));
408 418
409 if (!initialized()) 419 if (!initialized())
410 return; 420 return;
411 421
412 CategoryContent* content = &categories_[category]; 422 CategoryContent* content = &categories_[category];
413 if (content->dismissed.empty()) 423 if (content->dismissed.empty())
414 return; 424 return;
415 425
416 if (category == articles_category_) { 426 if (category == articles_category_) {
417 // The image got already deleted when the suggestion was dismissed. 427 // The image got already deleted when the suggestion was dismissed.
418 database_->DeleteSnippets(GetSnippetIDVector(content->dismissed)); 428 database_->DeleteSnippets(GetSnippetIDVector(content->dismissed));
419 } 429 }
420 content->dismissed.clear(); 430 content->dismissed.clear();
421 } 431 }
422 432
423 // static 433 // static
424 int NTPSnippetsService::GetMaxSnippetCountForTesting() { 434 int NTPSnippetsService::GetMaxSnippetCountForTesting() {
425 return kMaxSnippetCount; 435 return kMaxSnippetCount;
426 } 436 }
427 437
428 //////////////////////////////////////////////////////////////////////////////// 438 ////////////////////////////////////////////////////////////////////////////////
429 // Private methods 439 // Private methods
430 440
431 GURL NTPSnippetsService::FindSnippetImageUrl( 441 GURL NTPSnippetsService::FindSnippetImageUrl(
432 const ContentSuggestion::ID& suggestion_id) const { 442 const ContentSuggestion::ID& suggestion_id) const {
433 DCHECK(categories_.find(suggestion_id.category()) != categories_.end()); 443 DCHECK(base::ContainsKey(categories_, suggestion_id.category()));
434 444
435 const CategoryContent& content = categories_.at(suggestion_id.category()); 445 const CategoryContent& content = categories_.at(suggestion_id.category());
436 const NTPSnippet* snippet = 446 const NTPSnippet* snippet =
437 content.FindSnippet(suggestion_id.id_within_category()); 447 content.FindSnippet(suggestion_id.id_within_category());
438 if (!snippet) 448 if (!snippet)
439 return GURL(); 449 return GURL();
440 return snippet->salient_image_url(); 450 return snippet->salient_image_url();
441 } 451 }
442 452
443 // image_fetcher::ImageFetcherDelegate implementation. 453 // image_fetcher::ImageFetcherDelegate implementation.
(...skipping 16 matching lines...) Expand all
460 470
461 // Only cache the data in the DB, the actual serving is done in the callback 471 // Only cache the data in the DB, the actual serving is done in the callback
462 // provided to |image_fetcher_| (OnSnippetImageDecodedFromNetwork()). 472 // provided to |image_fetcher_| (OnSnippetImageDecodedFromNetwork()).
463 database_->SaveImage(id_within_category, image_data); 473 database_->SaveImage(id_within_category, image_data);
464 } 474 }
465 475
466 void NTPSnippetsService::OnDatabaseLoaded(NTPSnippet::PtrVector snippets) { 476 void NTPSnippetsService::OnDatabaseLoaded(NTPSnippet::PtrVector snippets) {
467 if (state_ == State::ERROR_OCCURRED) 477 if (state_ == State::ERROR_OCCURRED)
468 return; 478 return;
469 DCHECK(state_ == State::NOT_INITED); 479 DCHECK(state_ == State::NOT_INITED);
470 DCHECK_EQ(1u, categories_.size()); // Only articles category, so far. 480 DCHECK(base::ContainsKey(categories_, articles_category_));
471 DCHECK(categories_.find(articles_category_) != categories_.end());
472 481
473 // TODO(sfiera): support non-article categories in database. 482 // TODO(treib): Support non-article categories in database. crbug.com/653476
474 CategoryContent* content = &categories_[articles_category_]; 483 CategoryContent* content = &categories_[articles_category_];
475 for (std::unique_ptr<NTPSnippet>& snippet : snippets) { 484 for (std::unique_ptr<NTPSnippet>& snippet : snippets) {
476 if (snippet->is_dismissed()) 485 if (snippet->is_dismissed())
477 content->dismissed.emplace_back(std::move(snippet)); 486 content->dismissed.emplace_back(std::move(snippet));
478 else 487 else
479 content->snippets.emplace_back(std::move(snippet)); 488 content->snippets.emplace_back(std::move(snippet));
480 } 489 }
481 490
482 std::sort(content->snippets.begin(), content->snippets.end(), 491 std::sort(content->snippets.begin(), content->snippets.end(),
483 [](const std::unique_ptr<NTPSnippet>& lhs, 492 [](const std::unique_ptr<NTPSnippet>& lhs,
(...skipping 12 matching lines...) Expand all
496 void NTPSnippetsService::OnDatabaseError() { 505 void NTPSnippetsService::OnDatabaseError() {
497 EnterState(State::ERROR_OCCURRED); 506 EnterState(State::ERROR_OCCURRED);
498 UpdateAllCategoryStatus(CategoryStatus::LOADING_ERROR); 507 UpdateAllCategoryStatus(CategoryStatus::LOADING_ERROR);
499 } 508 }
500 509
501 void NTPSnippetsService::OnFetchFinished( 510 void NTPSnippetsService::OnFetchFinished(
502 NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories) { 511 NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories) {
503 if (!ready()) 512 if (!ready())
504 return; 513 return;
505 514
515 // Mark all categories as not provided by the server in the latest fetch. The
516 // ones we got will be marked again below.
506 for (auto& item : categories_) { 517 for (auto& item : categories_) {
507 CategoryContent* content = &item.second; 518 CategoryContent* content = &item.second;
508 content->provided_by_server = false; 519 content->provided_by_server = false;
509 } 520 }
510 521
511 // Clear up expired dismissed snippets before we use them to filter new ones. 522 // Clear up expired dismissed snippets before we use them to filter new ones.
512 ClearExpiredDismissedSnippets(); 523 ClearExpiredDismissedSnippets();
513 524
514 // If snippets were fetched successfully, update our |categories_| from each 525 // If snippets were fetched successfully, update our |categories_| from each
515 // category provided by the server. 526 // category provided by the server.
516 if (fetched_categories) { 527 if (fetched_categories) {
528 // TODO(treib): Reorder |categories_| to match the order we received from
529 // the server. crbug.com/653816
517 // TODO(jkrcal): A bit hard to understand with so many variables called 530 // TODO(jkrcal): A bit hard to understand with so many variables called
518 // "*categor*". Isn't here some room for simplification? 531 // "*categor*". Isn't here some room for simplification?
519 for (NTPSnippetsFetcher::FetchedCategory& fetched_category : 532 for (NTPSnippetsFetcher::FetchedCategory& fetched_category :
520 *fetched_categories) { 533 *fetched_categories) {
521 Category category = fetched_category.category; 534 Category category = fetched_category.category;
522 535
523 // The ChromeReader backend doesn't provide category titles, so don't 536 // The ChromeReader backend doesn't provide category titles, so don't
524 // overwrite the existing title for ARTICLES if the new one is empty. 537 // overwrite the existing title for ARTICLES if the new one is empty.
525 // TODO(treib): Remove this check after we fully switch to the content 538 // TODO(treib): Remove this check after we fully switch to the content
526 // suggestions backend. 539 // suggestions backend.
(...skipping 11 matching lines...) Expand all
538 if (category == articles_category_) { 551 if (category == articles_category_) {
539 UMA_HISTOGRAM_SPARSE_SLOWLY( 552 UMA_HISTOGRAM_SPARSE_SLOWLY(
540 "NewTabPage.Snippets.NumArticlesFetched", 553 "NewTabPage.Snippets.NumArticlesFetched",
541 std::min(fetched_category.snippets.size(), 554 std::min(fetched_category.snippets.size(),
542 static_cast<size_t>(kMaxSnippetCount + 1))); 555 static_cast<size_t>(kMaxSnippetCount + 1)));
543 } 556 }
544 ReplaceSnippets(category, std::move(fetched_category.snippets)); 557 ReplaceSnippets(category, std::move(fetched_category.snippets));
545 } 558 }
546 } 559 }
547 560
561 // We might have gotten new categories (or updated the titles of existing
562 // ones), so update the pref.
563 StoreCategoriesToPrefs();
564
548 for (const auto& item : categories_) { 565 for (const auto& item : categories_) {
549 Category category = item.first; 566 Category category = item.first;
550 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE); 567 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE);
551 } 568 }
552 569
553 // TODO(sfiera): equivalent metrics for non-articles. 570 // TODO(sfiera): equivalent metrics for non-articles.
554 const CategoryContent& content = categories_[articles_category_]; 571 const CategoryContent& content = categories_[articles_category_];
555 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticles", 572 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticles",
556 content.snippets.size()); 573 content.snippets.size());
557 if (content.snippets.empty() && !content.dismissed.empty()) { 574 if (content.snippets.empty() && !content.dismissed.empty()) {
558 UMA_HISTOGRAM_COUNTS("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded", 575 UMA_HISTOGRAM_COUNTS("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded",
559 content.dismissed.size()); 576 content.dismissed.size());
560 } 577 }
561 578
562 // TODO(sfiera): notify only when a category changed above. 579 // TODO(sfiera): notify only when a category changed above.
563 NotifyNewSuggestions(); 580 NotifyNewSuggestions();
564 581
565 // Reschedule after a successful fetch. This resets all currently scheduled 582 // Reschedule after a successful fetch. This resets all currently scheduled
566 // fetches, to make sure the fallback interval triggers only if no wifi fetch 583 // fetches, to make sure the fallback interval triggers only if no wifi fetch
567 // succeeded, and also that we don't do a background fetch immediately after 584 // succeeded, and also that we don't do a background fetch immediately after
568 // a user-initiated one. 585 // a user-initiated one.
569 if (fetched_categories) 586 if (fetched_categories)
570 RescheduleFetching(true); 587 RescheduleFetching(true);
571 } 588 }
572 589
573 void NTPSnippetsService::ArchiveSnippets(Category category, 590 void NTPSnippetsService::ArchiveSnippets(Category category,
574 NTPSnippet::PtrVector* to_archive) { 591 NTPSnippet::PtrVector* to_archive) {
575 CategoryContent* content = &categories_[category]; 592 CategoryContent* content = &categories_[category];
576 593
577 // TODO(sfiera): handle DB for non-articles too. 594 // TODO(treib): Handle DB for non-articles too. crbug.com/653476
578 if (category == articles_category_) { 595 if (category == articles_category_) {
579 database_->DeleteSnippets(GetSnippetIDVector(*to_archive)); 596 database_->DeleteSnippets(GetSnippetIDVector(*to_archive));
580 // Do not delete the thumbnail images as they are still handy on open NTPs. 597 // Do not delete the thumbnail images as they are still handy on open NTPs.
581 } 598 }
582 599
583 // Archive previous snippets - move them at the beginning of the list. 600 // Archive previous snippets - move them at the beginning of the list.
584 content->archived.insert(content->archived.begin(), 601 content->archived.insert(content->archived.begin(),
585 std::make_move_iterator(to_archive->begin()), 602 std::make_move_iterator(to_archive->begin()),
586 std::make_move_iterator(to_archive->end())); 603 std::make_move_iterator(to_archive->end()));
587 Compact(to_archive); 604 Compact(to_archive);
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
685 if (content->snippets.empty() && content->dismissed.empty() && 702 if (content->snippets.empty() && content->dismissed.empty() &&
686 category != articles_category_ && !content->provided_by_server) { 703 category != articles_category_ && !content->provided_by_server) {
687 categories_to_erase.push_back(category); 704 categories_to_erase.push_back(category);
688 } 705 }
689 } 706 }
690 707
691 for (Category category : categories_to_erase) { 708 for (Category category : categories_to_erase) {
692 UpdateCategoryStatus(category, CategoryStatus::NOT_PROVIDED); 709 UpdateCategoryStatus(category, CategoryStatus::NOT_PROVIDED);
693 categories_.erase(category); 710 categories_.erase(category);
694 } 711 }
712
713 StoreCategoriesToPrefs();
695 } 714 }
696 715
697 void NTPSnippetsService::ClearOrphanedImages() { 716 void NTPSnippetsService::ClearOrphanedImages() {
698 auto alive_snippets = base::MakeUnique<std::set<std::string>>(); 717 auto alive_snippets = base::MakeUnique<std::set<std::string>>();
699 for (const auto& snippet_ptr : categories_[articles_category_].snippets) { 718 for (const auto& snippet_ptr : categories_[articles_category_].snippets) {
700 alive_snippets->insert(snippet_ptr->id()); 719 alive_snippets->insert(snippet_ptr->id());
701 } 720 }
702 for (const auto& snippet_ptr : categories_[articles_category_].dismissed) { 721 for (const auto& snippet_ptr : categories_[articles_category_].dismissed) {
703 alive_snippets->insert(snippet_ptr->id()); 722 alive_snippets->insert(snippet_ptr->id());
704 } 723 }
(...skipping 14 matching lines...) Expand all
719 UpdateCategoryStatus(category, CategoryStatus::NOT_PROVIDED); 738 UpdateCategoryStatus(category, CategoryStatus::NOT_PROVIDED);
720 739
721 // Remove the category entirely; it may or may not reappear. 740 // Remove the category entirely; it may or may not reappear.
722 if (category != articles_category_) 741 if (category != articles_category_)
723 categories_to_erase.push_back(category); 742 categories_to_erase.push_back(category);
724 } 743 }
725 744
726 for (Category category : categories_to_erase) { 745 for (Category category : categories_to_erase) {
727 categories_.erase(category); 746 categories_.erase(category);
728 } 747 }
748
749 StoreCategoriesToPrefs();
729 } 750 }
730 751
731 void NTPSnippetsService::OnSnippetImageFetchedFromDatabase( 752 void NTPSnippetsService::OnSnippetImageFetchedFromDatabase(
732 const ImageFetchedCallback& callback, 753 const ImageFetchedCallback& callback,
733 const ContentSuggestion::ID& suggestion_id, 754 const ContentSuggestion::ID& suggestion_id,
734 std::string data) { 755 std::string data) {
735 // |image_decoder_| is null in tests. 756 // |image_decoder_| is null in tests.
736 if (image_decoder_ && !data.empty()) { 757 if (image_decoder_ && !data.empty()) {
737 image_decoder_->DecodeImage( 758 image_decoder_->DecodeImage(
738 data, base::Bind(&NTPSnippetsService::OnSnippetImageDecodedFromDatabase, 759 data, base::Bind(&NTPSnippetsService::OnSnippetImageDecodedFromDatabase,
(...skipping 16 matching lines...) Expand all
755 776
756 // If decoding the image failed, delete the DB entry. 777 // If decoding the image failed, delete the DB entry.
757 database_->DeleteImage(suggestion_id.id_within_category()); 778 database_->DeleteImage(suggestion_id.id_within_category());
758 779
759 FetchSnippetImageFromNetwork(suggestion_id, callback); 780 FetchSnippetImageFromNetwork(suggestion_id, callback);
760 } 781 }
761 782
762 void NTPSnippetsService::FetchSnippetImageFromNetwork( 783 void NTPSnippetsService::FetchSnippetImageFromNetwork(
763 const ContentSuggestion::ID& suggestion_id, 784 const ContentSuggestion::ID& suggestion_id,
764 const ImageFetchedCallback& callback) { 785 const ImageFetchedCallback& callback) {
765 if (categories_.find(suggestion_id.category()) == categories_.end()) { 786 if (!base::ContainsKey(categories_, suggestion_id.category())) {
766 OnSnippetImageDecodedFromNetwork( 787 OnSnippetImageDecodedFromNetwork(
767 callback, suggestion_id.id_within_category(), gfx::Image()); 788 callback, suggestion_id.id_within_category(), gfx::Image());
768 return; 789 return;
769 } 790 }
770 791
771 GURL image_url = FindSnippetImageUrl(suggestion_id); 792 GURL image_url = FindSnippetImageUrl(suggestion_id);
772 793
773 if (image_url.is_empty() || 794 if (image_url.is_empty() ||
774 !thumbnail_requests_throttler_.DemandQuotaForRequest( 795 !thumbnail_requests_throttler_.DemandQuotaForRequest(
775 /*interactive_request=*/true)) { 796 /*interactive_request=*/true)) {
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
960 } 981 }
961 982
962 DVLOG(1) << "NotifyNewSuggestions(): " << result.size() 983 DVLOG(1) << "NotifyNewSuggestions(): " << result.size()
963 << " items in category " << category; 984 << " items in category " << category;
964 observer()->OnNewSuggestions(this, category, std::move(result)); 985 observer()->OnNewSuggestions(this, category, std::move(result));
965 } 986 }
966 } 987 }
967 988
968 void NTPSnippetsService::UpdateCategoryStatus(Category category, 989 void NTPSnippetsService::UpdateCategoryStatus(Category category,
969 CategoryStatus status) { 990 CategoryStatus status) {
970 DCHECK(categories_.find(category) != categories_.end()); 991 DCHECK(base::ContainsKey(categories_, category));
971 CategoryContent& content = categories_[category]; 992 CategoryContent& content = categories_[category];
972 if (status == content.status) 993 if (status == content.status)
973 return; 994 return;
974 995
975 DVLOG(1) << "UpdateCategoryStatus(): " << category.id() << ": " 996 DVLOG(1) << "UpdateCategoryStatus(): " << category.id() << ": "
976 << static_cast<int>(content.status) << " -> " 997 << static_cast<int>(content.status) << " -> "
977 << static_cast<int>(status); 998 << static_cast<int>(status);
978 content.status = status; 999 content.status = status;
979 observer()->OnCategoryStatusChanged(this, category, content.status); 1000 observer()->OnCategoryStatusChanged(this, category, content.status);
980 } 1001 }
(...skipping 19 matching lines...) Expand all
1000 archived.begin(), archived.end(), 1021 archived.begin(), archived.end(),
1001 [&id_within_category](const std::unique_ptr<NTPSnippet>& snippet) { 1022 [&id_within_category](const std::unique_ptr<NTPSnippet>& snippet) {
1002 return snippet->id() == id_within_category; 1023 return snippet->id() == id_within_category;
1003 }); 1024 });
1004 if (it != archived.end()) 1025 if (it != archived.end())
1005 return it->get(); 1026 return it->get();
1006 1027
1007 return nullptr; 1028 return nullptr;
1008 } 1029 }
1009 1030
1031 namespace {
1032
1033 const char kCategoryContentId[] = "id";
Bernhard Bauer 2016/10/07 16:21:27 Hm... Shouldn't the anonymous namespace go to the
Marc Treib 2016/10/10 08:33:43 That's certainly the common thing, though the styl
1034 const char kCategoryContentTitle[] = "title";
1035 const char kCategoryContentProvidedByServer[] = "provided_by_server";
1036
1037 } // namespace
1038
1039 void NTPSnippetsService::RestoreCategoriesFromPrefs() {
1040 // This must only be called at startup, before there are any categories.
1041 DCHECK(categories_.empty());
1042
1043 const base::ListValue* list =
1044 pref_service_->GetList(prefs::kRemoteSuggestionCategories);
1045 for (const std::unique_ptr<base::Value>& entry : *list) {
1046 const base::DictionaryValue* dict = nullptr;
1047 if (!entry->GetAsDictionary(&dict)) {
1048 DLOG(WARNING) << "Invalid category pref value: " << *entry;
1049 continue;
1050 }
1051 int id = 0;
1052 if (!dict->GetInteger(kCategoryContentId, &id)) {
1053 DLOG(WARNING) << "Invalid category pref value, missing '"
1054 << kCategoryContentId << "': " << *entry;
1055 continue;
1056 }
1057 base::string16 title;
1058 if (!dict->GetString(kCategoryContentTitle, &title)) {
1059 DLOG(WARNING) << "Invalid category pref value, missing '"
1060 << kCategoryContentTitle << "': " << *entry;
1061 continue;
1062 }
1063 bool provided_by_server = false;
1064 if (!dict->GetBoolean(kCategoryContentProvidedByServer,
1065 &provided_by_server)) {
1066 DLOG(WARNING) << "Invalid category pref value, missing '"
1067 << kCategoryContentProvidedByServer << "': " << *entry;
1068 continue;
1069 }
1070
1071 Category category = category_factory()->FromIDValue(id);
1072 categories_[category] = CategoryContent();
1073 categories_[category].localized_title = title;
1074 categories_[category].provided_by_server = provided_by_server;
1075 }
1076 }
1077
1078 void NTPSnippetsService::StoreCategoriesToPrefs() {
1079 // Collect all the CategoryContents.
1080 std::vector<std::pair<Category, const CategoryContent*>> to_store;
1081 for (const auto& entry : categories_)
1082 to_store.emplace_back(entry.first, &entry.second);
1083 // Sort them into the proper category order.
1084 std::sort(to_store.begin(), to_store.end(),
1085 [this](const std::pair<Category, const CategoryContent*>& left,
1086 const std::pair<Category, const CategoryContent*>& right) {
1087 return category_factory()->CompareCategories(left.first,
1088 right.first);
1089 });
1090 // Convert the relevant info into a base::ListValue for storage.
1091 base::ListValue list;
1092 for (const auto& entry : to_store) {
1093 Category category = entry.first;
1094 const base::string16& title = entry.second->localized_title;
1095 bool provided_by_server = entry.second->provided_by_server;
1096 auto dict = base::MakeUnique<base::DictionaryValue>();
1097 dict->SetInteger(kCategoryContentId, category.id());
1098 dict->SetString(kCategoryContentTitle, title);
1099 dict->SetBoolean(kCategoryContentProvidedByServer, provided_by_server);
1100 list.Append(std::move(dict));
1101 }
1102 // Finally, store the result in the pref service.
1103 pref_service_->Set(prefs::kRemoteSuggestionCategories, list);
1104 }
1105
1010 NTPSnippetsService::CategoryContent::CategoryContent() = default; 1106 NTPSnippetsService::CategoryContent::CategoryContent() = default;
1011 NTPSnippetsService::CategoryContent::CategoryContent(CategoryContent&&) = 1107 NTPSnippetsService::CategoryContent::CategoryContent(CategoryContent&&) =
1012 default; 1108 default;
1013 NTPSnippetsService::CategoryContent::~CategoryContent() = default; 1109 NTPSnippetsService::CategoryContent::~CategoryContent() = default;
1014 NTPSnippetsService::CategoryContent& NTPSnippetsService::CategoryContent:: 1110 NTPSnippetsService::CategoryContent& NTPSnippetsService::CategoryContent::
1015 operator=(CategoryContent&&) = default; 1111 operator=(CategoryContent&&) = default;
1016 1112
1017 } // namespace ntp_snippets 1113 } // namespace ntp_snippets
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698