/** * Gets all subItems from a given parent item * * @param item the parent from which we add all items * @param items the list in which we add the subItems */ public static <Item extends IItem> void addAllSubItems(Item item, List<Item> items) { if (item instanceof IExpandable && !((IExpandable) item).isExpanded() && ((IExpandable) item).getSubItems() != null) { List<Item> subItems = (List<Item>) ((IExpandable<Item, ?>) item).getSubItems(); Item subItem; for (int i = 0, size = subItems.size(); i < size; i++) { subItem = subItems.get(i); items.add(subItem); addAllSubItems(subItem, items); } } } }
@Override public boolean onClick(@NonNull View v, int pos, @NonNull FastAdapter<Item> fastAdapter, @NonNull Item item) { boolean consumed = false; //if this is a expandable item :D (this has to happen after we handled the selection as we refer to the position) if (!consumed && item instanceof IExpandable) { if (((IExpandable) item).isAutoExpanding() && ((IExpandable) item).getSubItems() != null) { toggleExpandable(pos); } } //if there should be only one expanded item we want to collapse all the others but the current one (this has to happen after we handled the selection as we refer to the position) if (!consumed && mOnlyOneExpandedItem && item instanceof IExpandable) { if (((IExpandable) item).getSubItems() != null && ((IExpandable) item).getSubItems().size() > 0) { int[] expandedItems = getExpandedItemsSameLevel(pos); for (int i = expandedItems.length - 1; i >= 0; i--) { if (expandedItems[i] != pos) { collapse(expandedItems[i], true); } } } } return consumed; }
/** * opens the expandable item at the given position * * @param position the global position * @param notifyItemChanged true if we need to call notifyItemChanged. DEFAULT: false */ public void expand(int position, boolean notifyItemChanged) { Item item = mFastAdapter.getItem(position); if (item != null && item instanceof IExpandable) { IExpandable expandable = (IExpandable) item; //if this item is not already expanded and has sub items we go on if (!expandable.isExpanded() && expandable.getSubItems() != null && expandable.getSubItems().size() > 0) { IAdapter<Item> adapter = mFastAdapter.getAdapter(position); if (adapter != null && adapter instanceof IItemAdapter) { ((IItemAdapter<?, Item>) adapter).addInternal(position + 1, expandable.getSubItems()); } //remember that this item is now opened (not collapsed) expandable.withIsExpanded(true); //we need to notify to get the correct drawable if there is one showing the current state if (notifyItemChanged) { mFastAdapter.notifyItemChanged(position); } } } }
public static <T extends IItem & IExpandable> int countSelectedSubItems(Set<IItem> selections, T header) { int count = 0; List<IItem> subItems = header.getSubItems(); int items = header.getSubItems() != null ? header.getSubItems().size() : 0; for (int i = 0; i < items; i++) { if (selections.contains(subItems.get(i))) { count++; } if (subItems.get(i) instanceof IExpandable && ((IExpandable) subItems.get(i)).getSubItems() != null) { count += countSelectedSubItems(selections, (T) subItems.get(i)); } } return count; }
/** * @return a set with the global positions of all expanded items */ public int[] getExpandedItems() { int[] expandedItems; ArrayList<Integer> expandedItemsList = new ArrayList<>(); Item item; for (int i = 0, size = mFastAdapter.getItemCount(); i < size; i++) { item = mFastAdapter.getItem(i); if (item instanceof IExpandable && ((IExpandable) item).isExpanded()) { expandedItemsList.add(i); } } int expandedItemsListLength = expandedItemsList.size(); expandedItems = new int[expandedItemsListLength]; for (int i = 0; i < expandedItemsListLength; i++) { expandedItems[i] = expandedItemsList.get(i); } return expandedItems; }
private static void updateSelectedItemsWithCollapsed(Set<IItem> selected, List<IItem> items) { int length = items.size(); for (int i = 0; i < length; i++) { if (items.get(i).isSelected()) { selected.add(items.get(i)); } if (items.get(i) instanceof IExpandable && ((IExpandable) items.get(i)).getSubItems() != null) { updateSelectedItemsWithCollapsed(selected, ((IExpandable) items.get(i)).getSubItems()); } } }
@Override public void notifyAdapterItemRangeChanged(int position, int itemCount, Object payload) { for (int i = position; i < position + itemCount; i++) { Item item = mFastAdapter.getItem(position); if (item instanceof IExpandable && ((IExpandable) item).isExpanded()) { collapse(position); } } }
/** * calculates the count of expandable items before a given position * * @param from the global start position you should pass here the count of items of the previous adapters (or 0 if you want to start from the beginning) * @param position the global position * @return the count of expandable items before a given position */ public int getExpandedItemsCount(int from, int position) { int totalAddedItems = 0; //first we find out how many items were added in total //also counting subItems Item tmp; for (int i = from; i < position; i++) { tmp = mFastAdapter.getItem(i); if (tmp instanceof IExpandable) { IExpandable tmpExpandable = ((IExpandable) tmp); if (tmpExpandable.getSubItems() != null && tmpExpandable.isExpanded()) { totalAddedItems = totalAddedItems + tmpExpandable.getSubItems().size(); } } } return totalAddedItems; }
@Override public boolean apply(@NonNull IAdapter<Item> lastParentAdapter, int lastParentPosition, Item item, int position) { if (item.isSelected()) { //if it's a subitem remove it from the parent if (item instanceof ISubItem) { //a sub item which is not in the list can be instantly deleted IExpandable parent = (IExpandable) ((ISubItem) item).getParent(); //parent should not be null, but check in any case.. if (parent != null) { parent.getSubItems().remove(item); } } if (position != -1) { //a normal displayed item can only be deleted afterwards positions.add(position); } } return false; } }, false);
@Override public boolean apply(@NonNull IAdapter<Item> lastParentAdapter, int lastParentPosition, @NonNull Item item, int position) { //we do not care about non visible items if (position == -1) { return false; } //this is the entrance parent if (allowedParents.size() > 0 && item instanceof ISubItem) { // Go on until we hit an item with a parent which was not in our expandable hierarchy IItem parent = ((ISubItem) item).getParent(); if (parent == null || !allowedParents.contains(parent)) { return true; } } if (item instanceof IExpandable) { IExpandable expandable = (IExpandable) item; if (expandable.isExpanded()) { expandable.withIsExpanded(false); if (expandable.getSubItems() != null) { expandedItemsCount[0] += expandable.getSubItems().size(); allowedParents.add(item); } } } return false; } }, position, true);
@Override public void saveInstanceState(Bundle savedInstanceState, String prefix) { if (savedInstanceState == null) { return; } ArrayList<String> expandedItems = new ArrayList<>(); Item item; for (int i = 0, size = mFastAdapter.getItemCount(); i < size; i++) { item = mFastAdapter.getItem(i); if (item instanceof IExpandable && ((IExpandable) item).isExpanded()) { expandedItems.add(String.valueOf(item.getIdentifier())); } } //remember the collapsed states savedInstanceState.putStringArrayList(BUNDLE_EXPANDED + prefix, expandedItems); }
/** * internal method to restore the selection state of subItems * * @param item the parent item * @param selectedItems the list of selectedItems from the savedInstanceState */ public static <Item extends IItem> void restoreSubItemSelectionStatesForAlternativeStateManagement(Item item, List<String> selectedItems) { if (item instanceof IExpandable && !((IExpandable) item).isExpanded() && ((IExpandable) item).getSubItems() != null) { List<Item> subItems = (List<Item>) ((IExpandable<Item, ?>) item).getSubItems(); for (int i = 0, size = subItems.size(); i < size; i++) { Item subItem = subItems.get(i); String id = String.valueOf(subItem.getIdentifier()); if (selectedItems != null && selectedItems.contains(id)) { subItem.withSetSelected(true); } restoreSubItemSelectionStatesForAlternativeStateManagement(subItem, selectedItems); } } }
/** * notifies the fastAdapter about new / removed items within a sub hierarchy * NOTE this currently only works for sub items with only 1 level * * @param position the global position of the parent item * @param previousCount the previous count of sub items * @return the new count of subItems */ public int notifyAdapterSubItemsChanged(int position, int previousCount) { Item item = mFastAdapter.getItem(position); if (item != null && item instanceof IExpandable) { IExpandable expandable = (IExpandable) item; IAdapter adapter = mFastAdapter.getAdapter(position); if (adapter != null && adapter instanceof IItemAdapter) { ((IItemAdapter) adapter).removeRange(position + 1, previousCount); ((IItemAdapter) adapter).add(position + 1, expandable.getSubItems()); } return expandable.getSubItems().size(); } return 0; }
/** * toggles the expanded state of the given expandable item at the given position * * @param position the global position */ public void toggleExpandable(int position) { Item item = mFastAdapter.getItem(position); if (item instanceof IExpandable && ((IExpandable) item).isExpanded()) { collapse(position); } else { expand(position); } }
/** * internal method to find all selections from subItems and sub sub items so we can save those inside our savedInstanceState * * @param item the parent item * @param selections the ArrayList which will be stored in the savedInstanceState */ public static <Item extends IItem> void findSubItemSelections(Item item, List<String> selections) { if (item instanceof IExpandable && !((IExpandable) item).isExpanded() && ((IExpandable) item).getSubItems() != null) { List<Item> subItems = (List<Item>) ((IExpandable<Item, ?>) item).getSubItems(); for (int i = 0, size = subItems.size(); i < size; i++) { Item subItem = subItems.get(i); String id = String.valueOf(subItem.getIdentifier()); if (subItem.isSelected()) { selections.add(id); } findSubItemSelections(subItem, selections); } } }
@Override public boolean apply(@NonNull IAdapter<Item> lastParentAdapter, int lastParentPosition, Item item, int position) { if (identifier == item.getIdentifier()) { //if it's a subitem remove it from the parent if (item instanceof ISubItem) { //a sub item which is not in the list can be instantly deleted IExpandable parent = (IExpandable) ((ISubItem) item).getParent(); //parent should not be null, but check in any case.. if (parent != null) { parent.getSubItems().remove(item); } } if (position != -1) { //a normal displayed item can only be deleted afterwards remove(position); } } return false; } }, false);
if (item instanceof IExpandable && !((IExpandable)item).isExpanded()) { SubItemUtil.selectAllSubItems(mFastAdapter, (T) mFastAdapter.getAdapterItem(i), select, true, mPayload);
public static <Item extends IItem> Triple<Boolean, Item, Integer> recursiveSub(IAdapter<Item> lastParentAdapter, int lastParentPosition, IExpandable parent, AdapterPredicate<Item> predicate, boolean stopOnMatch) { if (!parent.isExpanded() && parent.getSubItems() != null) { for (int ii = 0; ii < parent.getSubItems().size(); ii++) { Item sub = (Item) parent.getSubItems().get(ii);
for (int i = 0; i < itemCount; i++) { item = items.get(i); if (item instanceof IExpandable && ((IExpandable) item).getSubItems() != null) { subItems = ((IExpandable) item).getSubItems(); if (predicate == null) { if (countHeaders) {
/** * returns the expanded items this contains position and the count of items * which are expanded by this position * * @return the expanded items */ public SparseIntArray getExpanded() { SparseIntArray expandedItems = new SparseIntArray(); Item item; for (int i = 0, size = mFastAdapter.getItemCount(); i < size; i++) { item = mFastAdapter.getItem(i); if (item instanceof IExpandable && ((IExpandable) item).isExpanded()) { expandedItems.put(i, ((IExpandable) item).getSubItems().size()); } } return expandedItems; }