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

Side by Side Diff: components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc

Issue 2560783002: [NTP::PhysicalWeb] Implement suggestion dismissal. (Closed)
Patch Set: rebase and bauerb@ nit. Created 4 years 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 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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/physical_web_pages/physical_web_page_suggestio ns_provider.h" 5 #include "components/ntp_snippets/physical_web_pages/physical_web_page_suggestio ns_provider.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <memory> 8 #include <memory>
9 #include <set>
9 #include <string> 10 #include <string>
10 #include <utility> 11 #include <utility>
11 12
12 #include "base/bind.h" 13 #include "base/bind.h"
13 #include "base/strings/string_number_conversions.h" 14 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_util.h" 15 #include "base/strings/string_util.h"
15 #include "base/strings/utf_string_conversions.h" 16 #include "base/strings/utf_string_conversions.h"
16 #include "base/threading/thread_task_runner_handle.h" 17 #include "base/threading/thread_task_runner_handle.h"
18 #include "components/ntp_snippets/pref_names.h"
19 #include "components/ntp_snippets/pref_util.h"
20 #include "components/prefs/pref_registry_simple.h"
21 #include "components/prefs/pref_service.h"
17 #include "grit/components_strings.h" 22 #include "grit/components_strings.h"
18 #include "ui/base/l10n/l10n_util.h" 23 #include "ui/base/l10n/l10n_util.h"
19 #include "ui/gfx/image/image.h" 24 #include "ui/gfx/image/image.h"
20 #include "url/gurl.h" 25 #include "url/gurl.h"
21 26
22 using base::DictionaryValue; 27 using base::DictionaryValue;
23 using base::ListValue; 28 using base::ListValue;
24 using base::Value; 29 using base::Value;
25 30
26 namespace ntp_snippets { 31 namespace ntp_snippets {
27 32
28 namespace { 33 namespace {
29 34
30 const size_t kMaxSuggestionsCount = 10; 35 const size_t kMaxSuggestionsCount = 10;
31 36
32 std::string GetPageId(const DictionaryValue& page_dictionary) { 37 std::string GetPageId(const DictionaryValue& page_dictionary) {
33 std::string raw_resolved_url; 38 std::string raw_resolved_url;
34 if (!page_dictionary.GetString(physical_web::kResolvedUrlKey, 39 if (!page_dictionary.GetString(physical_web::kResolvedUrlKey,
35 &raw_resolved_url)) { 40 &raw_resolved_url)) {
36 LOG(DFATAL) << physical_web::kResolvedUrlKey << " field is missing."; 41 LOG(DFATAL) << physical_web::kResolvedUrlKey << " field is missing.";
37 } 42 }
38 return raw_resolved_url; 43 return raw_resolved_url;
39 } 44 }
40 45
41 } // namespace 46 } // namespace
42 47
43 PhysicalWebPageSuggestionsProvider::PhysicalWebPageSuggestionsProvider( 48 PhysicalWebPageSuggestionsProvider::PhysicalWebPageSuggestionsProvider(
44 ContentSuggestionsProvider::Observer* observer, 49 ContentSuggestionsProvider::Observer* observer,
45 CategoryFactory* category_factory, 50 CategoryFactory* category_factory,
46 physical_web::PhysicalWebDataSource* physical_web_data_source) 51 physical_web::PhysicalWebDataSource* physical_web_data_source,
52 PrefService* pref_service)
47 : ContentSuggestionsProvider(observer, category_factory), 53 : ContentSuggestionsProvider(observer, category_factory),
48 category_status_(CategoryStatus::AVAILABLE), 54 category_status_(CategoryStatus::AVAILABLE),
49 provided_category_(category_factory->FromKnownCategory( 55 provided_category_(category_factory->FromKnownCategory(
50 KnownCategories::PHYSICAL_WEB_PAGES)), 56 KnownCategories::PHYSICAL_WEB_PAGES)),
51 physical_web_data_source_(physical_web_data_source) { 57 physical_web_data_source_(physical_web_data_source),
58 pref_service_(pref_service) {
52 observer->OnCategoryStatusChanged(this, provided_category_, category_status_); 59 observer->OnCategoryStatusChanged(this, provided_category_, category_status_);
53 physical_web_data_source_->RegisterListener(this); 60 physical_web_data_source_->RegisterListener(this);
54 // TODO(vitaliii): Rewrite initial fetch once crbug.com/667754 is resolved. 61 // TODO(vitaliii): Rewrite initial fetch once crbug.com/667754 is resolved.
55 FetchPhysicalWebPages(); 62 FetchPhysicalWebPages();
56 } 63 }
57 64
58 PhysicalWebPageSuggestionsProvider::~PhysicalWebPageSuggestionsProvider() { 65 PhysicalWebPageSuggestionsProvider::~PhysicalWebPageSuggestionsProvider() {
59 physical_web_data_source_->UnregisterListener(this); 66 physical_web_data_source_->UnregisterListener(this);
60 } 67 }
61 68
(...skipping 11 matching lines...) Expand all
73 ContentSuggestionsCardLayout::FULL_CARD, 80 ContentSuggestionsCardLayout::FULL_CARD,
74 /*has_more_action=*/true, 81 /*has_more_action=*/true,
75 /*has_reload_action=*/false, 82 /*has_reload_action=*/false,
76 /*has_view_all_action=*/false, 83 /*has_view_all_action=*/false,
77 /*show_if_empty=*/false, 84 /*show_if_empty=*/false,
78 l10n_util::GetStringUTF16(IDS_NTP_SUGGESTIONS_SECTION_EMPTY)); 85 l10n_util::GetStringUTF16(IDS_NTP_SUGGESTIONS_SECTION_EMPTY));
79 } 86 }
80 87
81 void PhysicalWebPageSuggestionsProvider::DismissSuggestion( 88 void PhysicalWebPageSuggestionsProvider::DismissSuggestion(
82 const ContentSuggestion::ID& suggestion_id) { 89 const ContentSuggestion::ID& suggestion_id) {
83 // TODO(vitaliii): Implement this and then 90 DCHECK_EQ(provided_category_, suggestion_id.category());
84 // ClearDismissedSuggestionsForDebugging. (crbug.com/667766) 91 std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs();
92 dismissed_ids.insert(suggestion_id.id_within_category());
93 StoreDismissedIDsToPrefs(dismissed_ids);
85 } 94 }
86 95
87 void PhysicalWebPageSuggestionsProvider::FetchSuggestionImage( 96 void PhysicalWebPageSuggestionsProvider::FetchSuggestionImage(
88 const ContentSuggestion::ID& suggestion_id, 97 const ContentSuggestion::ID& suggestion_id,
89 const ImageFetchedCallback& callback) { 98 const ImageFetchedCallback& callback) {
90 // TODO(vitaliii): Implement. (crbug.com/667765) 99 // TODO(vitaliii): Implement. (crbug.com/667765)
91 base::ThreadTaskRunnerHandle::Get()->PostTask( 100 base::ThreadTaskRunnerHandle::Get()->PostTask(
92 FROM_HERE, base::Bind(callback, gfx::Image())); 101 FROM_HERE, base::Bind(callback, gfx::Image()));
93 } 102 }
94 103
(...skipping 17 matching lines...) Expand all
112 } 121 }
113 122
114 void PhysicalWebPageSuggestionsProvider::ClearCachedSuggestions( 123 void PhysicalWebPageSuggestionsProvider::ClearCachedSuggestions(
115 Category category) { 124 Category category) {
116 // Ignored 125 // Ignored
117 } 126 }
118 127
119 void PhysicalWebPageSuggestionsProvider::GetDismissedSuggestionsForDebugging( 128 void PhysicalWebPageSuggestionsProvider::GetDismissedSuggestionsForDebugging(
120 Category category, 129 Category category,
121 const DismissedSuggestionsCallback& callback) { 130 const DismissedSuggestionsCallback& callback) {
122 // Not implemented. 131 DCHECK_EQ(provided_category_, category);
123 callback.Run(std::vector<ContentSuggestion>()); 132 std::unique_ptr<ListValue> page_values =
133 physical_web_data_source_->GetMetadata();
134 const std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs();
135 std::vector<ContentSuggestion> suggestions;
136 for (const std::unique_ptr<Value>& page_value : *page_values) {
137 const DictionaryValue* page_dictionary;
138 if (!page_value->GetAsDictionary(&page_dictionary)) {
139 LOG(DFATAL) << "Physical Web page is not a dictionary.";
140 continue;
141 }
142
143 if (dismissed_ids.count(GetPageId(*page_dictionary))) {
144 suggestions.push_back(ConvertPhysicalWebPage(*page_dictionary));
145 }
146 }
147
148 callback.Run(std::move(suggestions));
124 } 149 }
125 150
126 void PhysicalWebPageSuggestionsProvider::ClearDismissedSuggestionsForDebugging( 151 void PhysicalWebPageSuggestionsProvider::ClearDismissedSuggestionsForDebugging(
127 Category category) { 152 Category category) {
128 // TODO(vitaliii): Implement when dismissed suggestions are supported. 153 DCHECK_EQ(provided_category_, category);
154 StoreDismissedIDsToPrefs(std::set<std::string>());
155 FetchPhysicalWebPages();
156 }
157
158 // static
159 void PhysicalWebPageSuggestionsProvider::RegisterProfilePrefs(
160 PrefRegistrySimple* registry) {
161 registry->RegisterListPref(prefs::kDismissedPhysicalWebPageSuggestions);
129 } 162 }
130 163
131 //////////////////////////////////////////////////////////////////////////////// 164 ////////////////////////////////////////////////////////////////////////////////
132 // Private methods 165 // Private methods
133 166
134 void PhysicalWebPageSuggestionsProvider::NotifyStatusChanged( 167 void PhysicalWebPageSuggestionsProvider::NotifyStatusChanged(
135 CategoryStatus new_status) { 168 CategoryStatus new_status) {
136 if (category_status_ == new_status) { 169 if (category_status_ == new_status) {
137 return; 170 return;
138 } 171 }
139 category_status_ = new_status; 172 category_status_ = new_status;
140 observer()->OnCategoryStatusChanged(this, provided_category_, new_status); 173 observer()->OnCategoryStatusChanged(this, provided_category_, new_status);
141 } 174 }
142 175
143 void PhysicalWebPageSuggestionsProvider::FetchPhysicalWebPages() { 176 void PhysicalWebPageSuggestionsProvider::FetchPhysicalWebPages() {
144 DCHECK_EQ(CategoryStatus::AVAILABLE, category_status_); 177 DCHECK_EQ(CategoryStatus::AVAILABLE, category_status_);
145 observer()->OnNewSuggestions(this, provided_category_, 178 observer()->OnNewSuggestions(this, provided_category_,
146 GetMostRecentPhysicalWebPagesWithFilter( 179 GetMostRecentPhysicalWebPagesWithFilter(
147 kMaxSuggestionsCount, 180 kMaxSuggestionsCount,
148 /*excluded_ids=*/std::set<std::string>())); 181 /*excluded_ids=*/std::set<std::string>()));
149 } 182 }
150 183
151 std::vector<ContentSuggestion> 184 std::vector<ContentSuggestion>
152 PhysicalWebPageSuggestionsProvider::GetMostRecentPhysicalWebPagesWithFilter( 185 PhysicalWebPageSuggestionsProvider::GetMostRecentPhysicalWebPagesWithFilter(
153 int max_quantity, 186 int max_quantity,
154 const std::set<std::string>& excluded_ids) { 187 const std::set<std::string>& excluded_ids) {
155 std::unique_ptr<ListValue> page_values = 188 std::unique_ptr<ListValue> page_values =
156 physical_web_data_source_->GetMetadata(); 189 physical_web_data_source_->GetMetadata();
157 190
191 // These is to filter out dismissed suggestions and at the same time prune the
192 // dismissed IDs list removing nonavailable pages (this is need since some
193 // OnLost() calls may have been missed).
194 const std::set<std::string> old_dismissed_ids = ReadDismissedIDsFromPrefs();
195 std::set<std::string> new_dismissed_ids;
158 std::vector<const DictionaryValue*> page_dictionaries; 196 std::vector<const DictionaryValue*> page_dictionaries;
159 for (const std::unique_ptr<Value>& page_value : *page_values) { 197 for (const std::unique_ptr<Value>& page_value : *page_values) {
160 const DictionaryValue* page_dictionary; 198 const DictionaryValue* page_dictionary;
161 if (!page_value->GetAsDictionary(&page_dictionary)) { 199 if (!page_value->GetAsDictionary(&page_dictionary)) {
162 LOG(DFATAL) << "Physical Web page is not a dictionary."; 200 LOG(DFATAL) << "Physical Web page is not a dictionary.";
163 continue; 201 continue;
164 } 202 }
165 if (!excluded_ids.count(GetPageId(*page_dictionary))) { 203
204 const std::string page_id = GetPageId(*page_dictionary);
205 if (!excluded_ids.count(page_id) && !old_dismissed_ids.count(page_id)) {
166 page_dictionaries.push_back(page_dictionary); 206 page_dictionaries.push_back(page_dictionary);
167 } 207 }
208
209 if (old_dismissed_ids.count(page_id)) {
210 new_dismissed_ids.insert(page_id);
211 }
168 } 212 }
169 213
214 if (old_dismissed_ids.size() != new_dismissed_ids.size()) {
215 StoreDismissedIDsToPrefs(new_dismissed_ids);
216 }
217
170 std::sort(page_dictionaries.begin(), page_dictionaries.end(), 218 std::sort(page_dictionaries.begin(), page_dictionaries.end(),
171 [](const DictionaryValue* left, const DictionaryValue* right) { 219 [](const DictionaryValue* left, const DictionaryValue* right) {
172 double left_distance, right_distance; 220 double left_distance, right_distance;
173 bool success = left->GetDouble(physical_web::kDistanceEstimateKey, 221 bool success = left->GetDouble(physical_web::kDistanceEstimateKey,
174 &left_distance); 222 &left_distance);
175 success = right->GetDouble(physical_web::kDistanceEstimateKey, 223 success = right->GetDouble(physical_web::kDistanceEstimateKey,
176 &right_distance) && 224 &right_distance) &&
177 success; 225 success;
178 if (!success) { 226 if (!success) {
179 LOG(DFATAL) << "Distance field is missing."; 227 LOG(DFATAL) << "Distance field is missing.";
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
222 suggestion.set_snippet_text(base::UTF8ToUTF16(description)); 270 suggestion.set_snippet_text(base::UTF8ToUTF16(description));
223 return suggestion; 271 return suggestion;
224 } 272 }
225 273
226 // PhysicalWebListener implementation. 274 // PhysicalWebListener implementation.
227 void PhysicalWebPageSuggestionsProvider::OnFound(const std::string& url) { 275 void PhysicalWebPageSuggestionsProvider::OnFound(const std::string& url) {
228 FetchPhysicalWebPages(); 276 FetchPhysicalWebPages();
229 } 277 }
230 278
231 void PhysicalWebPageSuggestionsProvider::OnLost(const std::string& url) { 279 void PhysicalWebPageSuggestionsProvider::OnLost(const std::string& url) {
232 // TODO(vitaliii): Do not refetch, but just update the current state. 280 InvalidateSuggestion(url);
233 FetchPhysicalWebPages();
234 } 281 }
235 282
236 void PhysicalWebPageSuggestionsProvider::OnDistanceChanged( 283 void PhysicalWebPageSuggestionsProvider::OnDistanceChanged(
237 const std::string& url, 284 const std::string& url,
238 double distance_estimate) { 285 double distance_estimate) {
239 FetchPhysicalWebPages(); 286 FetchPhysicalWebPages();
240 } 287 }
241 288
289 void PhysicalWebPageSuggestionsProvider::InvalidateSuggestion(
290 const std::string& page_id) {
291 observer()->OnSuggestionInvalidated(
292 this, ContentSuggestion::ID(provided_category_, page_id));
293
294 // Remove |page_id| from dismissed suggestions, if present.
295 std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs();
296 auto it = dismissed_ids.find(page_id);
297 if (it != dismissed_ids.end()) {
298 dismissed_ids.erase(it);
299 StoreDismissedIDsToPrefs(dismissed_ids);
300 }
301 }
302
303 std::set<std::string>
304 PhysicalWebPageSuggestionsProvider::ReadDismissedIDsFromPrefs() const {
305 return prefs::ReadDismissedIDsFromPrefs(
306 *pref_service_, prefs::kDismissedPhysicalWebPageSuggestions);
307 }
308
309 void PhysicalWebPageSuggestionsProvider::StoreDismissedIDsToPrefs(
310 const std::set<std::string>& dismissed_ids) {
311 prefs::StoreDismissedIDsToPrefs(pref_service_,
312 prefs::kDismissedPhysicalWebPageSuggestions,
313 dismissed_ids);
314 }
315
242 } // namespace ntp_snippets 316 } // namespace ntp_snippets
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698