Organize ui by feature instead of layer
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
package eu.kanade.mangafeed.ui.library;
|
||||
|
||||
import android.content.Context;
|
||||
import android.widget.Filter;
|
||||
import android.widget.Filterable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import eu.kanade.mangafeed.data.models.Manga;
|
||||
import eu.kanade.mangafeed.ui.library.LibraryHolder;
|
||||
import rx.Observable;
|
||||
import uk.co.ribot.easyadapter.EasyAdapter;
|
||||
|
||||
public class LibraryAdapter extends EasyAdapter<Manga> implements Filterable {
|
||||
|
||||
List<Manga> mangas;
|
||||
Filter filter;
|
||||
|
||||
public LibraryAdapter(Context context) {
|
||||
super(context, LibraryHolder.class);
|
||||
filter = new LibraryFilter();
|
||||
}
|
||||
|
||||
public void setNewItems(List<Manga> list) {
|
||||
super.setItems(list);
|
||||
mangas = list;
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
package eu.kanade.mangafeed.ui.library;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.widget.SearchView;
|
||||
import android.view.ActionMode;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.GridView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import butterknife.Bind;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnItemClick;
|
||||
import eu.kanade.mangafeed.R;
|
||||
import eu.kanade.mangafeed.data.models.Manga;
|
||||
import eu.kanade.mangafeed.data.services.LibraryUpdateService;
|
||||
import eu.kanade.mangafeed.ui.manga.MangaActivity;
|
||||
import eu.kanade.mangafeed.ui.base.fragment.BaseRxFragment;
|
||||
import nucleus.factory.RequiresPresenter;
|
||||
|
||||
@RequiresPresenter(LibraryPresenter.class)
|
||||
public class LibraryFragment extends BaseRxFragment<LibraryPresenter> {
|
||||
|
||||
@Bind(R.id.gridView) GridView grid;
|
||||
private LibraryAdapter adapter;
|
||||
|
||||
public static LibraryFragment newInstance() {
|
||||
LibraryFragment fragment = new LibraryFragment();
|
||||
Bundle args = new Bundle();
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
View view = inflater.inflate(R.layout.fragment_library, container, false);
|
||||
setToolbarTitle(getString(R.string.library_title));
|
||||
ButterKnife.bind(this, view);
|
||||
|
||||
createAdapter();
|
||||
setMangaLongClickListener();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.library, menu);
|
||||
initializeSearch(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_refresh:
|
||||
if (!LibraryUpdateService.isRunning(getActivity())) {
|
||||
Intent intent = LibraryUpdateService.getStartIntent(getActivity());
|
||||
getActivity().startService(intent);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void initializeSearch(Menu menu) {
|
||||
final SearchView sv = (SearchView) menu.findItem(R.id.action_search).getActionView();
|
||||
sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
|
||||
@Override
|
||||
public boolean onQueryTextSubmit(String query) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextChange(String newText) {
|
||||
adapter.getFilter().filter(newText);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void createAdapter() {
|
||||
adapter = new LibraryAdapter(getActivity());
|
||||
grid.setAdapter(adapter);
|
||||
}
|
||||
|
||||
public void onNextMangas(List<Manga> mangas) {
|
||||
adapter.setNewItems(mangas);
|
||||
}
|
||||
|
||||
@OnItemClick(R.id.gridView)
|
||||
protected void onMangaClick(int position) {
|
||||
Intent intent = MangaActivity.newIntent(
|
||||
getActivity(),
|
||||
adapter.getItem(position)
|
||||
);
|
||||
getActivity().startActivity(intent);
|
||||
}
|
||||
|
||||
private void setMangaLongClickListener() {
|
||||
grid.setMultiChoiceModeListener(new GridView.MultiChoiceModeListener() {
|
||||
@Override
|
||||
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
|
||||
mode.setTitle(getResources().getString(R.string.library_selection_title)
|
||||
+ ": " + grid.getCheckedItemCount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
||||
MenuInflater inflater = mode.getMenuInflater();
|
||||
inflater.inflate(R.menu.library_selection, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_delete:
|
||||
getPresenter().onDelete(grid.getCheckedItemPositions(), adapter);
|
||||
mode.finish();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyActionMode(ActionMode mode) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package eu.kanade.mangafeed.ui.library;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
|
||||
import eu.kanade.mangafeed.R;
|
||||
import eu.kanade.mangafeed.data.models.Manga;
|
||||
import uk.co.ribot.easyadapter.ItemViewHolder;
|
||||
import uk.co.ribot.easyadapter.PositionInfo;
|
||||
import uk.co.ribot.easyadapter.annotations.LayoutId;
|
||||
import uk.co.ribot.easyadapter.annotations.ViewId;
|
||||
|
||||
|
||||
@LayoutId(R.layout.item_library)
|
||||
public class LibraryHolder extends ItemViewHolder<Manga> {
|
||||
|
||||
@ViewId(R.id.thumbnailImage)
|
||||
ImageView mThumbImage;
|
||||
|
||||
@ViewId(R.id.titleText)
|
||||
TextView mTitleText;
|
||||
|
||||
@ViewId(R.id.unreadText)
|
||||
TextView mUnreadText;
|
||||
|
||||
public LibraryHolder(View view) {
|
||||
super(view);
|
||||
}
|
||||
|
||||
public void onSetValues(Manga manga, PositionInfo positionInfo) {
|
||||
mTitleText.setText(manga.title);
|
||||
if (manga.unread > 0) {
|
||||
mUnreadText.setVisibility(View.VISIBLE);
|
||||
mUnreadText.setText(Integer.toString(manga.unread));
|
||||
}
|
||||
else {
|
||||
mUnreadText.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
String thumbnail;
|
||||
if (manga.thumbnail_url != null)
|
||||
thumbnail = manga.thumbnail_url;
|
||||
else
|
||||
thumbnail = "http://img1.wikia.nocookie.net/__cb20090524204255/starwars/images/thumb/1/1a/R2d2.jpg/400px-R2d2.jpg";
|
||||
|
||||
Glide.with(getContext())
|
||||
.load(thumbnail)
|
||||
.diskCacheStrategy(DiskCacheStrategy.RESULT)
|
||||
.centerCrop()
|
||||
.into(mThumbImage);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package eu.kanade.mangafeed.ui.library;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.util.SparseBooleanArray;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import eu.kanade.mangafeed.data.helpers.DatabaseHelper;
|
||||
import eu.kanade.mangafeed.data.helpers.PreferencesHelper;
|
||||
import eu.kanade.mangafeed.ui.base.presenter.BasePresenter;
|
||||
import rx.Observable;
|
||||
import rx.Subscription;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
|
||||
public class LibraryPresenter extends BasePresenter<LibraryFragment> {
|
||||
|
||||
@Inject DatabaseHelper db;
|
||||
@Inject PreferencesHelper prefs;
|
||||
|
||||
private Subscription mFavoriteMangasSubscription;
|
||||
private Subscription mDeleteMangaSubscription;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedState) {
|
||||
super.onCreate(savedState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTakeView(LibraryFragment view) {
|
||||
super.onTakeView(view);
|
||||
getFavoriteMangas();
|
||||
}
|
||||
|
||||
public void getFavoriteMangas() {
|
||||
if (mFavoriteMangasSubscription != null)
|
||||
return;
|
||||
|
||||
add(mFavoriteMangasSubscription = db.getMangasWithUnread().createObservable()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.compose(deliverLatestCache())
|
||||
.subscribe(this.split(LibraryFragment::onNextMangas)));
|
||||
}
|
||||
|
||||
public void onDelete(SparseBooleanArray checkedItems, LibraryAdapter adapter) {
|
||||
if (mDeleteMangaSubscription != null)
|
||||
remove(mDeleteMangaSubscription);
|
||||
|
||||
add(mDeleteMangaSubscription = Observable.range(0, checkedItems.size())
|
||||
.observeOn(Schedulers.io())
|
||||
.map(checkedItems::keyAt)
|
||||
.map(adapter::getItem)
|
||||
.map(manga -> {
|
||||
manga.favorite = false;
|
||||
return manga;
|
||||
})
|
||||
.toList()
|
||||
.flatMap(mangas -> db.insertMangas(mangas).createObservable())
|
||||
.subscribe());
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user