package io.virtualapp.widgets;
import android.os.Bundle;
import android.support.annotation.CallSuper;
import android.support.v7.widget.RecyclerView;
import java.util.ArrayList;
/**
* @author Aidan Follestad (afollestad)
*/
public abstract class DragSelectRecyclerViewAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {
private ArrayList<Integer> mSelectedIndices;
private SelectionListener mSelectionListener;
private int mLastCount = -1;
private int mMaxSelectionCount = -1;
protected DragSelectRecyclerViewAdapter() {
mSelectedIndices = new ArrayList<>();
}
private void fireSelectionListener() {
if (mLastCount == mSelectedIndices.size())
return;
mLastCount = mSelectedIndices.size();
if (mSelectionListener != null)
mSelectionListener.onDragSelectionChanged(mLastCount);
}
public void setMaxSelectionCount(int maxSelectionCount) {
this.mMaxSelectionCount = maxSelectionCount;
}
public void setSelectionListener(SelectionListener selectionListener) {
this.mSelectionListener = selectionListener;
}
public void saveInstanceState(Bundle out) {
saveInstanceState("selected_indices", out);
}
public void saveInstanceState(String key, Bundle out) {
out.putSerializable(key, mSelectedIndices);
}
public void restoreInstanceState(Bundle in) {
restoreInstanceState("selected_indices", in);
}
public void restoreInstanceState(String key, Bundle in) {
if (in != null && in.containsKey(key)) {
//noinspection unchecked
mSelectedIndices = (ArrayList<Integer>) in.getSerializable(key);
if (mSelectedIndices == null) mSelectedIndices = new ArrayList<>();
else fireSelectionListener();
}
}
public final void setSelected(int index, boolean selected) {
if (!isIndexSelectable(index))
selected = false;
if (selected) {
if (!mSelectedIndices.contains(index) &&
(mMaxSelectionCount == -1 ||
mSelectedIndices.size() < mMaxSelectionCount)) {
mSelectedIndices.add(index);
notifyItemChanged(index);
}
} else if (mSelectedIndices.contains(index)) {
mSelectedIndices.remove((Integer) index);
notifyItemChanged(index);
}
fireSelectionListener();
}
public final boolean toggleSelected(int index) {
boolean selectedNow = false;
if (isIndexSelectable(index)) {
if (mSelectedIndices.contains(index)) {
mSelectedIndices.remove((Integer) index);
} else if (mMaxSelectionCount == -1 ||
mSelectedIndices.size() < mMaxSelectionCount) {
mSelectedIndices.add(index);
selectedNow = true;
}
notifyItemChanged(index);
}
fireSelectionListener();
return selectedNow;
}
protected boolean isIndexSelectable(int index) {
return true;
}
@CallSuper
@Override
public void onBindViewHolder(VH holder, int position) {
holder.itemView.setTag(holder);
}
public final void selectRange(int from, int to, int min, int max) {
if (from == to) {
// Finger is back on the initial item, unselect everything else
for (int i = min; i <= max; i++) {
if (i == from) continue;
setSelected(i, false);
}
fireSelectionListener();
return;
}
if (to < from) {
// When selecting from one to previous items
for (int i = to; i <= from; i++)
setSelected(i, true);
if (min > -1 && min < to) {
// Unselect items that were selected during this drag but no longer are
for (int i = min; i < to; i++) {
if (i == from) continue;
setSelected(i, false);
}
}
if (max > -1) {
for (int i = from + 1; i <= max; i++)
setSelected(i, false);
}
} else {
// When selecting from one to next items
for (int i = from; i <= to; i++)
setSelected(i, true);
if (max > -1 && max > to) {
// Unselect items that were selected during this drag but no longer are
for (int i = to + 1; i <= max; i++) {
if (i == from) continue;
setSelected(i, false);
}
}
if (min > -1) {
for (int i = min; i < from; i++)
setSelected(i, false);
}
}
fireSelectionListener();
}
public final void selectAll() {
int max = getItemCount();
mSelectedIndices.clear();
for (int i = 0; i < max; i++) {
if (isIndexSelectable(i)) {
mSelectedIndices.add(i);
}
}
notifyDataSetChanged();
fireSelectionListener();
}
public final void clearSelected() {
mSelectedIndices.clear();
notifyDataSetChanged();
fireSelectionListener();
}
public final int getSelectedCount() {
return mSelectedIndices.size();
}
public final Integer[] getSelectedIndices() {
return mSelectedIndices.toArray(new Integer[mSelectedIndices.size()]);
}
public final boolean isIndexSelected(int index) {
return mSelectedIndices.contains(index);
}
public interface SelectionListener {
void onDragSelectionChanged(int count);
}
}