Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(457)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java

Issue 2396523002: Unify NewTabPageItem and ItemGroup into a single tree-structured interface. (Closed)
Patch Set: oo Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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.VisibleForTesting; 7 import org.chromium.base.VisibleForTesting;
8 import org.chromium.chrome.browser.ntp.snippets.CategoryInt; 8 import org.chromium.chrome.browser.ntp.snippets.CategoryInt;
9 import org.chromium.chrome.browser.ntp.snippets.CategoryStatus.CategoryStatusEnu m; 9 import org.chromium.chrome.browser.ntp.snippets.CategoryStatus.CategoryStatusEnu m;
10 import org.chromium.chrome.browser.ntp.snippets.SectionHeader; 10 import org.chromium.chrome.browser.ntp.snippets.SectionHeader;
11 import org.chromium.chrome.browser.ntp.snippets.SnippetArticle; 11 import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
12 import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge; 12 import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge;
13 13
14 import java.util.ArrayList; 14 import java.util.ArrayList;
15 import java.util.Collections; 15 import java.util.Collections;
16 import java.util.List; 16 import java.util.List;
17 17
18 /** 18 /**
19 * A group of suggestions, with a header, a status card, and a progress indicato r. 19 * A group of suggestions, with a header, a status card, and a progress indicato r.
20 */ 20 */
21 public class SuggestionsSection implements ItemGroup { 21 public class SuggestionsSection extends InnerNode {
22 private final List<SnippetArticle> mSuggestions = new ArrayList<>(); 22 private final List<SnippetArticle> mSuggestions = new ArrayList<>();
23 private final SectionHeader mHeader; 23 private final SectionHeader mHeader;
24 private final StatusItem mStatus; 24 private final StatusItem mStatus;
25 private final ProgressItem mProgressIndicator = new ProgressItem(); 25 private final ProgressItem mProgressIndicator = new ProgressItem();
26 private final ActionItem mMoreButton; 26 private final ActionItem mMoreButton;
27 private final Observer mObserver;
28 private final SuggestionsCategoryInfo mCategoryInfo; 27 private final SuggestionsCategoryInfo mCategoryInfo;
29 28
30 public SuggestionsSection(SuggestionsCategoryInfo info, Observer observer) { 29 public SuggestionsSection(NodeParent parent, SuggestionsCategoryInfo info) {
30 super(parent);
31 mHeader = new SectionHeader(info.getTitle()); 31 mHeader = new SectionHeader(info.getTitle());
32 mCategoryInfo = info; 32 mCategoryInfo = info;
33 mObserver = observer;
34 mMoreButton = new ActionItem(info); 33 mMoreButton = new ActionItem(info);
35 mStatus = StatusItem.createNoSuggestionsItem(info); 34 mStatus = StatusItem.createNoSuggestionsItem(info);
36 } 35 }
37 36
38 @Override 37 @Override
39 public List<NewTabPageItem> getItems() { 38 public List<TreeNode> getChildren() {
40 // Note: Keep this coherent with the various notify** calls on ItemGroup .Observer 39 // Note: Keep this coherent with the various notify** calls on ItemGroup .Observer
41 List<NewTabPageItem> items = new ArrayList<>(); 40 List<TreeNode> items = new ArrayList<>();
42 items.add(mHeader); 41 items.add(mHeader);
43 items.addAll(mSuggestions); 42 items.addAll(mSuggestions);
44 43
45 if (mSuggestions.isEmpty()) items.add(mStatus); 44 if (mSuggestions.isEmpty()) items.add(mStatus);
46 if (mCategoryInfo.hasMoreButton() || mSuggestions.isEmpty()) items.add(m MoreButton); 45 if (mCategoryInfo.hasMoreButton() || mSuggestions.isEmpty()) items.add(m MoreButton);
47 if (mSuggestions.isEmpty()) items.add(mProgressIndicator); 46 if (mSuggestions.isEmpty()) items.add(mProgressIndicator);
48 47
49 return Collections.unmodifiableList(items); 48 return Collections.unmodifiableList(items);
50 } 49 }
51 50
51 @Override
52 public SnippetArticle getSuggestionAt(int position) {
53 if (position < 1) throw new IndexOutOfBoundsException();
dgn 2016/10/13 15:42:41 why do we throw for 0 (the header) but just return
Bernhard Bauer 2016/10/13 16:13:14 Oh, good catch! Actually, I realized that the defa
54
55 if (position > mSuggestions.size()) {
56 if (position <= getChildren().size()) return null;
57
58 throw new IndexOutOfBoundsException();
59 }
60
61 return mSuggestions.get(position - 1);
62 }
63
52 public void removeSuggestion(SnippetArticle suggestion) { 64 public void removeSuggestion(SnippetArticle suggestion) {
53 int removedIndex = mSuggestions.indexOf(suggestion); 65 int removedIndex = mSuggestions.indexOf(suggestion);
54 if (removedIndex == -1) return; 66 if (removedIndex == -1) return;
55 67
56 mSuggestions.remove(removedIndex); 68 mSuggestions.remove(removedIndex);
57 if (mMoreButton != null) mMoreButton.setDismissable(!hasSuggestions()); 69 if (mMoreButton != null) mMoreButton.setDismissable(!hasSuggestions());
58 70
59 // Note: Keep this coherent with getItems() 71 // Note: Keep this coherent with getItems()
60 int globalRemovedIndex = removedIndex + 1; // Header has index 0 in the section. 72 int globalRemovedIndex = removedIndex + 1; // Header has index 0 in the section.
61 mObserver.onItemRangeRemoved(this, globalRemovedIndex, 1); 73 notifyItemRemoved(globalRemovedIndex);
62 74
63 // If we still have some suggestions, we are done. Otherwise, we'll have to notify about the 75 // If we still have some suggestions, we are done. Otherwise, we'll have to notify about the
64 // status-related items that are now present. 76 // status-related items that are now present.
65 if (hasSuggestions()) return; 77 if (hasSuggestions()) return;
66 mObserver.onItemRangeInserted(this, globalRemovedIndex, 1); // Status ca rd. 78 notifyItemInserted(globalRemovedIndex); // Status card.
67 if (!mCategoryInfo.hasMoreButton()) { 79 if (!mCategoryInfo.hasMoreButton()) {
68 mObserver.onItemRangeInserted(this, globalRemovedIndex + 1, 1); // A ction card. 80 notifyItemInserted(globalRemovedIndex + 1); // Action card.
69 } 81 }
70 mObserver.onItemRangeInserted(this, globalRemovedIndex + 2, 1); // Progr ess indicator. 82 notifyItemInserted(globalRemovedIndex + 2); // Progress indicator.
71 } 83 }
72 84
73 public void removeSuggestionById(String idWithinCategory) { 85 public void removeSuggestionById(String idWithinCategory) {
74 for (SnippetArticle suggestion : mSuggestions) { 86 for (SnippetArticle suggestion : mSuggestions) {
75 if (suggestion.mIdWithinCategory.equals(idWithinCategory)) { 87 if (suggestion.mIdWithinCategory.equals(idWithinCategory)) {
76 removeSuggestion(suggestion); 88 removeSuggestion(suggestion);
77 return; 89 return;
78 } 90 }
79 } 91 }
80 } 92 }
81 93
82 public boolean hasSuggestions() { 94 public boolean hasSuggestions() {
83 return !mSuggestions.isEmpty(); 95 return !mSuggestions.isEmpty();
84 } 96 }
85 97
86 public int getSuggestionsCount() { 98 public int getSuggestionsCount() {
87 return mSuggestions.size(); 99 return mSuggestions.size();
88 } 100 }
89 101
90 public void setSuggestions(List<SnippetArticle> suggestions, @CategoryStatus Enum int status) { 102 public void setSuggestions(List<SnippetArticle> suggestions, @CategoryStatus Enum int status) {
91 copyThumbnails(suggestions); 103 copyThumbnails(suggestions);
92 104
93 int itemCountBefore = getItems().size(); 105 int itemCountBefore = getItemCount();
94 setStatusInternal(status); 106 setStatusInternal(status);
95 107
96 mSuggestions.clear(); 108 mSuggestions.clear();
97 mSuggestions.addAll(suggestions); 109 mSuggestions.addAll(suggestions);
98 110
99 if (mMoreButton != null) { 111 if (mMoreButton != null) {
100 mMoreButton.setPosition(mSuggestions.size()); 112 mMoreButton.setPosition(mSuggestions.size());
101 mMoreButton.setDismissable(mSuggestions.isEmpty()); 113 mMoreButton.setDismissable(mSuggestions.isEmpty());
102 } 114 }
103 notifySectionChanged(itemCountBefore); 115 notifySectionChanged(itemCountBefore);
104 } 116 }
105 117
106 /** Sets the status for the section. Some statuses can cause the suggestions to be cleared. */ 118 /** Sets the status for the section. Some statuses can cause the suggestions to be cleared. */
107 public void setStatus(@CategoryStatusEnum int status) { 119 public void setStatus(@CategoryStatusEnum int status) {
108 int itemCountBefore = getItems().size(); 120 int itemCountBefore = getItemCount();
109 setStatusInternal(status); 121 setStatusInternal(status);
110 notifySectionChanged(itemCountBefore); 122 notifySectionChanged(itemCountBefore);
111 } 123 }
112 124
113 private void setStatusInternal(@CategoryStatusEnum int status) { 125 private void setStatusInternal(@CategoryStatusEnum int status) {
114 if (!SnippetsBridge.isCategoryStatusAvailable(status)) mSuggestions.clea r(); 126 if (!SnippetsBridge.isCategoryStatusAvailable(status)) mSuggestions.clea r();
115 127
116 mProgressIndicator.setVisible(SnippetsBridge.isCategoryLoading(status)); 128 mProgressIndicator.setVisible(SnippetsBridge.isCategoryLoading(status));
117 } 129 }
118 130
(...skipping 14 matching lines...) Expand all
133 /** 145 /**
134 * The dismiss sibling is an item that should be dismissed at the same time as the provided 146 * The dismiss sibling is an item that should be dismissed at the same time as the provided
135 * one. For example, if we want to dismiss a status card that has a More but ton attached, the 147 * one. For example, if we want to dismiss a status card that has a More but ton attached, the
136 * button is the card's dismiss sibling. This function return the adapter po sition delta to 148 * button is the card's dismiss sibling. This function return the adapter po sition delta to
137 * apply to get to the sibling from the provided item. For the previous exam ple, it would return 149 * apply to get to the sibling from the provided item. For the previous exam ple, it would return
138 * {@code +1}, as the button comes right after the status card. 150 * {@code +1}, as the button comes right after the status card.
139 * 151 *
140 * @return a position delta to apply to the position of the provided item to get the adapter 152 * @return a position delta to apply to the position of the provided item to get the adapter
141 * position of the item to animate. Returns {@code 0} if there is no dismiss sibling. 153 * position of the item to animate. Returns {@code 0} if there is no dismiss sibling.
142 */ 154 */
143 public int getDismissSiblingPosDelta(NewTabPageItem item) { 155 public int getDismissSiblingPosDelta(int position) {
144 // The only dismiss siblings we have so far are the More button and the status card. 156 // The only dismiss siblings we have so far are the More button and the status card.
145 // Exit early if there is no More button. 157 // Exit early if there is no More button.
146 if (mMoreButton == null) return 0; 158 if (mMoreButton == null) return 0;
147 159
148 // When there are suggestions we won't have contiguous status and action items. 160 // When there are suggestions we won't have contiguous status and action items.
149 if (hasSuggestions()) return 0; 161 if (hasSuggestions()) return 0;
150 162
163 TreeNode item = getChildren().get(position);
164
151 // The sibling of the more button is the status card, that should be rig ht above. 165 // The sibling of the more button is the status card, that should be rig ht above.
152 if (item == mMoreButton) return -1; 166 if (item == mMoreButton) return -1;
153 167
154 // The sibling of the status card is the more button when it exists, sho uld be right below. 168 // The sibling of the status card is the more button when it exists, sho uld be right below.
155 if (item == mStatus) return 1; 169 if (item == mStatus) return 1;
156 170
157 return 0; 171 return 0;
158 } 172 }
159 173
160 private void notifySectionChanged(int itemCountBefore) { 174 private void notifySectionChanged(int itemCountBefore) {
161 int itemCountAfter = getItems().size(); 175 int itemCountAfter = getItemCount();
162 176
163 // The header is stable in sections. Don't notify about it. 177 // The header is stable in sections. Don't notify about it.
164 final int startPos = 1; 178 final int startPos = 1;
165 itemCountBefore--; 179 itemCountBefore--;
166 itemCountAfter--; 180 itemCountAfter--;
167 181
168 mObserver.onItemRangeChanged(this, startPos, Math.min(itemCountBefore, i temCountAfter)); 182 notifyItemRangeChanged(startPos, Math.min(itemCountBefore, itemCountAfte r));
169 if (itemCountBefore < itemCountAfter) { 183 if (itemCountBefore < itemCountAfter) {
170 mObserver.onItemRangeInserted( 184 notifyItemRangeInserted(startPos + itemCountBefore, itemCountAfter - itemCountBefore);
171 this, startPos + itemCountBefore, itemCountAfter - itemCount Before);
172 } else if (itemCountBefore > itemCountAfter) { 185 } else if (itemCountBefore > itemCountAfter) {
173 mObserver.onItemRangeRemoved( 186 notifyItemRangeRemoved(startPos + itemCountAfter, itemCountBefore - itemCountAfter);
174 this, startPos + itemCountAfter, itemCountBefore - itemCount After);
175 } 187 }
176 } 188 }
177 189
190 /**
191 * @return The progress indicator.
192 */
193 @VisibleForTesting
194 ProgressItem getProgressItemForTesting() {
195 return mProgressIndicator;
196 }
197
178 @VisibleForTesting 198 @VisibleForTesting
179 ActionItem getActionItem() { 199 ActionItem getActionItem() {
180 return mMoreButton; 200 return mMoreButton;
181 } 201 }
182 202
183 @VisibleForTesting 203 @VisibleForTesting
184 StatusItem getStatusItem() { 204 StatusItem getStatusItem() {
185 return mStatus; 205 return mStatus;
186 } 206 }
187 } 207 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698