Chromium Code Reviews| OLD | NEW |
|---|---|
| 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> | |
| 8 #include <string> | |
| 7 #include <utility> | 9 #include <utility> |
| 8 | 10 |
| 9 #include "base/bind.h" | 11 #include "base/bind.h" |
| 10 #include "base/strings/string_number_conversions.h" | 12 #include "base/strings/string_number_conversions.h" |
| 11 #include "base/strings/string_util.h" | 13 #include "base/strings/string_util.h" |
| 12 #include "base/strings/utf_string_conversions.h" | 14 #include "base/strings/utf_string_conversions.h" |
| 13 #include "base/threading/thread_task_runner_handle.h" | 15 #include "base/threading/thread_task_runner_handle.h" |
| 14 #include "grit/components_strings.h" | 16 #include "grit/components_strings.h" |
| 15 #include "ui/base/l10n/l10n_util.h" | 17 #include "ui/base/l10n/l10n_util.h" |
| 16 #include "ui/gfx/image/image.h" | 18 #include "ui/gfx/image/image.h" |
| 19 #include "url/gurl.h" | |
| 20 | |
| 21 using base::Value; | |
|
Marc Treib
2016/11/23 09:47:52
The "base::" is spelled out for ListValue and Dict
vitaliii
2016/11/23 14:16:52
Done.
| |
| 17 | 22 |
| 18 namespace ntp_snippets { | 23 namespace ntp_snippets { |
| 19 | 24 |
| 20 namespace { | 25 namespace { |
| 21 | 26 |
| 22 const size_t kMaxSuggestionsCount = 10; | 27 const size_t kMaxSuggestionsCount = 10; |
| 23 | 28 |
| 24 } // namespace | 29 } // namespace |
| 25 | 30 |
| 26 // TODO(vitaliii): remove when Physical Web C++ interface is provided. | |
| 27 UrlInfo::UrlInfo() = default; | |
| 28 UrlInfo::~UrlInfo() = default; | |
| 29 UrlInfo::UrlInfo(const UrlInfo& other) = default; | |
| 30 | |
| 31 PhysicalWebPageSuggestionsProvider::PhysicalWebPageSuggestionsProvider( | 31 PhysicalWebPageSuggestionsProvider::PhysicalWebPageSuggestionsProvider( |
| 32 ContentSuggestionsProvider::Observer* observer, | 32 ContentSuggestionsProvider::Observer* observer, |
| 33 CategoryFactory* category_factory) | 33 CategoryFactory* category_factory, |
| 34 PhysicalWebDataSource* physical_web_data_source) | |
| 34 : ContentSuggestionsProvider(observer, category_factory), | 35 : ContentSuggestionsProvider(observer, category_factory), |
| 35 category_status_(CategoryStatus::AVAILABLE_LOADING), | 36 category_status_(CategoryStatus::AVAILABLE_LOADING), |
|
Marc Treib
2016/11/23 09:47:52
The status is immediately set to AVAILABLE in Fetc
vitaliii
2016/11/23 14:16:53
Done.
| |
| 36 provided_category_(category_factory->FromKnownCategory( | 37 provided_category_(category_factory->FromKnownCategory( |
| 37 KnownCategories::PHYSICAL_WEB_PAGES)) { | 38 KnownCategories::PHYSICAL_WEB_PAGES)), |
| 39 physical_web_data_source_(physical_web_data_source) { | |
| 38 observer->OnCategoryStatusChanged(this, provided_category_, category_status_); | 40 observer->OnCategoryStatusChanged(this, provided_category_, category_status_); |
| 41 physical_web_data_source_->RegisterListener(this); | |
| 42 // TODO(vitaliii): Rewrite initial fetch once crbug.com/667754 is resolved. | |
| 43 FetchPhysicalWebPages(); | |
| 39 } | 44 } |
| 40 | 45 |
| 41 PhysicalWebPageSuggestionsProvider::~PhysicalWebPageSuggestionsProvider() = | 46 PhysicalWebPageSuggestionsProvider::~PhysicalWebPageSuggestionsProvider() { |
| 42 default; | 47 physical_web_data_source_->UnregisterListener(this); |
| 43 | |
| 44 void PhysicalWebPageSuggestionsProvider::OnDisplayableUrlsChanged( | |
| 45 const std::vector<UrlInfo>& urls) { | |
| 46 NotifyStatusChanged(CategoryStatus::AVAILABLE); | |
| 47 std::vector<ContentSuggestion> suggestions; | |
| 48 | |
| 49 for (const UrlInfo& url_info : urls) { | |
| 50 if (suggestions.size() >= kMaxSuggestionsCount) { | |
| 51 break; | |
| 52 } | |
| 53 | |
| 54 ContentSuggestion suggestion(provided_category_, url_info.site_url.spec(), | |
| 55 url_info.site_url); | |
| 56 | |
| 57 suggestion.set_title(base::UTF8ToUTF16(url_info.title)); | |
| 58 suggestion.set_snippet_text(base::UTF8ToUTF16(url_info.description)); | |
| 59 suggestion.set_publish_date(url_info.scan_time); | |
| 60 suggestion.set_publisher_name(base::UTF8ToUTF16(url_info.site_url.host())); | |
| 61 suggestions.push_back(std::move(suggestion)); | |
| 62 } | |
| 63 | |
| 64 observer()->OnNewSuggestions(this, provided_category_, | |
| 65 std::move(suggestions)); | |
| 66 } | 48 } |
| 67 | 49 |
| 68 CategoryStatus PhysicalWebPageSuggestionsProvider::GetCategoryStatus( | 50 CategoryStatus PhysicalWebPageSuggestionsProvider::GetCategoryStatus( |
| 69 Category category) { | 51 Category category) { |
| 70 return category_status_; | 52 return category_status_; |
| 71 } | 53 } |
| 72 | 54 |
| 73 CategoryInfo PhysicalWebPageSuggestionsProvider::GetCategoryInfo( | 55 CategoryInfo PhysicalWebPageSuggestionsProvider::GetCategoryInfo( |
| 74 Category category) { | 56 Category category) { |
| 75 // TODO(vitaliii): Use the proper strings once they've been agreed on. | 57 // TODO(vitaliii): Use the proper string once it has been agreed on. |
| 58 // TODO(vitaliii): Use a translateable string. (crbug.com/667764) | |
| 59 // TODO(vitaliii): Implement More action. (crbug.com/667759) | |
| 76 return CategoryInfo( | 60 return CategoryInfo( |
| 77 base::ASCIIToUTF16("Physical web pages"), | 61 base::ASCIIToUTF16("Physical web pages"), |
| 78 ContentSuggestionsCardLayout::MINIMAL_CARD, | 62 ContentSuggestionsCardLayout::FULL_CARD, |
| 79 /*has_more_action=*/false, | 63 /*has_more_action=*/false, |
| 80 /*has_reload_action=*/false, | 64 /*has_reload_action=*/false, |
| 81 /*has_view_all_action=*/false, | 65 /*has_view_all_action=*/false, |
| 82 /*show_if_empty=*/false, | 66 /*show_if_empty=*/false, |
| 83 l10n_util::GetStringUTF16(IDS_NTP_SUGGESTIONS_SECTION_EMPTY)); | 67 l10n_util::GetStringUTF16(IDS_NTP_SUGGESTIONS_SECTION_EMPTY)); |
| 84 } | 68 } |
| 85 | 69 |
| 86 void PhysicalWebPageSuggestionsProvider::DismissSuggestion( | 70 void PhysicalWebPageSuggestionsProvider::DismissSuggestion( |
| 87 const ContentSuggestion::ID& suggestion_id) { | 71 const ContentSuggestion::ID& suggestion_id) { |
| 88 // TODO(vitaliii): Implement this and then | 72 // TODO(vitaliii): Implement this and then |
| 89 // ClearDismissedSuggestionsForDebugging. | 73 // ClearDismissedSuggestionsForDebugging. (crbug.com/667766) |
| 90 } | 74 } |
| 91 | 75 |
| 92 void PhysicalWebPageSuggestionsProvider::FetchSuggestionImage( | 76 void PhysicalWebPageSuggestionsProvider::FetchSuggestionImage( |
| 93 const ContentSuggestion::ID& suggestion_id, | 77 const ContentSuggestion::ID& suggestion_id, |
| 94 const ImageFetchedCallback& callback) { | 78 const ImageFetchedCallback& callback) { |
| 95 // TODO(vitaliii): Implement. | 79 // TODO(vitaliii): Implement. (crbug.com/667765) |
| 96 base::ThreadTaskRunnerHandle::Get()->PostTask( | 80 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 97 FROM_HERE, base::Bind(callback, gfx::Image())); | 81 FROM_HERE, base::Bind(callback, gfx::Image())); |
| 98 } | 82 } |
| 99 | 83 |
| 100 void PhysicalWebPageSuggestionsProvider::Fetch( | 84 void PhysicalWebPageSuggestionsProvider::Fetch( |
| 101 const Category& category, | 85 const Category& category, |
| 102 const std::set<std::string>& known_suggestion_ids, | 86 const std::set<std::string>& known_suggestion_ids, |
| 103 const FetchDoneCallback& callback) { | 87 const FetchDoneCallback& callback) { |
| 104 LOG(DFATAL) | 88 LOG(DFATAL) |
| 105 << "PhysicalWebPageSuggestionsProvider has no |Fetch| functionality!"; | 89 << "PhysicalWebPageSuggestionsProvider has no |Fetch| functionality!"; |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 131 } | 115 } |
| 132 | 116 |
| 133 void PhysicalWebPageSuggestionsProvider::ClearDismissedSuggestionsForDebugging( | 117 void PhysicalWebPageSuggestionsProvider::ClearDismissedSuggestionsForDebugging( |
| 134 Category category) { | 118 Category category) { |
| 135 // TODO(vitaliii): Implement when dismissed suggestions are supported. | 119 // TODO(vitaliii): Implement when dismissed suggestions are supported. |
| 136 } | 120 } |
| 137 | 121 |
| 138 //////////////////////////////////////////////////////////////////////////////// | 122 //////////////////////////////////////////////////////////////////////////////// |
| 139 // Private methods | 123 // Private methods |
| 140 | 124 |
| 141 // Updates the |category_status_| and notifies the |observer_|, if necessary. | |
| 142 void PhysicalWebPageSuggestionsProvider::NotifyStatusChanged( | 125 void PhysicalWebPageSuggestionsProvider::NotifyStatusChanged( |
| 143 CategoryStatus new_status) { | 126 CategoryStatus new_status) { |
| 144 if (category_status_ == new_status) { | 127 if (category_status_ == new_status) { |
| 145 return; | 128 return; |
| 146 } | 129 } |
| 147 category_status_ = new_status; | 130 category_status_ = new_status; |
| 148 observer()->OnCategoryStatusChanged(this, provided_category_, new_status); | 131 observer()->OnCategoryStatusChanged(this, provided_category_, new_status); |
| 149 } | 132 } |
| 150 | 133 |
| 134 void PhysicalWebPageSuggestionsProvider::FetchPhysicalWebPages() { | |
| 135 NotifyStatusChanged(CategoryStatus::AVAILABLE); | |
| 136 std::unique_ptr<base::ListValue> page_values = | |
| 137 physical_web_data_source_->GetMetadata(); | |
| 138 | |
| 139 std::vector<const base::DictionaryValue*> page_dictionaries; | |
| 140 for (const std::unique_ptr<Value>& page_value : *page_values) { | |
| 141 const base::DictionaryValue* page_dictionary; | |
| 142 bool success = page_value->GetAsDictionary(&page_dictionary); | |
| 143 DCHECK(success); | |
|
Marc Treib
2016/11/23 09:47:52
Are all the DCHECKs in this method really DCHECKs?
vitaliii
2016/11/23 14:16:52
We definitely can live without a title or a descri
Marc Treib
2016/11/23 14:22:45
Per the style guide, DCHECKs are treated as assert
vitaliii
2016/11/23 16:00:54
Done.
| |
| 144 page_dictionaries.push_back(page_dictionary); | |
| 145 } | |
| 146 | |
| 147 std::sort(page_dictionaries.begin(), page_dictionaries.end(), | |
| 148 [](const base::DictionaryValue* left, | |
| 149 const base::DictionaryValue* right) { | |
| 150 double left_distance, right_distance; | |
| 151 bool success = left->GetDouble(kPhysicalWebDistanceEstimateKey, | |
| 152 &left_distance); | |
| 153 DCHECK(success); | |
| 154 success = right->GetDouble(kPhysicalWebDistanceEstimateKey, | |
| 155 &right_distance); | |
| 156 DCHECK(success); | |
| 157 return left_distance < right_distance; | |
| 158 }); | |
| 159 | |
| 160 std::vector<ContentSuggestion> suggestions; | |
| 161 for (const base::DictionaryValue* page_dictionary : page_dictionaries) { | |
| 162 suggestions.push_back(ConvertPhysicalWebPage(page_dictionary)); | |
| 163 if (suggestions.size() == kMaxSuggestionsCount) | |
| 164 break; | |
|
Marc Treib
2016/11/23 09:47:52
nit: braces now :)
vitaliii
2016/11/23 14:16:52
Done.
This might have been written before we decid
| |
| 165 } | |
| 166 | |
| 167 observer()->OnNewSuggestions(this, provided_category_, | |
| 168 std::move(suggestions)); | |
| 169 } | |
| 170 | |
| 171 ContentSuggestion PhysicalWebPageSuggestionsProvider::ConvertPhysicalWebPage( | |
| 172 const base::DictionaryValue* page) const { | |
| 173 bool success; | |
| 174 std::string scanned_url; | |
| 175 success = page->GetString(kPhysicalWebScannedUrlKey, &scanned_url); | |
|
Marc Treib
2016/11/23 09:47:52
Oh wow, they have global constants without a names
vitaliii
2016/11/23 14:16:52
Acknowledged.
| |
| 176 DCHECK(success); | |
| 177 int scan_timestamp; | |
| 178 success = page->GetInteger(kPhysicalWebScanTimestampKey, &scan_timestamp); | |
| 179 DCHECK(success); | |
| 180 std::string raw_resolved_url; | |
| 181 success = page->GetString(kPhysicalWebResolvedUrlKey, &raw_resolved_url); | |
| 182 DCHECK(success); | |
| 183 std::string title; | |
| 184 success = page->GetString(kPhysicalWebTitleKey, &title); | |
| 185 DCHECK(success); | |
| 186 std::string description; | |
| 187 success = page->GetString(kPhysicalWebDescriptionKey, &description); | |
| 188 DCHECK(success); | |
| 189 | |
| 190 const GURL resolved_url(raw_resolved_url); | |
| 191 ContentSuggestion suggestion(provided_category_, scanned_url, resolved_url); | |
| 192 suggestion.set_title(base::UTF8ToUTF16(title)); | |
| 193 // TODO(vitaliii): Set the time properly once the proper value is provided | |
| 194 // (see crbug.com/667722). | |
| 195 suggestion.set_publish_date( | |
| 196 base::Time::FromTimeT(static_cast<time_t>(scan_timestamp))); | |
| 197 DCHECK(base::IsStringUTF8(resolved_url.host())); | |
|
Marc Treib
2016/11/23 09:47:52
Isn't this guaranteed anyway if the GURL parsed wi
vitaliii
2016/11/23 14:16:52
Done.
You are right, "... the host, path, etc. wil
| |
| 198 suggestion.set_publisher_name(base::UTF8ToUTF16(resolved_url.host())); | |
| 199 DCHECK(base::IsStringUTF8(description)); | |
| 200 suggestion.set_snippet_text(base::UTF8ToUTF16(description)); | |
| 201 return suggestion; | |
| 202 } | |
| 203 | |
| 204 // PhysicalWebListener implementation. | |
| 205 void PhysicalWebPageSuggestionsProvider::OnFound(const std::string& url) { | |
| 206 FetchPhysicalWebPages(); | |
| 207 } | |
| 208 void PhysicalWebPageSuggestionsProvider::OnLost(const std::string& url) { | |
| 209 // TODO(vitaliii): Do not refetch, but just update the current state. | |
| 210 FetchPhysicalWebPages(); | |
| 211 } | |
| 212 void PhysicalWebPageSuggestionsProvider::OnDistanceChanged( | |
|
Marc Treib
2016/11/23 09:47:52
nit: empty lines between method implementations
vitaliii
2016/11/23 14:16:52
Done.
| |
| 213 const std::string& url, | |
| 214 double distance_estimate) { | |
| 215 FetchPhysicalWebPages(); | |
| 216 } | |
| 217 | |
| 151 } // namespace ntp_snippets | 218 } // namespace ntp_snippets |
| OLD | NEW |