Add library search. Closes #64

This commit is contained in:
inorichi 2016-02-05 16:24:34 +01:00
parent ed06469885
commit 57ba368ae0
5 changed files with 63 additions and 53 deletions

View file

@ -3,8 +3,6 @@ package eu.kanade.tachiyomi.ui.library;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Filter;
import android.widget.Filterable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -12,28 +10,24 @@ import java.util.List;
import eu.davidea.flexibleadapter.FlexibleAdapter; import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.kanade.tachiyomi.R; import eu.kanade.tachiyomi.R;
import eu.kanade.tachiyomi.data.database.models.Manga; import eu.kanade.tachiyomi.data.database.models.Manga;
import rx.Observable;
public class LibraryCategoryAdapter extends FlexibleAdapter<LibraryHolder, Manga> public class LibraryCategoryAdapter extends FlexibleAdapter<LibraryHolder, Manga> {
implements Filterable {
List<Manga> mangas; private List<Manga> mangas;
Filter filter;
private LibraryCategoryFragment fragment; private LibraryCategoryFragment fragment;
public LibraryCategoryAdapter(LibraryCategoryFragment fragment) { public LibraryCategoryAdapter(LibraryCategoryFragment fragment) {
this.fragment = fragment; this.fragment = fragment;
mItems = new ArrayList<>(); mItems = new ArrayList<>();
filter = new LibraryFilter();
setHasStableIds(true); setHasStableIds(true);
} }
public void setItems(List<Manga> list) { public void setItems(List<Manga> list) {
mItems = list; mItems = list;
notifyDataSetChanged();
// TODO needed for filtering? // A copy of manga that it's always unfiltered
mangas = list; mangas = new ArrayList<>(list);
updateDataSet(null);
} }
public void clear() { public void clear() {
@ -47,7 +41,16 @@ public class LibraryCategoryAdapter extends FlexibleAdapter<LibraryHolder, Manga
@Override @Override
public void updateDataSet(String param) { public void updateDataSet(String param) {
if (mangas != null) {
filterItems(mangas);
notifyDataSetChanged();
}
}
@Override
protected boolean filterObject(Manga manga, String query) {
return (manga.title != null && manga.title.toLowerCase().contains(query)) ||
(manga.author != null && manga.author.toLowerCase().contains(query));
} }
@Override @Override
@ -70,40 +73,4 @@ public class LibraryCategoryAdapter extends FlexibleAdapter<LibraryHolder, Manga
return fragment.recycler.getItemWidth() / 3 * 4; return fragment.recycler.getItemWidth() / 3 * 4;
} }
@Override
public Filter getFilter() {
return filter;
}
private class LibraryFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence charSequence) {
FilterResults results = new FilterResults();
String query = charSequence.toString().toLowerCase();
if (query.length() == 0) {
results.values = mangas;
results.count = mangas.size();
} else {
List<Manga> filteredMangas = Observable.from(mangas)
.filter(x ->
(x.title != null && x.title.toLowerCase().contains(query)) ||
(x.author != null && x.author.toLowerCase().contains(query)) ||
(x.artist != null && x.artist.toLowerCase().contains(query)))
.toList()
.toBlocking()
.single();
results.values = filteredMangas;
results.count = filteredMangas.size();
}
return results;
}
@Override
public void publishResults(CharSequence constraint, FilterResults results) {
setItems((List<Manga>) results.values);
}
}
} }

View file

@ -37,6 +37,7 @@ public class LibraryCategoryFragment extends BaseFragment
private List<Manga> mangas; private List<Manga> mangas;
private Subscription numColumnsSubscription; private Subscription numColumnsSubscription;
private Subscription searchSubscription;
public static LibraryCategoryFragment newInstance(int position) { public static LibraryCategoryFragment newInstance(int position) {
LibraryCategoryFragment fragment = new LibraryCategoryFragment(); LibraryCategoryFragment fragment = new LibraryCategoryFragment();
@ -77,12 +78,19 @@ public class LibraryCategoryFragment extends BaseFragment
} }
} }
searchSubscription = getLibraryPresenter().searchSubject
.subscribe(text -> {
adapter.setSearchText(text);
adapter.updateDataSet();
});
return view; return view;
} }
@Override @Override
public void onDestroyView() { public void onDestroyView() {
numColumnsSubscription.unsubscribe(); numColumnsSubscription.unsubscribe();
searchSubscription.unsubscribe();
super.onDestroyView(); super.onDestroyView();
} }

View file

