Make the RecyclerView searchable
This commit is contained in:
parent
6275207362
commit
0a5124207d
6 changed files with 148 additions and 20 deletions
|
@ -35,6 +35,8 @@ import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
import android.widget.Filter;
|
||||||
|
import android.widget.Filterable;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
@ -48,19 +50,27 @@ import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
public class EntriesCardAdapter extends RecyclerView.Adapter<EntriesCardAdapter.EntryViewHolder>
|
public class EntriesCardAdapter extends RecyclerView.Adapter<EntriesCardAdapter.EntryViewHolder>
|
||||||
implements ItemTouchHelperAdapter {
|
implements ItemTouchHelperAdapter, Filterable {
|
||||||
|
|
||||||
private Context context;
|
private Context context;
|
||||||
|
private EntryFilter filter;
|
||||||
private ArrayList<Entry> entries;
|
private ArrayList<Entry> entries;
|
||||||
|
private ArrayList<Integer> displayedEntries;
|
||||||
public ViewHolderEventCallback viewHolderEventCallback;
|
public ViewHolderEventCallback viewHolderEventCallback;
|
||||||
|
|
||||||
public EntriesCardAdapter(Context context, ArrayList<Entry> entries) {
|
public EntriesCardAdapter(Context context, ArrayList<Entry> entries) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.entries = entries;
|
this.entries = entries;
|
||||||
|
|
||||||
|
displayedEntries = defaultIndices();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemCount() {
|
public int getItemCount() {
|
||||||
|
return displayedEntries.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFullItemCount() {
|
||||||
return entries.size();
|
return entries.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,11 +80,39 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntriesCardAdapter.
|
||||||
|
|
||||||
public void setEntries(ArrayList<Entry> e) {
|
public void setEntries(ArrayList<Entry> e) {
|
||||||
entries = e;
|
entries = e;
|
||||||
|
|
||||||
|
displayedEntries.clear();
|
||||||
|
displayedEntries = defaultIndices();
|
||||||
|
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<Integer> defaultIndices() {
|
||||||
|
ArrayList<Integer> newIdx = new ArrayList<>();
|
||||||
|
for (int i = 0; i < entries.size(); i++)
|
||||||
|
newIdx.add(i);
|
||||||
|
|
||||||
|
return newIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int removeIndex(int pos) {
|
||||||
|
int removed = displayedEntries.remove(pos);
|
||||||
|
|
||||||
|
ArrayList<Integer> newIdx = new ArrayList<>();
|
||||||
|
for (int i = 0; i < displayedEntries.size(); i++) {
|
||||||
|
int idx = displayedEntries.get(i);
|
||||||
|
if (idx > removed)
|
||||||
|
idx -= 1;
|
||||||
|
newIdx.add(idx);
|
||||||
|
}
|
||||||
|
displayedEntries = newIdx;
|
||||||
|
|
||||||
|
return removed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(EntryViewHolder entryViewHolder, int i) {
|
public void onBindViewHolder(EntryViewHolder entryViewHolder, int i) {
|
||||||
Entry entry = entries.get(i);
|
Entry entry = entries.get(displayedEntries.get(i));
|
||||||
|
|
||||||
entryViewHolder.OTPValue.setText(entry.getCurrentOTP());
|
entryViewHolder.OTPValue.setText(entry.getCurrentOTP());
|
||||||
entryViewHolder.OTPLabel.setText(entry.getLabel());
|
entryViewHolder.OTPLabel.setText(entry.getLabel());
|
||||||
|
@ -104,7 +142,7 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntriesCardAdapter.
|
||||||
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
|
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialogInterface, int i) {
|
public void onClick(DialogInterface dialogInterface, int i) {
|
||||||
entries.remove(position);
|
entries.remove(removeIndex(position));
|
||||||
notifyItemRemoved(position);
|
notifyItemRemoved(position);
|
||||||
|
|
||||||
SettingsHelper.store(context, entries);
|
SettingsHelper.store(context, entries);
|
||||||
|
@ -121,15 +159,7 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntriesCardAdapter.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onItemMove(int fromPosition, int toPosition) {
|
public boolean onItemMove(int fromPosition, int toPosition) {
|
||||||
if (fromPosition < toPosition) {
|
Collections.swap(entries, fromPosition, toPosition);
|
||||||
for (int i = fromPosition; i < toPosition; i++) {
|
|
||||||
Collections.swap(entries, i, i + 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (int i = fromPosition; i > toPosition; i--) {
|
|
||||||
Collections.swap(entries, i, i - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
notifyItemMoved(fromPosition, toPosition);
|
notifyItemMoved(fromPosition, toPosition);
|
||||||
|
|
||||||
SettingsHelper.store(context, entries);
|
SettingsHelper.store(context, entries);
|
||||||
|
@ -141,7 +171,7 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntriesCardAdapter.
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||||
|
|
||||||
final EditText input = new EditText(context);
|
final EditText input = new EditText(context);
|
||||||
input.setText(getItem(pos).getLabel());
|
input.setText(entries.get(displayedEntries.get(pos)).getLabel());
|
||||||
input.setSingleLine();
|
input.setSingleLine();
|
||||||
|
|
||||||
FrameLayout container = new FrameLayout(context);
|
FrameLayout container = new FrameLayout(context);
|
||||||
|
@ -156,7 +186,7 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntriesCardAdapter.
|
||||||
.setPositiveButton(R.string.button_save, new DialogInterface.OnClickListener() {
|
.setPositiveButton(R.string.button_save, new DialogInterface.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialogInterface, int i) {
|
public void onClick(DialogInterface dialogInterface, int i) {
|
||||||
getItem(pos).setLabel(input.getEditableText().toString());
|
entries.get(displayedEntries.get(pos)).setLabel(input.getEditableText().toString());
|
||||||
notifyItemChanged(pos);
|
notifyItemChanged(pos);
|
||||||
|
|
||||||
SettingsHelper.store(context, entries);
|
SettingsHelper.store(context, entries);
|
||||||
|
@ -207,6 +237,43 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntriesCardAdapter.
|
||||||
this.viewHolderEventCallback = cb;
|
this.viewHolderEventCallback = cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EntryFilter getFilter() {
|
||||||
|
if (filter == null)
|
||||||
|
filter = new EntryFilter();
|
||||||
|
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EntryFilter extends Filter {
|
||||||
|
@Override
|
||||||
|
protected FilterResults performFiltering(CharSequence constraint) {
|
||||||
|
final FilterResults filterResults = new FilterResults();
|
||||||
|
|
||||||
|
ArrayList<Integer> newIdx = new ArrayList<>();
|
||||||
|
if (constraint != null && constraint.length() != 0){
|
||||||
|
for (int i = 0; i < entries.size(); i++) {
|
||||||
|
if (entries.get(i).getLabel().toLowerCase().contains(constraint.toString().toLowerCase())) {
|
||||||
|
newIdx.add(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newIdx = defaultIndices();
|
||||||
|
}
|
||||||
|
|
||||||
|
filterResults.count = newIdx.size();
|
||||||
|
filterResults.values = newIdx;
|
||||||
|
|
||||||
|
return filterResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void publishResults(CharSequence constraint, FilterResults results) {
|
||||||
|
displayedEntries = (ArrayList<Integer>) results.values;
|
||||||
|
notifyDataSetChanged();
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public class EntryViewHolder extends RecyclerView.ViewHolder
|
public class EntryViewHolder extends RecyclerView.ViewHolder
|
||||||
implements ItemTouchHelperViewHolder {
|
implements ItemTouchHelperViewHolder {
|
||||||
|
|
||||||
|
|
|
@ -35,20 +35,30 @@ public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
|
||||||
|
|
||||||
public static final float ALPHA_FULL = 1.0f;
|
public static final float ALPHA_FULL = 1.0f;
|
||||||
|
|
||||||
|
private boolean dragEnabled = true;
|
||||||
|
private boolean swipeEnabled = true;
|
||||||
private final ItemTouchHelperAdapter mAdapter;
|
private final ItemTouchHelperAdapter mAdapter;
|
||||||
|
|
||||||
public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
|
public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
|
||||||
mAdapter = adapter;
|
mAdapter = adapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setDragEnabled(boolean newDragState) {
|
||||||
|
this.dragEnabled = newDragState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSwipeEnabled(boolean newSwipeState) {
|
||||||
|
this.swipeEnabled = newSwipeState;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLongPressDragEnabled() {
|
public boolean isLongPressDragEnabled() {
|
||||||
return true;
|
return dragEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isItemViewSwipeEnabled() {
|
public boolean isItemViewSwipeEnabled() {
|
||||||
return true;
|
return swipeEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -41,9 +41,11 @@ import android.support.annotation.NonNull;
|
||||||
import android.support.design.widget.FloatingActionButton;
|
import android.support.design.widget.FloatingActionButton;
|
||||||
import android.support.v4.app.ActivityCompat;
|
import android.support.v4.app.ActivityCompat;
|
||||||
import android.support.v4.content.ContextCompat;
|
import android.support.v4.content.ContextCompat;
|
||||||
|
import android.support.v4.view.MenuItemCompat;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.support.v7.widget.SearchView;
|
||||||
import android.support.v7.widget.Toolbar;
|
import android.support.v7.widget.Toolbar;
|
||||||
import android.support.v7.widget.helper.ItemTouchHelper;
|
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
|
@ -68,6 +70,7 @@ public class MainActivity extends AppCompatActivity {
|
||||||
private ArrayList<Entry> entries;
|
private ArrayList<Entry> entries;
|
||||||
private EntriesCardAdapter adapter;
|
private EntriesCardAdapter adapter;
|
||||||
private FloatingActionButton fab;
|
private FloatingActionButton fab;
|
||||||
|
private SimpleItemTouchHelperCallback touchHelperCallback;
|
||||||
|
|
||||||
private Handler handler;
|
private Handler handler;
|
||||||
private Runnable handlerTask;
|
private Runnable handlerTask;
|
||||||
|
@ -184,7 +187,6 @@ public class MainActivity extends AppCompatActivity {
|
||||||
if (success) {
|
if (success) {
|
||||||
entries = SettingsHelper.load(this);
|
entries = SettingsHelper.load(this);
|
||||||
adapter.setEntries(entries);
|
adapter.setEntries(entries);
|
||||||
adapter.notifyDataSetChanged();
|
|
||||||
|
|
||||||
Toast.makeText(this, R.string.msg_import_success, Toast.LENGTH_LONG).show();
|
Toast.makeText(this, R.string.msg_import_success, Toast.LENGTH_LONG).show();
|
||||||
} else {
|
} else {
|
||||||
|
@ -301,8 +303,8 @@ public class MainActivity extends AppCompatActivity {
|
||||||
adapter = new EntriesCardAdapter(this, entries);
|
adapter = new EntriesCardAdapter(this, entries);
|
||||||
recList.setAdapter(adapter);
|
recList.setAdapter(adapter);
|
||||||
|
|
||||||
ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(adapter);
|
touchHelperCallback = new SimpleItemTouchHelperCallback(adapter);
|
||||||
ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
|
ItemTouchHelper touchHelper = new ItemTouchHelper(touchHelperCallback);
|
||||||
touchHelper.attachToRecyclerView(recList);
|
touchHelper.attachToRecyclerView(recList);
|
||||||
|
|
||||||
final float durationScale = fixAnimationScale();
|
final float durationScale = fixAnimationScale();
|
||||||
|
@ -334,7 +336,7 @@ public class MainActivity extends AppCompatActivity {
|
||||||
animation.start();
|
animation.start();
|
||||||
|
|
||||||
boolean change = false;
|
boolean change = false;
|
||||||
for(int i =0;i < adapter.getItemCount(); i++){
|
for(int i =0;i < adapter.getFullItemCount(); i++){
|
||||||
boolean item_changed = adapter.getItem(i).updateOTP();
|
boolean item_changed = adapter.getItem(i).updateOTP();
|
||||||
change = change || item_changed;
|
change = change || item_changed;
|
||||||
}
|
}
|
||||||
|
@ -403,6 +405,38 @@ public class MainActivity extends AppCompatActivity {
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
getMenuInflater().inflate(R.menu.menu_main, menu);
|
getMenuInflater().inflate(R.menu.menu_main, menu);
|
||||||
|
|
||||||
|
MenuItem searchItem = menu.findItem(R.id.menu_search);
|
||||||
|
SearchView searchView = (SearchView) searchItem.getActionView();
|
||||||
|
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onQueryTextSubmit(String query) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onQueryTextChange(String newText) {
|
||||||
|
adapter.getFilter().filter(newText);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
MenuItemCompat.setOnActionExpandListener(searchItem, new MenuItemCompat.OnActionExpandListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onMenuItemActionExpand(MenuItem item) {
|
||||||
|
fab.setVisibility(View.GONE);
|
||||||
|
touchHelperCallback.setDragEnabled(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onMenuItemActionCollapse(MenuItem item) {
|
||||||
|
fab.setVisibility(View.VISIBLE);
|
||||||
|
touchHelperCallback.setDragEnabled(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
9
app/src/main/res/drawable/ic_search_white.xml
Normal file
9
app/src/main/res/drawable/ic_search_white.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFFFF"
|
||||||
|
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
|
||||||
|
</vector>
|
|
@ -1,6 +1,13 @@
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_search"
|
||||||
|
android:title="@string/title_search"
|
||||||
|
android:icon="@drawable/ic_search_white"
|
||||||
|
app:showAsAction="always|collapseActionView"
|
||||||
|
app:actionViewClass="android.support.v7.widget.SearchView" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/submenu_backup"
|
android:id="@+id/submenu_backup"
|
||||||
android:title="@string/menu_submenu_backup">
|
android:title="@string/menu_submenu_backup">
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
<string name="msg_storage_permissions">Storage permissions not granted</string>
|
<string name="msg_storage_permissions">Storage permissions not granted</string>
|
||||||
|
|
||||||
<string name="title_animator_duration">Animator duration scale</string>
|
<string name="title_animator_duration">Animator duration scale</string>
|
||||||
|
<string name="title_search">Search</string>
|
||||||
|
|
||||||
<string name="pref_animator_warning_displayed">animator_warning_displayed</string>
|
<string name="pref_animator_warning_displayed">animator_warning_displayed</string>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue