OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "components/ntp_snippets/content_suggestions_service.h" | |
6 | |
7 #include <algorithm> | |
8 #include <iterator> | |
9 | |
10 #include "base/bind.h" | |
11 #include "base/strings/string_number_conversions.h" | |
12 #include "ui/gfx/image/image.h" | |
13 | |
14 namespace ntp_snippets { | |
15 | |
16 ContentSuggestionsService::ContentSuggestionsService(State state) | |
17 : state_(state) {} | |
18 | |
19 ContentSuggestionsService::~ContentSuggestionsService() {} | |
20 | |
21 void ContentSuggestionsService::Shutdown() { | |
22 DCHECK(providers_.empty()); | |
23 DCHECK(categories_.empty()); | |
24 DCHECK(suggestions_by_category_.empty()); | |
25 DCHECK(id_category_map_.empty()); | |
26 state_ = State::DISABLED; | |
27 FOR_EACH_OBSERVER(Observer, observers_, ContentSuggestionsServiceShutdown()); | |
28 } | |
29 | |
30 ContentSuggestionsCategoryStatus ContentSuggestionsService::GetCategoryStatus( | |
31 ContentSuggestionsCategory category) const { | |
32 if (state_ == State::DISABLED) | |
33 return ContentSuggestionsCategoryStatus:: | |
Marc Treib
2016/07/07 09:37:51
nit: braces if the body doesn't fit on one line
Philipp Keck
2016/07/07 12:22:30
Done.
| |
34 ALL_SUGGESTIONS_EXPLICITLY_DISABLED; | |
35 | |
36 auto iterator = providers_.find(category); | |
37 if (iterator == providers_.end()) | |
38 return ContentSuggestionsCategoryStatus::NOT_PROVIDED; | |
39 | |
40 return iterator->second->GetCategoryStatus(category); | |
41 } | |
42 | |
43 const std::vector<ContentSuggestion>& | |
44 ContentSuggestionsService::GetSuggestionsForCategory( | |
45 ContentSuggestionsCategory category) const { | |
46 auto iterator = suggestions_by_category_.find(category); | |
47 if (iterator == suggestions_by_category_.end()) { | |
Bernhard Bauer
2016/07/07 10:02:19
And no braces here ☺
Philipp Keck
2016/07/07 12:22:29
Done.
| |
48 return no_suggestions_; | |
49 } | |
50 return iterator->second; | |
51 } | |
52 | |
53 void ContentSuggestionsService::FetchSuggestionImage( | |
54 const std::string& suggestion_id, | |
55 const ImageFetchedCallback& callback) { | |
56 if (!id_category_map_.count(suggestion_id)) { | |
57 LOG(WARNING) << "Requested image for unknown suggestion " << suggestion_id; | |
58 callback.Run(suggestion_id, gfx::Image()); | |
59 return; | |
60 } | |
61 ContentSuggestionsCategory category = id_category_map_[suggestion_id]; | |
62 if (!providers_.count(category)) { | |
63 LOG(WARNING) << "Requested image for suggestion " << suggestion_id | |
64 << " for unavailable category " << int(category); | |
65 callback.Run(suggestion_id, gfx::Image()); | |
66 return; | |
67 } | |
68 providers_[category]->FetchSuggestionImage(suggestion_id, callback); | |
69 } | |
70 | |
71 void ContentSuggestionsService::ClearCachedSuggestionsForDebugging() { | |
72 suggestions_by_category_.clear(); | |
73 id_category_map_.clear(); | |
74 for (auto& provider : providers_) { | |
Marc Treib
2016/07/07 09:37:51
nit: The elements are not providers, but category+
Philipp Keck
2016/07/07 12:22:30
Done.
| |
75 provider.second->ClearCachedSuggestionsForDebugging(); | |
76 } | |
77 FOR_EACH_OBSERVER(Observer, observers_, OnNewSuggestions()); | |
78 } | |
79 | |
80 void ContentSuggestionsService::ClearDiscardedSuggestionsForDebugging() { | |
81 for (auto& provider : providers_) { | |
Marc Treib
2016/07/07 09:37:51
Same here
Philipp Keck
2016/07/07 12:22:30
Done.
| |
82 provider.second->ClearDiscardedSuggestionsForDebugging(); | |
83 } | |
84 } | |
85 | |
86 void ContentSuggestionsService::DiscardSuggestion( | |
87 const std::string& suggestion_id) { | |
88 if (!id_category_map_.count(suggestion_id)) { | |
89 LOG(WARNING) << "Discarded unknown suggestion " << suggestion_id; | |
90 return; | |
91 } | |
92 ContentSuggestionsCategory category = id_category_map_[suggestion_id]; | |
93 if (!providers_.count(category)) { | |
94 LOG(WARNING) << "Discarded suggestion " << suggestion_id | |
95 << " for unavailable category " << int(category); | |
96 return; | |
97 } | |
98 providers_[category]->DiscardSuggestion(suggestion_id); | |
99 | |
100 // Remove the suggestion locally. | |
101 id_category_map_.erase(suggestion_id); | |
102 std::vector<ContentSuggestion>* suggestions = | |
103 &suggestions_by_category_[category]; | |
104 auto position = | |
105 std::find_if(suggestions->begin(), suggestions->end(), | |
106 [&suggestion_id](const ContentSuggestion& suggestion) { | |
107 return suggestion_id == suggestion.id(); | |
108 }); | |
109 DCHECK(position != suggestions->end()); | |
110 suggestions->erase(position); | |
111 } | |
112 | |
113 void ContentSuggestionsService::AddObserver(Observer* observer) { | |
114 observers_.AddObserver(observer); | |
115 } | |
116 | |
117 void ContentSuggestionsService::RemoveObserver(Observer* observer) { | |
118 observers_.RemoveObserver(observer); | |
119 } | |
120 | |
121 void ContentSuggestionsService::RegisterProvider( | |
122 ContentSuggestionsProvider* provider) { | |
123 if (state_ == State::DISABLED) | |
Marc Treib
2016/07/07 09:37:51
Are we sure about this? We'll have to change it on
Philipp Keck
2016/07/07 12:22:30
Yes. It is here because the NTPSnippetsService wil
Marc Treib
2016/07/07 12:32:16
Alright. Add a TODO maybe?
Philipp Keck
2016/07/07 12:44:06
Done.
| |
124 return; | |
125 | |
126 for (ContentSuggestionsCategory category : provider->provided_categories()) { | |
127 DCHECK_EQ(0ul, providers_.count(category)); | |
128 providers_[category] = provider; | |
129 // TODO(pke) In the future, make sure that the categories have some useful | |
Bernhard Bauer
2016/07/07 10:02:19
Nit: The exact format for TODOs is TODO(ldap): ☺
Philipp Keck
2016/07/07 12:22:29
Done.
| |
130 // (maybe constant, at least consistent) ordering for the UI. | |
131 categories_.push_back(category); | |
132 if (IsContentSuggestionsCategoryStatusAvailable( | |
133 provider->GetCategoryStatus(category))) { | |
134 suggestions_by_category_[category] = std::vector<ContentSuggestion>(); | |
135 } | |
136 provider->SetObserver(this); | |
Marc Treib
2016/07/07 09:37:51
This should go out of the loop
Philipp Keck
2016/07/07 12:22:29
Done.
| |
137 FOR_EACH_OBSERVER(Observer, observers_, | |
138 OnCategoryStatusChanged( | |
139 category, provider->GetCategoryStatus(category))); | |
140 } | |
141 } | |
142 | |
143 //////////////////////////////////////////////////////////////////////////////// | |
144 // Private methods | |
145 | |
146 void ContentSuggestionsService::OnNewSuggestions( | |
147 ContentSuggestionsCategory changed_category, | |
148 std::vector<ContentSuggestion> new_suggestions) { | |
149 DCHECK(IsCategoryRegistered(changed_category)); | |
150 | |
151 for (const ContentSuggestion& suggestion : | |
152 suggestions_by_category_[changed_category]) { | |
153 id_category_map_.erase(suggestion.id()); | |
154 } | |
155 | |
156 for (const ContentSuggestion& suggestion : new_suggestions) { | |
157 id_category_map_[suggestion.id()] = changed_category; | |
158 } | |
159 | |
160 suggestions_by_category_[changed_category] = std::move(new_suggestions); | |
161 | |
162 FOR_EACH_OBSERVER(Observer, observers_, OnNewSuggestions()); | |
163 } | |
164 | |
165 void ContentSuggestionsService::OnCategoryStatusChanged( | |
166 ContentSuggestionsCategory changed_category, | |
167 ContentSuggestionsCategoryStatus new_status) { | |
168 if (!IsContentSuggestionsCategoryStatusAvailable(new_status)) { | |
169 for (const ContentSuggestion& suggestion : | |
170 suggestions_by_category_[changed_category]) { | |
171 id_category_map_.erase(suggestion.id()); | |
172 } | |
173 suggestions_by_category_.erase(changed_category); | |
174 } | |
Marc Treib
2016/07/07 09:37:51
Do we also need to do something if it is now avail
Philipp Keck
2016/07/07 12:22:30
No. id_category_map_ and suggestions_by_category_
| |
175 FOR_EACH_OBSERVER(Observer, observers_, | |
176 OnCategoryStatusChanged(changed_category, new_status)); | |
177 } | |
178 | |
179 void ContentSuggestionsService::OnProviderShutdown( | |
180 ContentSuggestionsProvider* provider) { | |
181 for (ContentSuggestionsCategory category : provider->provided_categories()) { | |
182 auto iterator = std::find(categories_.begin(), categories_.end(), category); | |
183 DCHECK(iterator != categories_.end()); | |
184 categories_.erase(iterator); | |
185 for (const ContentSuggestion& suggestion : | |
186 suggestions_by_category_[category]) { | |
187 id_category_map_.erase(suggestion.id()); | |
188 } | |
189 suggestions_by_category_.erase(category); | |
190 providers_.erase(category); | |
191 FOR_EACH_OBSERVER( | |
192 Observer, observers_, | |
193 OnCategoryStatusChanged(category, GetCategoryStatus(category))); | |
Marc Treib
2016/07/07 09:37:51
optional: You could replace all the OnCategoryStat
Philipp Keck
2016/07/07 12:22:29
Done.
| |
194 } | |
195 } | |
196 | |
197 bool ContentSuggestionsService::IsCategoryRegistered( | |
198 ContentSuggestionsCategory category) const { | |
199 return std::find(categories_.begin(), categories_.end(), category) != | |
200 categories_.end(); | |
201 } | |
202 | |
203 } // namespace ntp_snippets | |
OLD | NEW |