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/offline_pages/offline_page_suggestions_provide r.h" | 5 #include "components/ntp_snippets/offline_pages/offline_page_suggestions_provide r.h" |
| 6 | 6 |
| 7 #include <algorithm> | |
| 8 | |
| 7 #include "base/bind.h" | 9 #include "base/bind.h" |
| 8 #include "base/location.h" | 10 #include "base/location.h" |
| 9 #include "base/strings/string_number_conversions.h" | 11 #include "base/strings/string_number_conversions.h" |
| 10 #include "base/strings/utf_string_conversions.h" | 12 #include "base/strings/utf_string_conversions.h" |
| 11 #include "base/threading/thread_task_runner_handle.h" | 13 #include "base/threading/thread_task_runner_handle.h" |
| 12 #include "base/values.h" | 14 #include "base/values.h" |
| 13 #include "components/ntp_snippets/pref_names.h" | 15 #include "components/ntp_snippets/pref_names.h" |
| 16 #include "components/offline_pages/client_namespace_constants.h" | |
| 14 #include "components/prefs/pref_registry_simple.h" | 17 #include "components/prefs/pref_registry_simple.h" |
| 15 #include "components/prefs/pref_service.h" | 18 #include "components/prefs/pref_service.h" |
| 19 #include "grit/components_strings.h" | |
| 20 #include "ui/base/l10n/l10n_util.h" | |
| 16 #include "ui/gfx/image/image.h" | 21 #include "ui/gfx/image/image.h" |
| 17 | 22 |
| 18 using offline_pages::MultipleOfflinePageItemResult; | 23 using offline_pages::MultipleOfflinePageItemResult; |
| 19 using offline_pages::OfflinePageModel; | 24 using offline_pages::OfflinePageModel; |
| 20 using offline_pages::OfflinePageItem; | 25 using offline_pages::OfflinePageItem; |
| 21 | 26 |
| 22 namespace ntp_snippets { | 27 namespace ntp_snippets { |
| 23 | 28 |
| 24 namespace { | 29 namespace { |
| 25 | 30 |
| 26 const int kMaxSuggestionsCount = 5; | 31 const int kMaxSuggestionsCount = 5; |
| 27 | 32 |
| 33 struct { | |
| 34 bool operator()(const OfflinePageItem* left, | |
| 35 const OfflinePageItem* right) const { | |
| 36 return left->last_access_time > right->last_access_time; | |
| 37 } | |
| 38 } OrderByMostRecentlyVisited; | |
| 39 | |
| 28 } // namespace | 40 } // namespace |
| 29 | 41 |
| 30 OfflinePageSuggestionsProvider::OfflinePageSuggestionsProvider( | 42 OfflinePageSuggestionsProvider::OfflinePageSuggestionsProvider( |
| 43 bool recent_tabs_enabled, | |
| 44 bool downloads_enabled, | |
| 31 ContentSuggestionsProvider::Observer* observer, | 45 ContentSuggestionsProvider::Observer* observer, |
| 32 CategoryFactory* category_factory, | 46 CategoryFactory* category_factory, |
| 33 OfflinePageModel* offline_page_model, | 47 OfflinePageModel* offline_page_model, |
| 34 PrefService* pref_service) | 48 PrefService* pref_service) |
| 35 : ContentSuggestionsProvider(observer, category_factory), | 49 : ContentSuggestionsProvider(observer, category_factory), |
| 36 category_status_(CategoryStatus::AVAILABLE_LOADING), | 50 recent_tabs_status_(recent_tabs_enabled |
| 51 ? CategoryStatus::AVAILABLE_LOADING | |
| 52 : CategoryStatus::NOT_PROVIDED), | |
| 53 downloads_status_(downloads_enabled ? CategoryStatus::AVAILABLE_LOADING | |
| 54 : CategoryStatus::NOT_PROVIDED), | |
| 37 offline_page_model_(offline_page_model), | 55 offline_page_model_(offline_page_model), |
| 38 provided_category_( | 56 recent_tabs_category_( |
| 39 category_factory->FromKnownCategory(KnownCategories::OFFLINE_PAGES)), | 57 category_factory->FromKnownCategory(KnownCategories::RECENT_TABS)), |
| 40 pref_service_(pref_service) { | 58 downloads_category_( |
| 59 category_factory->FromKnownCategory(KnownCategories::DOWNLOADS)), | |
| 60 pref_service_(pref_service), | |
| 61 dismissed_recent_tab_ids_(ReadDismissedIDsFromPrefs( | |
| 62 prefs::kDismissedRecentOfflineTabSuggestions)), | |
| 63 dismissed_download_ids_( | |
| 64 ReadDismissedIDsFromPrefs(prefs::kDismissedDownloadSuggestions)) { | |
| 65 DCHECK(recent_tabs_enabled || downloads_enabled); | |
| 41 offline_page_model_->AddObserver(this); | 66 offline_page_model_->AddObserver(this); |
| 42 ReadDismissedIDsFromPrefs(); | |
| 43 FetchOfflinePages(); | 67 FetchOfflinePages(); |
| 44 } | 68 } |
| 45 | 69 |
| 46 OfflinePageSuggestionsProvider::~OfflinePageSuggestionsProvider() { | 70 OfflinePageSuggestionsProvider::~OfflinePageSuggestionsProvider() { |
| 47 offline_page_model_->RemoveObserver(this); | 71 offline_page_model_->RemoveObserver(this); |
| 48 } | 72 } |
| 49 | 73 |
| 50 // static | 74 // static |
| 51 void OfflinePageSuggestionsProvider::RegisterProfilePrefs( | 75 void OfflinePageSuggestionsProvider::RegisterProfilePrefs( |
| 52 PrefRegistrySimple* registry) { | 76 PrefRegistrySimple* registry) { |
| 53 registry->RegisterListPref(prefs::kDismissedOfflinePageSuggestions); | 77 registry->RegisterListPref(prefs::kDismissedRecentOfflineTabSuggestions); |
| 78 registry->RegisterListPref(prefs::kDismissedDownloadSuggestions); | |
| 54 } | 79 } |
| 55 | 80 |
| 56 //////////////////////////////////////////////////////////////////////////////// | 81 //////////////////////////////////////////////////////////////////////////////// |
| 57 // Private methods | 82 // Private methods |
| 58 | 83 |
| 59 std::vector<Category> OfflinePageSuggestionsProvider::GetProvidedCategories() { | 84 std::vector<Category> OfflinePageSuggestionsProvider::GetProvidedCategories() { |
| 60 return std::vector<Category>({provided_category_}); | 85 std::vector<Category> provided_categories; |
| 86 if (recent_tabs_status_ != CategoryStatus::NOT_PROVIDED) { | |
| 87 provided_categories.push_back(recent_tabs_category_); | |
| 88 } | |
| 89 if (downloads_status_ != CategoryStatus::NOT_PROVIDED) { | |
| 90 provided_categories.push_back(downloads_category_); | |
| 91 } | |
| 92 return provided_categories; | |
| 61 } | 93 } |
| 62 | 94 |
| 63 CategoryStatus OfflinePageSuggestionsProvider::GetCategoryStatus( | 95 CategoryStatus OfflinePageSuggestionsProvider::GetCategoryStatus( |
| 64 Category category) { | 96 Category category) { |
| 65 DCHECK_EQ(category, provided_category_); | 97 if (category == recent_tabs_category_) { |
| 66 return category_status_; | 98 return recent_tabs_status_; |
| 99 } else if (category == downloads_category_) { | |
|
Marc Treib
2016/08/12 09:21:14
nit: No "else" after "return"
Philipp Keck
2016/08/12 09:56:40
Done. Don't really like this rule. Now the shape o
Marc Treib
2016/08/12 10:12:53
Well, the rule is the rule... in general, I do lik
Bernhard Bauer
2016/08/12 10:28:31
Alternatively, use a switch statement?
Philipp Keck
2016/08/12 11:02:25
Yeah, but that wouldn't get rid of the code duplic
| |
| 100 return downloads_status_; | |
| 101 } else { | |
| 102 NOTREACHED() << "Unknown category " << category.id(); | |
| 103 return CategoryStatus::NOT_PROVIDED; | |
| 104 } | |
| 67 } | 105 } |
| 68 | 106 |
| 69 CategoryInfo OfflinePageSuggestionsProvider::GetCategoryInfo( | 107 CategoryInfo OfflinePageSuggestionsProvider::GetCategoryInfo( |
| 70 Category category) { | 108 Category category) { |
| 71 // TODO(pke): Use the proper string once it's agreed on. | 109 if (category == recent_tabs_category_) { |
| 72 return CategoryInfo(base::ASCIIToUTF16("Offline pages"), | 110 return CategoryInfo(l10n_util::GetStringUTF16( |
| 73 ContentSuggestionsCardLayout::MINIMAL_CARD); | 111 IDS_NTP_RECENT_TAB_SUGGESTIONS_SECTION_HEADER), |
| 112 ContentSuggestionsCardLayout::MINIMAL_CARD); | |
| 113 } else if (category == downloads_category_) { | |
|
Marc Treib
2016/08/12 09:21:14
Same here
Philipp Keck
2016/08/12 09:56:40
Done.
| |
| 114 return CategoryInfo( | |
| 115 l10n_util::GetStringUTF16(IDS_NTP_DOWNLOAD_SUGGESTIONS_SECTION_HEADER), | |
| 116 ContentSuggestionsCardLayout::MINIMAL_CARD); | |
| 117 } else { | |
| 118 NOTREACHED() << "Unknown category " << category.id(); | |
| 119 return CategoryInfo(base::string16(), | |
| 120 ContentSuggestionsCardLayout::MINIMAL_CARD); | |
| 121 } | |
| 74 } | 122 } |
| 75 | 123 |
| 76 void OfflinePageSuggestionsProvider::DismissSuggestion( | 124 void OfflinePageSuggestionsProvider::DismissSuggestion( |
| 77 const std::string& suggestion_id) { | 125 const std::string& suggestion_id) { |
| 126 Category category = GetCategoryFromUniqueID(suggestion_id); | |
| 78 std::string offline_page_id = GetWithinCategoryIDFromUniqueID(suggestion_id); | 127 std::string offline_page_id = GetWithinCategoryIDFromUniqueID(suggestion_id); |
| 79 dismissed_ids_.insert(offline_page_id); | 128 if (category == recent_tabs_category_) { |
| 80 StoreDismissedIDsToPrefs(); | 129 DCHECK_NE(recent_tabs_status_, CategoryStatus::NOT_PROVIDED); |
|
Marc Treib
2016/08/12 09:21:14
This is enforced in the ContentSuggestionsService?
Philipp Keck
2016/08/12 09:56:40
Yes, but not only:
Firstly, if the status is NOT_P
Marc Treib
2016/08/12 10:12:53
Acknowledged.
| |
| 130 dismissed_recent_tab_ids_.insert(offline_page_id); | |
| 131 StoreDismissedIDsToPrefs(prefs::kDismissedRecentOfflineTabSuggestions, | |
| 132 dismissed_recent_tab_ids_); | |
| 133 } else if (category == downloads_category_) { | |
| 134 DCHECK_NE(downloads_status_, CategoryStatus::NOT_PROVIDED); | |
| 135 dismissed_download_ids_.insert(offline_page_id); | |
| 136 StoreDismissedIDsToPrefs(prefs::kDismissedDownloadSuggestions, | |
| 137 dismissed_download_ids_); | |
| 138 } | |
|
Marc Treib
2016/08/12 09:21:14
else NOTREACHED?
Philipp Keck
2016/08/12 09:56:40
Done.
| |
| 81 } | 139 } |
| 82 | 140 |
| 83 void OfflinePageSuggestionsProvider::FetchSuggestionImage( | 141 void OfflinePageSuggestionsProvider::FetchSuggestionImage( |
| 84 const std::string& suggestion_id, | 142 const std::string& suggestion_id, |
| 85 const ImageFetchedCallback& callback) { | 143 const ImageFetchedCallback& callback) { |
| 86 // TODO(pke): Fetch proper thumbnail from OfflinePageModel once it's available | 144 // TODO(pke): Fetch proper thumbnail from OfflinePageModel once it's available |
| 87 // there. | 145 // there. |
| 88 base::ThreadTaskRunnerHandle::Get()->PostTask( | 146 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 89 FROM_HERE, base::Bind(callback, suggestion_id, gfx::Image())); | 147 FROM_HERE, base::Bind(callback, suggestion_id, gfx::Image())); |
| 90 } | 148 } |
| 91 | 149 |
| 92 void OfflinePageSuggestionsProvider::ClearCachedSuggestionsForDebugging( | 150 void OfflinePageSuggestionsProvider::ClearCachedSuggestionsForDebugging( |
| 93 Category category) { | 151 Category category) { |
| 94 DCHECK_EQ(category, provided_category_); | |
| 95 // Ignored. | 152 // Ignored. |
| 96 } | 153 } |
| 97 | 154 |
| 98 std::vector<ContentSuggestion> | 155 std::vector<ContentSuggestion> |
| 99 OfflinePageSuggestionsProvider::GetDismissedSuggestionsForDebugging( | 156 OfflinePageSuggestionsProvider::GetDismissedSuggestionsForDebugging( |
| 100 Category category) { | 157 Category category) { |
| 101 // TODO(pke): Make GetDismissedSuggestionsForDebugging asynchronous so this | 158 // TODO(pke): Make GetDismissedSuggestionsForDebugging asynchronous so this |
| 102 // can return proper values. | 159 // can return proper values. |
| 103 DCHECK_EQ(category, provided_category_); | |
| 104 std::vector<ContentSuggestion> suggestions; | 160 std::vector<ContentSuggestion> suggestions; |
| 105 for (const std::string& dismissed_id : dismissed_ids_) { | 161 std::set<std::string>* dismissed_ids = nullptr; |
|
Marc Treib
2016/08/12 09:21:14
const?
Philipp Keck
2016/08/12 09:56:40
Done.
| |
| 162 if (category == recent_tabs_category_) { | |
| 163 DCHECK_NE(recent_tabs_status_, CategoryStatus::NOT_PROVIDED); | |
| 164 dismissed_ids = &dismissed_recent_tab_ids_; | |
| 165 } else if (category == downloads_category_) { | |
| 166 DCHECK_NE(downloads_status_, CategoryStatus::NOT_PROVIDED); | |
| 167 dismissed_ids = &dismissed_download_ids_; | |
| 168 } else { | |
| 169 return suggestions; | |
|
Marc Treib
2016/08/12 09:21:14
NOTREACHED?
Philipp Keck
2016/08/12 09:56:40
Done.
| |
| 170 } | |
| 171 | |
| 172 for (const std::string& dismissed_id : *dismissed_ids) { | |
| 106 ContentSuggestion suggestion( | 173 ContentSuggestion suggestion( |
| 107 MakeUniqueID(provided_category_, dismissed_id), | 174 MakeUniqueID(category, dismissed_id), |
| 108 GURL("http://dismissed-offline-page-" + dismissed_id)); | 175 GURL("http://dismissed-offline-page-" + dismissed_id)); |
| 109 suggestion.set_title(base::UTF8ToUTF16("Title not available")); | 176 suggestion.set_title(base::UTF8ToUTF16("Title not available")); |
| 110 suggestions.push_back(std::move(suggestion)); | 177 suggestions.push_back(std::move(suggestion)); |
| 111 } | 178 } |
| 112 return suggestions; | 179 return suggestions; |
| 113 } | 180 } |
| 114 | 181 |
| 115 void OfflinePageSuggestionsProvider::ClearDismissedSuggestionsForDebugging( | 182 void OfflinePageSuggestionsProvider::ClearDismissedSuggestionsForDebugging( |
| 116 Category category) { | 183 Category category) { |
| 117 DCHECK_EQ(category, provided_category_); | 184 if (category == recent_tabs_category_) { |
| 118 dismissed_ids_.clear(); | 185 DCHECK_NE(recent_tabs_status_, CategoryStatus::NOT_PROVIDED); |
| 119 StoreDismissedIDsToPrefs(); | 186 dismissed_recent_tab_ids_.clear(); |
| 187 StoreDismissedIDsToPrefs(prefs::kDismissedRecentOfflineTabSuggestions, | |
| 188 dismissed_recent_tab_ids_); | |
| 189 } else if (category == downloads_category_) { | |
| 190 DCHECK_NE(downloads_status_, CategoryStatus::NOT_PROVIDED); | |
| 191 dismissed_download_ids_.clear(); | |
| 192 StoreDismissedIDsToPrefs(prefs::kDismissedDownloadSuggestions, | |
| 193 dismissed_download_ids_); | |
| 194 } else { | |
| 195 NOTREACHED() << "Unknown category " << category.id(); | |
| 196 } | |
| 120 FetchOfflinePages(); | 197 FetchOfflinePages(); |
| 121 } | 198 } |
| 122 | 199 |
| 123 void OfflinePageSuggestionsProvider::OfflinePageModelLoaded( | 200 void OfflinePageSuggestionsProvider::OfflinePageModelLoaded( |
| 124 OfflinePageModel* model) { | 201 OfflinePageModel* model) { |
| 125 DCHECK_EQ(offline_page_model_, model); | 202 DCHECK_EQ(offline_page_model_, model); |
| 126 } | 203 } |
| 127 | 204 |
| 128 void OfflinePageSuggestionsProvider::OfflinePageModelChanged( | 205 void OfflinePageSuggestionsProvider::OfflinePageModelChanged( |
| 129 OfflinePageModel* model) { | 206 OfflinePageModel* model) { |
| 130 DCHECK_EQ(offline_page_model_, model); | 207 DCHECK_EQ(offline_page_model_, model); |
| 131 FetchOfflinePages(); | 208 FetchOfflinePages(); |
| 132 } | 209 } |
| 133 | 210 |
| 134 void OfflinePageSuggestionsProvider::OfflinePageDeleted( | 211 void OfflinePageSuggestionsProvider::OfflinePageDeleted( |
| 135 int64_t offline_id, | 212 int64_t offline_id, |
| 136 const offline_pages::ClientId& client_id) { | 213 const offline_pages::ClientId& client_id) { |
| 137 // TODO(pke): Implement, suggestion has to be removed from UI immediately. | 214 // TODO(pke): Implement, suggestion has to be removed from UI immediately. |
| 138 } | 215 } |
| 139 | 216 |
| 140 void OfflinePageSuggestionsProvider::FetchOfflinePages() { | 217 void OfflinePageSuggestionsProvider::FetchOfflinePages() { |
| 141 offline_page_model_->GetAllPages( | 218 offline_page_model_->GetAllPages( |
| 142 base::Bind(&OfflinePageSuggestionsProvider::OnOfflinePagesLoaded, | 219 base::Bind(&OfflinePageSuggestionsProvider::OnOfflinePagesLoaded, |
| 143 base::Unretained(this))); | 220 base::Unretained(this))); |
| 144 } | 221 } |
| 145 | 222 |
| 146 void OfflinePageSuggestionsProvider::OnOfflinePagesLoaded( | 223 void OfflinePageSuggestionsProvider::OnOfflinePagesLoaded( |
| 147 const MultipleOfflinePageItemResult& result) { | 224 const MultipleOfflinePageItemResult& result) { |
| 148 NotifyStatusChanged(CategoryStatus::AVAILABLE); | 225 bool needRecentTabs = recent_tabs_status_ != CategoryStatus::NOT_PROVIDED; |
|
Marc Treib
2016/08/12 09:21:14
need_recent_tabs, need_downloads
Philipp Keck
2016/08/12 09:56:40
Done.
| |
| 226 bool needDownloads = recent_tabs_status_ != CategoryStatus::NOT_PROVIDED; | |
|
Marc Treib
2016/08/12 09:21:14
downloads_status_
Philipp Keck
2016/08/12 09:56:40
Done. Good catch. The whole code duplication isn't
Marc Treib
2016/08/12 10:12:53
The alternative would be to have getters like GetS
Philipp Keck
2016/08/12 10:22:54
I'd refactor only after the provider has grown or
| |
| 227 if (needRecentTabs) | |
| 228 NotifyStatusChanged(recent_tabs_category_, CategoryStatus::AVAILABLE); | |
|
Marc Treib
2016/08/12 09:21:14
Braces for single=line bodies or not? Either is fi
Philipp Keck
2016/08/12 09:56:40
This file is supposed to be without. Changed two i
| |
| 229 if (needDownloads) | |
| 230 NotifyStatusChanged(downloads_category_, CategoryStatus::AVAILABLE); | |
| 149 | 231 |
| 150 std::vector<ContentSuggestion> suggestions; | 232 std::vector<const OfflinePageItem*> recent_tab_items; |
| 233 std::vector<const OfflinePageItem*> download_items; | |
| 151 for (const OfflinePageItem& item : result) { | 234 for (const OfflinePageItem& item : result) { |
| 152 if (dismissed_ids_.count(base::IntToString(item.offline_id))) | 235 if (needRecentTabs && |
| 153 continue; | 236 item.client_id.name_space == offline_pages::kLastNNamespace) { |
| 154 suggestions.push_back(ConvertOfflinePage(item)); | 237 if (!dismissed_recent_tab_ids_.count(base::IntToString(item.offline_id))) |
| 155 if (suggestions.size() == kMaxSuggestionsCount) | 238 recent_tab_items.push_back(&item); |
| 156 break; | 239 } else if (needDownloads && |
| 240 item.client_id.name_space == offline_pages::kDownloadNamespace) { | |
| 241 if (!dismissed_download_ids_.count(base::IntToString(item.offline_id))) | |
| 242 download_items.push_back(&item); | |
| 243 } | |
| 157 } | 244 } |
| 158 | 245 |
| 159 observer()->OnNewSuggestions(this, provided_category_, | 246 // TODO(pke): Once we have our BookmarkModel getter and that doesn't do it |
| 160 std::move(suggestions)); | 247 // already, filter out duplicate URLs for recent tabs here. Duplicates for |
| 248 // downloads are fine. | |
| 249 | |
| 250 if (needRecentTabs) { | |
| 251 observer()->OnNewSuggestions( | |
| 252 this, recent_tabs_category_, | |
| 253 GetMostRecentlyVisited(recent_tabs_category_, &recent_tab_items)); | |
| 254 } | |
| 255 if (needDownloads) { | |
| 256 observer()->OnNewSuggestions( | |
| 257 this, downloads_category_, | |
| 258 GetMostRecentlyVisited(downloads_category_, &download_items)); | |
| 259 } | |
| 161 } | 260 } |
| 162 | 261 |
| 163 void OfflinePageSuggestionsProvider::NotifyStatusChanged( | 262 void OfflinePageSuggestionsProvider::NotifyStatusChanged( |
| 263 Category category, | |
| 164 CategoryStatus new_status) { | 264 CategoryStatus new_status) { |
| 165 if (category_status_ == new_status) | 265 if (category == recent_tabs_category_) { |
| 166 return; | 266 DCHECK_NE(recent_tabs_status_, CategoryStatus::NOT_PROVIDED); |
| 167 category_status_ = new_status; | 267 if (recent_tabs_status_ == new_status) |
| 168 | 268 return; |
| 169 observer()->OnCategoryStatusChanged(this, provided_category_, new_status); | 269 recent_tabs_status_ = new_status; |
| 270 observer()->OnCategoryStatusChanged(this, category, new_status); | |
| 271 } else if (category == downloads_category_) { | |
| 272 DCHECK_NE(downloads_status_, CategoryStatus::NOT_PROVIDED); | |
| 273 if (downloads_status_ == new_status) | |
| 274 return; | |
| 275 downloads_status_ = new_status; | |
| 276 observer()->OnCategoryStatusChanged(this, category, new_status); | |
| 277 } else { | |
| 278 NOTREACHED() << "Unknown category " << category.id(); | |
| 279 } | |
| 170 } | 280 } |
| 171 | 281 |
| 172 ContentSuggestion OfflinePageSuggestionsProvider::ConvertOfflinePage( | 282 ContentSuggestion OfflinePageSuggestionsProvider::ConvertOfflinePage( |
| 283 Category category, | |
| 173 const OfflinePageItem& offline_page) const { | 284 const OfflinePageItem& offline_page) const { |
| 174 // TODO(pke): Make sure the URL is actually opened as an offline URL. | 285 // TODO(pke): Make sure the URL is actually opened as an offline URL. |
| 175 // Currently, the browser opens the offline URL and then immediately | 286 // Currently, the browser opens the offline URL and then immediately |
| 176 // redirects to the online URL if the device is online. | 287 // redirects to the online URL if the device is online. |
| 177 ContentSuggestion suggestion( | 288 ContentSuggestion suggestion( |
| 178 MakeUniqueID(provided_category_, | 289 MakeUniqueID(category, base::IntToString(offline_page.offline_id)), |
| 179 base::IntToString(offline_page.offline_id)), | |
| 180 offline_page.GetOfflineURL()); | 290 offline_page.GetOfflineURL()); |
| 181 | 291 |
| 182 // TODO(pke): Sort by most recently visited and only keep the top one of | |
| 183 // multiple entries for the same URL. | |
| 184 // TODO(pke): Get more reasonable data from the OfflinePageModel here. | 292 // TODO(pke): Get more reasonable data from the OfflinePageModel here. |
| 185 suggestion.set_title(base::UTF8ToUTF16(offline_page.url.spec())); | 293 suggestion.set_title(base::UTF8ToUTF16(offline_page.url.spec())); |
| 186 suggestion.set_snippet_text(base::string16()); | 294 suggestion.set_snippet_text(base::string16()); |
| 187 suggestion.set_publish_date(offline_page.creation_time); | 295 suggestion.set_publish_date(offline_page.creation_time); |
| 188 suggestion.set_publisher_name(base::UTF8ToUTF16(offline_page.url.host())); | 296 suggestion.set_publisher_name(base::UTF8ToUTF16(offline_page.url.host())); |
| 189 return suggestion; | 297 return suggestion; |
| 190 } | 298 } |
| 191 | 299 |
| 192 void OfflinePageSuggestionsProvider::ReadDismissedIDsFromPrefs() { | 300 std::vector<ContentSuggestion> |
| 193 dismissed_ids_.clear(); | 301 OfflinePageSuggestionsProvider::GetMostRecentlyVisited( |
| 194 const base::ListValue* list = | 302 Category category, |
| 195 pref_service_->GetList(prefs::kDismissedOfflinePageSuggestions); | 303 std::vector<const OfflinePageItem*>* offline_page_items) const { |
|
Marc Treib
2016/08/12 09:21:14
Hrm, I'm not a fan of this kind of mutable input a
Philipp Keck
2016/08/12 09:56:40
Done.
| |
| 304 std::sort(offline_page_items->begin(), offline_page_items->end(), | |
| 305 OrderByMostRecentlyVisited); | |
| 306 std::vector<ContentSuggestion> suggestions; | |
| 307 for (const OfflinePageItem* offline_page_item : *offline_page_items) { | |
| 308 suggestions.push_back(ConvertOfflinePage(category, *offline_page_item)); | |
| 309 if (suggestions.size() == kMaxSuggestionsCount) | |
| 310 break; | |
| 311 } | |
| 312 return suggestions; | |
| 313 } | |
| 314 | |
| 315 std::set<std::string> OfflinePageSuggestionsProvider::ReadDismissedIDsFromPrefs( | |
| 316 const std::string& pref_name) { | |
| 317 std::set<std::string> dismissed_ids; | |
| 318 const base::ListValue* list = pref_service_->GetList(pref_name); | |
| 196 for (const std::unique_ptr<base::Value>& value : *list) { | 319 for (const std::unique_ptr<base::Value>& value : *list) { |
| 197 std::string dismissed_id; | 320 std::string dismissed_id; |
| 198 bool success = value->GetAsString(&dismissed_id); | 321 bool success = value->GetAsString(&dismissed_id); |
| 199 DCHECK(success) << "Failed to parse dismissed offline page ID from prefs"; | 322 DCHECK(success) << "Failed to parse dismissed offline page ID from prefs"; |
| 200 dismissed_ids_.insert(std::move(dismissed_id)); | 323 dismissed_ids.insert(dismissed_id); |
| 201 } | 324 } |
| 325 return dismissed_ids; | |
| 202 } | 326 } |
| 203 | 327 |
| 204 void OfflinePageSuggestionsProvider::StoreDismissedIDsToPrefs() { | 328 void OfflinePageSuggestionsProvider::StoreDismissedIDsToPrefs( |
| 329 const std::string& pref_name, | |
| 330 const std::set<std::string>& dismissed_ids) { | |
| 205 base::ListValue list; | 331 base::ListValue list; |
| 206 for (const std::string& dismissed_id : dismissed_ids_) | 332 for (const std::string& dismissed_id : dismissed_ids) |
| 207 list.AppendString(dismissed_id); | 333 list.AppendString(dismissed_id); |
| 208 pref_service_->Set(prefs::kDismissedOfflinePageSuggestions, list); | 334 pref_service_->Set(pref_name, list); |
| 209 } | 335 } |
| 210 | 336 |
| 211 } // namespace ntp_snippets | 337 } // namespace ntp_snippets |
| OLD | NEW |