diff --git a/README.md b/README.md
index c59b4515..d33c29f3 100644
--- a/README.md
+++ b/README.md
@@ -134,6 +134,7 @@ public class MainActivity extends AppCompatActivity {
- Refactored module names, package signatures and gradle build files. Code remains unchanged.
- Configuration for JCenter, now FlexibleAdapter is a lightweight standalone library!
**Note:** FastScroller and ItemAnimators are excluded from the library, but you can see them in the example App.
+- New icon.
###### v4.0 - 2015.10.18
- Added **FilterAsyncTask** to asynchronously load the list (This might not work well and binding is excluded from Async).
diff --git a/flexibleAdapter/src/main/java/eu/davidea/common/FlexibleAdapter.java b/flexibleAdapter/src/main/java/eu/davidea/common/FlexibleAdapter.java
deleted file mode 100644
index a5da3888..00000000
--- a/flexibleAdapter/src/main/java/eu/davidea/common/FlexibleAdapter.java
+++ /dev/null
@@ -1,401 +0,0 @@
-package eu.davidea.common;
-
-import android.os.AsyncTask;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.support.v7.widget.RecyclerView;
-import android.util.Log;
-import android.view.ViewGroup;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Locale;
-
-/**
- * This class provides a set of standard methods to handle changes on the data set
- * such as adding, removing, moving an item.
- *
- * Remember to call {@link RecyclerView#scheduleLayoutAnimation()} after adding or
- * removing an item from the Adapter when the activity is paused.
- *
- * VH is your implementation of {@link RecyclerView.ViewHolder}.
- * T is your domain object containing the data.
- *
- * @author Davide Steduto
- */
-public abstract class FlexibleAdapter extends SelectableAdapter {
-
- private static final String TAG = FlexibleAdapter.class.getSimpleName();
- public static final long UNDO_TIMEOUT = 5000L;
-
- public interface OnUpdateListener {
- void onLoadComplete();
- //void onProgressUpdate(int progress);
- }
-
- /**
- * Lock used to modify the content of {@link #mItems}. Any write operation performed on the array should be
- * synchronized on this lock.
- */
- private final Object mLock = new Object();
-
- protected List mItems;
- protected List mDeletedItems;
- protected List mOriginalPosition;
- //Searchable fields
- protected static String mSearchText; //Static: It can exist only 1 searchText
- protected OnUpdateListener mUpdateListener;
- protected Handler mHandler;
-
- public FlexibleAdapter() {
- }
-
- /**
- * Constructor for Asynchronous loading.
- * Experimental: not working very well, it might be slow.
- *
- * @param listener {@link OnUpdateListener}
- */
- public FlexibleAdapter(Object listener) {
- if (listener instanceof OnUpdateListener)
- this.mUpdateListener = (OnUpdateListener) listener;
- else
- Log.w(TAG, "Listener is not an instance of OnUpdateListener!");
- }
-
- /**
- * Convenience method to call {@link #updateDataSet(String)} with {@link null} as param.
- */
- public void updateDataSet() {
- updateDataSet(null);
- };
- /**
- * This method will refresh the entire DataSet content.
- * The parameter is useful to filter the DataSet. It can be removed
- * or the type can be changed accordingly (String is the most used value).
- * Pass null value in case not used.
- *
- * @param param A custom parameter to filter the DataSet
- */
- public abstract void updateDataSet(String param);
-
- /**
- * This method execute {@link #updateDataSet(String)} asynchronously
- * with {@link FilterAsyncTask}.
- * Note: {@link #notifyDataSetChanged()} is automatically called at the end of the process.
- *
- * @param param A custom parameter to filter the DataSet
- */
- public void updateDataSetAsync(String param) {
- if (mUpdateListener == null) {
- Log.w(TAG, "OnUpdateListener is not initialized. UpdateDataSet is not using FilterAsyncTask!");
- updateDataSet(param);
- return;
- }
- new FilterAsyncTask().execute(param);
- }
-
- /**
- * Returns the custom object "Item".
- *
- * @param position The position of the item in the list
- * @return The custom "Item" object or null if item not found
- */
- public T getItem(int position) {
- if (position < 0 || position >= mItems.size()) return null;
- return mItems.get(position);
- }
-
- /**
- * Retrieve the position of the Item in the Adapter
- *
- * @param item The item
- * @return The position in the Adapter if found, -1 otherwise
- */
- public int getPositionForItem(T item) {
- return mItems != null && mItems.size() > 0 ? mItems.indexOf(item) : -1;
- }
-
- public boolean contains(T item) {
- return mItems != null && mItems.contains(item);
- }
-
- @Override
- public abstract VH onCreateViewHolder(ViewGroup parent, int viewType);
-
- @Override
- public abstract void onBindViewHolder(VH holder, final int position);
-
- @Override
- public int getItemCount() {
- return mItems != null ? mItems.size() : 0;
- }
-
- public void updateItem(int position, T item) {
- if (position < 0) return;
- synchronized (mLock) {
- mItems.set(position, item);
- }
- Log.d(TAG, "updateItem notifyItemChanged on position "+position);
- notifyItemChanged(position);
- }
-
- /**
- * Insert given Item at position or Add Item at last position.
- *
- * @param position Position of the item to add
- * @param item The item to add
- */
- public void addItem(int position, T item) {
- if (position < 0) return;
-
- //Insert Item
- if (position < mItems.size()) {
- Log.d(TAG, "addItem notifyItemInserted on position " + position);
- synchronized (mLock) {
- mItems.add(position, item);
- }
-
- //Add Item at the last position
- } else {
- Log.d(TAG, "addItem notifyItemInserted on last position");
- synchronized (mLock) {
- mItems.add(item);
- position = mItems.size();
- }
- }
-
- notifyItemInserted(position);
- }
-
- /* DELETE ITEMS METHODS */
-
- /**
- * The item is retained in a list for an eventual Undo.
- *
- * @param position The position of item to remove
- * @see #startUndoTimer()
- * @see #restoreDeletedItems()
- * @see #emptyBin()
- */
- public void removeItem(int position) {
- if (position < 0) return;
- if (position < mItems.size()) {
- Log.d(TAG, "removeItem notifyItemRemoved on position " + position);
- synchronized (mLock) {
- saveDeletedItem(position, mItems.remove(position));
- }
- notifyItemRemoved(position);
- } else {
- Log.w(TAG, "removeItem WARNING! Position OutOfBound! Review the position to remove!");
- }
- }
-
- /**
- * Every item is retained in a list for an eventual Undo.
- *
- * @param selectedPositions List of item positions to remove
- * @see #startUndoTimer()
- * @see #restoreDeletedItems()
- * @see #emptyBin()
- */
- public void removeItems(List selectedPositions) {
- Log.d(TAG, "removeItems reverse Sorting positions --------------");
- // Reverse-sort the list
- Collections.sort(selectedPositions, new Comparator() {
- @Override
- public int compare(Integer lhs, Integer rhs) {
- return rhs - lhs;
- }
- });
-
- // Split the list in ranges
- while (!selectedPositions.isEmpty()) {
- if (selectedPositions.size() == 1) {
- removeItem(selectedPositions.get(0));
- //Align the selection list when removing the item
- selectedPositions.remove(0);
- } else {
- int count = 1;
- while (selectedPositions.size() > count && selectedPositions.get(count).equals(selectedPositions.get(count - 1) - 1)) {
- ++count;
- }
-
- if (count == 1) {
- removeItem(selectedPositions.get(0));
- } else {
- removeRange(selectedPositions.get(count - 1), count);
- }
-
- for (int i = 0; i < count; ++i) {
- selectedPositions.remove(0);
- }
- }
- Log.d(TAG, "removeItems current selection " + getSelectedItems());
- }
- }
-
- private void removeRange(int positionStart, int itemCount) {
- Log.d(TAG, "removeRange positionStart="+positionStart+ " itemCount="+itemCount);
- for (int i = 0; i < itemCount; ++i) {
- synchronized (mLock) {
- saveDeletedItem(positionStart, mItems.remove(positionStart));
- }
- }
- Log.d(TAG, "removeRange notifyItemRangeRemoved");
- notifyItemRangeRemoved(positionStart, itemCount);
- }
-
- /* UNDO METHODS */
-
- /**
- * Save temporary Items for an eventual Undo.
- *
- * @param position The position of the item to retain.
- */
- public void saveDeletedItem(int position, T item) {
- if (mDeletedItems == null) {
- mDeletedItems = new ArrayList();
- mOriginalPosition = new ArrayList();
- }
- Log.d(TAG, "Recycled "+getItem(position)+" on position="+position);
- mDeletedItems.add(item);
- mOriginalPosition.add(position);
- }
-
- /**
- * @return The list of deleted items
- */
- public List getDeletedItems() {
- return mDeletedItems;
- }
-
- public boolean isRestoreInTime() {
- return mDeletedItems != null && mDeletedItems.size() > 0;
- }
-
- /**
- * Restore items just removed.
- */
- public void restoreDeletedItems() {
- stopUndoTimer();
- //Reverse insert (list was reverse ordered on Delete)
- for (int i = mOriginalPosition.size()-1; i >= 0; i--) {
- addItem(mOriginalPosition.get(i), mDeletedItems.get(i));
- }
- emptyBin();
- }
-
- /**
- * Clean memory from items just removed.
- * Note: This method is automatically called after timer is over and after a restoration.
- */
- public void emptyBin() {
- if (mDeletedItems != null) {
- mDeletedItems.clear();
- mOriginalPosition.clear();
- }
- }
-
- /**
- * Convenience method to start Undo timer with default timeout of 5''
- */
- public void startUndoTimer() {
- startUndoTimer(0);
- }
-
- /**
- * Start Undo timer with custom timeout
- *
- * @param timeout Custom timeout
- */
- public void startUndoTimer(long timeout) {
- mHandler = new Handler(Looper.getMainLooper(), new Handler.Callback() {
- public boolean handleMessage(Message message) {
- emptyBin();
- return true;
- }
- });
- mHandler.sendMessageDelayed(Message.obtain(mHandler), timeout > 0 ? timeout : UNDO_TIMEOUT);
- }
-
- /**
- * Stop Undo timer.
- *
Note: This method is automatically called in case of restoration.
- */
- private void stopUndoTimer() {
- if (mHandler != null) {
- mHandler.removeCallbacksAndMessages(null);
- mHandler = null;
- }
- }
-
- public static boolean hasSearchText() {
- return mSearchText != null && mSearchText.length() > 0;
- }
-
- public static String getSearchText() {
- return mSearchText;
- }
-
- public static void setSearchText(String searchText) {
- if (searchText != null)
- mSearchText = searchText.trim().toLowerCase(Locale.getDefault());
- else mSearchText = "";
- }
-
- /**
- * DEFAULT IMPLEMENTATION, OVERRIDE TO HAVE OWN FILTER!
- *
- *
- * Performs filtering on the provided object and returns true, if the object should be in the filtered collection,
- * or false if it shouldn't.
- *
- * @param myObject The object to be inspected
- * @param constraint Constraint, that the object has to fulfil
- * @return true, if the object should be in the filteredResult, false otherwise
- */
- protected boolean filterObject(T myObject, String constraint) {
- final String valueText = myObject.toString().toLowerCase();
-
- //First match against the whole, non-splitted value
- if (valueText.startsWith(constraint)) {
- return true;
- } else {
- final String[] words = valueText.split(" ");
-
- //Start at index 0, in case valueText starts with space(s)
- for (String word : words) {
- if (word.startsWith(constraint)) {
- return true;
- }
- }
- }
- //No match, so don't add to collection
- return false;
- }
-
- public class FilterAsyncTask extends AsyncTask {
-
- private final String TAG = FilterAsyncTask.class.getSimpleName();
-
- @Override
- protected Void doInBackground(String... params) {
- Log.i(TAG, "doInBackground - started FilterAsyncTask!");
- updateDataSet(params[0]);
- Log.i(TAG, "doInBackground - ended FilterAsyncTask!");
- return null;
- }
-
- @Override
- protected void onPostExecute(Void result) {
- super.onPostExecute(result);
- mUpdateListener.onLoadComplete();
- notifyDataSetChanged();
- }
- }
-
-}
\ No newline at end of file
diff --git a/flexibleAdapter/src/main/java/eu/davidea/common/SelectableAdapter.java b/flexibleAdapter/src/main/java/eu/davidea/common/SelectableAdapter.java
deleted file mode 100644
index f1e6ac2d..00000000
--- a/flexibleAdapter/src/main/java/eu/davidea/common/SelectableAdapter.java
+++ /dev/null
@@ -1,236 +0,0 @@
-package eu.davidea.common;
-
-import android.os.Bundle;
-import android.support.v7.widget.RecyclerView;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * This class provides a set of standard methods to handle the selection on the items of an Adapter.
- *
- * @author Davide Steduto
- */
-public abstract class SelectableAdapter extends RecyclerView.Adapter {
-
- private static final String TAG = SelectableAdapter.class.getSimpleName();
- /**
- * Default mode for selection
- */
- public static final int MODE_SINGLE = 1;
- /**
- * Multi selection will be activated
- */
- public static final int MODE_MULTI = 2;
-
- private ArrayList selectedItems;
- private int mode;
-
- public SelectableAdapter() {
- this.selectedItems = new ArrayList();
- this.mode = MODE_SINGLE;
- }
-
- /**
- * Set the mode of the selection, MODE_SINGLE is the default:
- *
- * - if {@link #MODE_SINGLE}, it will switch the selection position (previous selection is cleared automatically);
- *
- if {@link #MODE_MULTI}, it will add the position to the list of the items selected.
- *
- * NOTE: #mModeMultiJustFinished is set true when #MODE_MULTI is finished.
- *
- * @param mode MODE_SINGLE or MODE_MULTI
- */
- public void setMode(int mode) {
- this.mode = mode;
- }
-
- /**
- * The current selection mode of the Adapter.
- *
- * @return current mode
- * @see #MODE_SINGLE
- * @see #MODE_MULTI
- */
- public int getMode() {
- return mode;
- }
-
- /**
- * Indicates if the item at position position is selected.
- *
- * @param position Position of the item to check.
- * @return true if the item is selected, false otherwise.
- */
- public boolean isSelected(int position) {
- return selectedItems.contains(Integer.valueOf(position));
- }
-
- /**
- * Convenience method to never invalidate the Item.
- *
- * @param position Position of the item to toggle the selection status for.
- * @see #toggleSelection(int, boolean)
- */
- public void toggleSelection(int position) {
- toggleSelection(position, false);
- }
-
- /**
- * Toggle the selection status of the item at a given position.
- * The behaviour depends on the selection mode previously set with {@link #setMode}.
- *
- *
- * Optionally the item can be invalidated.
- * However it is preferable to set false and to handle the Activated/Selected State of
- * the ItemView in the Click events of the ViewHolder after the selection is registered and
- * up to date: Very Useful if the item has views with own animation to perform!
- *
- *
- * Usage:
- *
- * - If you don't want any item to be selected/activated at all, just don't call this method.
- * - To have actually the item visually selected you need to add a custom Selector Drawable to your layout/view of the Item.
- * It's preferable: android:background="?attr/selectableItemBackground" in your layout, pointing to a custom Drawable in the style.xml
- * (note: prefix ?android:attr seems to not work).
- * - In onClick, enable the Activated/Selected State of the ItemView of the ViewHolder after the listener consumed the event:
- * itemView.setActivated(mAdapter.isSelected(getAdapterPosition()));
- * - In onBindViewHolder, adjust the selection status: holder.itemView.setActivated(isSelected(position));
- * - If invalidate is set true, {@link #notifyItemChanged} is called and {@link #onBindViewHolder} will be automatically called
- * afterwards overriding any animation in the ItemView!
- *
T
- *
- * @param position Position of the item to toggle the selection status for.
- * @param invalidate Boolean to indicate if the row must be invalidated and item rebinded.
- */
- public void toggleSelection(int position, boolean invalidate) {
- if (position < 0) return;
- if (mode == MODE_SINGLE) clearSelection();
-
- int index = selectedItems.indexOf(position);
- if (index != -1) {
- Log.d(TAG, "toggleSelection removing selection on position "+position);
- selectedItems.remove(index);
- } else {
- Log.d(TAG, "toggleSelection adding selection on position "+position);
- selectedItems.add(position);
- }
- if (invalidate) {
- Log.d(TAG, "toggleSelection notifyItemChanged on position "+position);
- notifyItemChanged(position);
- }
- Log.d(TAG, "toggleSelection current selection " + selectedItems);
- }
-
- /**
- * Deprecated! Reasons:
- *
- Use {@link #toggleSelection} for normal situation instead.
- *
- Use {@link #getSelectedItems}.iterator() to avoid java.util.ConcurrentModificationException.
- *
- *
- * This method is used only after a removal of an Item and useful only in certain
- * situations such when not all selected Items can be removed (business exceptions dependencies)
- * while others still remains selected.
- *
For normal situations use {@link #toggleSelection} instead.
- *
- *
- * Remove the selection if at the specified
- * position the item was previously selected.
- *
- *
- * Note: notifyItemChanged on the position is NOT called to avoid double call
- * when removeItems!
- *
- * @param position
- */
- @Deprecated
- protected void removeSelection(int position) {
- if (position < 0) return;
- Log.d(TAG, "removeSelection on position "+position);
- int index = selectedItems.indexOf(Integer.valueOf(position));
- if (index != -1) selectedItems.remove(index);
- //Avoid double notification:
- //Usually the notification is made in FlexibleAdapter.removeItem();
- //notifyItemChanged(position);
- }
-
- /**
- * Convenience method when there is nothing to skip.
- */
- public void selectAll() {
- selectAll(-1);
- }
- /**
- * Add the selection status for all items.
- * The selector container is sequentially filled with All items positions.
- *
Note: All items are invalidated and rebinded!
- *
- * @param skipViewType ViewType for which we don't want selection
- */
- public void selectAll(int skipViewType) {
- Log.d(TAG, "selectAll");
- selectedItems = new ArrayList(getItemCount());
- for (int i = 0; i < getItemCount(); i++) {
- if (getItemViewType(i) == skipViewType) continue;
- selectedItems.add(i);
- Log.d(TAG, "selectAll notifyItemChanged on position "+i);
- notifyItemChanged(i);
- }
- }
-
- /**
- * Clear the selection status for all items one by one to not kill animations in the items.
- *
- * Note 1: Items are invalidated and rebinded!
- * Note 2: This method use java.util.Iterator to avoid java.util.ConcurrentModificationException.
- */
- public void clearSelection() {
- Iterator iterator = selectedItems.iterator();
- while (iterator.hasNext()) {
- //The notification is done only on items that are currently selected.
- int i = iterator.next();
- iterator.remove();
- Log.d(TAG, "clearSelection notifyItemChanged on position "+i);
- notifyItemChanged(i);
- }
- }
-
- /**
- * Count the selected items.
- *
- * @return Selected items count
- */
- public int getSelectedItemCount() {
- return selectedItems.size();
- }
-
- /**
- * Indicates the list of selected items.
- *
- * @return List of selected items ids
- */
- public List getSelectedItems() {
- return selectedItems;
- }
-
- /**
- * Save the state of the current selection on the items.
- *
- * @param outState
- */
- public void onSaveInstanceState(Bundle outState) {
- outState.putIntegerArrayList(TAG, selectedItems);
- }
-
- /**
- * Restore the previous state of the selection on the items.
- *
- * @param savedInstanceState
- */
- public void onRestoreInstanceState(Bundle savedInstanceState) {
- selectedItems = savedInstanceState.getIntegerArrayList(TAG);
- }
-
-}
\ No newline at end of file