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/recent_tab_suggestions_provider. h" | 5 #include "components/ntp_snippets/offline_pages/recent_tab_suggestions_provider. h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/memory/ptr_util.h" | 11 #include "base/memory/ptr_util.h" |
| 12 #include "base/strings/string_number_conversions.h" | 12 #include "base/strings/string_number_conversions.h" |
| 13 #include "base/strings/utf_string_conversions.h" | 13 #include "base/strings/utf_string_conversions.h" |
| 14 #include "base/threading/thread_task_runner_handle.h" | 14 #include "base/threading/thread_task_runner_handle.h" |
| 15 #include "components/ntp_snippets/features.h" | 15 #include "components/ntp_snippets/features.h" |
| 16 #include "components/ntp_snippets/pref_names.h" | 16 #include "components/ntp_snippets/pref_names.h" |
| 17 #include "components/ntp_snippets/pref_util.h" | 17 #include "components/ntp_snippets/pref_util.h" |
| 18 #include "components/offline_pages/core/client_policy_controller.h" | 18 #include "components/offline_pages/core/client_policy_controller.h" |
| 19 #include "components/offline_pages/core/offline_page_item.h" | 19 #include "components/offline_pages/core/offline_page_item.h" |
|
vitaliii
2017/02/15 10:12:15
I guess this won't be needed once you remove GetPa
dewittj
2017/02/15 19:49:44
Done.
| |
| 20 #include "components/offline_pages/core/offline_page_model_query.h" | 20 #include "components/offline_pages/core/offline_page_model_query.h" |
|
vitaliii
2017/02/15 10:12:15
Please remove this line.
dewittj
2017/02/15 19:49:44
Done.
| |
| 21 #include "components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_deleg ate.h" | |
| 21 #include "components/prefs/pref_registry_simple.h" | 22 #include "components/prefs/pref_registry_simple.h" |
| 22 #include "components/prefs/pref_service.h" | 23 #include "components/prefs/pref_service.h" |
| 23 #include "components/variations/variations_associated_data.h" | 24 #include "components/variations/variations_associated_data.h" |
| 24 #include "grit/components_strings.h" | 25 #include "grit/components_strings.h" |
| 25 #include "ui/base/l10n/l10n_util.h" | 26 #include "ui/base/l10n/l10n_util.h" |
| 26 #include "ui/gfx/image/image.h" | 27 #include "ui/gfx/image/image.h" |
| 27 | 28 |
| 28 using offline_pages::ClientId; | 29 using offline_pages::ClientId; |
| 30 using offline_pages::DownloadUIAdapter; | |
| 31 using offline_pages::DownloadUIItem; | |
| 29 using offline_pages::OfflinePageItem; | 32 using offline_pages::OfflinePageItem; |
| 30 using offline_pages::OfflinePageModelQuery; | 33 using offline_pages::OfflinePageModelQuery; |
| 31 using offline_pages::OfflinePageModelQueryBuilder; | 34 using offline_pages::OfflinePageModelQueryBuilder; |
| 32 | 35 |
| 33 namespace ntp_snippets { | 36 namespace ntp_snippets { |
| 34 | 37 |
| 35 namespace { | 38 namespace { |
| 36 | 39 |
| 37 const int kDefaultMaxSuggestionsCount = 5; | 40 const int kDefaultMaxSuggestionsCount = 5; |
| 38 | 41 |
| 39 const char* kMaxSuggestionsCountParamName = "recent_tabs_max_count"; | 42 const char* kMaxSuggestionsCountParamName = "recent_tabs_max_count"; |
| 40 | 43 |
| 41 int GetMaxSuggestionsCount() { | 44 int GetMaxSuggestionsCount() { |
| 42 return variations::GetVariationParamByFeatureAsInt( | 45 return variations::GetVariationParamByFeatureAsInt( |
| 43 kRecentOfflineTabSuggestionsFeature, kMaxSuggestionsCountParamName, | 46 kRecentOfflineTabSuggestionsFeature, kMaxSuggestionsCountParamName, |
| 44 kDefaultMaxSuggestionsCount); | 47 kDefaultMaxSuggestionsCount); |
| 45 } | 48 } |
| 46 | 49 |
| 47 struct OrderOfflinePagesByMostRecentlyCreatedFirst { | 50 struct OrderUIItemsByMostRecentlyCreatedFirst { |
| 48 bool operator()(const OfflinePageItem* left, | 51 bool operator()(const DownloadUIItem* left, |
| 49 const OfflinePageItem* right) const { | 52 const DownloadUIItem* right) const { |
| 50 return left->creation_time > right->creation_time; | 53 return left->start_time > right->start_time; |
| 51 } | 54 } |
| 52 }; | 55 }; |
| 53 | 56 |
| 54 struct OrderOfflinePagesByUrlAndThenMostRecentlyCreatedFirst { | 57 struct OrderUIItemsByUrlAndThenMostRecentlyCreatedFirst { |
| 55 bool operator()(const OfflinePageItem* left, | 58 bool operator()(const DownloadUIItem* left, |
| 56 const OfflinePageItem* right) const { | 59 const DownloadUIItem* right) const { |
| 57 if (left->url != right->url) { | 60 if (left->url != right->url) { |
| 58 return left->url < right->url; | 61 return left->url < right->url; |
| 59 } | 62 } |
| 60 return left->creation_time > right->creation_time; | 63 return left->start_time > right->start_time; |
| 61 } | 64 } |
| 62 }; | 65 }; |
| 63 | 66 |
| 64 std::unique_ptr<OfflinePageModelQuery> BuildRecentTabsQuery( | |
| 65 offline_pages::OfflinePageModel* model) { | |
| 66 OfflinePageModelQueryBuilder builder; | |
| 67 builder.RequireShownAsRecentlyVisitedSite( | |
| 68 OfflinePageModelQuery::Requirement::INCLUDE_MATCHING); | |
| 69 return builder.Build(model->GetPolicyController()); | |
| 70 } | |
| 71 | |
| 72 bool IsRecentTab(offline_pages::ClientPolicyController* policy_controller, | |
| 73 const OfflinePageItem& offline_page) { | |
| 74 return policy_controller->IsShownAsRecentlyVisitedSite( | |
| 75 offline_page.client_id.name_space); | |
| 76 } | |
| 77 | |
| 78 } // namespace | 67 } // namespace |
| 79 | 68 |
| 80 RecentTabSuggestionsProvider::RecentTabSuggestionsProvider( | 69 RecentTabSuggestionsProvider::RecentTabSuggestionsProvider( |
| 81 ContentSuggestionsProvider::Observer* observer, | 70 ContentSuggestionsProvider::Observer* observer, |
| 82 offline_pages::OfflinePageModel* offline_page_model, | 71 offline_pages::OfflinePageModel* offline_page_model, |
| 72 offline_pages::RequestCoordinator* request_coordinator, | |
| 83 PrefService* pref_service) | 73 PrefService* pref_service) |
| 84 : ContentSuggestionsProvider(observer), | 74 : ContentSuggestionsProvider(observer), |
| 85 category_status_(CategoryStatus::AVAILABLE_LOADING), | 75 category_status_(CategoryStatus::AVAILABLE_LOADING), |
| 86 provided_category_( | 76 provided_category_( |
| 87 Category::FromKnownCategory(KnownCategories::RECENT_TABS)), | 77 Category::FromKnownCategory(KnownCategories::RECENT_TABS)), |
| 88 offline_page_model_(offline_page_model), | |
| 89 pref_service_(pref_service), | 78 pref_service_(pref_service), |
| 90 weak_ptr_factory_(this) { | 79 weak_ptr_factory_(this) { |
| 91 observer->OnCategoryStatusChanged(this, provided_category_, category_status_); | 80 observer->OnCategoryStatusChanged(this, provided_category_, category_status_); |
| 92 offline_page_model_->AddObserver(this); | 81 |
| 93 FetchRecentTabs(); | 82 recent_tabs_ui_adapter_ = offline_pages::RecentTabsUIAdapterDelegate:: |
|
vitaliii
2017/02/15 10:12:15
Please do this in the factory and do not propagate
dewittj
2017/02/15 19:49:44
Done.
| |
| 83 GetOrCreateRecentTabsUIAdapter(offline_page_model, request_coordinator); | |
| 84 recent_tabs_ui_adapter_->AddObserver(this); | |
| 94 } | 85 } |
| 95 | 86 |
| 96 RecentTabSuggestionsProvider::~RecentTabSuggestionsProvider() { | 87 RecentTabSuggestionsProvider::~RecentTabSuggestionsProvider() { |
| 97 offline_page_model_->RemoveObserver(this); | 88 recent_tabs_ui_adapter_->RemoveObserver(this); |
| 98 } | 89 } |
| 99 | 90 |
| 91 // static | |
|
vitaliii
2017/02/15 10:12:15
Please remove this comment.
dewittj
2017/02/15 19:49:45
Done.
| |
| 100 CategoryStatus RecentTabSuggestionsProvider::GetCategoryStatus( | 92 CategoryStatus RecentTabSuggestionsProvider::GetCategoryStatus( |
| 101 Category category) { | 93 Category category) { |
| 102 if (category == provided_category_) { | 94 if (category == provided_category_) { |
| 103 return category_status_; | 95 return category_status_; |
| 104 } | 96 } |
| 105 NOTREACHED() << "Unknown category " << category.id(); | 97 NOTREACHED() << "Unknown category " << category.id(); |
| 106 return CategoryStatus::NOT_PROVIDED; | 98 return CategoryStatus::NOT_PROVIDED; |
| 107 } | 99 } |
| 108 | 100 |
| 109 CategoryInfo RecentTabSuggestionsProvider::GetCategoryInfo(Category category) { | 101 CategoryInfo RecentTabSuggestionsProvider::GetCategoryInfo(Category category) { |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 158 | 150 |
| 159 void RecentTabSuggestionsProvider::ClearCachedSuggestions(Category category) { | 151 void RecentTabSuggestionsProvider::ClearCachedSuggestions(Category category) { |
| 160 // Ignored. | 152 // Ignored. |
| 161 } | 153 } |
| 162 | 154 |
| 163 void RecentTabSuggestionsProvider::GetDismissedSuggestionsForDebugging( | 155 void RecentTabSuggestionsProvider::GetDismissedSuggestionsForDebugging( |
| 164 Category category, | 156 Category category, |
| 165 const DismissedSuggestionsCallback& callback) { | 157 const DismissedSuggestionsCallback& callback) { |
| 166 DCHECK_EQ(provided_category_, category); | 158 DCHECK_EQ(provided_category_, category); |
| 167 | 159 |
| 168 // Offline pages which are not related to recent tabs are also queried here, | 160 std::vector<const DownloadUIItem*> items = |
| 169 // so that they can be returned if they happen to be dismissed (e.g. due to a | 161 recent_tabs_ui_adapter_->GetAllItems(); |
| 170 // bug). | 162 |
| 171 OfflinePageModelQueryBuilder query_builder; | 163 std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs(); |
| 172 offline_page_model_->GetPagesMatchingQuery( | 164 std::vector<ContentSuggestion> suggestions; |
| 173 query_builder.Build(offline_page_model_->GetPolicyController()), | 165 for (const DownloadUIItem* item : items) { |
| 174 base::Bind(&RecentTabSuggestionsProvider:: | 166 int64_t offline_page_id = |
| 175 GetPagesMatchingQueryCallbackForGetDismissedSuggestions, | 167 recent_tabs_ui_adapter_->GetOfflineIdByGuid(item->guid); |
|
vitaliii
2017/02/15 10:12:15
Do I understand right that there may be different
dewittj
2017/02/15 19:49:44
Yes, this is currently a limitation with how we in
| |
| 176 weak_ptr_factory_.GetWeakPtr(), callback)); | 168 if (!dismissed_ids.count(base::IntToString(offline_page_id))) { |
| 169 continue; | |
| 170 } | |
| 171 | |
| 172 suggestions.push_back(ConvertUIItem(*item)); | |
| 173 } | |
| 174 callback.Run(std::move(suggestions)); | |
| 177 } | 175 } |
| 178 | 176 |
| 179 void RecentTabSuggestionsProvider::ClearDismissedSuggestionsForDebugging( | 177 void RecentTabSuggestionsProvider::ClearDismissedSuggestionsForDebugging( |
| 180 Category category) { | 178 Category category) { |
| 181 DCHECK_EQ(provided_category_, category); | 179 DCHECK_EQ(provided_category_, category); |
| 182 StoreDismissedIDsToPrefs(std::set<std::string>()); | 180 StoreDismissedIDsToPrefs(std::set<std::string>()); |
| 183 FetchRecentTabs(); | 181 FetchRecentTabs(); |
| 184 } | 182 } |
| 185 | 183 |
| 186 // static | 184 // static |
| 187 void RecentTabSuggestionsProvider::RegisterProfilePrefs( | 185 void RecentTabSuggestionsProvider::RegisterProfilePrefs( |
| 188 PrefRegistrySimple* registry) { | 186 PrefRegistrySimple* registry) { |
| 189 registry->RegisterListPref(prefs::kDismissedRecentOfflineTabSuggestions); | 187 registry->RegisterListPref(prefs::kDismissedRecentOfflineTabSuggestions); |
| 190 } | 188 } |
| 191 | 189 |
| 192 //////////////////////////////////////////////////////////////////////////////// | 190 //////////////////////////////////////////////////////////////////////////////// |
| 193 // Private methods | 191 // Private methods |
| 194 | 192 |
| 195 void RecentTabSuggestionsProvider:: | 193 void RecentTabSuggestionsProvider::ItemsLoaded() { |
| 196 GetPagesMatchingQueryCallbackForGetDismissedSuggestions( | 194 FetchRecentTabs(); |
| 197 const DismissedSuggestionsCallback& callback, | |
| 198 const std::vector<OfflinePageItem>& offline_pages) const { | |
| 199 std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs(); | |
| 200 std::vector<ContentSuggestion> suggestions; | |
| 201 for (const OfflinePageItem& item : offline_pages) { | |
| 202 if (!dismissed_ids.count(base::IntToString(item.offline_id))) { | |
| 203 continue; | |
| 204 } | |
| 205 | |
| 206 suggestions.push_back(ConvertOfflinePage(item)); | |
| 207 } | |
| 208 callback.Run(std::move(suggestions)); | |
| 209 } | 195 } |
| 210 | 196 |
| 211 void RecentTabSuggestionsProvider::OfflinePageModelLoaded( | 197 void RecentTabSuggestionsProvider::ItemAdded(const DownloadUIItem& ui_item) { |
|
vitaliii
2017/02/15 10:12:15
Is this called before |ItemsLoaded|?
If yes, we sh
dewittj
2017/02/15 19:49:45
No, the design of DownloadUIAdapter is that ItemsL
| |
| 212 offline_pages::OfflinePageModel* model) {} | 198 FetchRecentTabs(); |
| 199 } | |
| 213 | 200 |
| 214 void RecentTabSuggestionsProvider::OfflinePageAdded( | 201 void RecentTabSuggestionsProvider::ItemUpdated(const DownloadUIItem& ui_item) { |
| 215 offline_pages::OfflinePageModel* model, | 202 FetchRecentTabs(); |
| 216 const offline_pages::OfflinePageItem& added_page) { | 203 } |
| 217 DCHECK_EQ(offline_page_model_, model); | 204 |
| 218 if (IsRecentTab(model->GetPolicyController(), added_page)) { | 205 void RecentTabSuggestionsProvider::ItemDeleted( |
| 219 FetchRecentTabs(); | 206 const std::string& ui_item_guid) { |
| 220 } | 207 // Because we never switch to NOT_PROVIDED dynamically, there can be no open |
| 208 // UI containing an invalidated suggestion unless the status is something | |
| 209 // other than NOT_PROVIDED, so only notify invalidation in that case. | |
| 210 if (category_status_ != CategoryStatus::NOT_PROVIDED) | |
|
vitaliii
2017/02/15 10:12:15
Please add curly brackets { }.
We use curly bracke
dewittj
2017/02/15 19:49:44
Done.
| |
| 211 InvalidateSuggestion(ui_item_guid); | |
| 221 } | 212 } |
| 222 | 213 |
| 223 void RecentTabSuggestionsProvider:: | 214 void RecentTabSuggestionsProvider:: |
| 224 GetPagesMatchingQueryCallbackForFetchRecentTabs( | 215 GetPagesMatchingQueryCallbackForFetchRecentTabs( |
| 225 const std::vector<OfflinePageItem>& offline_pages) { | 216 const std::vector<OfflinePageItem>& offline_pages) {} |
|
carlosk
2017/02/15 01:20:54
It seems this method could be removed.
dewittj
2017/02/15 19:49:45
Done.
| |
| 217 | |
| 218 void RecentTabSuggestionsProvider::FetchRecentTabs() { | |
| 219 std::vector<const DownloadUIItem*> ui_items = | |
| 220 recent_tabs_ui_adapter_->GetAllItems(); | |
| 226 NotifyStatusChanged(CategoryStatus::AVAILABLE); | 221 NotifyStatusChanged(CategoryStatus::AVAILABLE); |
| 227 std::set<std::string> old_dismissed_ids = ReadDismissedIDsFromPrefs(); | 222 std::set<std::string> old_dismissed_ids = ReadDismissedIDsFromPrefs(); |
| 228 std::set<std::string> new_dismissed_ids; | 223 std::set<std::string> new_dismissed_ids; |
| 229 std::vector<const OfflinePageItem*> recent_tab_items; | 224 std::vector<const DownloadUIItem*> non_dismissed_items; |
| 230 for (const OfflinePageItem& item : offline_pages) { | 225 |
| 231 std::string offline_page_id = base::IntToString(item.offline_id); | 226 for (const DownloadUIItem* item : ui_items) { |
| 227 std::string offline_page_id = base::IntToString( | |
| 228 recent_tabs_ui_adapter_->GetOfflineIdByGuid(item->guid)); | |
| 232 if (old_dismissed_ids.count(offline_page_id)) { | 229 if (old_dismissed_ids.count(offline_page_id)) { |
| 233 new_dismissed_ids.insert(offline_page_id); | 230 new_dismissed_ids.insert(offline_page_id); |
| 234 } else { | 231 } else { |
| 235 recent_tab_items.push_back(&item); | 232 non_dismissed_items.push_back(item); |
| 236 } | 233 } |
| 237 } | 234 } |
| 238 | 235 |
| 239 observer()->OnNewSuggestions( | 236 observer()->OnNewSuggestions( |
| 240 this, provided_category_, | 237 this, provided_category_, |
| 241 GetMostRecentlyCreatedWithoutDuplicates(std::move(recent_tab_items))); | 238 GetMostRecentlyCreatedWithoutDuplicates(std::move(non_dismissed_items))); |
| 242 if (new_dismissed_ids.size() != old_dismissed_ids.size()) { | 239 if (new_dismissed_ids.size() != old_dismissed_ids.size()) { |
| 243 StoreDismissedIDsToPrefs(new_dismissed_ids); | 240 StoreDismissedIDsToPrefs(new_dismissed_ids); |
| 244 } | 241 } |
| 245 } | 242 } |
| 246 | 243 |
| 247 void RecentTabSuggestionsProvider::OfflinePageDeleted( | |
| 248 int64_t offline_id, | |
| 249 const ClientId& client_id) { | |
| 250 // Because we never switch to NOT_PROVIDED dynamically, there can be no open | |
| 251 // UI containing an invalidated suggestion unless the status is something | |
| 252 // other than NOT_PROVIDED, so only notify invalidation in that case. | |
| 253 if (category_status_ != CategoryStatus::NOT_PROVIDED) { | |
| 254 InvalidateSuggestion(offline_id); | |
| 255 } | |
| 256 } | |
| 257 | |
| 258 void RecentTabSuggestionsProvider::FetchRecentTabs() { | |
| 259 offline_page_model_->GetPagesMatchingQuery( | |
| 260 BuildRecentTabsQuery(offline_page_model_), | |
| 261 base::Bind(&RecentTabSuggestionsProvider:: | |
| 262 GetPagesMatchingQueryCallbackForFetchRecentTabs, | |
| 263 weak_ptr_factory_.GetWeakPtr())); | |
| 264 } | |
| 265 | |
| 266 void RecentTabSuggestionsProvider::NotifyStatusChanged( | 244 void RecentTabSuggestionsProvider::NotifyStatusChanged( |
| 267 CategoryStatus new_status) { | 245 CategoryStatus new_status) { |
| 268 DCHECK_NE(CategoryStatus::NOT_PROVIDED, category_status_); | 246 DCHECK_NE(CategoryStatus::NOT_PROVIDED, category_status_); |
| 269 if (category_status_ == new_status) { | 247 if (category_status_ == new_status) { |
| 270 return; | 248 return; |
| 271 } | 249 } |
| 272 category_status_ = new_status; | 250 category_status_ = new_status; |
| 273 observer()->OnCategoryStatusChanged(this, provided_category_, new_status); | 251 observer()->OnCategoryStatusChanged(this, provided_category_, new_status); |
| 274 } | 252 } |
| 275 | 253 |
| 276 ContentSuggestion RecentTabSuggestionsProvider::ConvertOfflinePage( | 254 ContentSuggestion RecentTabSuggestionsProvider::ConvertUIItem( |
| 277 const OfflinePageItem& offline_page) const { | 255 const DownloadUIItem& ui_item) const { |
| 256 // UI items have the Tab ID embedded in the GUID and the offline ID is | |
| 257 // available by querying. | |
| 258 // | |
| 278 // TODO(vitaliii): Make sure the URL is opened in the existing tab. | 259 // TODO(vitaliii): Make sure the URL is opened in the existing tab. |
| 260 int64_t offline_page_id = | |
| 261 recent_tabs_ui_adapter_->GetOfflineIdByGuid(ui_item.guid); | |
| 279 ContentSuggestion suggestion(provided_category_, | 262 ContentSuggestion suggestion(provided_category_, |
| 280 base::IntToString(offline_page.offline_id), | 263 base::IntToString(offline_page_id), ui_item.url); |
| 281 offline_page.url); | 264 suggestion.set_title(ui_item.title); |
| 282 | 265 suggestion.set_publish_date(ui_item.start_time); |
| 283 if (offline_page.title.empty()) { | 266 suggestion.set_publisher_name(base::UTF8ToUTF16(ui_item.url.host())); |
| 284 // TODO(vitaliii): Remove this fallback once the OfflinePageModel provides | |
| 285 // titles for all (relevant) OfflinePageItems. | |
| 286 suggestion.set_title(base::UTF8ToUTF16(offline_page.url.spec())); | |
| 287 } else { | |
| 288 suggestion.set_title(offline_page.title); | |
| 289 } | |
| 290 suggestion.set_publish_date(offline_page.creation_time); | |
| 291 suggestion.set_publisher_name(base::UTF8ToUTF16(offline_page.url.host())); | |
| 292 auto extra = base::MakeUnique<RecentTabSuggestionExtra>(); | 267 auto extra = base::MakeUnique<RecentTabSuggestionExtra>(); |
| 293 int tab_id; | 268 int tab_id; |
| 294 bool success = base::StringToInt(offline_page.client_id.id, &tab_id); | 269 bool success = base::StringToInt(ui_item.guid, &tab_id); |
| 295 DCHECK(success); | 270 DCHECK(success); |
| 296 extra->tab_id = tab_id; | 271 extra->tab_id = tab_id; |
| 297 extra->offline_page_id = offline_page.offline_id; | 272 extra->offline_page_id = offline_page_id; |
| 298 suggestion.set_recent_tab_suggestion_extra(std::move(extra)); | 273 suggestion.set_recent_tab_suggestion_extra(std::move(extra)); |
| 274 | |
| 299 return suggestion; | 275 return suggestion; |
| 300 } | 276 } |
| 301 | 277 |
| 302 std::vector<ContentSuggestion> | 278 std::vector<ContentSuggestion> |
| 303 RecentTabSuggestionsProvider::GetMostRecentlyCreatedWithoutDuplicates( | 279 RecentTabSuggestionsProvider::GetMostRecentlyCreatedWithoutDuplicates( |
| 304 std::vector<const OfflinePageItem*> offline_page_items) const { | 280 std::vector<const DownloadUIItem*> ui_items) const { |
| 305 // |std::unique| only removes duplicates that immediately follow each other. | 281 // |std::unique| only removes duplicates that immediately follow each other. |
| 306 // Thus, first, we have to sort by URL and creation time and only then remove | 282 // Thus, first, we have to sort by URL and creation time and only then remove |
| 307 // duplicates and sort the remaining items by creation time. | 283 // duplicates and sort the remaining items by creation time. |
| 308 std::sort(offline_page_items.begin(), offline_page_items.end(), | 284 std::sort(ui_items.begin(), ui_items.end(), |
| 309 OrderOfflinePagesByUrlAndThenMostRecentlyCreatedFirst()); | 285 OrderUIItemsByUrlAndThenMostRecentlyCreatedFirst()); |
| 310 std::vector<const OfflinePageItem*>::iterator new_end = std::unique( | 286 std::vector<const DownloadUIItem*>::iterator new_end = |
| 311 offline_page_items.begin(), offline_page_items.end(), | 287 std::unique(ui_items.begin(), ui_items.end(), |
| 312 [](const OfflinePageItem* left, const OfflinePageItem* right) { | 288 [](const DownloadUIItem* left, const DownloadUIItem* right) { |
| 313 return left->url == right->url; | 289 return left->url == right->url; |
| 314 }); | 290 }); |
| 315 offline_page_items.erase(new_end, offline_page_items.end()); | 291 ui_items.erase(new_end, ui_items.end()); |
| 316 std::sort(offline_page_items.begin(), offline_page_items.end(), | 292 std::sort(ui_items.begin(), ui_items.end(), |
| 317 OrderOfflinePagesByMostRecentlyCreatedFirst()); | 293 OrderUIItemsByMostRecentlyCreatedFirst()); |
| 318 std::vector<ContentSuggestion> suggestions; | 294 std::vector<ContentSuggestion> suggestions; |
| 319 for (const OfflinePageItem* offline_page_item : offline_page_items) { | 295 for (const DownloadUIItem* ui_item : ui_items) { |
| 320 suggestions.push_back(ConvertOfflinePage(*offline_page_item)); | 296 suggestions.push_back(ConvertUIItem(*ui_item)); |
| 321 if (static_cast<int>(suggestions.size()) == GetMaxSuggestionsCount()) { | 297 if (static_cast<int>(suggestions.size()) == GetMaxSuggestionsCount()) { |
| 322 break; | 298 break; |
| 323 } | 299 } |
| 324 } | 300 } |
| 325 return suggestions; | 301 return suggestions; |
| 326 } | 302 } |
| 327 | 303 |
| 328 void RecentTabSuggestionsProvider::InvalidateSuggestion(int64_t offline_id) { | 304 void RecentTabSuggestionsProvider::InvalidateSuggestion( |
| 329 std::string offline_page_id = base::IntToString(offline_id); | 305 const std::string& ui_item_guid) { |
| 306 std::string offline_page_id = base::IntToString( | |
| 307 recent_tabs_ui_adapter_->GetOfflineIdByGuid(ui_item_guid)); | |
| 330 observer()->OnSuggestionInvalidated( | 308 observer()->OnSuggestionInvalidated( |
| 331 this, ContentSuggestion::ID(provided_category_, offline_page_id)); | 309 this, ContentSuggestion::ID(provided_category_, offline_page_id)); |
| 332 | 310 |
| 333 std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs(); | 311 std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs(); |
| 334 auto it = dismissed_ids.find(offline_page_id); | 312 auto it = dismissed_ids.find(offline_page_id); |
| 335 if (it != dismissed_ids.end()) { | 313 if (it != dismissed_ids.end()) { |
| 336 dismissed_ids.erase(it); | 314 dismissed_ids.erase(it); |
| 337 StoreDismissedIDsToPrefs(dismissed_ids); | 315 StoreDismissedIDsToPrefs(dismissed_ids); |
| 338 } | 316 } |
| 339 } | 317 } |
| 340 | 318 |
| 341 std::set<std::string> RecentTabSuggestionsProvider::ReadDismissedIDsFromPrefs() | 319 std::set<std::string> RecentTabSuggestionsProvider::ReadDismissedIDsFromPrefs() |
| 342 const { | 320 const { |
| 343 return prefs::ReadDismissedIDsFromPrefs( | 321 return prefs::ReadDismissedIDsFromPrefs( |
| 344 *pref_service_, prefs::kDismissedRecentOfflineTabSuggestions); | 322 *pref_service_, prefs::kDismissedRecentOfflineTabSuggestions); |
| 345 } | 323 } |
| 346 | 324 |
| 347 void RecentTabSuggestionsProvider::StoreDismissedIDsToPrefs( | 325 void RecentTabSuggestionsProvider::StoreDismissedIDsToPrefs( |
| 348 const std::set<std::string>& dismissed_ids) { | 326 const std::set<std::string>& dismissed_ids) { |
| 349 prefs::StoreDismissedIDsToPrefs(pref_service_, | 327 prefs::StoreDismissedIDsToPrefs(pref_service_, |
| 350 prefs::kDismissedRecentOfflineTabSuggestions, | 328 prefs::kDismissedRecentOfflineTabSuggestions, |
| 351 dismissed_ids); | 329 dismissed_ids); |
| 352 } | 330 } |
| 353 | 331 |
| 354 } // namespace ntp_snippets | 332 } // namespace ntp_snippets |
| OLD | NEW |