@ -7,6 +7,8 @@ import android.support.design.widget.AppBarLayout;
import android.support.design.widget.TabLayout; import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager;
import android.support.v7.view.ActionMode; import android.support.v7.view.ActionMode;
import android.support.v7.widget.SearchView;
import android.text.TextUtils;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
@ -48,6 +50,7 @@ public class LibraryFragment extends BaseRxFragment<LibraryPresenter>
private ActionMode actionMode; private ActionMode actionMode;
@State int activeCategory; @State int activeCategory;
@State String query = "";
public static LibraryFragment newInstance() { public static LibraryFragment newInstance() {
return new LibraryFragment(); return new LibraryFragment();
@ -60,8 +63,7 @@ public class LibraryFragment extends BaseRxFragment<LibraryPresenter>
} }
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
Bundle savedInstanceState) {
// Inflate the layout for this fragment // Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_library, container, false); View view = inflater.inflate(R.layout.fragment_library, container, false);
setToolbarTitle(getString(R.string.label_library)); setToolbarTitle(getString(R.string.label_library));
@ -75,6 +77,10 @@ public class LibraryFragment extends BaseRxFragment<LibraryPresenter>
viewPager.setAdapter(adapter); viewPager.setAdapter(adapter);
tabs.setupWithViewPager(viewPager); tabs.setupWithViewPager(viewPager);
if (savedState != null) {
getPresenter().searchSubject.onNext(query);
}
return view; return view;
} }
@ -99,6 +105,29 @@ public class LibraryFragment extends BaseRxFragment<LibraryPresenter>
@Override @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.library, menu); inflater.inflate(R.menu.library, menu);
// Initialize search menu
MenuItem searchItem = menu.findItem(R.id.action_search);
final SearchView searchView = (SearchView) searchItem.getActionView();
if (!TextUtils.isEmpty(query)) {
searchItem.expandActionView();
searchView.setQuery(query, true);
searchView.clearFocus();
}
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
onSearchTextChange(query);
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
onSearchTextChange(newText);
return true;
}
});
} }
@Override @Override
@ -115,6 +144,11 @@ public class LibraryFragment extends BaseRxFragment<LibraryPresenter>
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
private void onSearchTextChange(String query) {
this.query = query;
getPresenter().searchSubject.onNext(query);
}
private void onEditCategories() { private void onEditCategories() {
Intent intent = CategoryActivity.newIntent(getActivity()); Intent intent = CategoryActivity.newIntent(getActivity());
startActivity(intent); startActivity(intent);

View file

@ -21,6 +21,7 @@ import eu.kanade.tachiyomi.event.LibraryMangasEvent;
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter; import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter;
import rx.Observable; import rx.Observable;
import rx.android.schedulers.AndroidSchedulers; import rx.android.schedulers.AndroidSchedulers;
import rx.subjects.BehaviorSubject;
public class LibraryPresenter extends BasePresenter<LibraryFragment> { public class LibraryPresenter extends BasePresenter<LibraryFragment> {
@ -32,6 +33,8 @@ public class LibraryPresenter extends BasePresenter<LibraryFragment> {
protected List<Category> categories; protected List<Category> categories;
protected List<Manga> selectedMangas; protected List<Manga> selectedMangas;
protected BehaviorSubject<String> searchSubject;
private static final int GET_LIBRARY = 1; private static final int GET_LIBRARY = 1;
@Override @Override
@ -40,6 +43,8 @@ public class LibraryPresenter extends BasePresenter<LibraryFragment> {
selectedMangas = new ArrayList<>(); selectedMangas = new ArrayList<>();
searchSubject = BehaviorSubject.create();
restartableLatestCache(GET_LIBRARY, restartableLatestCache(GET_LIBRARY,
this::getLibraryObservable, this::getLibraryObservable,
(view, pair) -> view.onNextLibraryUpdate(pair.first, pair.second)); (view, pair) -> view.onNextLibraryUpdate(pair.first, pair.second));

View file

@ -2,21 +2,17 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity"> xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity">
<!--
<item <item
android:id="@+id/action_search" android:id="@+id/action_search"
android:title="@string/action_search" android:title="@string/action_search"
android:icon="@drawable/ic_action_search" android:icon="@drawable/ic_action_search"
android:orderInCategory="100"
app:showAsAction="collapseActionView|ifRoom" app:showAsAction="collapseActionView|ifRoom"
app:actionViewClass="android.support.v7.widget.SearchView" /> app:actionViewClass="android.support.v7.widget.SearchView" />
-->
<item <item
android:id="@+id/action_refresh" android:id="@+id/action_refresh"
android:title="@string/action_refresh" android:title="@string/action_refresh"
android:icon="@drawable/ic_action_refresh" android:icon="@drawable/ic_action_refresh"
android:orderInCategory="1"
app:showAsAction="ifRoom" /> app:showAsAction="ifRoom" />
<item <item