mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-20 18:49:17 +01:00
Add library search. Closes #64
This commit is contained in:
parent
ed06469885
commit
57ba368ae0
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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));
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user