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 package org.chromium.chrome.browser.ntp.cards; | 5 package org.chromium.chrome.browser.ntp.cards; |
6 | 6 |
7 import org.chromium.base.Callback; | 7 import org.chromium.base.Callback; |
8 import org.chromium.base.Log; | 8 import org.chromium.base.Log; |
9 import org.chromium.base.VisibleForTesting; | 9 import org.chromium.base.VisibleForTesting; |
10 import org.chromium.chrome.browser.ntp.NewTabPage.DestructionObserver; | 10 import org.chromium.chrome.browser.ntp.NewTabPage.DestructionObserver; |
11 import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager; | |
12 import org.chromium.chrome.browser.ntp.snippets.CategoryInt; | 11 import org.chromium.chrome.browser.ntp.snippets.CategoryInt; |
13 import org.chromium.chrome.browser.ntp.snippets.CategoryStatus.CategoryStatusEnu
m; | 12 import org.chromium.chrome.browser.ntp.snippets.CategoryStatus.CategoryStatusEnu
m; |
14 import org.chromium.chrome.browser.ntp.snippets.SectionHeader; | 13 import org.chromium.chrome.browser.ntp.snippets.SectionHeader; |
15 import org.chromium.chrome.browser.ntp.snippets.SnippetArticle; | 14 import org.chromium.chrome.browser.ntp.snippets.SnippetArticle; |
16 import org.chromium.chrome.browser.ntp.snippets.SnippetArticleViewHolder; | 15 import org.chromium.chrome.browser.ntp.snippets.SnippetArticleViewHolder; |
17 import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge; | 16 import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge; |
18 import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource; | 17 import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource; |
19 import org.chromium.chrome.browser.offlinepages.ClientId; | 18 import org.chromium.chrome.browser.offlinepages.ClientId; |
20 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge; | 19 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge; |
21 import org.chromium.chrome.browser.offlinepages.OfflinePageItem; | 20 import org.chromium.chrome.browser.offlinepages.OfflinePageItem; |
22 import org.chromium.chrome.browser.suggestions.SuggestionsRanker; | 21 import org.chromium.chrome.browser.suggestions.SuggestionsRanker; |
| 22 import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegate; |
23 | 23 |
24 import java.util.ArrayList; | 24 import java.util.ArrayList; |
25 import java.util.Iterator; | 25 import java.util.Iterator; |
26 import java.util.List; | 26 import java.util.List; |
27 | 27 |
28 /** | 28 /** |
29 * A group of suggestions, with a header, a status card, and a progress indicato
r. This is | 29 * A group of suggestions, with a header, a status card, and a progress indicato
r. This is |
30 * responsible for tracking whether its suggestions have been saved offline. | 30 * responsible for tracking whether its suggestions have been saved offline. |
31 */ | 31 */ |
32 public class SuggestionsSection extends InnerNode { | 32 public class SuggestionsSection extends InnerNode { |
(...skipping 20 matching lines...) Expand all Loading... |
53 private boolean mSubsequentSuggestionsSeen; | 53 private boolean mSubsequentSuggestionsSeen; |
54 | 54 |
55 /** | 55 /** |
56 * Delegate interface that allows dismissing this section without introducin
g | 56 * Delegate interface that allows dismissing this section without introducin
g |
57 * a circular dependency. | 57 * a circular dependency. |
58 */ | 58 */ |
59 public interface Delegate { | 59 public interface Delegate { |
60 void dismissSection(SuggestionsSection section); | 60 void dismissSection(SuggestionsSection section); |
61 } | 61 } |
62 | 62 |
63 public SuggestionsSection(Delegate delegate, NewTabPageManager manager, | 63 public SuggestionsSection(Delegate delegate, SuggestionsUiDelegate uiDelegat
e, |
64 SuggestionsRanker ranker, OfflinePageBridge offlinePageBridge, | 64 SuggestionsRanker ranker, OfflinePageBridge offlinePageBridge, |
65 SuggestionsCategoryInfo info) { | 65 SuggestionsCategoryInfo info) { |
66 mDelegate = delegate; | 66 mDelegate = delegate; |
67 mCategoryInfo = info; | 67 mCategoryInfo = info; |
68 mOfflinePageBridge = offlinePageBridge; | 68 mOfflinePageBridge = offlinePageBridge; |
69 | 69 |
70 mHeader = new SectionHeader(info.getTitle()); | 70 mHeader = new SectionHeader(info.getTitle()); |
71 mSuggestionsList = new SuggestionsList(manager, ranker, info); | 71 mSuggestionsList = new SuggestionsList(uiDelegate, ranker, info); |
72 mStatus = StatusItem.createNoSuggestionsItem(info); | 72 mStatus = StatusItem.createNoSuggestionsItem(info); |
73 mMoreButton = new ActionItem(this, ranker); | 73 mMoreButton = new ActionItem(this, ranker); |
74 mProgressIndicator = new ProgressItem(); | 74 mProgressIndicator = new ProgressItem(); |
75 addChildren(mHeader, mSuggestionsList, mStatus, mMoreButton, mProgressIn
dicator); | 75 addChildren(mHeader, mSuggestionsList, mStatus, mMoreButton, mProgressIn
dicator); |
76 | 76 |
77 setupOfflinePageBridgeObserver(manager); | 77 setupOfflinePageBridgeObserver(uiDelegate); |
78 refreshChildrenVisibility(); | 78 refreshChildrenVisibility(); |
79 } | 79 } |
80 | 80 |
81 private static class SuggestionsList extends ChildNode implements Iterable<S
nippetArticle> { | 81 private static class SuggestionsList extends ChildNode implements Iterable<S
nippetArticle> { |
82 private final List<SnippetArticle> mSuggestions = new ArrayList<>(); | 82 private final List<SnippetArticle> mSuggestions = new ArrayList<>(); |
83 private final NewTabPageManager mNewTabPageManager; | 83 |
| 84 // TODO(crbug.com/677672): Replace by SuggestionSource when it handles d
estruction. |
| 85 private final SuggestionsUiDelegate mUiDelegate; |
84 private final SuggestionsRanker mSuggestionsRanker; | 86 private final SuggestionsRanker mSuggestionsRanker; |
85 private final SuggestionsCategoryInfo mCategoryInfo; | 87 private final SuggestionsCategoryInfo mCategoryInfo; |
86 | 88 |
87 public SuggestionsList(NewTabPageManager newTabPageManager, | 89 public SuggestionsList(SuggestionsUiDelegate uiDelegate, SuggestionsRank
er ranker, |
88 SuggestionsRanker ranker, SuggestionsCategoryInfo categoryInfo)
{ | 90 SuggestionsCategoryInfo categoryInfo) { |
89 mNewTabPageManager = newTabPageManager; | 91 mUiDelegate = uiDelegate; |
90 mSuggestionsRanker = ranker; | 92 mSuggestionsRanker = ranker; |
91 mCategoryInfo = categoryInfo; | 93 mCategoryInfo = categoryInfo; |
92 } | 94 } |
93 | 95 |
94 @Override | 96 @Override |
95 public int getItemCount() { | 97 public int getItemCount() { |
96 return mSuggestions.size(); | 98 return mSuggestions.size(); |
97 } | 99 } |
98 | 100 |
99 @Override | 101 @Override |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
159 } | 161 } |
160 | 162 |
161 @Override | 163 @Override |
162 public Iterator<SnippetArticle> iterator() { | 164 public Iterator<SnippetArticle> iterator() { |
163 return mSuggestions.iterator(); | 165 return mSuggestions.iterator(); |
164 } | 166 } |
165 | 167 |
166 @Override | 168 @Override |
167 public void dismissItem(int position, Callback<String> itemRemovedCallba
ck) { | 169 public void dismissItem(int position, Callback<String> itemRemovedCallba
ck) { |
168 checkIndex(position); | 170 checkIndex(position); |
169 SuggestionsSource suggestionsSource = mNewTabPageManager.getSuggesti
onsSource(); | 171 SuggestionsSource suggestionsSource = mUiDelegate.getSuggestionsSour
ce(); |
170 if (suggestionsSource == null) { | 172 if (suggestionsSource == null) { |
171 // It is possible for this method to be called after the NewTabP
age has had | 173 // It is possible for this method to be called after the NewTabP
age has had |
172 // destroy() called. This can happen when | 174 // destroy() called. This can happen when |
173 // NewTabPageRecyclerView.dismissWithAnimation() is called and t
he animation ends | 175 // NewTabPageRecyclerView.dismissWithAnimation() is called and t
he animation ends |
174 // after the user has navigated away. In this case we cannot inf
orm the native side | 176 // after the user has navigated away. In this case we cannot inf
orm the native side |
175 // that the snippet has been dismissed (http://crbug.com/649299)
. | 177 // that the snippet has been dismissed (http://crbug.com/649299)
. |
176 return; | 178 return; |
177 } | 179 } |
178 | 180 |
179 SnippetArticle suggestion = remove(position); | 181 SnippetArticle suggestion = remove(position); |
180 suggestionsSource.dismissSuggestion(suggestion); | 182 suggestionsSource.dismissSuggestion(suggestion); |
181 itemRemovedCallback.onResult(suggestion.mTitle); | 183 itemRemovedCallback.onResult(suggestion.mTitle); |
182 } | 184 } |
183 | 185 |
184 public void updateSuggestionOfflineId(SnippetArticle article, Long newId
) { | 186 public void updateSuggestionOfflineId(SnippetArticle article, Long newId
) { |
185 int index = mSuggestions.indexOf(article); | 187 int index = mSuggestions.indexOf(article); |
186 // The suggestions could have been removed / replaced in the meantim
e. | 188 // The suggestions could have been removed / replaced in the meantim
e. |
187 if (index == -1) return; | 189 if (index == -1) return; |
188 | 190 |
189 Long oldId = article.getOfflinePageOfflineId(); | 191 Long oldId = article.getOfflinePageOfflineId(); |
190 article.setOfflinePageOfflineId(newId); | 192 article.setOfflinePageOfflineId(newId); |
191 | 193 |
192 if ((oldId == null) == (newId == null)) return; | 194 if ((oldId == null) == (newId == null)) return; |
193 notifyItemChanged(index, SnippetArticleViewHolder.PARTIAL_UPDATE_OFF
LINE_ID); | 195 notifyItemChanged(index, SnippetArticleViewHolder.PARTIAL_UPDATE_OFF
LINE_ID); |
194 } | 196 } |
195 } | 197 } |
196 | 198 |
197 private void setupOfflinePageBridgeObserver(NewTabPageManager manager) { | 199 private void setupOfflinePageBridgeObserver(SuggestionsUiDelegate uiDelegate
) { |
198 final OfflinePageBridge.OfflinePageModelObserver observer = | 200 final OfflinePageBridge.OfflinePageModelObserver observer = |
199 new OfflinePageBridge.OfflinePageModelObserver() { | 201 new OfflinePageBridge.OfflinePageModelObserver() { |
200 @Override | 202 @Override |
201 public void offlinePageModelLoaded() { | 203 public void offlinePageModelLoaded() { |
202 updateAllSnippetOfflineAvailability(); | 204 updateAllSnippetOfflineAvailability(); |
203 } | 205 } |
204 | 206 |
205 @Override | 207 @Override |
206 public void offlinePageAdded(OfflinePageItem addedPage) { | 208 public void offlinePageAdded(OfflinePageItem addedPage) { |
207 updateAllSnippetOfflineAvailability(); | 209 updateAllSnippetOfflineAvailability(); |
208 } | 210 } |
209 | 211 |
210 @Override | 212 @Override |
211 public void offlinePageDeleted(long offlineId, ClientId clie
ntId) { | 213 public void offlinePageDeleted(long offlineId, ClientId clie
ntId) { |
212 for (SnippetArticle article : mSuggestionsList) { | 214 for (SnippetArticle article : mSuggestionsList) { |
213 if (article.requiresExactOfflinePage()) continue; | 215 if (article.requiresExactOfflinePage()) continue; |
214 Long articleOfflineId = article.getOfflinePageOfflin
eId(); | 216 Long articleOfflineId = article.getOfflinePageOfflin
eId(); |
215 if (articleOfflineId == null) continue; | 217 if (articleOfflineId == null) continue; |
216 if (articleOfflineId.longValue() != offlineId) conti
nue; | 218 if (articleOfflineId.longValue() != offlineId) conti
nue; |
217 // The old value cannot be simply removed without a
request to the | 219 // The old value cannot be simply removed without a
request to the |
218 // model, because there may be an older offline page
for the same | 220 // model, because there may be an older offline page
for the same |
219 // URL. | 221 // URL. |
220 updateSnippetOfflineAvailability(article); | 222 updateSnippetOfflineAvailability(article); |
221 } | 223 } |
222 } | 224 } |
223 }; | 225 }; |
224 | 226 |
225 mOfflinePageBridge.addObserver(observer); | 227 mOfflinePageBridge.addObserver(observer); |
226 | 228 |
227 manager.addDestructionObserver(new DestructionObserver() { | 229 uiDelegate.addDestructionObserver(new DestructionObserver() { |
228 @Override | 230 @Override |
229 public void onDestroy() { | 231 public void onDestroy() { |
230 mIsNtpDestroyed = true; | 232 mIsNtpDestroyed = true; |
231 mOfflinePageBridge.removeObserver(observer); | 233 mOfflinePageBridge.removeObserver(observer); |
232 } | 234 } |
233 }); | 235 }); |
234 } | 236 } |
235 | 237 |
236 private void refreshChildrenVisibility() { | 238 private void refreshChildrenVisibility() { |
237 mStatus.setVisible(!hasSuggestions()); | 239 mStatus.setVisible(!hasSuggestions()); |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
450 @VisibleForTesting | 452 @VisibleForTesting |
451 ActionItem getActionItem() { | 453 ActionItem getActionItem() { |
452 return mMoreButton; | 454 return mMoreButton; |
453 } | 455 } |
454 | 456 |
455 @VisibleForTesting | 457 @VisibleForTesting |
456 StatusItem getStatusItem() { | 458 StatusItem getStatusItem() { |
457 return mStatus; | 459 return mStatus; |
458 } | 460 } |
459 } | 461 } |
OLD | NEW |