Chromium Code Reviews| Index: chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java |
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java |
| index cc83745a439d0a56a0fdb6ffabf5665a78c5531b..c7d60ed1d610439847267126894b831b2eea44a1 100644 |
| --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java |
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java |
| @@ -21,7 +21,6 @@ import org.chromium.chrome.browser.ntp.UiConfig; |
| import org.chromium.chrome.browser.ntp.snippets.CategoryInt; |
| import org.chromium.chrome.browser.ntp.snippets.CategoryStatus; |
| import org.chromium.chrome.browser.ntp.snippets.CategoryStatus.CategoryStatusEnum; |
| -import org.chromium.chrome.browser.ntp.snippets.SectionHeader; |
| import org.chromium.chrome.browser.ntp.snippets.SectionHeaderViewHolder; |
| import org.chromium.chrome.browser.ntp.snippets.SnippetArticle; |
| import org.chromium.chrome.browser.ntp.snippets.SnippetArticleViewHolder; |
| @@ -41,8 +40,8 @@ import java.util.Map; |
| * the above-the-fold view (containing the logo, search box, and most visited tiles) and subsequent |
| * elements will be the cards shown to the user |
| */ |
| -public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> |
| - implements SuggestionsSource.Observer, ItemGroup.Observer { |
| +public class NewTabPageAdapter |
| + extends Adapter<NewTabPageViewHolder> implements SuggestionsSource.Observer, NodeParent { |
| private static final String TAG = "Ntp"; |
| private final NewTabPageManager mNewTabPageManager; |
| @@ -55,12 +54,13 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> |
| * List of all item groups (which can themselves contain multiple items. When flattened, this |
| * will be a list of all items the adapter exposes. |
| */ |
| - private final List<ItemGroup> mGroups = new ArrayList<>(); |
| + private final List<TreeNode> mGroups = new ArrayList<>(); |
| private final AboveTheFoldItem mAboveTheFold = new AboveTheFoldItem(); |
| - private final SignInPromo mSigninPromo = new SignInPromo(); |
| + private final SignInPromo mSigninPromo; |
| private final AllDismissedItem mAllDismissed = new AllDismissedItem(); |
| private final Footer mFooter = new Footer(); |
| private final SpacingItem mBottomSpacer = new SpacingItem(); |
| + private final InnerNode mRoot; |
| /** Maps suggestion categories to sections, with stable iteration ordering. */ |
| private final Map<Integer, SuggestionsSection> mSections = new LinkedHashMap<>(); |
| @@ -134,7 +134,14 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> |
| mNewTabPageManager = manager; |
| mAboveTheFoldView = aboveTheFoldView; |
| mUiConfig = uiConfig; |
| - mSigninPromo.setObserver(this); |
| + mRoot = new InnerNode(this) { |
| + @Override |
| + protected List<TreeNode> getChildren() { |
| + return mGroups; |
| + } |
| + }; |
| + |
| + mSigninPromo = new SignInPromo(mRoot); |
| resetSections(/*alwaysAllowEmptySections=*/false); |
| mNewTabPageManager.getSuggestionsSource().setObserver(this); |
| @@ -205,7 +212,7 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> |
| // Create the section if needed. |
| SuggestionsSection section = mSections.get(category); |
| if (section == null) { |
| - section = new SuggestionsSection(info, this); |
| + section = new SuggestionsSection(mRoot, info); |
| mSections.put(category, section); |
| } |
| @@ -285,52 +292,52 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> |
| } |
| @Override |
| - @NewTabPageItem.ViewType |
| + @ItemViewType |
| public int getItemViewType(int position) { |
| - return getItems().get(position).getType(); |
| + return mRoot.getItemViewType(position); |
| } |
| @Override |
| public NewTabPageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { |
| assert parent == mRecyclerView; |
|
dgn
2016/10/13 15:42:41
change it to as switch while we're at it?
Bernhard Bauer
2016/10/13 16:13:14
Done.
|
| - if (viewType == NewTabPageItem.VIEW_TYPE_ABOVE_THE_FOLD) { |
| + if (viewType == ItemViewType.VIEW_TYPE_ABOVE_THE_FOLD) { |
| return new NewTabPageViewHolder(mAboveTheFoldView); |
| } |
| - if (viewType == NewTabPageItem.VIEW_TYPE_HEADER) { |
| + if (viewType == ItemViewType.VIEW_TYPE_HEADER) { |
| return new SectionHeaderViewHolder(mRecyclerView, mUiConfig); |
| } |
| - if (viewType == NewTabPageItem.VIEW_TYPE_SNIPPET) { |
| + if (viewType == ItemViewType.VIEW_TYPE_SNIPPET) { |
| return new SnippetArticleViewHolder(mRecyclerView, mNewTabPageManager, mUiConfig); |
| } |
| - if (viewType == NewTabPageItem.VIEW_TYPE_SPACING) { |
| + if (viewType == ItemViewType.VIEW_TYPE_SPACING) { |
| return new NewTabPageViewHolder(SpacingItem.createView(parent)); |
| } |
| - if (viewType == NewTabPageItem.VIEW_TYPE_STATUS) { |
| + if (viewType == ItemViewType.VIEW_TYPE_STATUS) { |
| return new StatusCardViewHolder(mRecyclerView, mUiConfig); |
| } |
| - if (viewType == NewTabPageItem.VIEW_TYPE_PROGRESS) { |
| + if (viewType == ItemViewType.VIEW_TYPE_PROGRESS) { |
| return new ProgressViewHolder(mRecyclerView); |
| } |
| - if (viewType == NewTabPageItem.VIEW_TYPE_ACTION) { |
| + if (viewType == ItemViewType.VIEW_TYPE_ACTION) { |
| return new ActionItem.ViewHolder(mRecyclerView, mNewTabPageManager, mUiConfig); |
| } |
| - if (viewType == NewTabPageItem.VIEW_TYPE_PROMO) { |
| + if (viewType == ItemViewType.VIEW_TYPE_PROMO) { |
| return new SignInPromo.ViewHolder(mRecyclerView, mUiConfig); |
| } |
| - if (viewType == NewTabPageItem.VIEW_TYPE_FOOTER) { |
| + if (viewType == ItemViewType.VIEW_TYPE_FOOTER) { |
| return new Footer.ViewHolder(mRecyclerView, mNewTabPageManager); |
| } |
| - if (viewType == NewTabPageItem.VIEW_TYPE_ALL_DISMISSED) { |
| + if (viewType == ItemViewType.VIEW_TYPE_ALL_DISMISSED) { |
| return new AllDismissedItem.ViewHolder(mRecyclerView, mNewTabPageManager, this); |
| } |
| @@ -339,12 +346,12 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> |
| @Override |
| public void onBindViewHolder(NewTabPageViewHolder holder, final int position) { |
| - getItems().get(position).onBindViewHolder(holder); |
| + mRoot.onBindViewHolder(holder, position); |
| } |
| @Override |
| public int getItemCount() { |
| - return getItems().size(); |
| + return mRoot.getItemCount(); |
| } |
| public int getAboveTheFoldPosition() { |
| @@ -352,9 +359,9 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> |
| } |
| public int getFirstHeaderPosition() { |
| - List<NewTabPageItem> items = getItems(); |
| - for (int i = 0; i < items.size(); i++) { |
| - if (items.get(i) instanceof SectionHeader) return i; |
| + int count = getItemCount(); |
| + for (int i = 0; i < count; i++) { |
| + if (getItemViewType(i) == ItemViewType.VIEW_TYPE_HEADER) return i; |
| } |
| return RecyclerView.NO_POSITION; |
| } |
| @@ -374,11 +381,10 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> |
| return getGroupPositionOffset(mBottomSpacer); |
| } |
| - public int getSuggestionPosition(SnippetArticle article) { |
| - List<NewTabPageItem> items = getItems(); |
| - for (int i = 0; i < items.size(); i++) { |
| - NewTabPageItem item = items.get(i); |
| - if (article.equals(item)) return i; |
| + public int getSuggestionPosition(SnippetArticle foo) { |
|
dgn
2016/10/13 15:42:41
foo?
Bernhard Bauer
2016/10/13 16:13:14
Oops... renamed.
|
| + for (int i = 0; i < mRoot.getItemCount(); i++) { |
| + SnippetArticle article = mRoot.getSuggestionAt(i); |
| + if (article != null && article.equals(foo)) return i; |
| } |
| return RecyclerView.NO_POSITION; |
| } |
| @@ -421,7 +427,7 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> |
| mSections.remove(section.getCategory()); |
| int startPos = getGroupPositionOffset(section); |
| mGroups.remove(section); |
| - notifyItemRangeRemoved(startPos, section.getItems().size()); |
| + notifyItemRangeRemoved(startPos, section.getItemCount()); |
| if (hasAllBeenDismissed()) { |
| int footerPosition = getFooterPosition(); |
| @@ -433,23 +439,26 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> |
| } |
| @Override |
| - public void onItemRangeChanged(ItemGroup group, int itemPosition, int itemCount) { |
| + public void onItemRangeChanged(TreeNode child, int itemPosition, int itemCount) { |
| + assert child == mRoot; |
| if (mGroups.isEmpty()) return; // The sections have not been initialised yet. |
| - notifyItemRangeChanged(getGroupPositionOffset(group) + itemPosition, itemCount); |
| + notifyItemRangeChanged(itemPosition, itemCount); |
| } |
| @Override |
| - public void onItemRangeInserted(ItemGroup group, int itemPosition, int itemCount) { |
| + public void onItemRangeInserted(TreeNode child, int itemPosition, int itemCount) { |
| + assert child == mRoot; |
| if (mGroups.isEmpty()) return; // The sections have not been initialised yet. |
| - notifyItemRangeInserted(getGroupPositionOffset(group) + itemPosition, itemCount); |
| - notifyItemChanged(getItems().size() - 1); // Refresh the spacer too. |
| + notifyItemRangeInserted(itemPosition, itemCount); |
| + notifyItemChanged(getItemCount() - 1); // Refresh the spacer too. |
| } |
| @Override |
| - public void onItemRangeRemoved(ItemGroup group, int itemPosition, int itemCount) { |
| + public void onItemRangeRemoved(TreeNode child, int itemPosition, int itemCount) { |
| + assert child == mRoot; |
| if (mGroups.isEmpty()) return; // The sections have not been initialised yet. |
| - notifyItemRangeRemoved(getGroupPositionOffset(group) + itemPosition, itemCount); |
| - notifyItemChanged(getItems().size() - 1); // Refresh the spacer too. |
| + notifyItemRangeRemoved(itemPosition, itemCount); |
| + notifyItemChanged(getItemCount() - 1); // Refresh the spacer too. |
| } |
| @Override |
| @@ -477,16 +486,16 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> |
| // TODO(dgn): Polymorphism is supposed to allow to avoid that kind of stuff. |
| switch (itemViewType) { |
| - case NewTabPageItem.VIEW_TYPE_STATUS: |
| - case NewTabPageItem.VIEW_TYPE_ACTION: |
| - dismissSection((SuggestionsSection) getGroup(position)); |
| + case ItemViewType.VIEW_TYPE_STATUS: |
| + case ItemViewType.VIEW_TYPE_ACTION: |
| + dismissSection(getSuggestionsSection(position)); |
| return; |
| - case NewTabPageItem.VIEW_TYPE_SNIPPET: |
| + case ItemViewType.VIEW_TYPE_SNIPPET: |
| dismissSuggestion(position); |
| return; |
| - case NewTabPageItem.VIEW_TYPE_PROMO: |
| + case ItemViewType.VIEW_TYPE_PROMO: |
| dismissPromo(); |
| return; |
| @@ -502,8 +511,7 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> |
| } |
| private void dismissSuggestion(int position) { |
| - SnippetArticle suggestion = (SnippetArticle) getItems().get(position); |
| - |
| + SnippetArticle suggestion = mRoot.getSuggestionAt(position); |
| SuggestionsSource suggestionsSource = mNewTabPageManager.getSuggestionsSource(); |
| if (suggestionsSource == null) { |
| // It is possible for this method to be called after the NewTabPage has had destroy() |
| @@ -516,7 +524,7 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> |
| announceItemRemoved(suggestion.mTitle); |
| suggestionsSource.dismissSuggestion(suggestion); |
| - SuggestionsSection section = (SuggestionsSection) getGroup(position); |
| + SuggestionsSection section = getSuggestionsSection(position); |
| section.removeSuggestion(suggestion); |
| } |
| @@ -532,27 +540,13 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> |
| } |
| /** |
| - * Returns an unmodifiable list containing all items in the adapter. |
| - */ |
| - private List<NewTabPageItem> getItems() { |
| - List<NewTabPageItem> items = new ArrayList<>(); |
| - for (ItemGroup group : mGroups) { |
| - items.addAll(group.getItems()); |
| - } |
| - return Collections.unmodifiableList(items); |
| - } |
| - |
| - /** |
| * Returns another view holder that should be dismissed at the same time as the provided one. |
| */ |
| public ViewHolder getDismissSibling(ViewHolder viewHolder) { |
| int swipePos = viewHolder.getAdapterPosition(); |
| - ItemGroup group = getGroup(swipePos); |
| - |
| - if (!(group instanceof SuggestionsSection)) return null; |
| - |
| - SuggestionsSection section = (SuggestionsSection) group; |
| - int siblingPosDelta = section.getDismissSiblingPosDelta(getItems().get(swipePos)); |
| + SuggestionsSection section = getSuggestionsSection(swipePos); |
|
dgn
2016/10/13 15:42:41
You can swipe the signin promo and it's not a sugg
Bernhard Bauer
2016/10/13 16:13:14
Good catch! Done.
|
| + int siblingPosDelta = |
| + section.getDismissSiblingPosDelta(swipePos - getGroupPositionOffset(section)); |
| if (siblingPosDelta == 0) return null; |
| return mRecyclerView.findViewHolderForAdapterPosition(siblingPosDelta + swipePos); |
| @@ -563,35 +557,23 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> |
| } |
| @VisibleForTesting |
| - ItemGroup getGroup(int itemPosition) { |
| - int itemsSkipped = 0; |
| - for (ItemGroup group : mGroups) { |
| - List<NewTabPageItem> items = group.getItems(); |
| - itemsSkipped += items.size(); |
| - if (itemPosition < itemsSkipped) return group; |
| - } |
| - return null; |
| + SuggestionsSection getSuggestionsSection(int itemPosition) { |
| + return (SuggestionsSection) mGroups.get(mRoot.getChildIndexForPosition(itemPosition)); |
| } |
| @VisibleForTesting |
| - List<ItemGroup> getGroups() { |
| + List<TreeNode> getGroups() { |
| return Collections.unmodifiableList(mGroups); |
| } |
| @VisibleForTesting |
| - int getGroupPositionOffset(ItemGroup group) { |
| - int positionOffset = 0; |
| - for (ItemGroup candidateGroup : mGroups) { |
| - if (candidateGroup == group) return positionOffset; |
| - positionOffset += candidateGroup.getItems().size(); |
| - } |
| - Log.d(TAG, "Group not found: %s", group); |
| - return RecyclerView.NO_POSITION; |
| + int getGroupPositionOffset(TreeNode group) { |
| + return mRoot.getStartingOffsetForChild(group); |
| } |
| @VisibleForTesting |
| SnippetArticle getSuggestionAt(int position) { |
| - return (SnippetArticle) getItems().get(position); |
| + return mRoot.getSuggestionAt(position); |
| } |
| private void announceItemRemoved(String suggestionTitle) { |