diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 125217586..0178dda65 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -27,15 +27,11 @@ android:name=".ui.activity.MangaDetailActivity" android:label="@string/title_activity_manga_detail" android:parentActivityName=".ui.activity.MainActivity" > - { private String mSearchName; private boolean mSearchMode; private final int SEARCH_TIMEOUT = 1000; - private int mCurrentPage = 1; - private Subscription mMangaFetchSubscription; - private Subscription mMangaSearchSubscription; + @State protected int mCurrentPage; + private RxPager pager; + private Subscription mSearchViewSubscription; private Subscription mMangaDetailFetchSubscription; private PublishSubject> mSearchViewPublishSubject; private PublishSubject>> mMangaDetailPublishSubject; - private SubscriptionList mResultSubscriptions = new SubscriptionList(); - private final String CURRENT_PAGE = "CATALOGUE_CURRENT_PAGE"; + private static final int GET_MANGA_LIST = 1; @Override protected void onCreate(Bundle savedState) { super.onCreate(savedState); - if (savedState != null) { - mCurrentPage = savedState.getInt(CURRENT_PAGE); - } + restartableReplay(GET_MANGA_LIST, + () -> pager.pages().>>concatMap( + page -> getMangaObs(page + 1) + .map(mangas -> new PageBundle<>(page, mangas)) + .observeOn(AndroidSchedulers.mainThread()) + ), + (view, page) -> { + view.hideProgressBar(); + view.onAddPage(page); + if (mMangaDetailPublishSubject != null) + mMangaDetailPublishSubject.onNext(Observable.just(page.data)); + }); - selectedSource = sourceManager.getSelectedSource(); - getMangasFromSource(mCurrentPage); initializeSearch(); initializeMangaDetailsLoader(); } @@ -63,24 +70,40 @@ public class CataloguePresenter extends RxPresenter { protected void onTakeView(CatalogueActivity view) { super.onTakeView(view); - view.setScrollPage(mCurrentPage - 1); - view.setToolbarTitle(selectedSource.getName()); if (view.getAdapter().getCount() == 0) view.showProgressBar(); } - @Override - protected void onSave(@NonNull Bundle state) { - super.onSave(state); - state.putInt(CURRENT_PAGE, mCurrentPage); + public void requestNext() { + pager.requestNext(++mCurrentPage); } - @Override - protected void onDestroy() { - super.onDestroy(); - mResultSubscriptions.unsubscribe(); + public void initializeRequest(int source_id) { + this.selectedSource = sourceManager.get(source_id); + restartRequest(); + } + + private void restartRequest() { + stop(GET_MANGA_LIST); + mCurrentPage = 1; + pager = new RxPager(); + start(GET_MANGA_LIST); + } + + private Observable> getMangaObs(int page) { + Observable> obs; + if (mSearchMode) + obs = selectedSource.searchMangasFromNetwork(mSearchName, page); + else + obs = selectedSource.pullPopularMangasFromNetwork(page); + + return obs.subscribeOn(Schedulers.io()) + .flatMap(Observable::from) + .map(this::networkToLocalManga) + .toList() + .observeOn(AndroidSchedulers.mainThread()); } private void initializeSearch() { @@ -134,36 +157,6 @@ public class CataloguePresenter extends RxPresenter { add(mMangaDetailFetchSubscription); } - public void getMangasFromSource(int page) { - mMangaFetchSubscription = getMangasSubscriber( - selectedSource.pullPopularMangasFromNetwork(page)); - - mResultSubscriptions.add(mMangaFetchSubscription); - } - - public void getMangasFromSearch(int page) { - mMangaSearchSubscription = getMangasSubscriber( - selectedSource.searchMangasFromNetwork(mSearchName, page)); - - mResultSubscriptions.add(mMangaSearchSubscription); - } - - private Subscription getMangasSubscriber(Observable> mangas) { - return mangas - .subscribeOn(Schedulers.io()) - .flatMap(Observable::from) - .map(this::networkToLocalManga) - .toList() - .observeOn(AndroidSchedulers.mainThread()) - .compose(deliverReplay()) - .subscribe(this.split((view, newMangas) -> { - view.hideProgressBar(); - view.onMangasNext(newMangas); - if (mMangaDetailPublishSubject != null) - mMangaDetailPublishSubject.onNext(Observable.just(newMangas)); - })); - } - private Manga networkToLocalManga(Manga networkManga) { Manga localManga = db.getMangaBlock(networkManga.url); if (localManga == null) { @@ -186,31 +179,20 @@ public class CataloguePresenter extends RxPresenter { // If going to search mode else if (mSearchName.equals("") && !query.equals("")) { mSearchMode = true; - mResultSubscriptions.clear(); } // If going to normal mode else if (!mSearchName.equals("") && query.equals("")) { mSearchMode = false; - mResultSubscriptions.clear(); } mSearchName = query; - getView().getAdapter().getItems().clear(); - getView().showProgressBar(); - getView().resetScrollListener(); - loadMoreMangas(1); - } - - public void loadMoreMangas(int page) { - if (page > 1) { - getView().showGridProgressBar(); + if (getView() != null) { + if (mCurrentPage == 1) + getView().showProgressBar(); + else + getView().showGridProgressBar(); } - if (mSearchMode) { - getMangasFromSearch(page); - } else { - getMangasFromSource(page); - } - mCurrentPage = page; + restartRequest(); } } diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/activity/CatalogueActivity.java b/app/src/main/java/eu/kanade/mangafeed/ui/activity/CatalogueActivity.java index 64d88e1b8..067de0e43 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/activity/CatalogueActivity.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/activity/CatalogueActivity.java @@ -13,6 +13,7 @@ import android.widget.ProgressBar; import com.bumptech.glide.Glide; +import java.util.ArrayList; import java.util.List; import butterknife.Bind; @@ -22,6 +23,7 @@ import eu.kanade.mangafeed.R; import eu.kanade.mangafeed.data.models.Manga; import eu.kanade.mangafeed.presenter.CataloguePresenter; import eu.kanade.mangafeed.ui.adapter.CatalogueHolder; +import eu.kanade.mangafeed.util.PageBundle; import eu.kanade.mangafeed.widget.EndlessScrollListener; import nucleus.factory.RequiresPresenter; import uk.co.ribot.easyadapter.EasyAdapter; @@ -62,6 +64,11 @@ public class CatalogueActivity extends BaseActivity { initializeAdapter(); initializeScrollListener(); + + int source_id = getIntent().getIntExtra(SOURCE_ID, -1); + + if (savedInstanceState == null) + getPresenter().initializeRequest(source_id); } @Override @@ -107,14 +114,7 @@ public class CatalogueActivity extends BaseActivity { } public void initializeScrollListener() { - scroll_listener = new EndlessScrollListener() { - @Override - public boolean onLoadMore(int page, int totalItemsCount) { - getPresenter().loadMoreMangas(page); - return true; - } - }; - + scroll_listener = new EndlessScrollListener(getPresenter()::requestNext); manga_list.setOnScrollListener(scroll_listener); } @@ -122,14 +122,6 @@ public class CatalogueActivity extends BaseActivity { scroll_listener.resetScroll(); } - public int getScrollPage() { - return scroll_listener.getCurrentPage(); - } - - public void setScrollPage(int page) { - scroll_listener.setCurrentPage(page); - } - public void showProgressBar() { progress.setVisibility(ProgressBar.VISIBLE); } @@ -143,8 +135,12 @@ public class CatalogueActivity extends BaseActivity { progress_grid.setVisibility(ProgressBar.GONE); } - public void onMangasNext(List newMangas) { - adapter.addItems(newMangas); + public void onAddPage(PageBundle> page) { + if (page.page == 0) { + adapter.setItems(new ArrayList<>()); + resetScrollListener(); + } + adapter.addItems(page.data); } private int getMangaIndex(Manga manga) { @@ -175,4 +171,5 @@ public class CatalogueActivity extends BaseActivity { .into(imageView); } } + } diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/activity/MangaDetailActivity.java b/app/src/main/java/eu/kanade/mangafeed/ui/activity/MangaDetailActivity.java index 53dd5f169..48551794a 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/activity/MangaDetailActivity.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/activity/MangaDetailActivity.java @@ -10,6 +10,7 @@ import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; import android.support.v7.widget.Toolbar; +import android.view.MenuItem; import butterknife.Bind; import butterknife.ButterKnife; @@ -57,6 +58,16 @@ public class MangaDetailActivity extends BaseActivity { setupViewPager(); } + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + finish(); + return true; + } + return super.onOptionsItemSelected(item); + } + private void disableToolbarElevation() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { toolbar.setElevation(0); diff --git a/app/src/main/java/eu/kanade/mangafeed/util/PageBundle.java b/app/src/main/java/eu/kanade/mangafeed/util/PageBundle.java new file mode 100644 index 000000000..5ad33bdc4 --- /dev/null +++ b/app/src/main/java/eu/kanade/mangafeed/util/PageBundle.java @@ -0,0 +1,12 @@ +package eu.kanade.mangafeed.util; + +public class PageBundle { + + public final int page; + public final T data; + + public PageBundle(int page, T data) { + this.page = page; + this.data = data; + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/mangafeed/util/RxPager.java b/app/src/main/java/eu/kanade/mangafeed/util/RxPager.java new file mode 100644 index 000000000..032c5898b --- /dev/null +++ b/app/src/main/java/eu/kanade/mangafeed/util/RxPager.java @@ -0,0 +1,32 @@ +package eu.kanade.mangafeed.util; + +import rx.Observable; +import rx.subjects.PublishSubject; + +public class RxPager { + + private final int initialPageCount; + private final PublishSubject requests = PublishSubject.create(); + private int requestedCount; + + public RxPager() { + this(1); + } + + public RxPager(int initialPageCount) { + this.initialPageCount = initialPageCount; + } + + public void requestNext(int page) { + requests.onNext(page); + } + + public Observable pages() { + return requests + .concatMap(targetPage -> targetPage <= requestedCount ? + Observable.never() : + Observable.range(requestedCount, targetPage - requestedCount)) + .startWith(Observable.range(0, initialPageCount)) + .doOnNext(it -> requestedCount = it + 1); + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/mangafeed/widget/EndlessScrollListener.java b/app/src/main/java/eu/kanade/mangafeed/widget/EndlessScrollListener.java index 1ebeed1ef..8aff6d9b9 100644 --- a/app/src/main/java/eu/kanade/mangafeed/widget/EndlessScrollListener.java +++ b/app/src/main/java/eu/kanade/mangafeed/widget/EndlessScrollListener.java @@ -2,35 +2,25 @@ package eu.kanade.mangafeed.widget; import android.widget.AbsListView; -public abstract class EndlessScrollListener implements AbsListView.OnScrollListener { +import rx.functions.Action0; + +public class EndlessScrollListener implements AbsListView.OnScrollListener { // The minimum amount of items to have below your current scroll position // before loading more. private int visibleThreshold = 5; - // The current offset index of data you have loaded - private int currentPage = 0; // The total number of items in the dataset after the last load private int previousTotalItemCount = 0; // True if we are still waiting for the last set of data to load. private boolean loading = true; - // Sets the starting page index - private int startingPageIndex = 0; - public EndlessScrollListener() { - } + private Action0 requestNext; - public EndlessScrollListener(int visibleThreshold) { - this.visibleThreshold = visibleThreshold; - } - - public EndlessScrollListener(int visibleThreshold, int startPage) { - this.visibleThreshold = visibleThreshold; - this.startingPageIndex = startPage; - this.currentPage = startPage; + public EndlessScrollListener(Action0 requestNext) { + this.requestNext = requestNext; } public void resetScroll() { - this.currentPage = 0; - this.startingPageIndex = 0; + this.previousTotalItemCount = 0; this.loading = true; } @@ -43,7 +33,6 @@ public abstract class EndlessScrollListener implements AbsListView.OnScrollListe // If the total item count is zero and the previous isn't, assume the // list is invalidated and should be reset back to initial state if (totalItemCount < previousTotalItemCount) { - this.currentPage = this.startingPageIndex; this.previousTotalItemCount = totalItemCount; if (totalItemCount == 0) { this.loading = true; } } @@ -53,31 +42,20 @@ public abstract class EndlessScrollListener implements AbsListView.OnScrollListe if (loading && (totalItemCount > previousTotalItemCount)) { loading = false; previousTotalItemCount = totalItemCount; - currentPage++; } // If it isn’t currently loading, we check to see if we have breached // the visibleThreshold and need to reload more data. // If we do need to reload some more data, we execute onLoadMore to fetch the data. if (!loading && (totalItemCount - visibleItemCount)<=(firstVisibleItem + visibleThreshold)) { - loading = onLoadMore(currentPage + 1, totalItemCount); + requestNext.call(); + loading = true; } } - // Defines the process for actually loading more data based on page - // Returns true if more data is being loaded; returns false if there is no more data to load. - public abstract boolean onLoadMore(int page, int totalItemsCount); - @Override public void onScrollStateChanged(AbsListView view, int scrollState) { // Don't take any action on changed } - public int getCurrentPage() { - return currentPage; - } - - public void setCurrentPage(int currentPage) { - this.currentPage = currentPage; - } } \ No newline at end of file