mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-31 22:37:56 +01:00 
			
		
		
		
	Add multiple chapters selection and allow to mark them as read/unread
This commit is contained in:
		| @@ -18,6 +18,7 @@ import eu.kanade.mangafeed.ui.fragment.MangaChaptersFragment; | ||||
| import eu.kanade.mangafeed.util.EventBusHook; | ||||
| import eu.kanade.mangafeed.util.PostResult; | ||||
| import rx.Observable; | ||||
| import rx.Subscription; | ||||
| import rx.android.schedulers.AndroidSchedulers; | ||||
| import rx.schedulers.Schedulers; | ||||
|  | ||||
| @@ -32,6 +33,8 @@ public class MangaChaptersPresenter extends BasePresenter<MangaChaptersFragment> | ||||
|     private static final int DB_CHAPTERS = 1; | ||||
|     private static final int ONLINE_CHAPTERS = 2; | ||||
|  | ||||
|     private Subscription menuOperationSubscription; | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedState) { | ||||
|         super.onCreate(savedState); | ||||
| @@ -106,4 +109,22 @@ public class MangaChaptersPresenter extends BasePresenter<MangaChaptersFragment> | ||||
|     public void onChapterClicked(Chapter chapter) { | ||||
|         EventBus.getDefault().postSticky(new SourceChapterEvent(source, chapter)); | ||||
|     } | ||||
|  | ||||
|     public void markChaptersRead(Observable<Chapter> selectedChapters, boolean read) { | ||||
|         if (menuOperationSubscription != null) | ||||
|             remove(menuOperationSubscription); | ||||
|  | ||||
|         add(menuOperationSubscription = selectedChapters | ||||
|                 .subscribeOn(Schedulers.io()) | ||||
|                 .map(chapter -> { | ||||
|                     chapter.read = read; | ||||
|                     return chapter; | ||||
|                 }) | ||||
|                 .toList() | ||||
|                 .flatMap(db::insertChapters) | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|                 .subscribe(result -> { | ||||
|  | ||||
|                 })); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,52 @@ | ||||
| package eu.kanade.mangafeed.ui.adapter; | ||||
|  | ||||
| import android.content.Context; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
|  | ||||
| import eu.davidea.flexibleadapter.FlexibleAdapter; | ||||
| import eu.kanade.mangafeed.R; | ||||
| import eu.kanade.mangafeed.data.models.Chapter; | ||||
| import eu.kanade.mangafeed.ui.fragment.base.BaseFragment; | ||||
| import eu.kanade.mangafeed.ui.holder.ChaptersHolder; | ||||
|  | ||||
| public class ChaptersAdapter extends FlexibleAdapter<ChaptersHolder, Chapter> { | ||||
|  | ||||
|     private Context context; | ||||
|     public OnItemClickListener clickListener; | ||||
|  | ||||
|     public ChaptersAdapter(BaseFragment fragment) { | ||||
|         this.context = fragment.getActivity(); | ||||
|         mItems = new ArrayList<>(); | ||||
|         clickListener = (OnItemClickListener) fragment; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void updateDataSet(String param) {} | ||||
|  | ||||
|     @Override | ||||
|     public ChaptersHolder onCreateViewHolder(ViewGroup parent, int viewType) { | ||||
|         View v = LayoutInflater.from(context).inflate(R.layout.item_chapter, parent, false); | ||||
|         return new ChaptersHolder(v, this); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onBindViewHolder(ChaptersHolder holder, int position) { | ||||
|         final Chapter chapter = getItem(position); | ||||
|         holder.onSetValues(context, chapter); | ||||
|     } | ||||
|  | ||||
|     public void setItems(List<Chapter> chapters) { | ||||
|         mItems = chapters; | ||||
|         notifyDataSetChanged(); | ||||
|     } | ||||
|  | ||||
|     public interface OnItemClickListener { | ||||
|         boolean onListItemClick(int position); | ||||
|         void onListItemLongClick(int position); | ||||
|     } | ||||
| } | ||||
| @@ -4,6 +4,7 @@ import android.content.Intent; | ||||
| import android.os.Bundle; | ||||
| import android.support.v4.app.Fragment; | ||||
| import android.support.v4.widget.SwipeRefreshLayout; | ||||
| import android.support.v7.view.ActionMode; | ||||
| import android.support.v7.widget.LinearLayoutManager; | ||||
| import android.support.v7.widget.RecyclerView; | ||||
| import android.view.LayoutInflater; | ||||
| @@ -22,18 +23,22 @@ import eu.kanade.mangafeed.data.models.Chapter; | ||||
| import eu.kanade.mangafeed.presenter.MangaChaptersPresenter; | ||||
| import eu.kanade.mangafeed.ui.activity.MangaDetailActivity; | ||||
| import eu.kanade.mangafeed.ui.activity.ReaderActivity; | ||||
| import eu.kanade.mangafeed.ui.holder.ChapterListHolder; | ||||
| import eu.kanade.mangafeed.ui.activity.base.BaseActivity; | ||||
| import eu.kanade.mangafeed.ui.adapter.ChaptersAdapter; | ||||
| import eu.kanade.mangafeed.ui.fragment.base.BaseRxFragment; | ||||
| import nucleus.factory.RequiresPresenter; | ||||
| import uk.co.ribot.easyadapter.EasyRecyclerAdapter; | ||||
| import rx.Observable; | ||||
|  | ||||
| @RequiresPresenter(MangaChaptersPresenter.class) | ||||
| public class MangaChaptersFragment extends BaseRxFragment<MangaChaptersPresenter> { | ||||
| public class MangaChaptersFragment extends BaseRxFragment<MangaChaptersPresenter> implements | ||||
|         ActionMode.Callback, ChaptersAdapter.OnItemClickListener { | ||||
|  | ||||
|     @Bind(R.id.chapter_list) RecyclerView chapters; | ||||
|     @Bind(R.id.swipe_refresh) SwipeRefreshLayout swipeRefresh; | ||||
|  | ||||
|     private EasyRecyclerAdapter<Chapter> adapter; | ||||
|     private ChaptersAdapter adapter; | ||||
|  | ||||
|     private ActionMode actionMode; | ||||
|  | ||||
|     public static Fragment newInstance() { | ||||
|         return new MangaChaptersFragment(); | ||||
| @@ -76,13 +81,7 @@ public class MangaChaptersFragment extends BaseRxFragment<MangaChaptersPresenter | ||||
|     } | ||||
|  | ||||
|     private void createAdapter() { | ||||
|         ChapterListHolder.ChapterListener listener = chapter -> { | ||||
|             getPresenter().onChapterClicked(chapter); | ||||
|             Intent intent = ReaderActivity.newInstance(getActivity()); | ||||
|             startActivity(intent); | ||||
|         }; | ||||
|  | ||||
|         adapter = new EasyRecyclerAdapter<>(getActivity(), ChapterListHolder.class, listener); | ||||
|         adapter = new ChaptersAdapter(this); | ||||
|         chapters.setAdapter(adapter); | ||||
|     } | ||||
|  | ||||
| @@ -92,6 +91,7 @@ public class MangaChaptersFragment extends BaseRxFragment<MangaChaptersPresenter | ||||
|  | ||||
|     public void onNextChapters(List<Chapter> chapters) { | ||||
|         adapter.setItems(chapters); | ||||
|         closeActionMode(); | ||||
|     } | ||||
|  | ||||
|     public void onNextOnlineChapters() { | ||||
| @@ -105,4 +105,87 @@ public class MangaChaptersFragment extends BaseRxFragment<MangaChaptersPresenter | ||||
|     public boolean isOnlineManga() { | ||||
|         return ((MangaDetailActivity)getActivity()).isOnlineManga(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onCreateActionMode(ActionMode mode, Menu menu) { | ||||
|         mode.getMenuInflater().inflate(R.menu.chapter_selection, menu); | ||||
|         adapter.setMode(ChaptersAdapter.MODE_MULTI); | ||||
|         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_select_all: | ||||
|                 adapter.selectAll(); | ||||
|                 return true; | ||||
|             case R.id.action_mark_as_read: | ||||
|                 getPresenter().markChaptersRead(getSelectedChapters(), true); | ||||
|                 return true; | ||||
|             case R.id.action_mark_as_unread: | ||||
|                 getPresenter().markChaptersRead(getSelectedChapters(), false); | ||||
|                 return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onDestroyActionMode(ActionMode mode) { | ||||
|         adapter.setMode(ChaptersAdapter.MODE_SINGLE); | ||||
|         adapter.clearSelection(); | ||||
|         actionMode = null; | ||||
|     } | ||||
|  | ||||
|     private Observable<Chapter> getSelectedChapters() { | ||||
|         return Observable.from(adapter.getSelectedItems()) | ||||
|                 .map(adapter::getItem); | ||||
|     } | ||||
|  | ||||
|     public void closeActionMode() { | ||||
|         if (actionMode != null) | ||||
|             actionMode.finish(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onListItemClick(int position) { | ||||
|         if (actionMode != null && adapter.getMode() == ChaptersAdapter.MODE_MULTI) { | ||||
|             toggleSelection(position); | ||||
|             return true; | ||||
|         } else { | ||||
|             getPresenter().onChapterClicked(adapter.getItem(position)); | ||||
|             Intent intent = ReaderActivity.newInstance(getActivity()); | ||||
|             startActivity(intent); | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onListItemLongClick(int position) { | ||||
|         if (actionMode == null) | ||||
|             actionMode = ((BaseActivity)getActivity()).startSupportActionMode(this); | ||||
|  | ||||
|         toggleSelection(position); | ||||
|     } | ||||
|  | ||||
|     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)); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,60 +0,0 @@ | ||||
| package eu.kanade.mangafeed.ui.holder; | ||||
|  | ||||
| import android.graphics.Color; | ||||
| import android.support.v4.content.ContextCompat; | ||||
| import android.view.View; | ||||
| import android.widget.ImageView; | ||||
| import android.widget.TextView; | ||||
|  | ||||
| import eu.kanade.mangafeed.R; | ||||
| import eu.kanade.mangafeed.data.models.Chapter; | ||||
| 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_chapter) | ||||
| public class ChapterListHolder extends ItemViewHolder<Chapter> { | ||||
|  | ||||
|     @ViewId(R.id.chapter_title) TextView title; | ||||
|     @ViewId(R.id.chapter_download_image) ImageView download_icon; | ||||
|     @ViewId(R.id.chapter_pages) TextView pages; | ||||
|  | ||||
|     View view; | ||||
|  | ||||
|     public ChapterListHolder(View view) { | ||||
|         super(view); | ||||
|         this.view = view; | ||||
|     } | ||||
|  | ||||
|     public void onSetValues(Chapter chapter, PositionInfo positionInfo) { | ||||
|         title.setText(chapter.name); | ||||
|         download_icon.setImageResource(R.drawable.ic_file_download_black_48dp); | ||||
|  | ||||
|         if (chapter.read) { | ||||
|             title.setTextColor(ContextCompat.getColor(getContext(), R.color.chapter_read_text)); | ||||
|         } else { | ||||
|             title.setTextColor(Color.BLACK); | ||||
|         } | ||||
|  | ||||
|         if (chapter.last_page_read > 0 && !chapter.read) { | ||||
|             pages.setText(getContext().getString(R.string.chapter_progress, chapter.last_page_read+1)); | ||||
|         } else { | ||||
|             pages.setText(""); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onSetListeners() { | ||||
|         view.setOnClickListener(view -> { | ||||
|             ChapterListener listener = getListener(ChapterListener.class); | ||||
|             if (listener != null) { | ||||
|                 listener.onRowClicked(getItem()); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     public interface ChapterListener { | ||||
|         void onRowClicked(Chapter chapter); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,74 @@ | ||||
| package eu.kanade.mangafeed.ui.holder; | ||||
|  | ||||
| import android.content.Context; | ||||
| import android.graphics.Color; | ||||
| import android.support.v4.content.ContextCompat; | ||||
| import android.support.v7.widget.RecyclerView; | ||||
| import android.view.View; | ||||
| import android.widget.ImageView; | ||||
| import android.widget.TextView; | ||||
|  | ||||
| import butterknife.Bind; | ||||
| import butterknife.ButterKnife; | ||||
| import eu.kanade.mangafeed.R; | ||||
| import eu.kanade.mangafeed.data.models.Chapter; | ||||
| import eu.kanade.mangafeed.ui.adapter.ChaptersAdapter; | ||||
|  | ||||
| public class ChaptersHolder extends RecyclerView.ViewHolder implements | ||||
|         View.OnClickListener, View.OnLongClickListener { | ||||
|  | ||||
|     private ChaptersAdapter adapter; | ||||
|  | ||||
|     @Bind(R.id.chapter_title) TextView title; | ||||
|     @Bind(R.id.chapter_download_image) ImageView download_icon; | ||||
|     @Bind(R.id.chapter_pages) TextView pages; | ||||
|  | ||||
|     public ChaptersHolder(View view) { | ||||
|         super(view); | ||||
|         ButterKnife.bind(this, view); | ||||
|     } | ||||
|  | ||||
|     public ChaptersHolder(View view, final ChaptersAdapter adapter) { | ||||
|         this(view); | ||||
|  | ||||
|         this.adapter = adapter; | ||||
|         itemView.setOnClickListener(this); | ||||
|         itemView.setOnLongClickListener(this); | ||||
|     } | ||||
|  | ||||
|     public void onSetValues(Context context, Chapter chapter) { | ||||
|         title.setText(chapter.name); | ||||
|         download_icon.setImageResource(R.drawable.ic_file_download_black_48dp); | ||||
|  | ||||
|         if (chapter.read) { | ||||
|             title.setTextColor(ContextCompat.getColor(context, R.color.chapter_read_text)); | ||||
|         } else { | ||||
|             title.setTextColor(Color.BLACK); | ||||
|         } | ||||
|  | ||||
|         if (chapter.last_page_read > 0 && !chapter.read) { | ||||
|             pages.setText(context.getString(R.string.chapter_progress, chapter.last_page_read + 1)); | ||||
|         } else { | ||||
|             pages.setText(""); | ||||
|         } | ||||
|  | ||||
|         toggleActivation(); | ||||
|     } | ||||
|  | ||||
|     private void toggleActivation() { | ||||
|         itemView.setActivated(adapter.isSelected(getAdapterPosition())); | ||||
|     } | ||||
|  | ||||
|     @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; | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user