package com.mikepenz.fastadapter_extensions; import android.os.Bundle; import com.mikepenz.fastadapter.IExpandable; import com.mikepenz.fastadapter.IItem; import com.mikepenz.fastadapter.commons.adapters.FastItemAdapter; import com.mikepenz.fastadapter_extensions.utilities.SubItemUtil; /** * Created by Michael on 15.09.2016. */ public class RangeSelectorHelper { protected static final String BUNDLE_LAST_LONG_PRESS = "bundle_last_long_press"; private FastItemAdapter mFastAdapter; private ActionModeHelper mActionModeHelper; private boolean mSupportSubItems = false; private Object mPayload = null; private Integer mLastLongPressIndex; public RangeSelectorHelper(FastItemAdapter adapter) { mFastAdapter = adapter; } /** * set the ActionModeHelper, if you want to notify it after a range was selected * so that it can update the ActionMode title * * @param actionModeHelper the action mode helper that should be used * @return this, for supporting function call chaining */ public RangeSelectorHelper withActionModeHelper(ActionModeHelper actionModeHelper) { mActionModeHelper = actionModeHelper; return this; } /** * enable this, if you want the range selector to correclty handle sub items as well * * @param supportSubItems true, if sub items are supported, false otherwise * @return this, for supporting function call chaining */ public RangeSelectorHelper withSupportSubItems(boolean supportSubItems) { this.mSupportSubItems = supportSubItems; return this; } /** * the provided payload will be passed to the adapters notify function, if one is provided * * @param payload the paylaod that should be passed to the adapter on selection state change * @return this, for supporting function call chaining */ public RangeSelectorHelper withPayload(Object payload) { mPayload = payload; return this; } /** * resets the last long pressed index, we only want to respect two consecutive long clicks for selecting a range of items */ public void onClick() { reset(); } /** * resets the last long pressed index, we only want to respect two consecutive long presses for selecting a range of items */ public void reset() { mLastLongPressIndex = null; } /** * will take care to save the long pressed index * or to select all items in the range between the current long pressed item and the last long pressed item * * @param index the index of the long pressed item * @return true, if the long press was handled */ public boolean onLongClick(int index) { return onLongClick(index, true); } /** * will take care to save the long pressed index * or to select all items in the range between the current long pressed item and the last long pressed item * * @param index the index of the long pressed item * @param selectItem true, if the item at the index should be selected, false if this was already done outside of this helper or is not desired * @return true, if the long press was handled */ public boolean onLongClick(int index, boolean selectItem) { if (mLastLongPressIndex == null) { // we only consider long presses on not selected items if (mFastAdapter.getAdapterItem(index).isSelectable()) { mLastLongPressIndex = index; // we select this item as well if (selectItem) mFastAdapter.select(index); if (mActionModeHelper != null) mActionModeHelper.checkActionMode(null); // works with null as well, as the ActionMode is active for sure! return true; } } else if (mLastLongPressIndex != index) { // select all items in the range between the two long clicks selectRange(mLastLongPressIndex, index, true); // reset the index mLastLongPressIndex = null; } return false; } /** * selects all items in a range, from and to indizes are inclusive * * @param from the from index * @param to the to index * @param select true, if the provided range should be selected, false otherwise */ public <T extends IItem & IExpandable> void selectRange(int from, int to, boolean select) { selectRange(from, to, select, false); } /** * selects all items in a range, from and to indizes are inclusive * * @param from the from index * @param to the to index * @param select true, if the provided range should be selected, false otherwise * @param skipHeaders true, if you do not want to process headers, false otherwise */ public <T extends IItem & IExpandable> void selectRange(int from, int to, boolean select, boolean skipHeaders) { if (from > to) { int temp = from; from = to; to = temp; } IItem item; for (int i = from; i <= to; i++) { item = mFastAdapter.getAdapterItem(i); if (item.isSelectable()) { if (select) { mFastAdapter.select(i); } else { mFastAdapter.deselect(i); } } if (mSupportSubItems && !skipHeaders) { // if a group is collapsed, select all sub items if (item instanceof IExpandable && !((IExpandable)item).isExpanded()) { SubItemUtil.selectAllSubItems(mFastAdapter, (T) mFastAdapter.getAdapterItem(i), select, true, mPayload); } } } if (mActionModeHelper != null) { mActionModeHelper.checkActionMode(null); // works with null as well, as the ActionMode is active for sure! } } /** * add the values to the bundle for saveInstanceState * * @param savedInstanceState If the activity is being re-initialized after * previously being shut down then this Bundle contains the data it most * recently supplied in Note: Otherwise it is null. * @return the passed bundle with the newly added data */ public Bundle saveInstanceState(Bundle savedInstanceState) { return saveInstanceState(savedInstanceState, ""); } /** * add the values to the bundle for saveInstanceState * * @param savedInstanceState If the activity is being re-initialized after * previously being shut down then this Bundle contains the data it most * recently supplied in Note: Otherwise it is null. * @param prefix a prefix added to the savedInstance key so we can store multiple states * @return the passed bundle with the newly added data */ public Bundle saveInstanceState(Bundle savedInstanceState, String prefix) { if (savedInstanceState != null && mLastLongPressIndex != null) savedInstanceState.putInt(BUNDLE_LAST_LONG_PRESS, mLastLongPressIndex); return savedInstanceState; } /** * restore the index of the last long pressed index * * @param savedInstanceState If the activity is being re-initialized after * previously being shut down then this Bundle contains the data it most * recently supplied in Note: Otherwise it is null. * @return this */ public RangeSelectorHelper withSavedInstanceState(Bundle savedInstanceState) { return withSavedInstanceState(savedInstanceState, ""); } /** * restore the index of the last long pressed index * IMPORTANT! Call this method only after all items where added to the adapters again. Otherwise it may select wrong items! * * @param savedInstanceState If the activity is being re-initialized after * previously being shut down then this Bundle contains the data it most * recently supplied in Note: Otherwise it is null. * @param prefix a prefix added to the savedInstance key so we can store multiple states * @return this */ public RangeSelectorHelper withSavedInstanceState(Bundle savedInstanceState, String prefix) { if (savedInstanceState != null && savedInstanceState.containsKey(BUNDLE_LAST_LONG_PRESS + prefix)) mLastLongPressIndex = savedInstanceState.getInt(BUNDLE_LAST_LONG_PRESS + prefix); return this; } }