| 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> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/guid.h" | 10 #include "base/guid.h" |
| (...skipping 20 matching lines...) Expand all Loading... |
| 31 | 31 |
| 32 const int kMaxSuggestionsCount = 5; | 32 const int kMaxSuggestionsCount = 5; |
| 33 | 33 |
| 34 struct OrderByMostRecentlyVisited { | 34 struct OrderByMostRecentlyVisited { |
| 35 bool operator()(const OfflinePageItem* left, | 35 bool operator()(const OfflinePageItem* left, |
| 36 const OfflinePageItem* right) const { | 36 const OfflinePageItem* right) const { |
| 37 return left->last_access_time > right->last_access_time; | 37 return left->last_access_time > right->last_access_time; |
| 38 } | 38 } |
| 39 }; | 39 }; |
| 40 | 40 |
| 41 bool IsRecentTab(const offline_pages::ClientId& client_id) { |
| 42 return client_id.name_space == offline_pages::kLastNNamespace; |
| 43 } |
| 44 |
| 45 bool IsDownload(const offline_pages::ClientId& client_id) { |
| 46 // TODO(pke): Use kDownloadNamespace once the OfflinePageModel uses that. |
| 47 // The current logic is taken from DownloadUIAdapter::IsVisibleInUI. |
| 48 return client_id.name_space == offline_pages::kAsyncNamespace && |
| 49 base::IsValidGUID(client_id.id); |
| 50 } |
| 51 |
| 41 } // namespace | 52 } // namespace |
| 42 | 53 |
| 43 OfflinePageSuggestionsProvider::OfflinePageSuggestionsProvider( | 54 OfflinePageSuggestionsProvider::OfflinePageSuggestionsProvider( |
| 44 bool recent_tabs_enabled, | 55 bool recent_tabs_enabled, |
| 45 bool downloads_enabled, | 56 bool downloads_enabled, |
| 46 bool download_manager_ui_enabled, | 57 bool download_manager_ui_enabled, |
| 47 ContentSuggestionsProvider::Observer* observer, | 58 ContentSuggestionsProvider::Observer* observer, |
| 48 CategoryFactory* category_factory, | 59 CategoryFactory* category_factory, |
| 49 OfflinePageModel* offline_page_model, | 60 OfflinePageModel* offline_page_model, |
| 50 PrefService* pref_service) | 61 PrefService* pref_service) |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 135 // there. | 146 // there. |
| 136 base::ThreadTaskRunnerHandle::Get()->PostTask( | 147 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 137 FROM_HERE, base::Bind(callback, suggestion_id, gfx::Image())); | 148 FROM_HERE, base::Bind(callback, suggestion_id, gfx::Image())); |
| 138 } | 149 } |
| 139 | 150 |
| 140 void OfflinePageSuggestionsProvider::ClearCachedSuggestionsForDebugging( | 151 void OfflinePageSuggestionsProvider::ClearCachedSuggestionsForDebugging( |
| 141 Category category) { | 152 Category category) { |
| 142 // Ignored. | 153 // Ignored. |
| 143 } | 154 } |
| 144 | 155 |
| 145 std::vector<ContentSuggestion> | 156 void OfflinePageSuggestionsProvider::GetDismissedSuggestionsForDebugging( |
| 146 OfflinePageSuggestionsProvider::GetDismissedSuggestionsForDebugging( | 157 Category category, |
| 147 Category category) { | 158 const DismissedSuggestionsCallback& callback) { |
| 148 // TODO(pke): Make GetDismissedSuggestionsForDebugging asynchronous so this | 159 offline_page_model_->GetAllPages( |
| 149 // can return proper values. | 160 base::Bind(&OfflinePageSuggestionsProvider:: |
| 150 std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs(category); | 161 OnOfflinePagesLoadedForDismissedDebugging, |
| 151 std::vector<ContentSuggestion> suggestions; | 162 base::Unretained(this), category, callback)); |
| 152 for (const std::string& dismissed_id : dismissed_ids) { | |
| 153 ContentSuggestion suggestion( | |
| 154 MakeUniqueID(category, dismissed_id), | |
| 155 GURL("http://dismissed-offline-page-" + dismissed_id)); | |
| 156 suggestion.set_title(base::UTF8ToUTF16("Title not available")); | |
| 157 suggestions.push_back(std::move(suggestion)); | |
| 158 } | |
| 159 return suggestions; | |
| 160 } | 163 } |
| 161 | 164 |
| 162 void OfflinePageSuggestionsProvider::ClearDismissedSuggestionsForDebugging( | 165 void OfflinePageSuggestionsProvider::ClearDismissedSuggestionsForDebugging( |
| 163 Category category) { | 166 Category category) { |
| 164 StoreDismissedIDsToPrefs(category, std::set<std::string>()); | 167 StoreDismissedIDsToPrefs(category, std::set<std::string>()); |
| 165 FetchOfflinePages(); | 168 FetchOfflinePages(); |
| 166 } | 169 } |
| 167 | 170 |
| 168 void OfflinePageSuggestionsProvider::OfflinePageModelLoaded( | 171 void OfflinePageSuggestionsProvider::OfflinePageModelLoaded( |
| 169 OfflinePageModel* model) { | 172 OfflinePageModel* model) { |
| 170 DCHECK_EQ(offline_page_model_, model); | 173 DCHECK_EQ(offline_page_model_, model); |
| 171 } | 174 } |
| 172 | 175 |
| 173 void OfflinePageSuggestionsProvider::OfflinePageModelChanged( | 176 void OfflinePageSuggestionsProvider::OfflinePageModelChanged( |
| 174 OfflinePageModel* model) { | 177 OfflinePageModel* model) { |
| 175 DCHECK_EQ(offline_page_model_, model); | 178 DCHECK_EQ(offline_page_model_, model); |
| 176 FetchOfflinePages(); | 179 FetchOfflinePages(); |
| 177 } | 180 } |
| 178 | 181 |
| 179 void OfflinePageSuggestionsProvider::OfflinePageDeleted( | 182 void OfflinePageSuggestionsProvider::OfflinePageDeleted( |
| 180 int64_t offline_id, | 183 int64_t offline_id, |
| 181 const offline_pages::ClientId& client_id) { | 184 const offline_pages::ClientId& client_id) { |
| 182 // Because we never switch to NOT_PROVIDED dynamically, there can be no open | 185 // Because we never switch to NOT_PROVIDED dynamically, there can be no open |
| 183 // UI containing an invalidated suggestion unless the status is something | 186 // UI containing an invalidated suggestion unless the status is something |
| 184 // other than NOT_PROVIDED, so only notify invalidation in that case. | 187 // other than NOT_PROVIDED, so only notify invalidation in that case. |
| 185 if (recent_tabs_status_ != CategoryStatus::NOT_PROVIDED && | 188 if (recent_tabs_status_ != CategoryStatus::NOT_PROVIDED && |
| 186 client_id.name_space == offline_pages::kLastNNamespace) { | 189 IsRecentTab(client_id)) { |
| 187 InvalidateSuggestion(recent_tabs_category_, offline_id); | 190 InvalidateSuggestion(recent_tabs_category_, offline_id); |
| 188 } else if (downloads_status_ != CategoryStatus::NOT_PROVIDED && | 191 } else if (downloads_status_ != CategoryStatus::NOT_PROVIDED && |
| 189 client_id.name_space == offline_pages::kAsyncNamespace && | 192 IsDownload(client_id)) { |
| 190 base::IsValidGUID(client_id.id)) { | |
| 191 InvalidateSuggestion(downloads_category_, offline_id); | 193 InvalidateSuggestion(downloads_category_, offline_id); |
| 192 } | 194 } |
| 193 } | 195 } |
| 194 | 196 |
| 195 void OfflinePageSuggestionsProvider::FetchOfflinePages() { | 197 void OfflinePageSuggestionsProvider::FetchOfflinePages() { |
| 196 // TODO(pke): When something other than GetAllPages is used here, the | 198 // TODO(pke): When something other than GetAllPages is used here, the |
| 197 // dismissed IDs cleanup in OnOfflinePagesLoaded needs to be changed to avoid | 199 // dismissed IDs cleanup in OnOfflinePagesLoaded needs to be changed to avoid |
| 198 // suggestions being undismissed accidentally. | 200 // suggestions being undismissed accidentally. |
| 199 offline_page_model_->GetAllPages( | 201 offline_page_model_->GetAllPages( |
| 200 base::Bind(&OfflinePageSuggestionsProvider::OnOfflinePagesLoaded, | 202 base::Bind(&OfflinePageSuggestionsProvider::OnOfflinePagesLoaded, |
| (...skipping 12 matching lines...) Expand all Loading... |
| 213 std::set<std::string> dismissed_recent_tab_ids = | 215 std::set<std::string> dismissed_recent_tab_ids = |
| 214 ReadDismissedIDsFromPrefs(recent_tabs_category_); | 216 ReadDismissedIDsFromPrefs(recent_tabs_category_); |
| 215 std::set<std::string> dismissed_download_ids = | 217 std::set<std::string> dismissed_download_ids = |
| 216 ReadDismissedIDsFromPrefs(downloads_category_); | 218 ReadDismissedIDsFromPrefs(downloads_category_); |
| 217 std::set<std::string> cleaned_recent_tab_ids; | 219 std::set<std::string> cleaned_recent_tab_ids; |
| 218 std::set<std::string> cleaned_download_ids; | 220 std::set<std::string> cleaned_download_ids; |
| 219 std::vector<const OfflinePageItem*> recent_tab_items; | 221 std::vector<const OfflinePageItem*> recent_tab_items; |
| 220 std::vector<const OfflinePageItem*> download_items; | 222 std::vector<const OfflinePageItem*> download_items; |
| 221 for (const OfflinePageItem& item : result) { | 223 for (const OfflinePageItem& item : result) { |
| 222 std::string offline_page_id = base::IntToString(item.offline_id); | 224 std::string offline_page_id = base::IntToString(item.offline_id); |
| 223 if (need_recent_tabs && | 225 if (need_recent_tabs && IsRecentTab(item.client_id)) { |
| 224 item.client_id.name_space == offline_pages::kLastNNamespace) { | |
| 225 if (dismissed_recent_tab_ids.count(offline_page_id)) | 226 if (dismissed_recent_tab_ids.count(offline_page_id)) |
| 226 cleaned_recent_tab_ids.insert(offline_page_id); | 227 cleaned_recent_tab_ids.insert(offline_page_id); |
| 227 else | 228 else |
| 228 recent_tab_items.push_back(&item); | 229 recent_tab_items.push_back(&item); |
| 229 } | 230 } |
| 230 | 231 |
| 231 // TODO(pke): Use kDownloadNamespace once the OfflinePageModel uses that. | 232 if (need_downloads && IsDownload(item.client_id)) { |
| 232 // The current logic is taken from DownloadUIAdapter::IsVisibleInUI. | |
| 233 // Note: This is also copied in |OfflinePageDeleted| above. | |
| 234 if (need_downloads && | |
| 235 item.client_id.name_space == offline_pages::kAsyncNamespace && | |
| 236 base::IsValidGUID(item.client_id.id)) { | |
| 237 if (dismissed_download_ids.count(offline_page_id)) | 233 if (dismissed_download_ids.count(offline_page_id)) |
| 238 cleaned_download_ids.insert(offline_page_id); | 234 cleaned_download_ids.insert(offline_page_id); |
| 239 else | 235 else |
| 240 download_items.push_back(&item); | 236 download_items.push_back(&item); |
| 241 } | 237 } |
| 242 } | 238 } |
| 243 | 239 |
| 244 // TODO(pke): Once we have our OfflinePageModel getter and that doesn't do it | 240 // TODO(pke): Once we have our OfflinePageModel getter and that doesn't do it |
| 245 // already, filter out duplicate URLs for recent tabs here. Duplicates for | 241 // already, filter out duplicate URLs for recent tabs here. Duplicates for |
| 246 // downloads are fine. | 242 // downloads are fine. |
| 247 | 243 |
| 248 if (need_recent_tabs) { | 244 if (need_recent_tabs) { |
| 249 observer()->OnNewSuggestions( | 245 observer()->OnNewSuggestions( |
| 250 this, recent_tabs_category_, | 246 this, recent_tabs_category_, |
| 251 GetMostRecentlyVisited(recent_tabs_category_, | 247 GetMostRecentlyVisited(recent_tabs_category_, |
| 252 std::move(recent_tab_items))); | 248 std::move(recent_tab_items))); |
| 253 if (cleaned_recent_tab_ids.size() != dismissed_recent_tab_ids.size()) | 249 if (cleaned_recent_tab_ids.size() != dismissed_recent_tab_ids.size()) |
| 254 StoreDismissedIDsToPrefs(recent_tabs_category_, cleaned_recent_tab_ids); | 250 StoreDismissedIDsToPrefs(recent_tabs_category_, cleaned_recent_tab_ids); |
| 255 } | 251 } |
| 256 if (need_downloads) { | 252 if (need_downloads) { |
| 257 observer()->OnNewSuggestions( | 253 observer()->OnNewSuggestions( |
| 258 this, downloads_category_, | 254 this, downloads_category_, |
| 259 GetMostRecentlyVisited(downloads_category_, std::move(download_items))); | 255 GetMostRecentlyVisited(downloads_category_, std::move(download_items))); |
| 260 if (cleaned_download_ids.size() != dismissed_download_ids.size()) | 256 if (cleaned_download_ids.size() != dismissed_download_ids.size()) |
| 261 StoreDismissedIDsToPrefs(downloads_category_, cleaned_download_ids); | 257 StoreDismissedIDsToPrefs(downloads_category_, cleaned_download_ids); |
| 262 } | 258 } |
| 263 } | 259 } |
| 264 | 260 |
| 261 void OfflinePageSuggestionsProvider::OnOfflinePagesLoadedForDismissedDebugging( |
| 262 Category category, |
| 263 const DismissedSuggestionsCallback& callback, |
| 264 const offline_pages::MultipleOfflinePageItemResult& result) { |
| 265 std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs(category); |
| 266 std::vector<ContentSuggestion> suggestions; |
| 267 for (const OfflinePageItem& item : result) { |
| 268 if (category == recent_tabs_category_ && !IsRecentTab(item.client_id)) |
| 269 continue; |
| 270 if (category == downloads_category_ && !IsDownload(item.client_id)) |
| 271 continue; |
| 272 if (!dismissed_ids.count(base::IntToString(item.offline_id))) |
| 273 continue; |
| 274 suggestions.push_back(ConvertOfflinePage(category, item)); |
| 275 } |
| 276 callback.Run(std::move(suggestions)); |
| 277 } |
| 278 |
| 265 void OfflinePageSuggestionsProvider::NotifyStatusChanged( | 279 void OfflinePageSuggestionsProvider::NotifyStatusChanged( |
| 266 Category category, | 280 Category category, |
| 267 CategoryStatus new_status) { | 281 CategoryStatus new_status) { |
| 268 if (category == recent_tabs_category_) { | 282 if (category == recent_tabs_category_) { |
| 269 DCHECK_NE(CategoryStatus::NOT_PROVIDED, recent_tabs_status_); | 283 DCHECK_NE(CategoryStatus::NOT_PROVIDED, recent_tabs_status_); |
| 270 if (recent_tabs_status_ == new_status) | 284 if (recent_tabs_status_ == new_status) |
| 271 return; | 285 return; |
| 272 recent_tabs_status_ = new_status; | 286 recent_tabs_status_ = new_status; |
| 273 observer()->OnCategoryStatusChanged(this, category, new_status); | 287 observer()->OnCategoryStatusChanged(this, category, new_status); |
| 274 } else if (category == downloads_category_) { | 288 } else if (category == downloads_category_) { |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 361 void OfflinePageSuggestionsProvider::StoreDismissedIDsToPrefs( | 375 void OfflinePageSuggestionsProvider::StoreDismissedIDsToPrefs( |
| 362 Category category, | 376 Category category, |
| 363 const std::set<std::string>& dismissed_ids) { | 377 const std::set<std::string>& dismissed_ids) { |
| 364 base::ListValue list; | 378 base::ListValue list; |
| 365 for (const std::string& dismissed_id : dismissed_ids) | 379 for (const std::string& dismissed_id : dismissed_ids) |
| 366 list.AppendString(dismissed_id); | 380 list.AppendString(dismissed_id); |
| 367 pref_service_->Set(GetDismissedPref(category), list); | 381 pref_service_->Set(GetDismissedPref(category), list); |
| 368 } | 382 } |
| 369 | 383 |
| 370 } // namespace ntp_snippets | 384 } // namespace ntp_snippets |
| OLD | NEW |