Last active
July 8, 2017 05:11
-
-
Save TimVelo/2c419096a0e58b3e47580c6c83c9de21 to your computer and use it in GitHub Desktop.
Fast Adapter Multi Select View Helper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.orangelinephotography.athenaeum.ui.actionMode; | |
import android.os.Bundle; | |
import com.mikepenz.fastadapter.FastAdapter; | |
import com.mikepenz.fastadapter.IItem; | |
/** | |
* Created by tvelo on 7/7/2017. | |
* based on extension from mikepenz; will PR for this to help others with non Action Mode views like | |
* implemented here. | |
*/ | |
public class ViewModeHelper { | |
private static final String ACTION_VIEW_STATE = "VIEW_MODE_ACTION_VIEW_STATE"; | |
private static final String FIRST_POS_STATE = "VIEW_MODE_FIRST_POS_STATE"; | |
private static final String RANGE_ENABLED_STATE = "VIEW_MODE_RANGE_ENABLED_STATE"; | |
private static final String AUTO_DESELECT_ENABLED_STATE = "VIEW_MODE_AUTO_DESELECT_ENABLED_STATE"; | |
private static final String NEW_RANGE_ON_SELECT_ENABLED_STATE = "VIEW_MODE_NEW_RANGE_ON_SELECT_ENABLED_STATE"; | |
private final ViewModeInteractionListener viewModeInteractionListener; | |
private FastAdapter mFastAdapter; | |
private boolean actionViewEnabled = false; | |
private boolean mAutoDeselect; | |
private boolean rangeEnabled; | |
private Integer firstLongClickPos; | |
private boolean newRangeOnSelection; | |
/** | |
* @param fastAdapter current fastAdapter | |
* @param viewModeInteractionListener listened to trigger custom view display | |
*/ | |
public ViewModeHelper(FastAdapter fastAdapter, ViewModeInteractionListener viewModeInteractionListener) { | |
this.mFastAdapter = fastAdapter; | |
checkActionMode(fastAdapter.getSelectedItems().size()); | |
this.viewModeInteractionListener = viewModeInteractionListener; | |
} | |
/** | |
* @param savedInstanceState generated instance state from activity or fragment | |
* @return self for builder | |
*/ | |
public ViewModeHelper withInstanceState(Bundle savedInstanceState) { | |
if (savedInstanceState != null) { | |
if (savedInstanceState.get(ACTION_VIEW_STATE) != null) | |
actionViewEnabled = savedInstanceState.getBoolean(ACTION_VIEW_STATE, false); | |
if (savedInstanceState.get(FIRST_POS_STATE) != null) | |
firstLongClickPos = savedInstanceState.getInt(FIRST_POS_STATE); | |
if (savedInstanceState.get(RANGE_ENABLED_STATE) != null) | |
rangeEnabled = savedInstanceState.getBoolean(RANGE_ENABLED_STATE, false); | |
if (savedInstanceState.get(AUTO_DESELECT_ENABLED_STATE) != null) | |
mAutoDeselect = savedInstanceState.getBoolean(AUTO_DESELECT_ENABLED_STATE, false); | |
if (savedInstanceState.get(NEW_RANGE_ON_SELECT_ENABLED_STATE) != null) | |
newRangeOnSelection = savedInstanceState.getBoolean(NEW_RANGE_ON_SELECT_ENABLED_STATE, false); | |
} | |
return this; | |
} | |
/** | |
* @param outState Activity or fragment state | |
* @return new built state | |
*/ | |
public Bundle saveInstanceState(Bundle outState) { | |
outState.putBoolean(ACTION_VIEW_STATE, actionViewEnabled); | |
if (firstLongClickPos != null) | |
outState.putInt(FIRST_POS_STATE, firstLongClickPos); | |
outState.putBoolean(AUTO_DESELECT_ENABLED_STATE, mAutoDeselect); | |
outState.putBoolean(RANGE_ENABLED_STATE, rangeEnabled); | |
outState.putBoolean(NEW_RANGE_ON_SELECT_ENABLED_STATE, newRangeOnSelection); | |
return outState; | |
} | |
/** | |
* @param autoDeselect auto-deselect on final | |
* @return self for builder | |
*/ | |
public ViewModeHelper withAutoDeselect(boolean autoDeselect) { | |
this.mAutoDeselect = autoDeselect; | |
return this; | |
} | |
/** | |
* @param rangeEnabled enable range selection mode | |
* @return self for builder | |
*/ | |
public ViewModeHelper withRangeEnabled(boolean rangeEnabled) { | |
this.rangeEnabled = rangeEnabled; | |
return this; | |
} | |
/** | |
* allow groups of ranges to be selected for each "set" of two long presses | |
* | |
* @param newRangeOnSelection enable multi-tiered range selection | |
* @return self for builder | |
*/ | |
public ViewModeHelper withNewRangeOnSelection(boolean newRangeOnSelection) { | |
this.newRangeOnSelection = newRangeOnSelection; | |
return this; | |
} | |
/** | |
* @param item the current item | |
* @return null if nothing was done, or a boolean to inform if the event was consumed | |
*/ | |
public Boolean onClick(IItem item) { | |
if (mFastAdapter != null) { | |
if (actionViewEnabled && mFastAdapter.getSelections().size() == 1 && item.isSelected()) { | |
finish(); | |
return true; | |
} | |
if (actionViewEnabled) { | |
// calculate the selection count for the action mode | |
int selected = mFastAdapter.getSelections().size(); | |
if (item.isSelected()) | |
selected--; | |
else if (item.isSelectable()) | |
selected++; | |
checkActionMode(selected); | |
} | |
} | |
return null; | |
} | |
/** | |
* @param position the position of the clicked item | |
* @return the consumption of longClick, null if nothing happened from us. | |
*/ | |
public Boolean onLongClick(int position) { | |
if (!actionViewEnabled && mFastAdapter.getItem(position).isSelectable()) { | |
firstLongClickPos = position; | |
//we have to select this on our own as we will consume the event | |
if (mFastAdapter != null) | |
mFastAdapter.select(position); | |
// init action view | |
//we consume this event so the normal onClick isn't called anymore | |
return checkActionMode(1); | |
} else if (rangeEnabled && actionViewEnabled && mFastAdapter.getItem(position).isSelectable()) { | |
if (firstLongClickPos != null) { | |
selectRange(position, firstLongClickPos, true); | |
if (newRangeOnSelection) | |
firstLongClickPos = null; | |
return checkActionMode(mFastAdapter.getSelections().size()); | |
} else { | |
firstLongClickPos = position; | |
if (mFastAdapter != null) | |
mFastAdapter.select(position); | |
} | |
} | |
return null; | |
} | |
/** | |
* @param from start range | |
* @param to end range | |
* @param select select or deselect | |
*/ | |
private void selectRange(int from, int to, boolean select) { | |
if (from == to) | |
return; | |
if (from > to) { | |
int temp = from; | |
from = to; | |
to = temp; | |
} | |
for (int i = from; i <= to; i++) { | |
if (mFastAdapter.getItem(i).isSelectable()) { | |
if (select && mFastAdapter != null) | |
mFastAdapter.select(i); | |
else if (mFastAdapter != null) | |
mFastAdapter.deselect(i); | |
} | |
} | |
} | |
/** | |
* @param selected number of selected recrods | |
* @return boolean as the action mode is enabled. | |
*/ | |
private boolean checkActionMode(int selected) { | |
if (selected == 0) { | |
if (actionViewEnabled) | |
finish(); | |
} else if (!actionViewEnabled) | |
showActionView(); | |
else if (viewModeInteractionListener != null) | |
viewModeInteractionListener.onSelectionsChanged(selected); | |
return actionViewEnabled; | |
} | |
/** | |
* designate mode as multi-mode and do the needful | |
*/ | |
private void showActionView() { | |
actionViewEnabled = true; | |
//as we are now in the actionMode a single click is fine for multiSelection | |
if (mFastAdapter != null) | |
mFastAdapter.withSelectOnLongClick(false); | |
if (viewModeInteractionListener != null) | |
viewModeInteractionListener.onCreateSelectionView(); | |
} | |
/** | |
* mark the helper as done, deselect all, and close all custom views. | |
*/ | |
private void finish() { | |
actionViewEnabled = false; | |
//after we are done with the actionMode we fallback to longClick for multi-select | |
if (mFastAdapter != null) | |
mFastAdapter.withSelectOnLongClick(true); | |
//actionMode end. deselect everything | |
if (mAutoDeselect && mFastAdapter != null) // just in-case | |
mFastAdapter.deselect(); | |
if (viewModeInteractionListener != null) | |
viewModeInteractionListener.onDestroySelectionView(); | |
} | |
/** | |
* deselect all and close custom view | |
*/ | |
public void deselectAll() { | |
if (mFastAdapter != null) | |
mFastAdapter.deselect(); | |
finish(); | |
} | |
/** | |
* @return the mode of selection tools | |
*/ | |
public boolean getSelectMode() { | |
return actionViewEnabled; | |
} | |
/** | |
* call onCreateSelectionView to show the custom view of selection tools if possible | |
*/ | |
public void showIfNeeded() { | |
if (actionViewEnabled && viewModeInteractionListener != null) | |
viewModeInteractionListener.onCreateSelectionView(); | |
} | |
/** | |
* Call onDestroySelectionView to hide the custom view of selection tools if possible | |
*/ | |
public void hideIfPossible() { | |
if (actionViewEnabled && viewModeInteractionListener != null) | |
viewModeInteractionListener.onDestroySelectionView(); | |
} | |
/** | |
* ViewModeInteractionListener handles calls from the ViewModeHelper to update UI changes for | |
* Collection | |
*/ | |
public interface ViewModeInteractionListener { | |
/** | |
* called when custom view is needed for multi-select | |
*/ | |
void onCreateSelectionView(); | |
/** | |
* called when selection has changed | |
* | |
* @param count number of selected records | |
*/ | |
void onSelectionsChanged(int count); | |
/** | |
* called when custom view is to be hidden or destroyed | |
*/ | |
void onDestroySelectionView(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment