package com.mikepenz.fastadapter_extensions;
import android.support.annotation.MenuRes;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
import com.mikepenz.fastadapter.FastAdapter;
import com.mikepenz.fastadapter.IItem;
import com.mikepenz.fastadapter_extensions.utilities.SubItemUtil;
/**
* Created by mikepenz on 02.01.16.
*/
public class ActionModeHelper {
private FastAdapter mFastAdapter;
@MenuRes
private int mCabMenu;
private ActionMode.Callback mInternalCallback;
private ActionMode.Callback mCallback;
private ActionMode mActionMode;
private boolean mSupportSubItems = false;
private boolean mAutoDeselect = true;
private ActionModeTitleProvider mTitleProvider;
public ActionModeHelper(FastAdapter fastAdapter, int cabMenu) {
this.mFastAdapter = fastAdapter;
this.mCabMenu = cabMenu;
this.mInternalCallback = new ActionBarCallBack();
}
public ActionModeHelper(FastAdapter fastAdapter, int cabMenu, ActionMode.Callback callback) {
this.mFastAdapter = fastAdapter;
this.mCabMenu = cabMenu;
this.mCallback = callback;
this.mInternalCallback = new ActionBarCallBack();
}
public ActionModeHelper withTitleProvider(ActionModeTitleProvider titleProvider) {
this.mTitleProvider = titleProvider;
return this;
}
public ActionModeHelper withAutoDeselect(boolean enabled) {
this.mAutoDeselect = enabled;
return this;
}
public ActionModeHelper withSupportSubItems(boolean supportSubItems) {
this.mSupportSubItems = supportSubItems;
return this;
}
public ActionMode getActionMode() {
return mActionMode;
}
/**
* convenient method to check if action mode is active or nor
*
* @return true, if ActionMode is active, false otherwise
*/
public boolean isActive() {
return mActionMode != null;
}
/**
* implements the basic behavior of a CAB and multi select behavior,
* including logics if the clicked item is collapsible
*
* @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) {
return onClick(null, item);
}
/**
* implements the basic behavior of a CAB and multi select behavior,
* including logics if the clicked item is collapsible
*
* @param act the current Activity
* @param item the current item
* @return null if nothing was done, or a boolean to inform if the event was consumed
*/
public Boolean onClick(AppCompatActivity act, IItem item) {
//if we are current in CAB mode, and we remove the last selection, we want to finish the actionMode
if (mActionMode != null && (mSupportSubItems ? SubItemUtil.getSelectedItems(mFastAdapter).size() == 1 : mFastAdapter.getSelections().size() == 1) && item.isSelected()) {
mActionMode.finish();
mFastAdapter.deselect();
return true;
}
if (mActionMode != null) {
// calculate the selection count for the action mode
// because current selection is not reflecting the future state yet!
int selected = mSupportSubItems ? SubItemUtil.getSelectedItems(mFastAdapter).size() : mFastAdapter.getSelections().size();
if (item.isSelected())
selected--;
else if (item.isSelectable())
selected++;
checkActionMode(act, selected);
}
return null;
}
/**
* implements the basic behavior of a CAB and multi select behavior onLongClick
*
* @param act the current Activity
* @param position the position of the clicked item
* @return the initialized ActionMode or null if nothing was done
*/
public ActionMode onLongClick(AppCompatActivity act, int position) {
if (mActionMode == null && mFastAdapter.getItem(position).isSelectable()) {
//may check if actionMode is already displayed
mActionMode = act.startSupportActionMode(mInternalCallback);
//we have to select this on our own as we will consume the event
mFastAdapter.select(position);
// update title
checkActionMode(act, 1);
//we consume this event so the normal onClick isn't called anymore
return mActionMode;
}
return mActionMode;
}
/**
* check if the ActionMode should be shown or not depending on the currently selected items
* Additionally, it will also update the title in the CAB for you
*
* @param act the current Activity
* @return the initialized ActionMode or null if no ActionMode is active after calling this function
*/
public ActionMode checkActionMode(AppCompatActivity act) {
int selected = mSupportSubItems ? SubItemUtil.getSelectedItems(mFastAdapter).size() : mFastAdapter.getSelections().size();
return checkActionMode(act, selected);
}
/**
* reset any active action mode if it is active, useful, to avoid leaking the activity if this helper class is retained
*/
public void reset() {
if (mActionMode != null) {
mActionMode.finish();
mActionMode = null;
}
}
private ActionMode checkActionMode(AppCompatActivity act, int selected) {
if (selected == 0) {
if (mActionMode != null) {
mActionMode.finish();
mActionMode = null;
}
} else if (mActionMode == null) {
if (act != null) // without an activity, we cannot start the action mode
mActionMode = act.startSupportActionMode(mInternalCallback);
}
updateTitle(selected);
return mActionMode;
}
/**
* updates the title to reflect the current selected items or to show a user defined title
*
* @param selected number of selected items
*/
private void updateTitle(int selected) {
if (mActionMode != null) {
if (mTitleProvider != null)
mActionMode.setTitle(mTitleProvider.getTitle(selected));
else
mActionMode.setTitle(String.valueOf(selected));
}
}
/**
* Our ActionBarCallBack to showcase the CAB
*/
private class ActionBarCallBack implements ActionMode.Callback {
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
boolean consumed = false;
if (mCallback != null) {
consumed = mCallback.onActionItemClicked(mode, item);
}
if (!consumed) {
if (mSupportSubItems) {
SubItemUtil.deleteSelected(mFastAdapter, true, false);
}
else {
mFastAdapter.deleteAllSelectedItems();
}
//finish the actionMode
mode.finish();
}
return consumed;
}
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(mCabMenu, menu);
//as we are now in the actionMode a single click is fine for multiSelection
mFastAdapter.withSelectOnLongClick(false);
return mCallback == null || mCallback.onCreateActionMode(mode, menu);
}
@Override
public void onDestroyActionMode(ActionMode mode) {
mActionMode = null;
//after we are done with the actionMode we fallback to longClick for multiselect
mFastAdapter.withSelectOnLongClick(true);
//actionMode end. deselect everything
if (mAutoDeselect)
mFastAdapter.deselect();
if (mCallback != null) {
//we notify the provided callback
mCallback.onDestroyActionMode(mode);
}
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return mCallback != null && mCallback.onPrepareActionMode(mode, menu);
}
}
// --------------------------
// Interfaces
// --------------------------
public interface ActionModeTitleProvider {
String getTitle(int selected);
}
}