Эх сурвалжийг харах

Allow to display manga from catalogue as a simple list (#35)

inorichi 9 жил өмнө
parent
commit
e1aa460106
29 өөрчлөгдсөн 286 нэмэгдсэн , 62 устгасан
  1. 4 0
      app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.java
  2. 11 2
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueAdapter.java
  3. 79 15
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueFragment.java
  4. 38 0
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueGridHolder.java
  5. 3 26
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueHolder.java
  6. 24 0
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueListHolder.java
  7. 32 8
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CataloguePresenter.java
  8. 1 1
      app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.java
  9. 2 2
      app/src/main/java/eu/kanade/tachiyomi/widget/EndlessGridScrollListener.java
  10. 49 0
      app/src/main/java/eu/kanade/tachiyomi/widget/EndlessListScrollListener.java
  11. BIN
      app/src/main/res/drawable-hdpi/ic_view_list_white_24dp.png
  12. BIN
      app/src/main/res/drawable-hdpi/ic_view_module_white_24dp.png
  13. BIN
      app/src/main/res/drawable-ldpi/ic_view_list_white_24dp.png
  14. BIN
      app/src/main/res/drawable-ldpi/ic_view_module_white_24dp.png
  15. BIN
      app/src/main/res/drawable-mdpi/ic_view_list_white_24dp.png
  16. BIN
      app/src/main/res/drawable-mdpi/ic_view_module_white_24dp.png
  17. BIN
      app/src/main/res/drawable-xhdpi/ic_view_list_white_24dp.png
  18. BIN
      app/src/main/res/drawable-xhdpi/ic_view_module_white_24dp.png
  19. BIN
      app/src/main/res/drawable-xxhdpi/ic_view_list_white_24dp.png
  20. BIN
      app/src/main/res/drawable-xxhdpi/ic_view_module_white_24dp.png
  21. BIN
      app/src/main/res/drawable-xxxhdpi/ic_view_list_white_24dp.png
  22. BIN
      app/src/main/res/drawable-xxxhdpi/ic_view_module_white_24dp.png
  23. 17 6
      app/src/main/res/layout/fragment_catalogue.xml
  24. 1 1
      app/src/main/res/layout/fragment_library_category.xml
  25. 0 0
      app/src/main/res/layout/item_catalogue_grid.xml
  26. 16 0
      app/src/main/res/layout/item_catalogue_list.xml
  27. 6 1
      app/src/main/res/menu/catalogue_list.xml
  28. 2 0
      app/src/main/res/values/keys.xml
  29. 1 0
      app/src/main/res/values/strings.xml

+ 4 - 0
app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.java

@@ -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(), "");
     }

+ 11 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueAdapter.java

@@ -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

+ 79 - 15
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueFragment.java

@@ -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() {

+ 38 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueGridHolder.java

@@ -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);
+        }
+    }
+}

+ 3 - 26
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueHolder.java

@@ -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);
+}

+ 24 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueListHolder.java

@@ -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);
+    }
+}

+ 32 - 8
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CataloguePresenter.java

@@ -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);
+    }
+
 }

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.java

@@ -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);
     }
 

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/widget/EndlessRecyclerScrollListener.java → app/src/main/java/eu/kanade/tachiyomi/widget/EndlessGridScrollListener.java

@@ -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;
     }

+ 49 - 0
app/src/main/java/eu/kanade/tachiyomi/widget/EndlessListScrollListener.java

@@ -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;
+        }
+    }
+
+}

BIN
app/src/main/res/drawable-hdpi/ic_view_list_white_24dp.png


BIN
app/src/main/res/drawable-hdpi/ic_view_module_white_24dp.png


BIN
app/src/main/res/drawable-ldpi/ic_view_list_white_24dp.png


BIN
app/src/main/res/drawable-ldpi/ic_view_module_white_24dp.png


BIN
app/src/main/res/drawable-mdpi/ic_view_list_white_24dp.png


BIN
app/src/main/res/drawable-mdpi/ic_view_module_white_24dp.png


BIN
app/src/main/res/drawable-xhdpi/ic_view_list_white_24dp.png


