mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-30 22:07:57 +01:00 
			
		
		
		
	Allow to display manga from catalogue as a simple list (#35)
This commit is contained in:
		| @@ -116,6 +116,10 @@ public class PreferencesHelper { | ||||
|         return rxPrefs.getInteger(getKey(R.string.pref_reader_theme_key), 0); | ||||
|     } | ||||
|  | ||||
|     public Preference<Boolean> catalogueAsList() { | ||||
|         return rxPrefs.getBoolean(getKey(R.string.pref_display_catalogue_as_list), false); | ||||
|     } | ||||
|  | ||||
|     public String getSourceUsername(Source source) { | ||||
|         return prefs.getString(SOURCE_ACCOUNT_USERNAME + source.getId(), ""); | ||||
|     } | ||||
|   | ||||
| @@ -31,6 +31,10 @@ public class CatalogueAdapter extends FlexibleAdapter<CatalogueHolder, Manga> { | ||||
|         notifyDataSetChanged(); | ||||
|     } | ||||
|  | ||||
|     public List<Manga> getItems() { | ||||
|         return mItems; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public long getItemId(int position) { | ||||
|         return mItems.get(position).id; | ||||
| @@ -44,8 +48,13 @@ public class CatalogueAdapter extends FlexibleAdapter<CatalogueHolder, Manga> { | ||||
|     @Override | ||||
|     public CatalogueHolder onCreateViewHolder(ViewGroup parent, int viewType) { | ||||
|         LayoutInflater inflater = fragment.getActivity().getLayoutInflater(); | ||||
|         View v = inflater.inflate(R.layout.item_catalogue, parent, false); | ||||
|         return new CatalogueHolder(v, this, fragment); | ||||
|         if (parent.getId() == R.id.catalogue_grid) { | ||||
|             View v = inflater.inflate(R.layout.item_catalogue_grid, parent, false); | ||||
|             return new CatalogueGridHolder(v, this, fragment); | ||||
|         } else { | ||||
|             View v = inflater.inflate(R.layout.item_catalogue_list, parent, false); | ||||
|             return new CatalogueListHolder(v, this, fragment); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|   | ||||
| @@ -4,7 +4,10 @@ import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.os.Bundle; | ||||
| import android.support.annotation.Nullable; | ||||
| import android.support.v4.content.ContextCompat; | ||||
| import android.support.v7.widget.GridLayoutManager; | ||||
| import android.support.v7.widget.LinearLayoutManager; | ||||
| import android.support.v7.widget.RecyclerView; | ||||
| import android.support.v7.widget.SearchView; | ||||
| import android.support.v7.widget.Toolbar; | ||||
| import android.text.TextUtils; | ||||
| @@ -14,9 +17,12 @@ import android.view.MenuInflater; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.view.animation.Animation; | ||||
| import android.view.animation.AnimationUtils; | ||||
| import android.widget.AdapterView; | ||||
| import android.widget.ProgressBar; | ||||
| import android.widget.Spinner; | ||||
| import android.widget.ViewSwitcher; | ||||
|  | ||||
| import com.afollestad.materialdialogs.MaterialDialog; | ||||
|  | ||||
| @@ -30,11 +36,13 @@ import eu.kanade.tachiyomi.data.database.models.Manga; | ||||
| import eu.kanade.tachiyomi.data.source.base.Source; | ||||
| import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder; | ||||
| import eu.kanade.tachiyomi.ui.base.fragment.BaseRxFragment; | ||||
| import eu.kanade.tachiyomi.ui.decoration.DividerItemDecoration; | ||||
| import eu.kanade.tachiyomi.ui.main.MainActivity; | ||||
| import eu.kanade.tachiyomi.ui.manga.MangaActivity; | ||||
| import eu.kanade.tachiyomi.util.ToastUtil; | ||||
| import eu.kanade.tachiyomi.widget.AutofitRecyclerView; | ||||
| import eu.kanade.tachiyomi.widget.EndlessRecyclerScrollListener; | ||||
| import eu.kanade.tachiyomi.widget.EndlessGridScrollListener; | ||||
| import eu.kanade.tachiyomi.widget.EndlessListScrollListener; | ||||
| import icepick.State; | ||||
| import nucleus.factory.RequiresPresenter; | ||||
| import rx.Subscription; | ||||
| @@ -45,14 +53,17 @@ import rx.subjects.PublishSubject; | ||||
| public class CatalogueFragment extends BaseRxFragment<CataloguePresenter> | ||||
|         implements FlexibleViewHolder.OnListItemClickListener { | ||||
|  | ||||
|     @Bind(R.id.recycler) AutofitRecyclerView recycler; | ||||
|     @Bind(R.id.switcher) ViewSwitcher switcher; | ||||
|     @Bind(R.id.catalogue_grid) AutofitRecyclerView catalogueGrid; | ||||
|     @Bind(R.id.catalogue_list) RecyclerView catalogueList; | ||||
|     @Bind(R.id.progress) ProgressBar progress; | ||||
|     @Bind(R.id.progress_grid) ProgressBar progressGrid; | ||||
|  | ||||
|     private Toolbar toolbar; | ||||
|     private Spinner spinner; | ||||
|     private CatalogueAdapter adapter; | ||||
|     private EndlessRecyclerScrollListener scrollListener; | ||||
|     private EndlessGridScrollListener gridScrollListener; | ||||
|     private EndlessListScrollListener listScrollListener; | ||||
|  | ||||
|     @State String query = ""; | ||||
|     @State int selectedIndex = -1; | ||||
| @@ -61,6 +72,8 @@ public class CatalogueFragment extends BaseRxFragment<CataloguePresenter> | ||||
|     private PublishSubject<String> queryDebouncerSubject; | ||||
|     private Subscription queryDebouncerSubscription; | ||||
|  | ||||
|     private MenuItem displayMode; | ||||
|  | ||||
|     public static CatalogueFragment newInstance() { | ||||
|         return new CatalogueFragment(); | ||||
|     } | ||||
| @@ -77,13 +90,32 @@ public class CatalogueFragment extends BaseRxFragment<CataloguePresenter> | ||||
|         View view = inflater.inflate(R.layout.fragment_catalogue, container, false); | ||||
|         ButterKnife.bind(this, view); | ||||
|  | ||||
|         // Initialize adapter and scroll listener | ||||
|         GridLayoutManager layoutManager = (GridLayoutManager) recycler.getLayoutManager(); | ||||
|         // Initialize adapter, scroll listener and recycler views | ||||
|         adapter = new CatalogueAdapter(this); | ||||
|         scrollListener = new EndlessRecyclerScrollListener(layoutManager, this::requestNextPage); | ||||
|         recycler.setHasFixedSize(true); | ||||
|         recycler.setAdapter(adapter); | ||||
|         recycler.addOnScrollListener(scrollListener); | ||||
|  | ||||
|         GridLayoutManager glm = (GridLayoutManager) catalogueGrid.getLayoutManager(); | ||||
|         gridScrollListener = new EndlessGridScrollListener(glm, this::requestNextPage); | ||||
|         catalogueGrid.setHasFixedSize(true); | ||||
|         catalogueGrid.setAdapter(adapter); | ||||
|         catalogueGrid.addOnScrollListener(gridScrollListener); | ||||
|  | ||||
|         LinearLayoutManager llm = new LinearLayoutManager(getActivity()); | ||||
|         listScrollListener = new EndlessListScrollListener(llm, this::requestNextPage); | ||||
|         catalogueList.setHasFixedSize(true); | ||||
|         catalogueList.setAdapter(adapter); | ||||
|         catalogueList.setLayoutManager(llm); | ||||
|         catalogueList.addOnScrollListener(listScrollListener); | ||||
|         catalogueList.addItemDecoration(new DividerItemDecoration( | ||||
|                 ContextCompat.getDrawable(getContext(), R.drawable.line_divider))); | ||||
|  | ||||
|         if (getPresenter().isListMode()) { | ||||
|             switcher.showNext(); | ||||
|         } | ||||
|  | ||||
|         Animation inAnim = AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_in); | ||||
|         Animation outAnim = AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_out); | ||||
|         switcher.setInAnimation(inAnim); | ||||
|         switcher.setOutAnimation(outAnim); | ||||
|  | ||||
|         // Create toolbar spinner | ||||
|         Context themedContext = getBaseActivity().getSupportActionBar() != null ? | ||||
| @@ -109,7 +141,8 @@ public class CatalogueFragment extends BaseRxFragment<CataloguePresenter> | ||||
|                     } else { | ||||
|                         selectedIndex = position; | ||||
|                         showProgressBar(); | ||||
|                         recycler.setAdapter(adapter); | ||||
|                         glm.scrollToPositionWithOffset(0, 0); | ||||
|                         llm.scrollToPositionWithOffset(0, 0); | ||||
|                         getPresenter().startRequesting(source); | ||||
|                     } | ||||
|                 } | ||||
| @@ -152,6 +185,22 @@ public class CatalogueFragment extends BaseRxFragment<CataloguePresenter> | ||||
|                 return true; | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         // Show next display mode | ||||
|         displayMode = menu.findItem(R.id.action_display_mode); | ||||
|         int icon = getPresenter().isListMode() ? | ||||
|                 R.drawable.ic_view_module_white_24dp : R.drawable.ic_view_list_white_24dp; | ||||
|         displayMode.setIcon(icon); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         switch (item.getItemId()) { | ||||
|             case R.id.action_display_mode: | ||||
|                 swapDisplayMode(); | ||||
|                 break; | ||||
|         } | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
| @@ -198,7 +247,8 @@ public class CatalogueFragment extends BaseRxFragment<CataloguePresenter> | ||||
|  | ||||
|         query = newQuery; | ||||
|         showProgressBar(); | ||||
|         recycler.getLayoutManager().scrollToPosition(0); | ||||
|         catalogueGrid.getLayoutManager().scrollToPosition(0); | ||||
|         catalogueList.getLayoutManager().scrollToPosition(0); | ||||
|  | ||||
|         getPresenter().restartRequest(query); | ||||
|     } | ||||
| @@ -214,7 +264,8 @@ public class CatalogueFragment extends BaseRxFragment<CataloguePresenter> | ||||
|         hideProgressBar(); | ||||
|         if (page == 0) { | ||||
|             adapter.clear(); | ||||
|             scrollListener.resetScroll(); | ||||
|             gridScrollListener.resetScroll(); | ||||
|             listScrollListener.resetScroll(); | ||||
|         } | ||||
|         adapter.addItems(mangas); | ||||
|     } | ||||
| @@ -224,15 +275,28 @@ public class CatalogueFragment extends BaseRxFragment<CataloguePresenter> | ||||
|     } | ||||
|  | ||||
|     public void updateImage(Manga manga) { | ||||
|         CatalogueHolder holder = getHolder(manga); | ||||
|         CatalogueGridHolder holder = getHolder(manga); | ||||
|         if (holder != null) { | ||||
|             holder.setImage(manga, getPresenter()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public void swapDisplayMode() { | ||||
|         getPresenter().swapDisplayMode(); | ||||
|         boolean isListMode = getPresenter().isListMode(); | ||||
|         int icon = isListMode ? | ||||
|                 R.drawable.ic_view_module_white_24dp : R.drawable.ic_view_list_white_24dp; | ||||
|         displayMode.setIcon(icon); | ||||
|         switcher.showNext(); | ||||
|         if (!isListMode) { | ||||
|             // Initialize mangas if going to grid view | ||||
|             getPresenter().initializeMangas(adapter.getItems()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Nullable | ||||
|     private CatalogueHolder getHolder(Manga manga) { | ||||
|         return (CatalogueHolder) recycler.findViewHolderForItemId(manga.id); | ||||
|     private CatalogueGridHolder getHolder(Manga manga) { | ||||
|         return (CatalogueGridHolder) catalogueGrid.findViewHolderForItemId(manga.id); | ||||
|     } | ||||
|  | ||||
|     private void showProgressBar() { | ||||
|   | ||||
| @@ -0,0 +1,38 @@ | ||||
| package eu.kanade.tachiyomi.ui.catalogue; | ||||
|  | ||||
| import android.view.View; | ||||
| import android.widget.ImageView; | ||||
| import android.widget.TextView; | ||||
|  | ||||
| import butterknife.Bind; | ||||
| import butterknife.ButterKnife; | ||||
| import eu.kanade.tachiyomi.R; | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga; | ||||
|  | ||||
| public class CatalogueGridHolder extends CatalogueHolder { | ||||
|  | ||||
|     @Bind(R.id.title) TextView title; | ||||
|     @Bind(R.id.thumbnail) ImageView thumbnail; | ||||
|     @Bind(R.id.favorite_sticker) ImageView favoriteSticker; | ||||
|  | ||||
|     public CatalogueGridHolder(View view, CatalogueAdapter adapter, OnListItemClickListener listener) { | ||||
|         super(view, adapter, listener); | ||||
|         ButterKnife.bind(this, view); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onSetValues(Manga manga, CataloguePresenter presenter) { | ||||
|         title.setText(manga.title); | ||||
|         favoriteSticker.setVisibility(manga.favorite ? View.VISIBLE : View.GONE); | ||||
|         setImage(manga, presenter); | ||||
|     } | ||||
|  | ||||
|     public void setImage(Manga manga, CataloguePresenter presenter) { | ||||
|         if (manga.thumbnail_url != null) { | ||||
|             presenter.coverCache.loadFromNetwork(thumbnail, manga.thumbnail_url, | ||||
|                     presenter.getSource().getGlideHeaders()); | ||||
|         } else { | ||||
|             thumbnail.setImageResource(android.R.color.transparent); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,38 +1,15 @@ | ||||
| package eu.kanade.tachiyomi.ui.catalogue; | ||||
|  | ||||
| import android.view.View; | ||||
| import android.widget.ImageView; | ||||
| import android.widget.TextView; | ||||
|  | ||||
| import butterknife.Bind; | ||||
| import butterknife.ButterKnife; | ||||
| import eu.kanade.tachiyomi.R; | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga; | ||||
| import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder; | ||||
|  | ||||
| public class CatalogueHolder extends FlexibleViewHolder { | ||||
|  | ||||
|     @Bind(R.id.title) TextView title; | ||||
|     @Bind(R.id.thumbnail) ImageView thumbnail; | ||||
|     @Bind(R.id.favorite_sticker) ImageView favoriteSticker; | ||||
| public abstract class CatalogueHolder extends FlexibleViewHolder { | ||||
|  | ||||
|     public CatalogueHolder(View view, CatalogueAdapter adapter, OnListItemClickListener listener) { | ||||
|         super(view, adapter, listener); | ||||
|         ButterKnife.bind(this, view); | ||||
|     } | ||||
|  | ||||
|     public void onSetValues(Manga manga, CataloguePresenter presenter) { | ||||
|         title.setText(manga.title); | ||||
|         favoriteSticker.setVisibility(manga.favorite ? View.VISIBLE : View.GONE); | ||||
|         setImage(manga, presenter); | ||||
|     } | ||||
|  | ||||
|     public void setImage(Manga manga, CataloguePresenter presenter) { | ||||
|         if (manga.thumbnail_url != null) { | ||||
|             presenter.coverCache.loadFromNetwork(thumbnail, manga.thumbnail_url, | ||||
|                     presenter.getSource().getGlideHeaders()); | ||||
|         } else { | ||||
|             thumbnail.setImageResource(android.R.color.transparent); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|     abstract void onSetValues(Manga manga, CataloguePresenter presenter); | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,24 @@ | ||||
| package eu.kanade.tachiyomi.ui.catalogue; | ||||
|  | ||||
| import android.view.View; | ||||
| import android.widget.TextView; | ||||
|  | ||||
| import butterknife.Bind; | ||||
| import butterknife.ButterKnife; | ||||
| import eu.kanade.tachiyomi.R; | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga; | ||||
|  | ||||
| public class CatalogueListHolder extends CatalogueHolder { | ||||
|  | ||||
|     @Bind(R.id.title) TextView title; | ||||
|  | ||||
|     public CatalogueListHolder(View view, CatalogueAdapter adapter, OnListItemClickListener listener) { | ||||
|         super(view, adapter, listener); | ||||
|         ButterKnife.bind(this, view); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onSetValues(Manga manga, CataloguePresenter presenter) { | ||||
|         title.setText(manga.title); | ||||
|     } | ||||
| } | ||||
| @@ -42,6 +42,8 @@ public class CataloguePresenter extends BasePresenter<CatalogueFragment> { | ||||
|  | ||||
|     private PublishSubject<List<Manga>> mangaDetailSubject; | ||||
|  | ||||
|     private boolean isListMode; | ||||
|  | ||||
|     private static final int GET_MANGA_LIST = 1; | ||||
|     private static final int GET_MANGA_DETAIL = 2; | ||||
|     private static final int GET_MANGA_PAGE = 3; | ||||
| @@ -72,12 +74,14 @@ public class CataloguePresenter extends BasePresenter<CatalogueFragment> { | ||||
|                         .observeOn(Schedulers.io()) | ||||
|                         .flatMap(Observable::from) | ||||
|                         .filter(manga -> !manga.initialized) | ||||
|                         .window(3) | ||||
|                         .concatMap(pack -> pack.concatMap(this::getMangaDetails)) | ||||
|                         .concatMap(this::getMangaDetails) | ||||
|                         .onBackpressureBuffer() | ||||
|                         .observeOn(AndroidSchedulers.mainThread()), | ||||
|                 CatalogueFragment::updateImage, | ||||
|                 (view, error) -> Timber.e(error.getMessage())); | ||||
|  | ||||
|         add(prefs.catalogueAsList().asObservable() | ||||
|                 .subscribe(this::setDisplayMode)); | ||||
|     } | ||||
|  | ||||
|     private void onProcessRestart() { | ||||
| @@ -87,6 +91,15 @@ public class CataloguePresenter extends BasePresenter<CatalogueFragment> { | ||||
|         stop(GET_MANGA_PAGE); | ||||
|     } | ||||
|  | ||||
|     private void setDisplayMode(boolean asList) { | ||||
|         this.isListMode = asList; | ||||
|         if (asList) { | ||||
|             stop(GET_MANGA_DETAIL); | ||||
|         } else { | ||||
|             start(GET_MANGA_DETAIL); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public void startRequesting(Source source) { | ||||
|         this.source = source; | ||||
|         sourceId = source.getId(); | ||||
| @@ -98,7 +111,9 @@ public class CataloguePresenter extends BasePresenter<CatalogueFragment> { | ||||
|         stop(GET_MANGA_PAGE); | ||||
|         lastMangasPage = null; | ||||
|  | ||||
|         start(GET_MANGA_DETAIL); | ||||
|         if (!isListMode) { | ||||
|             start(GET_MANGA_DETAIL); | ||||
|         } | ||||
|         start(GET_MANGA_LIST); | ||||
|         start(GET_MANGA_PAGE); | ||||
|     } | ||||
| @@ -124,10 +139,7 @@ public class CataloguePresenter extends BasePresenter<CatalogueFragment> { | ||||
|                 .flatMap(mangasPage -> Observable.from(mangasPage.mangas)) | ||||
|                 .map(this::networkToLocalManga) | ||||
|                 .toList() | ||||
|                 .doOnNext(mangas -> { | ||||
|                     if (mangaDetailSubject != null) | ||||
|                         mangaDetailSubject.onNext(mangas); | ||||
|                 }) | ||||
|                 .doOnNext(this::initializeMangas) | ||||
|                 .observeOn(AndroidSchedulers.mainThread()); | ||||
|     } | ||||
|  | ||||
| @@ -141,9 +153,12 @@ public class CataloguePresenter extends BasePresenter<CatalogueFragment> { | ||||
|         return localManga; | ||||
|     } | ||||
|  | ||||
|     public void initializeMangas(List<Manga> mangas) { | ||||
|         mangaDetailSubject.onNext(mangas); | ||||
|     } | ||||
|  | ||||
|     private Observable<Manga> getMangaDetails(final Manga manga) { | ||||
|         return source.pullMangaFromNetwork(manga.url) | ||||
|                 .subscribeOn(Schedulers.io()) | ||||
|                 .flatMap(networkManga -> { | ||||
|                     manga.copyFrom(networkManga); | ||||
|                     db.insertManga(manga).executeAsBlocking(); | ||||
| @@ -181,4 +196,13 @@ public class CataloguePresenter extends BasePresenter<CatalogueFragment> { | ||||
|         manga.favorite = !manga.favorite; | ||||
|         db.insertManga(manga).executeAsBlocking(); | ||||
|     } | ||||
|  | ||||
|     public boolean isListMode() { | ||||
|         return isListMode; | ||||
|     } | ||||
|  | ||||
|     public void swapDisplayMode() { | ||||
|         prefs.catalogueAsList().set(!isListMode); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -52,7 +52,7 @@ public class LibraryCategoryAdapter extends FlexibleAdapter<LibraryHolder, Manga | ||||
|  | ||||
|     @Override | ||||
|     public LibraryHolder onCreateViewHolder(ViewGroup parent, int viewType) { | ||||
|         View v = LayoutInflater.from(fragment.getActivity()).inflate(R.layout.item_catalogue, parent, false); | ||||
|         View v = LayoutInflater.from(fragment.getActivity()).inflate(R.layout.item_catalogue_grid, parent, false); | ||||
|         return new LibraryHolder(v, this, fragment); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -5,7 +5,7 @@ import android.support.v7.widget.RecyclerView; | ||||
| 
 | ||||
| import rx.functions.Action0; | ||||
| 
 | ||||
| public class EndlessRecyclerScrollListener extends RecyclerView.OnScrollListener { | ||||
| public class EndlessGridScrollListener extends RecyclerView.OnScrollListener { | ||||
| 
 | ||||
|     private int previousTotal = 0; // The total number of items in the dataset after the last load | ||||
|     private boolean loading = true; // True if we are still waiting for the last set of data to load. | ||||
| @@ -16,7 +16,7 @@ public class EndlessRecyclerScrollListener extends RecyclerView.OnScrollListener | ||||
| 
 | ||||
|     private Action0 requestNext; | ||||
| 
 | ||||
|     public EndlessRecyclerScrollListener(GridLayoutManager layoutManager, Action0 requestNext) { | ||||
|     public EndlessGridScrollListener(GridLayoutManager layoutManager, Action0 requestNext) { | ||||
|         this.layoutManager = layoutManager; | ||||
|         this.requestNext = requestNext; | ||||
|     } | ||||
| @@ -0,0 +1,49 @@ | ||||
| package eu.kanade.tachiyomi.widget; | ||||
|  | ||||
| import android.support.v7.widget.LinearLayoutManager; | ||||
| import android.support.v7.widget.RecyclerView; | ||||
|  | ||||
| import rx.functions.Action0; | ||||
|  | ||||
| public class EndlessListScrollListener extends RecyclerView.OnScrollListener { | ||||
|  | ||||
|     private int previousTotal = 0; // The total number of items in the dataset after the last load | ||||
|     private boolean loading = true; // True if we are still waiting for the last set of data to load. | ||||
|     private int visibleThreshold = 5; // The minimum amount of items to have below your current scroll position before loading more. | ||||
|     int firstVisibleItem, visibleItemCount, totalItemCount; | ||||
|  | ||||
|     private LinearLayoutManager layoutManager; | ||||
|  | ||||
|     private Action0 requestNext; | ||||
|  | ||||
|     public EndlessListScrollListener(LinearLayoutManager layoutManager, Action0 requestNext) { | ||||
|         this.layoutManager = layoutManager; | ||||
|         this.requestNext = requestNext; | ||||
|     } | ||||
|  | ||||
|     public void resetScroll() { | ||||
|         previousTotal = 0; | ||||
|         loading = true; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onScrolled(RecyclerView recyclerView, int dx, int dy) { | ||||
|         super.onScrolled(recyclerView, dx, dy); | ||||
|  | ||||
|         visibleItemCount = recyclerView.getChildCount(); | ||||
|         totalItemCount = layoutManager.getItemCount(); | ||||
|         firstVisibleItem = layoutManager.findFirstVisibleItemPosition(); | ||||
|  | ||||
|         if (loading && (totalItemCount > previousTotal)) { | ||||
|             loading = false; | ||||
|             previousTotal = totalItemCount; | ||||
|         } | ||||
|         if (!loading && (totalItemCount - visibleItemCount) | ||||
|                 <= (firstVisibleItem + visibleThreshold)) { | ||||
|             // End has been reached | ||||
|             requestNext.call(); | ||||
|             loading = true; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
		Reference in New Issue
	
	Block a user