Index: components/ntp_snippets/ntp_snippets_service.cc |
diff --git a/components/ntp_snippets/ntp_snippets_service.cc b/components/ntp_snippets/ntp_snippets_service.cc |
index 1f0909290671e5b99efe52cb9d8630e2a48f1b50..99546b7f2e9ad352b9b6e6c091d5804633cb1c11 100644 |
--- a/components/ntp_snippets/ntp_snippets_service.cc |
+++ b/components/ntp_snippets/ntp_snippets_service.cc |
@@ -202,10 +202,9 @@ |
std::unique_ptr<NTPSnippetsStatusService> status_service) |
: ContentSuggestionsProvider(observer, category_factory), |
state_(State::NOT_INITED), |
+ category_status_(CategoryStatus::INITIALIZING), |
pref_service_(pref_service), |
suggestions_service_(suggestions_service), |
- articles_category_( |
- category_factory->FromKnownCategory(KnownCategories::ARTICLES)), |
application_language_code_(application_language_code), |
scheduler_(scheduler), |
history_service_observer_(this), |
@@ -216,16 +215,14 @@ |
snippets_status_service_(std::move(status_service)), |
fetch_after_load_(false), |
nuke_after_load_(false), |
+ provided_category_( |
+ category_factory->FromKnownCategory(KnownCategories::ARTICLES)), |
thumbnail_requests_throttler_( |
pref_service, |
RequestThrottler::RequestType::CONTENT_SUGGESTION_THUMBNAIL) { |
- // Articles category always exists; others will be added as needed. |
- categories_[articles_category_] = CategoryContent(); |
- observer->OnCategoryStatusChanged(this, articles_category_, |
- categories_[articles_category_].status); |
+ observer->OnCategoryStatusChanged(this, provided_category_, category_status_); |
if (database_->IsErrorState()) { |
- EnterState(State::ERROR_OCCURRED); |
- UpdateAllCategoryStatus(CategoryStatus::LOADING_ERROR); |
+ EnterState(State::ERROR_OCCURRED, CategoryStatus::LOADING_ERROR); |
return; |
} |
@@ -265,19 +262,12 @@ |
if (!ready()) |
return; |
- // Empty categories are marked as loading; others are unchanged. |
- for (const auto& item : categories_) { |
- Category category = item.first; |
- const CategoryContent& content = item.second; |
- if (content.snippets.empty()) |
- UpdateCategoryStatus(category, CategoryStatus::AVAILABLE_LOADING); |
- } |
+ if (snippets_.empty()) |
+ UpdateCategoryStatus(CategoryStatus::AVAILABLE_LOADING); |
std::set<std::string> excluded_ids; |
- for (const auto& item : categories_) { |
- const CategoryContent& content = item.second; |
- for (const auto& snippet : content.dismissed) |
- excluded_ids.insert(snippet->id()); |
+ for (const auto& snippet : dismissed_snippets_) { |
+ excluded_ids.insert(snippet->id()); |
} |
snippets_fetcher_->FetchSnippetsFromHosts(hosts, application_language_code_, |
excluded_ids, kMaxSnippetCount, |
@@ -300,13 +290,11 @@ |
} |
CategoryStatus NTPSnippetsService::GetCategoryStatus(Category category) { |
- DCHECK(categories_.find(category) != categories_.end()); |
- return categories_[category].status; |
+ DCHECK(category.IsKnownCategory(KnownCategories::ARTICLES)); |
+ return category_status_; |
} |
CategoryInfo NTPSnippetsService::GetCategoryInfo(Category category) { |
- DCHECK(categories_.find(category) != categories_.end()); |
- // TODO(sfiera): pass back titles for server categories. |
return CategoryInfo( |
l10n_util::GetStringUTF16(IDS_NTP_ARTICLE_SUGGESTIONS_SECTION_HEADER), |
ContentSuggestionsCardLayout::FULL_CARD, |
@@ -318,27 +306,23 @@ |
if (!ready()) |
return; |
- Category category = GetCategoryFromUniqueID(suggestion_id); |
std::string snippet_id = GetWithinCategoryIDFromUniqueID(suggestion_id); |
- DCHECK(categories_.find(category) != categories_.end()); |
- |
- CategoryContent* content = &categories_[category]; |
auto it = |
- std::find_if(content->snippets.begin(), content->snippets.end(), |
+ std::find_if(snippets_.begin(), snippets_.end(), |
[&snippet_id](const std::unique_ptr<NTPSnippet>& snippet) { |
return snippet->id() == snippet_id; |
}); |
- if (it == content->snippets.end()) |
+ if (it == snippets_.end()) |
return; |
(*it)->set_dismissed(true); |
database_->SaveSnippet(**it); |
- database_->DeleteImage(snippet_id); |
- |
- content->dismissed.push_back(std::move(*it)); |
- content->snippets.erase(it); |
+ database_->DeleteImage((*it)->id()); |
+ |
+ dismissed_snippets_.push_back(std::move(*it)); |
+ snippets_.erase(it); |
} |
void NTPSnippetsService::FetchSuggestionImage( |
@@ -348,22 +332,19 @@ |
database_->LoadImage( |
snippet_id, |
base::Bind(&NTPSnippetsService::OnSnippetImageFetchedFromDatabase, |
- base::Unretained(this), callback, suggestion_id)); |
+ base::Unretained(this), callback, snippet_id)); |
} |
void NTPSnippetsService::ClearCachedSuggestions(Category category) { |
+ DCHECK_EQ(category, provided_category_); |
if (!initialized()) |
return; |
- if (categories_.find(category) == categories_.end()) |
- return; |
- CategoryContent* content = &categories_[category]; |
- if (content->snippets.empty()) |
- return; |
- |
- if (category == articles_category_) |
- database_->DeleteSnippets(content->snippets); |
- content->snippets.clear(); |
+ if (snippets_.empty()) |
+ return; |
+ |
+ database_->DeleteSnippets(snippets_); |
+ snippets_.clear(); |
NotifyNewSuggestions(); |
} |
@@ -371,15 +352,14 @@ |
void NTPSnippetsService::GetDismissedSuggestionsForDebugging( |
Category category, |
const DismissedSuggestionsCallback& callback) { |
- DCHECK(categories_.find(category) != categories_.end()); |
- |
+ DCHECK_EQ(category, provided_category_); |
std::vector<ContentSuggestion> result; |
- const CategoryContent& content = categories_[category]; |
- for (const std::unique_ptr<NTPSnippet>& snippet : content.dismissed) { |
+ for (const std::unique_ptr<NTPSnippet>& snippet : dismissed_snippets_) { |
if (!snippet->is_complete()) |
continue; |
- ContentSuggestion suggestion(MakeUniqueID(category, snippet->id()), |
- snippet->best_source().url); |
+ ContentSuggestion suggestion( |
+ MakeUniqueID(provided_category_, snippet->id()), |
+ snippet->best_source().url); |
suggestion.set_amp_url(snippet->best_source().amp_url); |
suggestion.set_title(base::UTF8ToUTF16(snippet->title())); |
suggestion.set_snippet_text(base::UTF8ToUTF16(snippet->snippet())); |
@@ -394,18 +374,15 @@ |
void NTPSnippetsService::ClearDismissedSuggestionsForDebugging( |
Category category) { |
- DCHECK(categories_.find(category) != categories_.end()); |
- |
+ DCHECK_EQ(category, provided_category_); |
if (!initialized()) |
return; |
- CategoryContent* content = &categories_[category]; |
- if (content->dismissed.empty()) |
- return; |
- |
- if (category == articles_category_) |
- database_->DeleteSnippets(content->dismissed); |
- content->dismissed.clear(); |
+ if (dismissed_snippets_.empty()) |
+ return; |
+ |
+ database_->DeleteSnippets(dismissed_snippets_); |
+ dismissed_snippets_.clear(); |
} |
std::set<std::string> NTPSnippetsService::GetSuggestionsHosts() const { |
@@ -449,27 +426,18 @@ |
} |
// image_fetcher::ImageFetcherDelegate implementation. |
-void NTPSnippetsService::OnImageDataFetched(const std::string& suggestion_id, |
+void NTPSnippetsService::OnImageDataFetched(const std::string& snippet_id, |
const std::string& image_data) { |
if (image_data.empty()) |
return; |
- Category category = GetCategoryFromUniqueID(suggestion_id); |
- std::string snippet_id = GetWithinCategoryIDFromUniqueID(suggestion_id); |
- |
- auto category_it = categories_.find(category); |
- if (category_it == categories_.end()) |
- return; |
- |
- const CategoryContent& content = category_it->second; |
- |
// Only save the image if the corresponding snippet still exists. |
auto it = |
- std::find_if(content.snippets.begin(), content.snippets.end(), |
+ std::find_if(snippets_.begin(), snippets_.end(), |
[&snippet_id](const std::unique_ptr<NTPSnippet>& snippet) { |
return snippet->id() == snippet_id; |
}); |
- if (it == content.snippets.end()) |
+ if (it == snippets_.end()) |
return; |
database_->SaveImage(snippet_id, image_data); |
@@ -479,19 +447,15 @@ |
if (state_ == State::ERROR_OCCURRED) |
return; |
DCHECK(state_ == State::NOT_INITED); |
- DCHECK(categories_.size() == 1); // Only articles category, so far. |
- DCHECK(categories_.find(articles_category_) != categories_.end()); |
- |
- // TODO(sfiera): support non-article categories in database. |
- CategoryContent* content = &categories_[articles_category_]; |
+ DCHECK(snippets_.empty()); |
+ DCHECK(dismissed_snippets_.empty()); |
for (std::unique_ptr<NTPSnippet>& snippet : snippets) { |
if (snippet->is_dismissed()) |
- content->dismissed.emplace_back(std::move(snippet)); |
+ dismissed_snippets_.emplace_back(std::move(snippet)); |
else |
- content->snippets.emplace_back(std::move(snippet)); |
- } |
- |
- std::sort(content->snippets.begin(), content->snippets.end(), |
+ snippets_.emplace_back(std::move(snippet)); |
+ } |
+ std::sort(snippets_.begin(), snippets_.end(), |
[](const std::unique_ptr<NTPSnippet>& lhs, |
const std::unique_ptr<NTPSnippet>& rhs) { |
return lhs->score() > rhs->score(); |
@@ -502,8 +466,7 @@ |
} |
void NTPSnippetsService::OnDatabaseError() { |
- EnterState(State::ERROR_OCCURRED); |
- UpdateAllCategoryStatus(CategoryStatus::LOADING_ERROR); |
+ EnterState(State::ERROR_OCCURRED, CategoryStatus::LOADING_ERROR); |
} |
// TODO(dgn): name clash between content suggestions and suggestions hosts. |
@@ -517,21 +480,15 @@ |
return; |
// Remove existing snippets that aren't in the suggestions anymore. |
- // |
// TODO(treib,maybelle): If there is another source with an allowed host, |
// then we should fall back to that. |
- // |
- // TODO(sfiera): determine when non-article categories should restrict hosts, |
- // and apply the same logic to them here. Maybe never? |
- // |
// First, move them over into |to_delete|. |
- CategoryContent* content = &categories_[articles_category_]; |
NTPSnippet::PtrVector to_delete; |
- for (std::unique_ptr<NTPSnippet>& snippet : content->snippets) { |
+ for (std::unique_ptr<NTPSnippet>& snippet : snippets_) { |
if (!hosts.count(snippet->best_source().url.host())) |
to_delete.emplace_back(std::move(snippet)); |
} |
- Compact(&content->snippets); |
+ Compact(&snippets_); |
// Then delete the removed snippets from the database. |
database_->DeleteSnippets(to_delete); |
@@ -550,76 +507,48 @@ |
if (!ready()) |
return; |
- for (auto& item : categories_) { |
- CategoryContent* content = &item.second; |
- content->provided_by_server = false; |
- } |
- |
- // If snippets were fetched successfully, update our |categories_| from each |
- // category provided by the server. |
- if (snippets) { |
- for (std::pair<const Category, NTPSnippet::PtrVector>& item : *snippets) { |
- Category category = item.first; |
- NTPSnippet::PtrVector& new_snippets = item.second; |
- |
- DCHECK_LE(snippets->size(), static_cast<size_t>(kMaxSnippetCount)); |
- // TODO(sfiera): histograms for server categories. |
- // Sparse histogram used because the number of snippets is small (bound by |
- // kMaxSnippetCount). |
- if (category == articles_category_) { |
- UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticlesFetched", |
- new_snippets.size()); |
- } |
- |
- MergeSnippets(category, std::move(new_snippets)); |
- |
- // If there are more snippets than we want to show, delete the extra ones. |
- CategoryContent* content = &categories_[category]; |
- content->provided_by_server = true; |
- if (content->snippets.size() > kMaxSnippetCount) { |
- NTPSnippet::PtrVector to_delete( |
- std::make_move_iterator(content->snippets.begin() + |
- kMaxSnippetCount), |
- std::make_move_iterator(content->snippets.end())); |
- content->snippets.resize(kMaxSnippetCount); |
- if (category == articles_category_) |
- database_->DeleteSnippets(to_delete); |
- } |
- } |
- } |
- |
- // Trigger expiration. This probably won't expire any current snippets (old |
- // ones should have already been expired by the timer, and new ones shouldn't |
- // have expired yet), but it will update the timer for the next run. |
+ DCHECK(category_status_ == CategoryStatus::AVAILABLE || |
+ category_status_ == CategoryStatus::AVAILABLE_LOADING); |
+ |
+ // TODO(sfiera): support more than just the provided_category_ ARTICLES. |
+ if (snippets && (snippets->find(provided_category_) != snippets->end())) { |
+ // Sparse histogram used because the number of snippets is small (bound by |
+ // kMaxSnippetCount). |
+ DCHECK_LE(snippets->size(), static_cast<size_t>(kMaxSnippetCount)); |
+ UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticlesFetched", |
+ (*snippets)[provided_category_].size()); |
+ MergeSnippets(std::move((*snippets)[provided_category_])); |
+ } |
+ |
ClearExpiredSnippets(); |
- for (const auto& item : categories_) { |
- Category category = item.first; |
- UpdateCategoryStatus(category, CategoryStatus::AVAILABLE); |
- } |
- |
- // TODO(sfiera): equivalent metrics for non-articles. |
- const CategoryContent& content = categories_[articles_category_]; |
+ // If there are more snippets than we want to show, delete the extra ones. |
+ if (snippets_.size() > kMaxSnippetCount) { |
+ NTPSnippet::PtrVector to_delete( |
+ std::make_move_iterator(snippets_.begin() + kMaxSnippetCount), |
+ std::make_move_iterator(snippets_.end())); |
+ snippets_.resize(kMaxSnippetCount); |
+ database_->DeleteSnippets(to_delete); |
+ } |
+ |
UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticles", |
- content.snippets.size()); |
- if (content.snippets.empty() && !content.dismissed.empty()) { |
+ snippets_.size()); |
+ if (snippets_.empty() && !dismissed_snippets_.empty()) { |
UMA_HISTOGRAM_COUNTS("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded", |
- content.dismissed.size()); |
- } |
- |
- // TODO(sfiera): notify only when a category changed above. |
+ dismissed_snippets_.size()); |
+ } |
+ |
+ UpdateCategoryStatus(CategoryStatus::AVAILABLE); |
NotifyNewSuggestions(); |
} |
-void NTPSnippetsService::MergeSnippets(Category category, |
- NTPSnippet::PtrVector new_snippets) { |
+void NTPSnippetsService::MergeSnippets(NTPSnippet::PtrVector new_snippets) { |
DCHECK(ready()); |
- CategoryContent* content = &categories_[category]; |
// Remove new snippets that we already have, or that have been dismissed. |
std::set<std::string> old_snippet_ids; |
- InsertAllIDs(content->dismissed, &old_snippet_ids); |
- InsertAllIDs(content->snippets, &old_snippet_ids); |
+ InsertAllIDs(dismissed_snippets_, &old_snippet_ids); |
+ InsertAllIDs(snippets_, &old_snippet_ids); |
new_snippets.erase( |
std::remove_if( |
new_snippets.begin(), new_snippets.end(), |
@@ -667,15 +596,13 @@ |
} |
} |
- // Save new articles to the DB. |
- // TODO(sfiera): save non-articles to DB too. |
- if (category == articles_category_) |
- database_->SaveSnippets(new_snippets); |
+ // Save the new snippets to the DB. |
+ database_->SaveSnippets(new_snippets); |
// Insert the new snippets at the front. |
- content->snippets.insert(content->snippets.begin(), |
- std::make_move_iterator(new_snippets.begin()), |
- std::make_move_iterator(new_snippets.end())); |
+ snippets_.insert(snippets_.begin(), |
+ std::make_move_iterator(new_snippets.begin()), |
+ std::make_move_iterator(new_snippets.end())); |
} |
std::set<std::string> NTPSnippetsService::GetSnippetHostsFromPrefs() const { |
@@ -699,156 +626,106 @@ |
} |
void NTPSnippetsService::ClearExpiredSnippets() { |
- std::vector<Category> categories_to_erase; |
- |
- const base::Time expiry = base::Time::Now(); |
+ base::Time expiry = base::Time::Now(); |
+ |
+ // Move expired snippets over into |to_delete|. |
+ NTPSnippet::PtrVector to_delete; |
+ for (std::unique_ptr<NTPSnippet>& snippet : snippets_) { |
+ if (snippet->expiry_date() <= expiry) |
+ to_delete.emplace_back(std::move(snippet)); |
+ } |
+ Compact(&snippets_); |
+ |
+ // Move expired dismissed snippets over into |to_delete| as well. |
+ for (std::unique_ptr<NTPSnippet>& snippet : dismissed_snippets_) { |
+ if (snippet->expiry_date() <= expiry) |
+ to_delete.emplace_back(std::move(snippet)); |
+ } |
+ Compact(&dismissed_snippets_); |
+ |
+ // Finally, actually delete the removed snippets from the DB. |
+ database_->DeleteSnippets(to_delete); |
+ |
+ // If there are any snippets left, schedule a timer for the next expiry. |
+ if (snippets_.empty() && dismissed_snippets_.empty()) |
+ return; |
+ |
base::Time next_expiry = base::Time::Max(); |
- |
- for (auto& item : categories_) { |
- Category category = item.first; |
- CategoryContent* content = &item.second; |
- |
- // Move expired snippets over into |to_delete|. |
- NTPSnippet::PtrVector to_delete; |
- for (std::unique_ptr<NTPSnippet>& snippet : content->snippets) { |
- if (snippet->expiry_date() <= expiry) |
- to_delete.emplace_back(std::move(snippet)); |
- } |
- Compact(&content->snippets); |
- |
- // Move expired dismissed snippets over into |to_delete| as well. |
- for (std::unique_ptr<NTPSnippet>& snippet : content->dismissed) { |
- if (snippet->expiry_date() <= expiry) |
- to_delete.emplace_back(std::move(snippet)); |
- } |
- Compact(&content->dismissed); |
- |
- // Finally, actually delete the removed snippets from the DB. |
- if (category == articles_category_) |
- database_->DeleteSnippets(to_delete); |
- |
- if (content->snippets.empty() && content->dismissed.empty()) { |
- if ((category != articles_category_) && !content->provided_by_server) |
- categories_to_erase.push_back(category); |
- continue; |
- } |
- |
- for (const auto& snippet : content->snippets) { |
- if (snippet->expiry_date() < next_expiry) |
- next_expiry = snippet->expiry_date(); |
- } |
- for (const auto& snippet : content->dismissed) { |
- if (snippet->expiry_date() < next_expiry) |
- next_expiry = snippet->expiry_date(); |
- } |
- } |
- |
- for (Category category : categories_to_erase) { |
- UpdateCategoryStatus(category, CategoryStatus::NOT_PROVIDED); |
- categories_.erase(category); |
- } |
- |
- // Unless there are no snippets left, schedule a timer for the next expiry. |
+ for (const auto& snippet : snippets_) { |
+ if (snippet->expiry_date() < next_expiry) |
+ next_expiry = snippet->expiry_date(); |
+ } |
+ for (const auto& snippet : dismissed_snippets_) { |
+ if (snippet->expiry_date() < next_expiry) |
+ next_expiry = snippet->expiry_date(); |
+ } |
DCHECK_GT(next_expiry, expiry); |
- if (next_expiry < base::Time::Max()) { |
- expiry_timer_.Start(FROM_HERE, next_expiry - expiry, |
- base::Bind(&NTPSnippetsService::ClearExpiredSnippets, |
- base::Unretained(this))); |
- } |
+ expiry_timer_.Start(FROM_HERE, next_expiry - expiry, |
+ base::Bind(&NTPSnippetsService::ClearExpiredSnippets, |
+ base::Unretained(this))); |
} |
void NTPSnippetsService::NukeAllSnippets() { |
- std::vector<Category> categories_to_erase; |
- |
- // Empty the ARTICLES category and remove all others, since they may or may |
- // not be personalized. |
- for (const auto& item : categories_) { |
- Category category = item.first; |
- |
- ClearCachedSuggestions(category); |
- ClearDismissedSuggestionsForDebugging(category); |
- |
- if (category == articles_category_) { |
- // Temporarily enter an "explicitly disabled" state, so that any open UIs |
- // will clear the suggestions too. |
- CategoryContent& content = categories_[category]; |
- if (content.status != CategoryStatus::CATEGORY_EXPLICITLY_DISABLED) { |
- CategoryStatus old_category_status = content.status; |
- UpdateCategoryStatus(category, |
- CategoryStatus::CATEGORY_EXPLICITLY_DISABLED); |
- UpdateCategoryStatus(category, old_category_status); |
- } |
- } else { |
- // Remove other categories entirely; they may or may not reappear. |
- UpdateCategoryStatus(category, CategoryStatus::NOT_PROVIDED); |
- categories_to_erase.push_back(category); |
- } |
- } |
- |
- for (Category category : categories_to_erase) { |
- categories_.erase(category); |
+ ClearCachedSuggestions(provided_category_); |
+ ClearDismissedSuggestionsForDebugging(provided_category_); |
+ |
+ // Temporarily enter an "explicitly disabled" state, so that any open UIs |
+ // will clear the suggestions too. |
+ if (category_status_ != CategoryStatus::CATEGORY_EXPLICITLY_DISABLED) { |
+ CategoryStatus old_category_status = category_status_; |
+ UpdateCategoryStatus(CategoryStatus::CATEGORY_EXPLICITLY_DISABLED); |
+ UpdateCategoryStatus(old_category_status); |
} |
} |
void NTPSnippetsService::OnSnippetImageFetchedFromDatabase( |
const ImageFetchedCallback& callback, |
- const std::string& suggestion_id, |
+ const std::string& snippet_id, |
std::string data) { |
// |image_decoder_| is null in tests. |
if (image_decoder_ && !data.empty()) { |
image_decoder_->DecodeImage( |
std::move(data), |
base::Bind(&NTPSnippetsService::OnSnippetImageDecodedFromDatabase, |
- base::Unretained(this), callback, suggestion_id)); |
+ base::Unretained(this), callback, snippet_id)); |
return; |
} |
// Fetching from the DB failed; start a network fetch. |
- FetchSnippetImageFromNetwork(suggestion_id, callback); |
+ FetchSnippetImageFromNetwork(snippet_id, callback); |
} |
void NTPSnippetsService::OnSnippetImageDecodedFromDatabase( |
const ImageFetchedCallback& callback, |
- const std::string& suggestion_id, |
+ const std::string& snippet_id, |
const gfx::Image& image) { |
if (!image.IsEmpty()) { |
- callback.Run(suggestion_id, image); |
+ callback.Run(MakeUniqueID(provided_category_, snippet_id), image); |
return; |
} |
// If decoding the image failed, delete the DB entry. |
- std::string snippet_id = GetWithinCategoryIDFromUniqueID(suggestion_id); |
database_->DeleteImage(snippet_id); |
- FetchSnippetImageFromNetwork(suggestion_id, callback); |
+ FetchSnippetImageFromNetwork(snippet_id, callback); |
} |
void NTPSnippetsService::FetchSnippetImageFromNetwork( |
- const std::string& suggestion_id, |
+ const std::string& snippet_id, |
const ImageFetchedCallback& callback) { |
- Category category = GetCategoryFromUniqueID(suggestion_id); |
- std::string snippet_id = GetWithinCategoryIDFromUniqueID(suggestion_id); |
- |
- auto category_it = categories_.find(category); |
- if (category_it == categories_.end()) { |
- OnSnippetImageDecodedFromNetwork(callback, suggestion_id, gfx::Image()); |
- return; |
- } |
- |
- const CategoryContent& content = category_it->second; |
auto it = |
- std::find_if(content.snippets.begin(), content.snippets.end(), |
+ std::find_if(snippets_.begin(), snippets_.end(), |
[&snippet_id](const std::unique_ptr<NTPSnippet>& snippet) { |
return snippet->id() == snippet_id; |
}); |
- if (it == content.snippets.end() || |
+ if (it == snippets_.end() || |
!thumbnail_requests_throttler_.DemandQuotaForRequest( |
/*interactive_request=*/true)) { |
// Return an empty image. Directly, this is never synchronous with the |
// original FetchSuggestionImage() call - an asynchronous database query has |
// happened in the meantime. |
- OnSnippetImageDecodedFromNetwork(callback, suggestion_id, gfx::Image()); |
+ OnSnippetImageDecodedFromNetwork(callback, snippet_id, gfx::Image()); |
return; |
} |
@@ -861,16 +738,16 @@ |
// is an ImageFetcherDelegate) and then also |
// OnSnippetImageDecodedFromNetwork() after the raw data gets decoded. |
image_fetcher_->StartOrQueueNetworkRequest( |
- suggestion_id, snippet.salient_image_url(), |
+ snippet.id(), snippet.salient_image_url(), |
base::Bind(&NTPSnippetsService::OnSnippetImageDecodedFromNetwork, |
base::Unretained(this), callback)); |
} |
void NTPSnippetsService::OnSnippetImageDecodedFromNetwork( |
const ImageFetchedCallback& callback, |
- const std::string& suggestion_id, |
+ const std::string& snippet_id, |
const gfx::Image& image) { |
- callback.Run(suggestion_id, image); |
+ callback.Run(MakeUniqueID(provided_category_, snippet_id), image); |
} |
void NTPSnippetsService::EnterStateEnabled(bool fetch_snippets) { |
@@ -879,10 +756,8 @@ |
// FetchSnippets should set the status to |AVAILABLE_LOADING| if relevant, |
// otherwise we transition to |AVAILABLE| here. |
- if (categories_[articles_category_].status != |
- CategoryStatus::AVAILABLE_LOADING) { |
- UpdateCategoryStatus(articles_category_, CategoryStatus::AVAILABLE); |
- } |
+ if (category_status_ != CategoryStatus::AVAILABLE_LOADING) |
+ UpdateCategoryStatus(CategoryStatus::AVAILABLE); |
// If host restrictions are enabled, register for host list updates. |
// |suggestions_service_| can be null in tests. |
@@ -896,23 +771,8 @@ |
} |
void NTPSnippetsService::EnterStateDisabled() { |
- std::vector<Category> categories_to_erase; |
- |
- // Empty the ARTICLES category and remove all others, since they may or may |
- // not be personalized. |
- for (const auto& item : categories_) { |
- Category category = item.first; |
- ClearCachedSuggestions(category); |
- ClearDismissedSuggestionsForDebugging(category); |
- if (category != articles_category_) { |
- UpdateCategoryStatus(category, CategoryStatus::NOT_PROVIDED); |
- categories_to_erase.push_back(category); |
- } |
- } |
- |
- for (Category category : categories_to_erase) { |
- categories_.erase(category); |
- } |
+ ClearCachedSuggestions(provided_category_); |
+ ClearDismissedSuggestionsForDebugging(provided_category_); |
expiry_timer_.Stop(); |
suggestions_service_subscription_.reset(); |
@@ -957,22 +817,22 @@ |
switch (disabled_reason) { |
case DisabledReason::NONE: |
// Do not change the status. That will be done in EnterStateEnabled() |
- EnterState(State::READY); |
+ EnterState(State::READY, category_status_); |
break; |
case DisabledReason::EXPLICITLY_DISABLED: |
- EnterState(State::DISABLED); |
- UpdateAllCategoryStatus(CategoryStatus::CATEGORY_EXPLICITLY_DISABLED); |
+ EnterState(State::DISABLED, CategoryStatus::CATEGORY_EXPLICITLY_DISABLED); |
break; |
case DisabledReason::SIGNED_OUT: |
- EnterState(State::DISABLED); |
- UpdateAllCategoryStatus(CategoryStatus::SIGNED_OUT); |
+ EnterState(State::DISABLED, CategoryStatus::SIGNED_OUT); |
break; |
} |
} |
-void NTPSnippetsService::EnterState(State state) { |
+void NTPSnippetsService::EnterState(State state, CategoryStatus status) { |
+ UpdateCategoryStatus(status); |
+ |
if (state == state_) |
return; |
@@ -985,8 +845,7 @@ |
case State::READY: { |
DCHECK(state_ == State::NOT_INITED || state_ == State::DISABLED); |
- bool fetch_snippets = |
- categories_[articles_category_].snippets.empty() || fetch_after_load_; |
+ bool fetch_snippets = snippets_.empty() || fetch_after_load_; |
DVLOG(1) << "Entering state: READY"; |
state_ = State::READY; |
fetch_after_load_ = false; |
@@ -1011,61 +870,32 @@ |
} |
void NTPSnippetsService::NotifyNewSuggestions() { |
- for (const auto& item : categories_) { |
- Category category = item.first; |
- const CategoryContent& content = item.second; |
- |
- std::vector<ContentSuggestion> result; |
- for (const std::unique_ptr<NTPSnippet>& snippet : content.snippets) { |
- // TODO(sfiera): if a snippet is not going to be displayed, move it |
- // directly to content.dismissed on fetch. Otherwise, we might prune |
- // other snippets to get down to kMaxSnippetCount, only to hide one of the |
- // incomplete ones we kept. |
- if (!snippet->is_complete()) |
- continue; |
- ContentSuggestion suggestion(MakeUniqueID(category, snippet->id()), |
- snippet->best_source().url); |
- suggestion.set_amp_url(snippet->best_source().amp_url); |
- suggestion.set_title(base::UTF8ToUTF16(snippet->title())); |
- suggestion.set_snippet_text(base::UTF8ToUTF16(snippet->snippet())); |
- suggestion.set_publish_date(snippet->publish_date()); |
- suggestion.set_publisher_name( |
- base::UTF8ToUTF16(snippet->best_source().publisher_name)); |
- suggestion.set_score(snippet->score()); |
- result.emplace_back(std::move(suggestion)); |
- } |
- |
- DVLOG(1) << "NotifyNewSuggestions(): " << result.size() |
- << " items in category " << category; |
- observer()->OnNewSuggestions(this, category, std::move(result)); |
- } |
-} |
- |
-void NTPSnippetsService::UpdateCategoryStatus(Category category, |
- CategoryStatus status) { |
- DCHECK(categories_.find(category) != categories_.end()); |
- CategoryContent& content = categories_[category]; |
- if (status == content.status) |
- return; |
- |
- DVLOG(1) << "UpdateCategoryStatus(): " << category.id() << ": " |
- << static_cast<int>(content.status) << " -> " |
- << static_cast<int>(status); |
- content.status = status; |
- observer()->OnCategoryStatusChanged(this, category, content.status); |
-} |
- |
-void NTPSnippetsService::UpdateAllCategoryStatus(CategoryStatus status) { |
- for (const auto& category : categories_) { |
- UpdateCategoryStatus(category.first, status); |
- } |
-} |
- |
-NTPSnippetsService::CategoryContent::CategoryContent() = default; |
-NTPSnippetsService::CategoryContent::CategoryContent(CategoryContent&&) = |
- default; |
-NTPSnippetsService::CategoryContent::~CategoryContent() = default; |
-NTPSnippetsService::CategoryContent& NTPSnippetsService::CategoryContent:: |
-operator=(CategoryContent&&) = default; |
+ std::vector<ContentSuggestion> result; |
+ for (const std::unique_ptr<NTPSnippet>& snippet : snippets_) { |
+ if (!snippet->is_complete()) |
+ continue; |
+ ContentSuggestion suggestion( |
+ MakeUniqueID(provided_category_, snippet->id()), |
+ snippet->best_source().url); |
+ suggestion.set_amp_url(snippet->best_source().amp_url); |
+ suggestion.set_title(base::UTF8ToUTF16(snippet->title())); |
+ suggestion.set_snippet_text(base::UTF8ToUTF16(snippet->snippet())); |
+ suggestion.set_publish_date(snippet->publish_date()); |
+ suggestion.set_publisher_name( |
+ base::UTF8ToUTF16(snippet->best_source().publisher_name)); |
+ suggestion.set_score(snippet->score()); |
+ result.emplace_back(std::move(suggestion)); |
+ } |
+ observer()->OnNewSuggestions(this, provided_category_, std::move(result)); |
+} |
+ |
+void NTPSnippetsService::UpdateCategoryStatus(CategoryStatus status) { |
+ if (status == category_status_) |
+ return; |
+ |
+ category_status_ = status; |
+ observer()->OnCategoryStatusChanged(this, provided_category_, |
+ category_status_); |
+} |
} // namespace ntp_snippets |