Allow to display manga from catalogue as a simple list (#35)
@ -116,6 +116,10 @@ public class PreferencesHelper {
|
|||||||
return rxPrefs.getInteger(getKey(R.string.pref_reader_theme_key), 0);
|
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) {
|
public String getSourceUsername(Source source) {
|
||||||
return prefs.getString(SOURCE_ACCOUNT_USERNAME + source.getId(), "");
|
return prefs.getString(SOURCE_ACCOUNT_USERNAME + source.getId(), "");
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,10 @@ public class CatalogueAdapter extends FlexibleAdapter<CatalogueHolder, Manga> {
|
|||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Manga> getItems() {
|
||||||
|
return mItems;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getItemId(int position) {
|
public long getItemId(int position) {
|
||||||
return mItems.get(position).id;
|
return mItems.get(position).id;
|
||||||
@ -44,8 +48,13 @@ public class CatalogueAdapter extends FlexibleAdapter<CatalogueHolder, Manga> {
|
|||||||
@Override
|
@Override
|
||||||
public CatalogueHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
public CatalogueHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||||
LayoutInflater inflater = fragment.getActivity().getLayoutInflater();
|
LayoutInflater inflater = fragment.getActivity().getLayoutInflater();
|
||||||
View v = inflater.inflate(R.layout.item_catalogue, parent, false);
|
if (parent.getId() == R.id.catalogue_grid) {
|
||||||
return new CatalogueHolder(v, this, fragment);
|
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
|
@Override
|
||||||
|
@ -4,7 +4,10 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.v4.content.ContextCompat;
|
||||||
import android.support.v7.widget.GridLayoutManager;
|
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.SearchView;
|
||||||
import android.support.v7.widget.Toolbar;
|
import android.support.v7.widget.Toolbar;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
@ -14,9 +17,12 @@ import android.view.MenuInflater;
|
|||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.view.animation.Animation;
|
||||||
|
import android.view.animation.AnimationUtils;
|
||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
|
import android.widget.ViewSwitcher;
|
||||||
|
|
||||||
import com.afollestad.materialdialogs.MaterialDialog;
|
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.data.source.base.Source;
|
||||||
import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder;
|
import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder;
|
||||||
import eu.kanade.tachiyomi.ui.base.fragment.BaseRxFragment;
|
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.main.MainActivity;
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaActivity;
|
import eu.kanade.tachiyomi.ui.manga.MangaActivity;
|
||||||
import eu.kanade.tachiyomi.util.ToastUtil;
|
import eu.kanade.tachiyomi.util.ToastUtil;
|
||||||
import eu.kanade.tachiyomi.widget.AutofitRecyclerView;
|
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 icepick.State;
|
||||||
import nucleus.factory.RequiresPresenter;
|
import nucleus.factory.RequiresPresenter;
|
||||||
import rx.Subscription;
|
import rx.Subscription;
|
||||||
@ -45,14 +53,17 @@ import rx.subjects.PublishSubject;
|
|||||||
public class CatalogueFragment extends BaseRxFragment<CataloguePresenter>
|
public class CatalogueFragment extends BaseRxFragment<CataloguePresenter>
|
||||||
implements FlexibleViewHolder.OnListItemClickListener {
|
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) ProgressBar progress;
|
||||||
@Bind(R.id.progress_grid) ProgressBar progressGrid;
|
@Bind(R.id.progress_grid) ProgressBar progressGrid;
|
||||||
|
|
||||||
private Toolbar toolbar;
|
private Toolbar toolbar;
|
||||||
private Spinner spinner;
|
private Spinner spinner;
|
||||||
private CatalogueAdapter adapter;
|
private CatalogueAdapter adapter;
|
||||||
private EndlessRecyclerScrollListener scrollListener;
|
private EndlessGridScrollListener gridScrollListener;
|
||||||
|
private EndlessListScrollListener listScrollListener;
|
||||||
|
|
||||||
@State String query = "";
|
@State String query = "";
|
||||||
@State int selectedIndex = -1;
|
@State int selectedIndex = -1;
|
||||||
@ -61,6 +72,8 @@ public class CatalogueFragment extends BaseRxFragment<CataloguePresenter>
|
|||||||
private PublishSubject<String> queryDebouncerSubject;
|
private PublishSubject<String> queryDebouncerSubject;
|
||||||
private Subscription queryDebouncerSubscription;
|
private Subscription queryDebouncerSubscription;
|
||||||
|
|
||||||
|
private MenuItem displayMode;
|
||||||
|
|
||||||
public static CatalogueFragment newInstance() {
|
public static CatalogueFragment newInstance() {
|
||||||
return new CatalogueFragment();
|
return new CatalogueFragment();
|
||||||
}
|
}
|
||||||
@ -77,13 +90,32 @@ public class CatalogueFragment extends BaseRxFragment<CataloguePresenter>
|
|||||||
View view = inflater.inflate(R.layout.fragment_catalogue, container, false);
|
View view = inflater.inflate(R.layout.fragment_catalogue, container, false);
|
||||||
ButterKnife.bind(this, view);
|
ButterKnife.bind(this, view);
|
||||||
|
|
||||||
// Initialize adapter and scroll listener
|
// Initialize adapter, scroll listener and recycler views
|
||||||
GridLayoutManager layoutManager = (GridLayoutManager) recycler.getLayoutManager();
|
|
||||||
adapter = new CatalogueAdapter(this);
|
adapter = new CatalogueAdapter(this);
|
||||||
scrollListener = new EndlessRecyclerScrollListener(layoutManager, this::requestNextPage);
|
|
||||||
recycler.setHasFixedSize(true);
|
GridLayoutManager glm = (GridLayoutManager) catalogueGrid.getLayoutManager();
|
||||||
recycler.setAdapter(adapter);
|
gridScrollListener = new EndlessGridScrollListener(glm, this::requestNextPage);
|
||||||
recycler.addOnScrollListener(scrollListener);
|
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
|
// Create toolbar spinner
|
||||||
Context themedContext = getBaseActivity().getSupportActionBar() != null ?
|
Context themedContext = getBaseActivity().getSupportActionBar() != null ?
|
||||||
@ -109,7 +141,8 @@ public class CatalogueFragment extends BaseRxFragment<CataloguePresenter>
|
|||||||
} else {
|
} else {
|
||||||
selectedIndex = position;
|
selectedIndex = position;
|
||||||
showProgressBar();
|
showProgressBar();
|
||||||
recycler.setAdapter(adapter);
|
glm.scrollToPositionWithOffset(0, 0);
|
||||||
|
llm.scrollToPositionWithOffset(0, 0);
|
||||||
getPresenter().startRequesting(source);
|
getPresenter().startRequesting(source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,6 +185,22 @@ public class CatalogueFragment extends BaseRxFragment<CataloguePresenter>
|
|||||||
return true;
|
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
|
@Override
|
||||||
@ -198,7 +247,8 @@ public class CatalogueFragment extends BaseRxFragment<CataloguePresenter>
|
|||||||
|
|
||||||
query = newQuery;
|
query = newQuery;
|
||||||
showProgressBar();
|
showProgressBar();
|
||||||
recycler.getLayoutManager().scrollToPosition(0);
|
catalogueGrid.getLayoutManager().scrollToPosition(0);
|
||||||
|
catalogueList.getLayoutManager().scrollToPosition(0);
|
||||||
|
|
||||||
getPresenter().restartRequest(query);
|
getPresenter().restartRequest(query);
|
||||||
}
|
}
|
||||||
@ -214,7 +264,8 @@ public class CatalogueFragment extends BaseRxFragment<CataloguePresenter>
|
|||||||
hideProgressBar();
|
hideProgressBar();
|
||||||
if (page == 0) {
|
if (page == 0) {
|
||||||
adapter.clear();
|
adapter.clear();
|
||||||
scrollListener.resetScroll();
|
gridScrollListener.resetScroll();
|
||||||
|
listScrollListener.resetScroll();
|
||||||
}
|
}
|
||||||
adapter.addItems(mangas);
|
adapter.addItems(mangas);
|
||||||
}
|
}
|
||||||
@ -224,15 +275,28 @@ public class CatalogueFragment extends BaseRxFragment<CataloguePresenter>
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void updateImage(Manga manga) {
|
public void updateImage(Manga manga) {
|
||||||
CatalogueHolder holder = getHolder(manga);
|
CatalogueGridHolder holder = getHolder(manga);
|
||||||
if (holder != null) {
|
if (holder != null) {
|
||||||
holder.setImage(manga, getPresenter());
|
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
|
@Nullable
|
||||||
private CatalogueHolder getHolder(Manga manga) {
|
private CatalogueGridHolder getHolder(Manga manga) {
|
||||||
return (CatalogueHolder) recycler.findViewHolderForItemId(manga.id);
|
return (CatalogueGridHolder) catalogueGrid.findViewHolderForItemId(manga.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showProgressBar() {
|
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;
|
package eu.kanade.tachiyomi.ui.catalogue;
|
||||||
|
|
||||||
import android.view.View;
|
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.data.database.models.Manga;
|
||||||
import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder;
|
import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder;
|
||||||
|
|
||||||
public class CatalogueHolder extends FlexibleViewHolder {
|
public abstract class CatalogueHolder extends FlexibleViewHolder {
|
||||||
|
|
||||||
@Bind(R.id.title) TextView title;
|
|
||||||
@Bind(R.id.thumbnail) ImageView thumbnail;
|
|
||||||
@Bind(R.id.favorite_sticker) ImageView favoriteSticker;
|
|
||||||
|
|
||||||
public CatalogueHolder(View view, CatalogueAdapter adapter, OnListItemClickListener listener) {
|
public CatalogueHolder(View view, CatalogueAdapter adapter, OnListItemClickListener listener) {
|
||||||
super(view, adapter, listener);
|
super(view, adapter, listener);
|
||||||
ButterKnife.bind(this, view);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onSetValues(Manga manga, CataloguePresenter presenter) {
|
abstract 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -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 PublishSubject<List<Manga>> mangaDetailSubject;
|
||||||
|
|
||||||
|
private boolean isListMode;
|
||||||
|
|
||||||
private static final int GET_MANGA_LIST = 1;
|
private static final int GET_MANGA_LIST = 1;
|
||||||
private static final int GET_MANGA_DETAIL = 2;
|
private static final int GET_MANGA_DETAIL = 2;
|
||||||
private static final int GET_MANGA_PAGE = 3;
|
private static final int GET_MANGA_PAGE = 3;
|
||||||
@ -72,12 +74,14 @@ public class CataloguePresenter extends BasePresenter<CatalogueFragment> {
|
|||||||
.observeOn(Schedulers.io())
|
.observeOn(Schedulers.io())
|
||||||
.flatMap(Observable::from)
|
.flatMap(Observable::from)
|
||||||
.filter(manga -> !manga.initialized)
|
.filter(manga -> !manga.initialized)
|
||||||
.window(3)
|
.concatMap(this::getMangaDetails)
|
||||||
.concatMap(pack -> pack.concatMap(this::getMangaDetails))
|
|
||||||
.onBackpressureBuffer()
|
.onBackpressureBuffer()
|
||||||
.observeOn(AndroidSchedulers.mainThread()),
|
.observeOn(AndroidSchedulers.mainThread()),
|
||||||
CatalogueFragment::updateImage,
|
CatalogueFragment::updateImage,
|
||||||
(view, error) -> Timber.e(error.getMessage()));
|
(view, error) -> Timber.e(error.getMessage()));
|
||||||
|
|
||||||
|
add(prefs.catalogueAsList().asObservable()
|
||||||
|
.subscribe(this::setDisplayMode));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onProcessRestart() {
|
private void onProcessRestart() {
|
||||||
@ -87,6 +91,15 @@ public class CataloguePresenter extends BasePresenter<CatalogueFragment> {
|
|||||||
stop(GET_MANGA_PAGE);
|
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) {
|
public void startRequesting(Source source) {
|
||||||
this.source = source;
|
this.source = source;
|
||||||
sourceId = source.getId();
|
sourceId = source.getId();
|
||||||
@ -98,7 +111,9 @@ public class CataloguePresenter extends BasePresenter<CatalogueFragment> {
|
|||||||
stop(GET_MANGA_PAGE);
|
stop(GET_MANGA_PAGE);
|
||||||
lastMangasPage = null;
|
lastMangasPage = null;
|
||||||
|
|
||||||
|
if (!isListMode) {
|
||||||
start(GET_MANGA_DETAIL);
|
start(GET_MANGA_DETAIL);
|
||||||
|
}
|
||||||
start(GET_MANGA_LIST);
|
start(GET_MANGA_LIST);
|
||||||
start(GET_MANGA_PAGE);
|
start(GET_MANGA_PAGE);
|
||||||
}
|
}
|
||||||
@ -124,10 +139,7 @@ public class CataloguePresenter extends BasePresenter<CatalogueFragment> {
|
|||||||
.flatMap(mangasPage -> Observable.from(mangasPage.mangas))
|
.flatMap(mangasPage -> Observable.from(mangasPage.mangas))
|
||||||
.map(this::networkToLocalManga)
|
.map(this::networkToLocalManga)
|
||||||
.toList()
|
.toList()
|
||||||
.doOnNext(mangas -> {
|
.doOnNext(this::initializeMangas)
|
||||||
if (mangaDetailSubject != null)
|
|
||||||
mangaDetailSubject.onNext(mangas);
|
|
||||||
})
|
|
||||||
.observeOn(AndroidSchedulers.mainThread());
|
.observeOn(AndroidSchedulers.mainThread());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,9 +153,12 @@ public class CataloguePresenter extends BasePresenter<CatalogueFragment> {
|
|||||||
return localManga;
|
return localManga;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void initializeMangas(List<Manga> mangas) {
|
||||||
|
mangaDetailSubject.onNext(mangas);
|
||||||
|
}
|
||||||
|
|
||||||
private Observable<Manga> getMangaDetails(final Manga manga) {
|
private Observable<Manga> getMangaDetails(final Manga manga) {
|
||||||
return source.pullMangaFromNetwork(manga.url)
|
return source.pullMangaFromNetwork(manga.url)
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.flatMap(networkManga -> {
|
.flatMap(networkManga -> {
|
||||||
manga.copyFrom(networkManga);
|
manga.copyFrom(networkManga);
|
||||||
db.insertManga(manga).executeAsBlocking();
|
db.insertManga(manga).executeAsBlocking();
|
||||||
@ -181,4 +196,13 @@ public class CataloguePresenter extends BasePresenter<CatalogueFragment> {
|
|||||||
manga.favorite = !manga.favorite;
|
manga.favorite = !manga.favorite;
|
||||||
db.insertManga(manga).executeAsBlocking();
|
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
|
@Override
|
||||||
public LibraryHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
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);
|
return new LibraryHolder(v, this, fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import android.support.v7.widget.RecyclerView;
|
|||||||
|
|
||||||
import rx.functions.Action0;
|
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 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 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;
|
private Action0 requestNext;
|
||||||
|
|
||||||
public EndlessRecyclerScrollListener(GridLayoutManager layoutManager, Action0 requestNext) {
|
public EndlessGridScrollListener(GridLayoutManager layoutManager, Action0 requestNext) {
|
||||||
this.layoutManager = layoutManager;
|
this.layoutManager = layoutManager;
|
||||||
this.requestNext = requestNext;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
BIN
app/src/main/res/drawable-hdpi/ic_view_list_white_24dp.png
Normal file
After Width: | Height: | Size: 125 B |
BIN
app/src/main/res/drawable-hdpi/ic_view_module_white_24dp.png
Normal file
After Width: | Height: | Size: 115 B |
BIN
app/src/main/res/drawable-ldpi/ic_view_list_white_24dp.png
Normal file
After Width: | Height: | Size: 187 B |
BIN
app/src/main/res/drawable-ldpi/ic_view_module_white_24dp.png
Normal file
After Width: | Height: | Size: 278 B |
BIN
app/src/main/res/drawable-mdpi/ic_view_list_white_24dp.png
Normal file
After Width: | Height: | Size: 89 B |
BIN
app/src/main/res/drawable-mdpi/ic_view_module_white_24dp.png
Normal file
After Width: | Height: | Size: 87 B |
BIN
app/src/main/res/drawable-xhdpi/ic_view_list_white_24dp.png
Normal file
After Width: | Height: | Size: 117 B |
BIN
app/src/main/res/drawable-xhdpi/ic_view_module_white_24dp.png
Normal file
After Width: | Height: | Size: 115 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_view_list_white_24dp.png
Normal file
After Width: | Height: | Size: 144 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_view_module_white_24dp.png
Normal file
After Width: | Height: | Size: 139 B |
BIN
app/src/main/res/drawable-xxxhdpi/ic_view_list_white_24dp.png
Normal file
After Width: | Height: | Size: 176 B |
BIN
app/src/main/res/drawable-xxxhdpi/ic_view_module_white_24dp.png
Normal file
After Width: | Height: | Size: 171 B |
@ -11,17 +11,28 @@
|
|||||||
android:id="@+id/progress"
|
android:id="@+id/progress"
|
||||||
style="?android:attr/progressBarStyleLarge"
|
style="?android:attr/progressBarStyleLarge"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="fill_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_gravity="center_vertical|center_horizontal"
|
android:layout_gravity="center_vertical|center_horizontal"
|
||||||
android:visibility="gone"/>
|
android:visibility="gone"/>
|
||||||
|
|
||||||
<eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
<ViewSwitcher
|
||||||
android:id="@+id/recycler"
|
android:layout_width="match_parent"
|
||||||
style="@style/AppTheme.GridView"
|
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
|
android:id="@+id/switcher">
|
||||||
|
|
||||||
|
<eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
||||||
|
android:id="@+id/catalogue_grid"
|
||||||
|
style="@style/AppTheme.GridView"
|
||||||
android:columnWidth="140dp"
|
android:columnWidth="140dp"
|
||||||
tools:listitem="@layout/item_catalogue" />
|
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
|
<ProgressBar
|
||||||
android:id="@+id/progress_grid"
|
android:id="@+id/progress_grid"
|
||||||
|
@ -8,6 +8,6 @@
|
|||||||
android:id="@+id/library_mangas"
|
android:id="@+id/library_mangas"
|
||||||
style="@style/AppTheme.GridView"
|
style="@style/AppTheme.GridView"
|
||||||
android:columnWidth="140dp"
|
android:columnWidth="140dp"
|
||||||
tools:listitem="@layout/item_catalogue" />
|
tools:listitem="@layout/item_catalogue_grid" />
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
16
app/src/main/res/layout/item_catalogue_list.xml
Normal file
@ -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>
|
@ -1,11 +1,16 @@
|
|||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools" tools:context=".CatalogueListActivity">
|
xmlns:tools="http://schemas.android.com/tools" tools:context=".CatalogueListActivity">
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_search"
|
android:id="@+id/action_search"
|
||||||
android:title="@string/action_search"
|
android:title="@string/action_search"
|
||||||
android:icon="@drawable/ic_action_search"
|
android:icon="@drawable/ic_action_search"
|
||||||
android:orderInCategory="100"
|
|
||||||
app:showAsAction="collapseActionView|ifRoom"
|
app:showAsAction="collapseActionView|ifRoom"
|
||||||
app:actionViewClass="android.support.v7.widget.SearchView"/>
|
app:actionViewClass="android.support.v7.widget.SearchView"/>
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_display_mode"
|
||||||
|
android:title="@string/action_display_mode"
|
||||||
|
app:showAsAction="ifRoom"/>
|
||||||
</menu>
|
</menu>
|
||||||
|
@ -35,4 +35,6 @@
|
|||||||
|
|
||||||
<string name="pref_version">pref_version</string>
|
<string name="pref_version">pref_version</string>
|
||||||
<string name="pref_build_time">pref_build_time</string>
|
<string name="pref_build_time">pref_build_time</string>
|
||||||
|
|
||||||
|
<string name="pref_display_catalogue_as_list">pref_display_catalogue_as_list</string>
|
||||||
</resources>
|
</resources>
|
@ -38,6 +38,7 @@
|
|||||||
<string name="action_previous_chapter">Previous chapter</string>
|
<string name="action_previous_chapter">Previous chapter</string>
|
||||||
<string name="action_next_chapter">Next chapter</string>
|
<string name="action_next_chapter">Next chapter</string>
|
||||||
<string name="action_retry">Retry</string>
|
<string name="action_retry">Retry</string>
|
||||||
|
<string name="action_display_mode">Change display mode</string>
|
||||||
|
|
||||||
|
|
||||||
<!-- Buttons -->
|
<!-- Buttons -->
|
||||||
|