Use recyclerview in library

This commit is contained in:
inorichi 2015-12-26 21:54:10 +01:00
parent 043ab7eca9
commit 1c86828b65
12 changed files with 286 additions and 181 deletions

View File

@ -93,7 +93,7 @@ dependencies {
compile 'com.squareup.okhttp:okhttp-urlconnection:2.7.0'
compile 'com.squareup.okhttp:okhttp:2.7.0'
compile 'com.squareup.okio:okio:1.6.0'
compile 'com.google.code.gson:gson:2.4'
compile 'com.google.code.gson:gson:2.5'
compile 'com.jakewharton:disklrucache:2.0.2'
compile 'org.jsoup:jsoup:1.8.3'
compile 'io.reactivex:rxandroid:1.1.0'
@ -111,7 +111,7 @@ dependencies {
compile "frankiesardo:icepick:$ICEPICK_VERSION"
provided "frankiesardo:icepick-processor:$ICEPICK_VERSION"
compile 'com.github.dmytrodanylyk.android-process-button:library:1.0.4'
compile 'eu.davidea:flexible-adapter:4.1.0@aar'
compile 'eu.davidea:flexible-adapter:4.2.0@aar'
compile 'com.nononsenseapps:filepicker:2.5.0'
compile "com.google.dagger:dagger:$DAGGER_VERSION"
@ -119,10 +119,10 @@ dependencies {
apt "com.pushtorefresh.storio:sqlite-annotations-processor:$STORIO_VERSION"
provided 'org.glassfish:javax.annotation:10.0-b28'
compile('com.mikepenz:materialdrawer:4.5.9@aar') {
compile('com.mikepenz:materialdrawer:4.6.1@aar') {
transitive = true
}
compile('com.github.afollestad.material-dialogs:core:0.8.5.2@aar') {
compile('com.github.afollestad.material-dialogs:core:0.8.5.3@aar') {
transitive = true
}

View File

@ -0,0 +1,48 @@
package eu.kanade.mangafeed.ui.base.adapter;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import eu.davidea.flexibleadapter.FlexibleAdapter;
public abstract class FlexibleViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener, View.OnLongClickListener {
private final FlexibleAdapter adapter;
private final OnListItemClickListener onListItemClickListener;
public FlexibleViewHolder(View itemView,FlexibleAdapter adapter,
OnListItemClickListener onListItemClickListener) {
super(itemView);
this.adapter = adapter;
this.onListItemClickListener = onListItemClickListener;
this.itemView.setOnClickListener(this);
this.itemView.setOnLongClickListener(this);
}
@Override
public void onClick(View view) {
if (onListItemClickListener.onListItemClick(getAdapterPosition())) {
toggleActivation();
}
}
@Override
public boolean onLongClick(View view) {
onListItemClickListener.onListItemLongClick(getAdapterPosition());
toggleActivation();
return true;
}
protected void toggleActivation() {
itemView.setActivated(adapter.isSelected(getAdapterPosition()));
}
public interface OnListItemClickListener {
boolean onListItemClick(int position);
void onListItemLongClick(int position);
}
}

View File

@ -43,7 +43,6 @@ public class CatalogueAdapter extends ArrayAdapter<Manga> {
static class ViewHolder {
@Bind(R.id.title) TextView title;
@Bind(R.id.author) TextView author;
@Bind(R.id.thumbnail) ImageView thumbnail;
@Bind(R.id.favorite_sticker) ImageView favorite_sticker;
@ -56,7 +55,6 @@ public class CatalogueAdapter extends ArrayAdapter<Manga> {
public void onSetValues(Manga manga) {
title.setText(manga.title);
author.setText(manga.author);
if (manga.thumbnail_url != null) {
presenter.coverCache.loadFromCacheOrNetwork(thumbnail, manga.thumbnail_url,

View File

@ -1,34 +1,71 @@
package eu.kanade.mangafeed.ui.library;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Filter;
import android.widget.Filterable;
import java.util.ArrayList;
import java.util.List;
import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.kanade.mangafeed.R;
import eu.kanade.mangafeed.data.database.models.Manga;
import eu.kanade.mangafeed.ui.main.MainActivity;
import rx.Observable;
import uk.co.ribot.easyadapter.EasyAdapter;
public class LibraryCategoryAdapter extends EasyAdapter<Manga> implements Filterable {
public class LibraryCategoryAdapter extends FlexibleAdapter<LibraryHolder, Manga>
implements Filterable {
List<Manga> mangas;
Filter filter;
private LibraryPresenter presenter;
private LibraryCategoryFragment fragment;
public LibraryCategoryAdapter(MainActivity activity) {
super(activity, LibraryHolder.class);
public LibraryCategoryAdapter(LibraryCategoryFragment fragment) {
this.fragment = fragment;
mItems = new ArrayList<>();
filter = new LibraryFilter();
presenter = ((LibraryFragment) activity.getActiveFragment()).getPresenter();
setHasStableIds(true);
}
public void setNewItems(List<Manga> list) {
super.setItems(list);
public void setItems(List<Manga> list) {
mItems = list;
notifyDataSetChanged();
// TODO needed for filtering?
mangas = list;
}
public void clear() {
mItems.clear();
}
@Override
public long getItemId(int position) {
return mItems.get(position).id;
}
@Override
public void updateDataSet(String param) {
}
@Override
public LibraryHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(fragment.getActivity()).inflate(R.layout.item_catalogue, parent, false);
return new LibraryHolder(v, this, fragment);
}
@Override
public void onBindViewHolder(LibraryHolder holder, int position) {
final LibraryPresenter presenter = ((LibraryFragment) fragment.getParentFragment()).getPresenter();
final Manga manga = getItem(position);
holder.onSetValues(manga, presenter);
//When user scrolls this bind the correct selection status
holder.itemView.setActivated(isSelected(position));
}
@Override
public Filter getFilter() {
return filter;
@ -65,12 +102,4 @@ public class LibraryCategoryAdapter extends EasyAdapter<Manga> implements Filter
}
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
LibraryHolder holder = (LibraryHolder) view.getTag();
Manga manga = getItem(position);
holder.loadCover(manga, presenter.sourceManager.get(manga.source), presenter.coverCache);
return view;
}
}

View File

@ -2,33 +2,41 @@ package eu.kanade.mangafeed.ui.library;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.view.ActionMode;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.Menu;
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.database.models.Category;
import eu.kanade.mangafeed.data.database.models.Manga;
import eu.kanade.mangafeed.event.LibraryMangasEvent;
import eu.kanade.mangafeed.ui.base.activity.BaseActivity;
import eu.kanade.mangafeed.ui.base.adapter.FlexibleViewHolder;
import eu.kanade.mangafeed.ui.base.fragment.BaseFragment;
import eu.kanade.mangafeed.ui.main.MainActivity;
import eu.kanade.mangafeed.ui.manga.MangaActivity;
import eu.kanade.mangafeed.util.EventBusHook;
import icepick.Icepick;
import icepick.State;
public class LibraryCategoryFragment extends BaseFragment {
public class LibraryCategoryFragment extends BaseFragment implements
ActionMode.Callback, FlexibleViewHolder.OnListItemClickListener {
@Bind(R.id.gridView) GridView grid;
@Bind(R.id.library_mangas) RecyclerView recycler;
protected LibraryCategoryAdapter adapter;
@State Category category;
private LibraryCategoryAdapter adapter;
private ActionMode actionMode;
private static final int INVALID_POSITION = -1;
public static LibraryCategoryFragment newInstance(Category category) {
LibraryCategoryFragment fragment = new LibraryCategoryFragment();
@ -43,8 +51,11 @@ public class LibraryCategoryFragment extends BaseFragment {
ButterKnife.bind(this, view);
Icepick.restoreInstanceState(this, savedState);
adapter = new LibraryCategoryAdapter((MainActivity) getActivity());
grid.setAdapter(adapter);
recycler.setHasFixedSize(true);
recycler.setLayoutManager(new GridLayoutManager(getActivity(), 4));
adapter = new LibraryCategoryAdapter(this);
recycler.setAdapter(adapter);
return view;
}
@ -72,21 +83,75 @@ public class LibraryCategoryFragment extends BaseFragment {
setMangas(event.getMangas().get(category.id));
}
@OnItemClick(R.id.gridView)
protected void onMangaClick(int position) {
Intent intent = MangaActivity.newIntent(
getActivity(),
adapter.getItem(position)
);
protected void openManga(Manga manga) {
Intent intent = MangaActivity.newIntent(getActivity(), manga);
getActivity().startActivity(intent);
}
public void setMangas(List<Manga> mangas) {
if (mangas != null) {
adapter.setNewItems(mangas);
adapter.setItems(mangas);
} else {
adapter.getItems().clear();
adapter.clear();
}
}
@Override
public boolean onListItemClick(int position) {
if (actionMode != null && position != INVALID_POSITION) {
toggleSelection(position);
return true;
} else {
openManga(adapter.getItem(position));
return false;
}
}
@Override
public void onListItemLongClick(int position) {
if (actionMode == null)
actionMode = ((BaseActivity) getActivity()).startSupportActionMode(this);
toggleSelection(position);
}
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(R.menu.library_selection, menu);
adapter.setMode(LibraryCategoryAdapter.MODE_MULTI);
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
adapter.setMode(LibraryCategoryAdapter.MODE_SINGLE);
adapter.clearSelection();
actionMode = null;
}
private void toggleSelection(int position) {
adapter.toggleSelection(position, false);
int count = adapter.getSelectedItemCount();
if (count == 0) {
actionMode.finish();
} else {
setContextTitle(count);
actionMode.invalidate();
}
}
private void setContextTitle(int count) {
actionMode.setTitle(getString(R.string.selected_chapters_title, count));
}
}

View File

@ -4,31 +4,28 @@ import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import butterknife.Bind;
import butterknife.ButterKnife;
import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.kanade.mangafeed.R;
import eu.kanade.mangafeed.data.cache.CoverCache;
import eu.kanade.mangafeed.data.database.models.Manga;
import eu.kanade.mangafeed.data.source.base.Source;
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;
import eu.kanade.mangafeed.ui.base.adapter.FlexibleViewHolder;
public class LibraryHolder extends FlexibleViewHolder {
@LayoutId(R.layout.item_catalogue)
public class LibraryHolder extends ItemViewHolder<Manga> {
@Bind(R.id.thumbnail) ImageView thumbnail;
@Bind(R.id.title) TextView title;
@Bind(R.id.unreadText) TextView unreadText;
@ViewId(R.id.thumbnail) ImageView thumbnail;
@ViewId(R.id.title) TextView title;
@ViewId(R.id.author) TextView author;
@ViewId(R.id.unreadText) TextView unreadText;
public LibraryHolder(View view) {
super(view);
public LibraryHolder(View view, FlexibleAdapter adapter, OnListItemClickListener listener) {
super(view, adapter, listener);
ButterKnife.bind(this, view);
}
public void onSetValues(Manga manga, PositionInfo positionInfo) {
public void onSetValues(Manga manga, LibraryPresenter presenter) {
title.setText(manga.title);
author.setText(manga.author);
if (manga.unread > 0) {
unreadText.setVisibility(View.VISIBLE);
@ -36,9 +33,11 @@ public class LibraryHolder extends ItemViewHolder<Manga> {
} else {
unreadText.setVisibility(View.GONE);
}
loadCover(manga, presenter.sourceManager.get(manga.source), presenter.coverCache);
}
public void loadCover(Manga manga, Source source, CoverCache coverCache) {
private void loadCover(Manga manga, Source source, CoverCache coverCache) {
if (manga.thumbnail_url != null) {
coverCache.saveAndLoadFromCache(thumbnail, manga.thumbnail_url, source.getGlideHeaders());
} else {

View File

@ -10,17 +10,18 @@ import java.util.List;
import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.kanade.mangafeed.R;
import eu.kanade.mangafeed.data.database.models.Chapter;
import eu.kanade.mangafeed.ui.base.adapter.FlexibleViewHolder;
import eu.kanade.mangafeed.ui.base.fragment.BaseFragment;
public class ChaptersAdapter extends FlexibleAdapter<ChaptersHolder, Chapter> {
private BaseFragment fragment;
public OnItemClickListener clickListener;
public FlexibleViewHolder.OnListItemClickListener clickListener;
public ChaptersAdapter(BaseFragment fragment) {
this.fragment = fragment;
mItems = new ArrayList<>();
clickListener = (OnItemClickListener) fragment;
clickListener = (FlexibleViewHolder.OnListItemClickListener) fragment;
setHasStableIds(true);
}
@ -30,13 +31,16 @@ public class ChaptersAdapter extends FlexibleAdapter<ChaptersHolder, Chapter> {
@Override
public ChaptersHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(fragment.getActivity()).inflate(R.layout.item_chapter, parent, false);
return new ChaptersHolder(v, this);
return new ChaptersHolder(v, this, clickListener);
}
@Override
public void onBindViewHolder(ChaptersHolder holder, int position) {
final Chapter chapter = getItem(position);
holder.onSetValues(fragment.getActivity(), chapter);
//When user scrolls this bind the correct selection status
holder.itemView.setActivated(isSelected(position));
}
@Override
@ -49,11 +53,6 @@ public class ChaptersAdapter extends FlexibleAdapter<ChaptersHolder, Chapter> {
notifyDataSetChanged();
}
public interface OnItemClickListener {
boolean onListItemClick(int position);
void onListItemLongClick(int position);
}
public ChaptersFragment getChaptersFragment() {
return (ChaptersFragment) fragment;
}

View File

@ -28,6 +28,7 @@ import eu.kanade.mangafeed.data.database.models.Chapter;
import eu.kanade.mangafeed.data.download.DownloadService;
import eu.kanade.mangafeed.data.download.model.Download;
import eu.kanade.mangafeed.ui.base.activity.BaseActivity;
import eu.kanade.mangafeed.ui.base.adapter.FlexibleViewHolder;
import eu.kanade.mangafeed.ui.base.fragment.BaseRxFragment;
import eu.kanade.mangafeed.ui.decoration.DividerItemDecoration;
import eu.kanade.mangafeed.ui.manga.MangaActivity;
@ -41,7 +42,7 @@ import rx.schedulers.Schedulers;
@RequiresPresenter(ChaptersPresenter.class)
public class ChaptersFragment extends BaseRxFragment<ChaptersPresenter> implements
ActionMode.Callback, ChaptersAdapter.OnItemClickListener {
ActionMode.Callback, FlexibleViewHolder.OnListItemClickListener {
@Bind(R.id.chapter_list) RecyclerView recyclerView;
@Bind(R.id.swipe_refresh) SwipeRefreshLayout swipeRefresh;
@ -254,14 +255,14 @@ public class ChaptersFragment extends BaseRxFragment<ChaptersPresenter> implemen
}
public void closeActionMode() {
if (actionMode != null)
if (actionMode != null) {
actionMode.finish();
}
}
protected boolean onSelectAll() {
adapter.selectAll();
setContextTitle(adapter.getSelectedItemCount());
actionMode.invalidate();
return true;
}

View File

@ -2,7 +2,6 @@ package eu.kanade.mangafeed.ui.manga.chapter;
import android.content.Context;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.PopupMenu;
import android.widget.RelativeLayout;
@ -16,12 +15,12 @@ import butterknife.ButterKnife;
import eu.kanade.mangafeed.R;
import eu.kanade.mangafeed.data.database.models.Chapter;
import eu.kanade.mangafeed.data.download.model.Download;
import eu.kanade.mangafeed.ui.base.adapter.FlexibleViewHolder;
import rx.Observable;
public class ChaptersHolder extends RecyclerView.ViewHolder implements
View.OnClickListener, View.OnLongClickListener {
public class ChaptersHolder extends FlexibleViewHolder {
private ChaptersAdapter adapter;
private final ChaptersAdapter adapter;
private Chapter item;
@Bind(R.id.chapter_title) TextView title;
@ -32,17 +31,11 @@ public class ChaptersHolder extends RecyclerView.ViewHolder implements
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
public ChaptersHolder(View view) {
super(view);
ButterKnife.bind(this, view);
}
public ChaptersHolder(View view, final ChaptersAdapter adapter) {
this(view);
public ChaptersHolder(View view, ChaptersAdapter adapter, OnListItemClickListener listener) {
super(view, adapter, listener);
this.adapter = adapter;
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
ButterKnife.bind(this, view);
chapterMenu.setOnClickListener(v -> v.post(() -> showPopupMenu(v)));
}
@ -64,12 +57,6 @@ public class ChaptersHolder extends RecyclerView.ViewHolder implements
onStatusChange(chapter.status);
date.setText(sdf.format(new Date(chapter.date_upload)));
toggleActivation();
}
private void toggleActivation() {
itemView.setActivated(adapter.isSelected(getAdapterPosition()));
}
public void onStatusChange(int status) {
@ -92,20 +79,6 @@ public class ChaptersHolder extends RecyclerView.ViewHolder implements
R.string.chapter_downloading_progress, downloaded, total));
}
@Override
public void onClick(View v) {
if (adapter.clickListener.onListItemClick(getAdapterPosition()))
toggleActivation();
}
@Override
public boolean onLongClick(View v) {
adapter.clickListener.onListItemLongClick(getAdapterPosition());
toggleActivation();
return true;
}
private void showPopupMenu(View view) {
// Create a PopupMenu, giving it the clicked view for an anchor
PopupMenu popup = new PopupMenu(adapter.getChaptersFragment().getActivity(), view);

View File

@ -4,10 +4,9 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<GridView
android:id="@+id/gridView"
<android.support.v7.widget.RecyclerView
android:id="@+id/library_mangas"
style="@style/AppTheme.GridView"
android:choiceMode="multipleChoiceModal"
android:columnWidth="140dp"
tools:listitem="@layout/item_catalogue" />

View File

@ -1,10 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/card_background"
android:orientation="vertical">
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@drawable/selector_chapter_light">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/card_background">
<ImageView
android:id="@+id/thumbnail"
@ -12,8 +18,7 @@
android:layout_height="220dp"
android:background="@color/white"
tools:background="@color/md_red_100"
tools:src="@mipmap/ic_launcher"
/>
tools:src="@mipmap/ic_launcher"/>
<TextView
android:id="@+id/unreadText"
@ -49,35 +54,25 @@
android:layout_alignLeft="@+id/unreadText"
android:layout_alignStart="@+id/unreadText"
android:background="@color/white"
android:gravity="center"
android:orientation="vertical">
<TextView
<eu.kanade.mangafeed.widget.PTSansTextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
app:typeface="ptsansNarrowBold"
android:ellipsize="end"
android:maxLines="1"
android:maxLines="2"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:textColor="@color/primary_text"
android:textSize="13sp"
android:textStyle="bold"
tools:text="Sample name"/>
<TextView
android:id="@+id/author"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:ellipsize="end"
android:maxLines="1"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:textColor="@color/hint_text"
android:textSize="13sp"
android:textSize="14sp"
tools:text="Sample name"/>
</LinearLayout>
</RelativeLayout>
</FrameLayout>

View File

@ -47,7 +47,6 @@
<item name="android:numColumns">auto_fit</item>
<item name="android:stretchMode">columnWidth</item>
<item name="android:scrollbarStyle">outsideOverlay</item>
<item name="android:background">#e5e5e5</item>
</style>
<style name="FilePickerTheme" parent="NNF_BaseTheme.Light">