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) { |