diff --git a/app/build.gradle b/app/build.gradle index de74104d91..4bd222b693 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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 } diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/base/adapter/FlexibleViewHolder.java b/app/src/main/java/eu/kanade/mangafeed/ui/base/adapter/FlexibleViewHolder.java new file mode 100644 index 0000000000..762bc32262 --- /dev/null +++ b/app/src/main/java/eu/kanade/mangafeed/ui/base/adapter/FlexibleViewHolder.java @@ -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); + } + +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/catalogue/CatalogueAdapter.java b/app/src/main/java/eu/kanade/mangafeed/ui/catalogue/CatalogueAdapter.java index 74181e42e7..10958b2624 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/catalogue/CatalogueAdapter.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/catalogue/CatalogueAdapter.java @@ -43,7 +43,6 @@ public class CatalogueAdapter extends ArrayAdapter { 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 { 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, diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryCategoryAdapter.java b/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryCategoryAdapter.java index 0d109846d3..76ff470fad 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryCategoryAdapter.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryCategoryAdapter.java @@ -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 implements Filterable { +public class LibraryCategoryAdapter extends FlexibleAdapter + implements Filterable { List 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 list) { - super.setItems(list); + public void setItems(List 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 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; - } } diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryCategoryFragment.java b/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryCategoryFragment.java index 207a5ce5c7..b1112c8abe 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryCategoryFragment.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryCategoryFragment.java @@ -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 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)); + } } diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryHolder.java b/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryHolder.java index 6f5bf94c12..bef27042a9 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryHolder.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryHolder.java @@ -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 { + @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 { } 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 { diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/manga/chapter/ChaptersAdapter.java b/app/src/main/java/eu/kanade/mangafeed/ui/manga/chapter/ChaptersAdapter.java index 78123c0b39..b5787e37b6 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/manga/chapter/ChaptersAdapter.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/manga/chapter/ChaptersAdapter.java @@ -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 { 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 { @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 { notifyDataSetChanged(); } - public interface OnItemClickListener { - boolean onListItemClick(int position); - void onListItemLongClick(int position); - } - public ChaptersFragment getChaptersFragment() { return (ChaptersFragment) fragment; } diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/manga/chapter/ChaptersFragment.java b/app/src/main/java/eu/kanade/mangafeed/ui/manga/chapter/ChaptersFragment.java index ff5dcb3e7b..5af5dd895e 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/manga/chapter/ChaptersFragment.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/manga/chapter/ChaptersFragment.java @@ -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 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 implemen } public void closeActionMode() { - if (actionMode != null) + if (actionMode != null) { actionMode.finish(); + } } protected boolean onSelectAll() { adapter.selectAll(); setContextTitle(adapter.getSelectedItemCount()); - actionMode.invalidate(); return true; } diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/manga/chapter/ChaptersHolder.java b/app/src/main/java/eu/kanade/mangafeed/ui/manga/chapter/ChaptersHolder.java index b761b9bbe1..8bf6798e09 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/manga/chapter/ChaptersHolder.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/manga/chapter/ChaptersHolder.java @@ -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); diff --git a/app/src/main/res/layout/fragment_library_category.xml b/app/src/main/res/layout/fragment_library_category.xml index 173caa14b3..1d124e5a72 100644 --- a/app/src/main/res/layout/fragment_library_category.xml +++ b/app/src/main/res/layout/fragment_library_category.xml @@ -4,10 +4,9 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - diff --git a/app/src/main/res/layout/item_catalogue.xml b/app/src/main/res/layout/item_catalogue.xml index eeb72151e3..0b28cb80c6 100644 --- a/app/src/main/res/layout/item_catalogue.xml +++ b/app/src/main/res/layout/item_catalogue.xml @@ -1,83 +1,78 @@ - + + + + + + + + + + + + + android:layout_gravity="center_vertical" + app:typeface="ptsansNarrowBold" + android:ellipsize="end" + android:maxLines="2" + android:paddingLeft="8dp" + android:paddingRight="8dp" + android:textColor="@color/primary_text" + android:textSize="14sp" + tools:text="Sample name"/> - + - + - - - - - - - - - - - + \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 258b513d42..7bbc8ac8c1 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -47,7 +47,6 @@ auto_fit columnWidth outsideOverlay - #e5e5e5