BIN
app/src/main/res/drawable-xhdpi/ic_view_module_white_24dp.png


BIN
app/src/main/res/drawable-xxhdpi/ic_view_list_white_24dp.png


BIN
app/src/main/res/drawable-xxhdpi/ic_view_module_white_24dp.png


BIN
app/src/main/res/drawable-xxxhdpi/ic_view_list_white_24dp.png


BIN
app/src/main/res/drawable-xxxhdpi/ic_view_module_white_24dp.png


+ 17 - 6
app/src/main/res/layout/fragment_catalogue.xml

@@ -11,17 +11,28 @@
         android:id="@+id/progress"
         style="?android:attr/progressBarStyleLarge"
         android:layout_width="wrap_content"
-        android:layout_height="fill_parent"
+        android:layout_height="match_parent"
         android:layout_gravity="center_vertical|center_horizontal"
         android:visibility="gone"/>
 
-    <eu.kanade.tachiyomi.widget.AutofitRecyclerView
-        android:id="@+id/recycler"
-        style="@style/AppTheme.GridView"
+    <ViewSwitcher
+        android:layout_width="match_parent"
         android:layout_height="0dp"
         android:layout_weight="1"
-        android:columnWidth="140dp"
-        tools:listitem="@layout/item_catalogue" />
+        android:id="@+id/switcher">
+
+        <eu.kanade.tachiyomi.widget.AutofitRecyclerView
+            android:id="@+id/catalogue_grid"
+            style="@style/AppTheme.GridView"
+            android:columnWidth="140dp"
+            tools:listitem="@layout/item_catalogue_grid" />
+
+        <android.support.v7.widget.RecyclerView
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:id="@+id/catalogue_list"/>
+
+    </ViewSwitcher>
 
     <ProgressBar
         android:id="@+id/progress_grid"

+ 1 - 1
app/src/main/res/layout/fragment_library_category.xml

@@ -8,6 +8,6 @@
         android:id="@+id/library_mangas"
         style="@style/AppTheme.GridView"
         android:columnWidth="140dp"
-        tools:listitem="@layout/item_catalogue" />
+        tools:listitem="@layout/item_catalogue_grid" />
 
 </FrameLayout>

+ 0 - 0
app/src/main/res/layout/item_catalogue.xml → app/src/main/res/layout/item_catalogue_grid.xml


+ 16 - 0
app/src/main/res/layout/item_catalogue_list.xml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="?android:listPreferredItemHeightSmall"
+    android:background="@drawable/selector_chapter_light">
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:paddingLeft="?android:listPreferredItemPaddingLeft"
+        android:paddingRight="?android:listPreferredItemPaddingLeft"
+        android:id="@+id/title"/>
+
+</FrameLayout>

+ 6 - 1
app/src/main/res/menu/catalogue_list.xml

@@ -1,11 +1,16 @@
 <menu xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools" tools:context=".CatalogueListActivity">
+
     <item
         android:id="@+id/action_search"
         android:title="@string/action_search"
         android:icon="@drawable/ic_action_search"
-        android:orderInCategory="100"
         app:showAsAction="collapseActionView|ifRoom"
         app:actionViewClass="android.support.v7.widget.SearchView"/>
+
+    <item
+        android:id="@+id/action_display_mode"
+        android:title="@string/action_display_mode"
+        app:showAsAction="ifRoom"/>
 </menu>

+ 2 - 0
app/src/main/res/values/keys.xml

@@ -35,4 +35,6 @@
 
     <string name="pref_version">pref_version</string>
     <string name="pref_build_time">pref_build_time</string>
+
+    <string name="pref_display_catalogue_as_list">pref_display_catalogue_as_list</string>
 </resources>

+ 1 - 0
app/src/main/res/values/strings.xml

@@ -38,6 +38,7 @@
     <string name="action_previous_chapter">Previous chapter</string>
     <string name="action_next_chapter">Next chapter</string>
     <string name="action_retry">Retry</string>
+    <string name="action_display_mode">Change display mode</string>
 
 
     <!-- Buttons -->