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/content_suggestions_service.h" | 5 #include "components/ntp_snippets/content_suggestions_service.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <iterator> | 8 #include <iterator> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/strings/string_number_conversions.h" | 11 #include "base/strings/string_number_conversions.h" |
12 #include "ui/gfx/image/image.h" | 12 #include "ui/gfx/image/image.h" |
13 | 13 |
14 namespace ntp_snippets { | 14 namespace ntp_snippets { |
15 | 15 |
| 16 bool ContentSuggestionsService::CompareCategoriesByID::operator()( |
| 17 const ContentSuggestionsCategory& left, |
| 18 const ContentSuggestionsCategory& right) const { |
| 19 return left.id() < right.id(); |
| 20 } |
| 21 |
16 ContentSuggestionsService::ContentSuggestionsService(State state) | 22 ContentSuggestionsService::ContentSuggestionsService(State state) |
17 : state_(state) {} | 23 : state_(state) {} |
18 | 24 |
19 ContentSuggestionsService::~ContentSuggestionsService() {} | 25 ContentSuggestionsService::~ContentSuggestionsService() {} |
20 | 26 |
21 void ContentSuggestionsService::Shutdown() { | 27 void ContentSuggestionsService::Shutdown() { |
22 DCHECK(providers_.empty()); | 28 DCHECK(providers_.empty()); |
23 DCHECK(categories_.empty()); | 29 DCHECK(categories_.empty()); |
24 DCHECK(suggestions_by_category_.empty()); | 30 DCHECK(suggestions_by_category_.empty()); |
25 DCHECK(id_category_map_.empty()); | 31 DCHECK(id_category_map_.empty()); |
(...skipping 25 matching lines...) Expand all Loading... |
51 } | 57 } |
52 | 58 |
53 void ContentSuggestionsService::FetchSuggestionImage( | 59 void ContentSuggestionsService::FetchSuggestionImage( |
54 const std::string& suggestion_id, | 60 const std::string& suggestion_id, |
55 const ImageFetchedCallback& callback) { | 61 const ImageFetchedCallback& callback) { |
56 if (!id_category_map_.count(suggestion_id)) { | 62 if (!id_category_map_.count(suggestion_id)) { |
57 LOG(WARNING) << "Requested image for unknown suggestion " << suggestion_id; | 63 LOG(WARNING) << "Requested image for unknown suggestion " << suggestion_id; |
58 callback.Run(suggestion_id, gfx::Image()); | 64 callback.Run(suggestion_id, gfx::Image()); |
59 return; | 65 return; |
60 } | 66 } |
61 ContentSuggestionsCategory category = id_category_map_[suggestion_id]; | 67 ContentSuggestionsCategory category = id_category_map_.at(suggestion_id); |
62 if (!providers_.count(category)) { | 68 if (!providers_.count(category)) { |
63 LOG(WARNING) << "Requested image for suggestion " << suggestion_id | 69 LOG(WARNING) << "Requested image for suggestion " << suggestion_id |
64 << " for unavailable category " << static_cast<int>(category); | 70 << " for unavailable category " << category; |
65 callback.Run(suggestion_id, gfx::Image()); | 71 callback.Run(suggestion_id, gfx::Image()); |
66 return; | 72 return; |
67 } | 73 } |
68 providers_[category]->FetchSuggestionImage(suggestion_id, callback); | 74 providers_[category]->FetchSuggestionImage(suggestion_id, callback); |
69 } | 75 } |
70 | 76 |
71 void ContentSuggestionsService::ClearCachedSuggestionsForDebugging() { | 77 void ContentSuggestionsService::ClearCachedSuggestionsForDebugging() { |
72 suggestions_by_category_.clear(); | 78 suggestions_by_category_.clear(); |
73 id_category_map_.clear(); | 79 id_category_map_.clear(); |
74 for (auto& category_provider_pair : providers_) { | 80 for (auto& category_provider_pair : providers_) { |
75 category_provider_pair.second->ClearCachedSuggestionsForDebugging(); | 81 category_provider_pair.second->ClearCachedSuggestionsForDebugging(); |
76 } | 82 } |
77 FOR_EACH_OBSERVER(Observer, observers_, OnNewSuggestions()); | 83 FOR_EACH_OBSERVER(Observer, observers_, OnNewSuggestions()); |
78 } | 84 } |
79 | 85 |
80 void ContentSuggestionsService::ClearDismissedSuggestionsForDebugging() { | 86 void ContentSuggestionsService::ClearDismissedSuggestionsForDebugging() { |
81 for (auto& category_provider_pair : providers_) { | 87 for (auto& category_provider_pair : providers_) { |
82 category_provider_pair.second->ClearDismissedSuggestionsForDebugging(); | 88 category_provider_pair.second->ClearDismissedSuggestionsForDebugging(); |
83 } | 89 } |
84 } | 90 } |
85 | 91 |
86 void ContentSuggestionsService::DismissSuggestion( | 92 void ContentSuggestionsService::DismissSuggestion( |
87 const std::string& suggestion_id) { | 93 const std::string& suggestion_id) { |
88 if (!id_category_map_.count(suggestion_id)) { | 94 if (!id_category_map_.count(suggestion_id)) { |
89 LOG(WARNING) << "Dismissed unknown suggestion " << suggestion_id; | 95 LOG(WARNING) << "Dismissed unknown suggestion " << suggestion_id; |
90 return; | 96 return; |
91 } | 97 } |
92 ContentSuggestionsCategory category = id_category_map_[suggestion_id]; | 98 ContentSuggestionsCategory category = id_category_map_.at(suggestion_id); |
93 if (!providers_.count(category)) { | 99 if (!providers_.count(category)) { |
94 LOG(WARNING) << "Dismissed suggestion " << suggestion_id | 100 LOG(WARNING) << "Dismissed suggestion " << suggestion_id |
95 << " for unavailable category " << static_cast<int>(category); | 101 << " for unavailable category " << category; |
96 return; | 102 return; |
97 } | 103 } |
98 providers_[category]->DismissSuggestion(suggestion_id); | 104 providers_[category]->DismissSuggestion(suggestion_id); |
99 | 105 |
100 // Remove the suggestion locally. | 106 // Remove the suggestion locally. |
101 id_category_map_.erase(suggestion_id); | 107 id_category_map_.erase(suggestion_id); |
102 std::vector<ContentSuggestion>* suggestions = | 108 std::vector<ContentSuggestion>* suggestions = |
103 &suggestions_by_category_[category]; | 109 &suggestions_by_category_[category]; |
104 auto position = | 110 auto position = |
105 std::find_if(suggestions->begin(), suggestions->end(), | 111 std::find_if(suggestions->begin(), suggestions->end(), |
(...skipping 15 matching lines...) Expand all Loading... |
121 observers_.RemoveObserver(observer); | 127 observers_.RemoveObserver(observer); |
122 } | 128 } |
123 | 129 |
124 void ContentSuggestionsService::RegisterProvider( | 130 void ContentSuggestionsService::RegisterProvider( |
125 ContentSuggestionsProvider* provider) { | 131 ContentSuggestionsProvider* provider) { |
126 // TODO(pke): When NTPSnippetsService is purely a provider, think about | 132 // TODO(pke): When NTPSnippetsService is purely a provider, think about |
127 // removing this state check. | 133 // removing this state check. |
128 if (state_ == State::DISABLED) | 134 if (state_ == State::DISABLED) |
129 return; | 135 return; |
130 | 136 |
131 for (ContentSuggestionsCategory category : provider->provided_categories()) { | 137 for (ContentSuggestionsCategory category : |
| 138 provider->GetProvidedCategories()) { |
132 DCHECK_EQ(0ul, providers_.count(category)); | 139 DCHECK_EQ(0ul, providers_.count(category)); |
133 providers_[category] = provider; | 140 providers_[category] = provider; |
134 // TODO(pke): In the future, make sure that the categories have some useful | |
135 // (maybe constant, at least consistent) ordering for the UI. | |
136 categories_.push_back(category); | 141 categories_.push_back(category); |
137 if (IsContentSuggestionsCategoryStatusAvailable( | 142 if (IsContentSuggestionsCategoryStatusAvailable( |
138 provider->GetCategoryStatus(category))) { | 143 provider->GetCategoryStatus(category))) { |
139 suggestions_by_category_[category] = std::vector<ContentSuggestion>(); | 144 suggestions_by_category_[category] = std::vector<ContentSuggestion>(); |
140 } | 145 } |
141 NotifyCategoryStatusChanged(category); | 146 NotifyCategoryStatusChanged(category); |
142 } | 147 } |
| 148 std::sort(categories_.begin(), categories_.end(), |
| 149 [this](const ContentSuggestionsCategory& left, |
| 150 const ContentSuggestionsCategory& right) { |
| 151 return category_factory_.CompareCategories(left, right); |
| 152 }); |
143 provider->SetObserver(this); | 153 provider->SetObserver(this); |
144 } | 154 } |
145 | 155 |
146 //////////////////////////////////////////////////////////////////////////////// | 156 //////////////////////////////////////////////////////////////////////////////// |
147 // Private methods | 157 // Private methods |
148 | 158 |
149 void ContentSuggestionsService::OnNewSuggestions( | 159 void ContentSuggestionsService::OnNewSuggestions( |
150 ContentSuggestionsCategory changed_category, | 160 ContentSuggestionsCategory changed_category, |
151 std::vector<ContentSuggestion> new_suggestions) { | 161 std::vector<ContentSuggestion> new_suggestions) { |
152 DCHECK(IsCategoryRegistered(changed_category)); | 162 DCHECK(IsCategoryRegistered(changed_category)); |
153 | 163 |
154 for (const ContentSuggestion& suggestion : | 164 for (const ContentSuggestion& suggestion : |
155 suggestions_by_category_[changed_category]) { | 165 suggestions_by_category_[changed_category]) { |
156 id_category_map_.erase(suggestion.id()); | 166 id_category_map_.erase(suggestion.id()); |
157 } | 167 } |
158 | 168 |
159 for (const ContentSuggestion& suggestion : new_suggestions) { | 169 for (const ContentSuggestion& suggestion : new_suggestions) { |
160 id_category_map_[suggestion.id()] = changed_category; | 170 id_category_map_.insert(std::make_pair(suggestion.id(), changed_category)); |
161 } | 171 } |
162 | 172 |
163 suggestions_by_category_[changed_category] = std::move(new_suggestions); | 173 suggestions_by_category_[changed_category] = std::move(new_suggestions); |
164 | 174 |
165 FOR_EACH_OBSERVER(Observer, observers_, OnNewSuggestions()); | 175 FOR_EACH_OBSERVER(Observer, observers_, OnNewSuggestions()); |
166 } | 176 } |
167 | 177 |
168 void ContentSuggestionsService::OnCategoryStatusChanged( | 178 void ContentSuggestionsService::OnCategoryStatusChanged( |
169 ContentSuggestionsCategory changed_category, | 179 ContentSuggestionsCategory changed_category, |
170 ContentSuggestionsCategoryStatus new_status) { | 180 ContentSuggestionsCategoryStatus new_status) { |
171 if (!IsContentSuggestionsCategoryStatusAvailable(new_status)) { | 181 if (!IsContentSuggestionsCategoryStatusAvailable(new_status)) { |
172 for (const ContentSuggestion& suggestion : | 182 for (const ContentSuggestion& suggestion : |
173 suggestions_by_category_[changed_category]) { | 183 suggestions_by_category_[changed_category]) { |
174 id_category_map_.erase(suggestion.id()); | 184 id_category_map_.erase(suggestion.id()); |
175 } | 185 } |
176 suggestions_by_category_.erase(changed_category); | 186 suggestions_by_category_.erase(changed_category); |
177 } | 187 } |
178 NotifyCategoryStatusChanged(changed_category); | 188 NotifyCategoryStatusChanged(changed_category); |
179 } | 189 } |
180 | 190 |
181 void ContentSuggestionsService::OnProviderShutdown( | 191 void ContentSuggestionsService::OnProviderShutdown( |
182 ContentSuggestionsProvider* provider) { | 192 ContentSuggestionsProvider* provider) { |
183 for (ContentSuggestionsCategory category : provider->provided_categories()) { | 193 for (ContentSuggestionsCategory category : |
| 194 provider->GetProvidedCategories()) { |
184 auto iterator = std::find(categories_.begin(), categories_.end(), category); | 195 auto iterator = std::find(categories_.begin(), categories_.end(), category); |
185 DCHECK(iterator != categories_.end()); | 196 DCHECK(iterator != categories_.end()); |
186 categories_.erase(iterator); | 197 categories_.erase(iterator); |
187 for (const ContentSuggestion& suggestion : | 198 for (const ContentSuggestion& suggestion : |
188 suggestions_by_category_[category]) { | 199 suggestions_by_category_[category]) { |
189 id_category_map_.erase(suggestion.id()); | 200 id_category_map_.erase(suggestion.id()); |
190 } | 201 } |
191 suggestions_by_category_.erase(category); | 202 suggestions_by_category_.erase(category); |
192 providers_.erase(category); | 203 providers_.erase(category); |
193 NotifyCategoryStatusChanged(category); | 204 NotifyCategoryStatusChanged(category); |
194 } | 205 } |
195 } | 206 } |
196 | 207 |
197 bool ContentSuggestionsService::IsCategoryRegistered( | 208 bool ContentSuggestionsService::IsCategoryRegistered( |
198 ContentSuggestionsCategory category) const { | 209 ContentSuggestionsCategory category) const { |
199 return std::find(categories_.begin(), categories_.end(), category) != | 210 return std::find(categories_.begin(), categories_.end(), category) != |
200 categories_.end(); | 211 categories_.end(); |
201 } | 212 } |
202 | 213 |
203 void ContentSuggestionsService::NotifyCategoryStatusChanged( | 214 void ContentSuggestionsService::NotifyCategoryStatusChanged( |
204 ContentSuggestionsCategory category) { | 215 ContentSuggestionsCategory category) { |
205 FOR_EACH_OBSERVER( | 216 FOR_EACH_OBSERVER( |
206 Observer, observers_, | 217 Observer, observers_, |
207 OnCategoryStatusChanged(category, GetCategoryStatus(category))); | 218 OnCategoryStatusChanged(category, GetCategoryStatus(category))); |
208 } | 219 } |
209 | 220 |
210 } // namespace ntp_snippets | 221 } // namespace ntp_snippets |
OLD | NEW |