diff --git a/app/build.gradle b/app/build.gradle index 27dfbea4ac..00d7b39f55 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -54,7 +54,7 @@ dependencies { final HAMCREST_VERSION = '1.3' final MOCKITO_VERSION = '1.10.19' final STORIO_VERSION = '1.6.1' - final NUCLEUS_VERSION = '2.0.1' + final NUCLEUS_VERSION = '2.0.3' final ICEPICK_VERSION = '3.1.0' compile fileTree(dir: 'libs', include: ['*.jar']) @@ -76,8 +76,6 @@ dependencies { compile "com.pushtorefresh.storio:sqlite:$STORIO_VERSION" compile "com.pushtorefresh.storio:sqlite-annotations:$STORIO_VERSION" compile "info.android15.nucleus:nucleus:$NUCLEUS_VERSION" - compile "info.android15.nucleus:nucleus-support-v4:$NUCLEUS_VERSION" - compile "info.android15.nucleus:nucleus-support-v7:$NUCLEUS_VERSION" compile 'de.greenrobot:eventbus:2.4.0' compile 'com.github.bumptech.glide:glide:3.6.1' compile 'com.jakewharton:butterknife:7.0.1' diff --git a/app/src/main/java/eu/kanade/mangafeed/data/download/DownloadManager.java b/app/src/main/java/eu/kanade/mangafeed/data/download/DownloadManager.java index b5f11659aa..343da2c3b2 100644 --- a/app/src/main/java/eu/kanade/mangafeed/data/download/DownloadManager.java +++ b/app/src/main/java/eu/kanade/mangafeed/data/download/DownloadManager.java @@ -171,9 +171,9 @@ public class DownloadManager { .doOnNext(pages -> download.downloadedImages = 0) .doOnNext(pages -> download.setStatus(Download.DOWNLOADING)) // Get all the URLs to the source images, fetch pages if necessary - .flatMap(pageList -> Observable.merge( - Observable.from(pageList).filter(page -> page.getImageUrl() != null), - download.source.getRemainingImageUrlsFromPageList(pageList))) + .flatMap(pageList -> Observable.from(pageList) + .filter(page -> page.getImageUrl() != null) + .mergeWith(download.source.getRemainingImageUrlsFromPageList(pageList))) // Start downloading images, consider we can have downloaded images already .concatMap(page -> getDownloadedImage(page, download.source, download.directory)) .doOnNext(p -> download.downloadedImages++) diff --git a/app/src/main/java/eu/kanade/mangafeed/data/source/base/Source.java b/app/src/main/java/eu/kanade/mangafeed/data/source/base/Source.java index 0fe51cf6f0..528cc382b4 100644 --- a/app/src/main/java/eu/kanade/mangafeed/data/source/base/Source.java +++ b/app/src/main/java/eu/kanade/mangafeed/data/source/base/Source.java @@ -101,7 +101,7 @@ public abstract class Source extends BaseSource { .concatMap(batchedPages -> batchedPages.concatMap(this::getImageUrlFromPage)); } - private Observable getImageUrlFromPage(final Page page) { + public Observable getImageUrlFromPage(final Page page) { page.setStatus(Page.LOAD_PAGE); return mNetworkService .getStringResponse(overrideRemainingPagesUrl(page.getUrl()), mRequestHeaders, null) @@ -118,26 +118,30 @@ public abstract class Source extends BaseSource { } public Observable getCachedImage(final Page page) { - Observable obs = Observable.just(page); + Observable pageObservable = Observable.just(page); if (page.getImageUrl() == null) - return obs; + return pageObservable; - if (!mCacheManager.isImageInCache(page.getImageUrl())) { - page.setStatus(Page.DOWNLOAD_IMAGE); - obs = cacheImage(page); - } - - return obs.flatMap(p -> { - page.setImagePath(mCacheManager.getImagePath(page.getImageUrl())); - page.setStatus(Page.READY); - return Observable.just(page); - }).onErrorResumeNext(e -> { - page.setStatus(Page.ERROR); - return Observable.just(page); - }); + return pageObservable + .flatMap(p -> { + if (!mCacheManager.isImageInCache(page.getImageUrl())) { + return cacheImage(page); + } + return Observable.just(page); + }) + .flatMap(p -> { + page.setImagePath(mCacheManager.getImagePath(page.getImageUrl())); + page.setStatus(Page.READY); + return Observable.just(page); + }) + .onErrorResumeNext(e -> { + page.setStatus(Page.ERROR); + return Observable.just(page); + }); } private Observable cacheImage(final Page page) { + page.setStatus(Page.DOWNLOAD_IMAGE); return getImageProgressResponse(page) .flatMap(resp -> { if (!mCacheManager.putImageToDiskCache(page.getImageUrl(), resp)) { diff --git a/app/src/main/java/eu/kanade/mangafeed/event/RetryPageEvent.java b/app/src/main/java/eu/kanade/mangafeed/event/RetryPageEvent.java new file mode 100644 index 0000000000..7ff8c7ad0c --- /dev/null +++ b/app/src/main/java/eu/kanade/mangafeed/event/RetryPageEvent.java @@ -0,0 +1,17 @@ +package eu.kanade.mangafeed.event; + +import eu.kanade.mangafeed.data.source.model.Page; + +public class RetryPageEvent { + + private Page page; + + public RetryPageEvent(Page page) { + this.page = page; + } + + public Page getPage() { + return page; + } + +} diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/reader/ReaderPresenter.java b/app/src/main/java/eu/kanade/mangafeed/ui/reader/ReaderPresenter.java index 1d6d639d85..423ca0a244 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/reader/ReaderPresenter.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/reader/ReaderPresenter.java @@ -15,6 +15,7 @@ import eu.kanade.mangafeed.data.download.DownloadManager; import eu.kanade.mangafeed.data.preference.PreferencesHelper; import eu.kanade.mangafeed.data.source.base.Source; import eu.kanade.mangafeed.data.source.model.Page; +import eu.kanade.mangafeed.event.RetryPageEvent; import eu.kanade.mangafeed.event.SourceMangaChapterEvent; import eu.kanade.mangafeed.ui.base.presenter.BasePresenter; import eu.kanade.mangafeed.util.EventBusHook; @@ -23,6 +24,7 @@ import rx.Observable; import rx.Subscription; import rx.android.schedulers.AndroidSchedulers; import rx.schedulers.Schedulers; +import rx.subjects.PublishSubject; import timber.log.Timber; public class ReaderPresenter extends BasePresenter { @@ -40,21 +42,29 @@ public class ReaderPresenter extends BasePresenter { private boolean isDownloaded; @State int currentPage; + private PublishSubject retryPageSubject; + private Subscription nextChapterSubscription; private Subscription previousChapterSubscription; private static final int GET_PAGE_LIST = 1; private static final int GET_PAGE_IMAGES = 2; + private static final int RETRY_IMAGES = 3; @Override protected void onCreate(Bundle savedState) { super.onCreate(savedState); + retryPageSubject = PublishSubject.create(); + restartableLatestCache(GET_PAGE_LIST, () -> getPageListObservable() .doOnNext(pages -> pageList = pages) - .doOnCompleted(this::getAdjacentChapters) - .doOnCompleted(() -> start(GET_PAGE_IMAGES)), + .doOnCompleted(() -> { + getAdjacentChapters(); + start(GET_PAGE_IMAGES); + start(RETRY_IMAGES); + }), (view, pages) -> { view.onPageListReady(pages); if (currentPage != 0) @@ -67,6 +77,10 @@ public class ReaderPresenter extends BasePresenter { (view, page) -> {}, (view, error) -> Timber.e("An error occurred while downloading an image")); + restartableLatestCache(RETRY_IMAGES, + this::getRetryPageObservable, + (view, page) -> {}, + (view, error) -> Timber.e("An error occurred while downloading an image")); } @Override @@ -95,6 +109,14 @@ public class ReaderPresenter extends BasePresenter { loadChapter(event.getChapter()); } + @EventBusHook + public void onEventMainThread(RetryPageEvent event) { + EventBus.getDefault().removeStickyEvent(event); + Page page = event.getPage(); + page.setStatus(Page.QUEUE); + retryPageSubject.onNext(page); + } + private void loadChapter(Chapter chapter) { this.chapter = chapter; isDownloaded = isChapterDownloaded(chapter); @@ -129,9 +151,9 @@ public class ReaderPresenter extends BasePresenter { Observable pages; if (!isDownloaded) { - pages = Observable - .merge(Observable.from(pageList).filter(page -> page.getImageUrl() != null), - source.getRemainingImageUrlsFromPageList(pageList)) + pages = Observable.from(pageList) + .filter(page -> page.getImageUrl() != null) + .mergeWith(source.getRemainingImageUrlsFromPageList(pageList)) .flatMap(source::getCachedImage); } else { File chapterDir = downloadManager.getAbsoluteChapterDirectory(source, manga, chapter); @@ -144,8 +166,15 @@ public class ReaderPresenter extends BasePresenter { .observeOn(AndroidSchedulers.mainThread()); } - public void retryPage(Page page) { - + private Observable getRetryPageObservable() { + return retryPageSubject + .flatMap(page -> { + if (page.getImageUrl() == null) + return source.getImageUrlFromPage(page); + return Observable.just(page); + }) + .flatMap(source::getCachedImage) + .subscribeOn(Schedulers.io()); } public void setCurrentPage(int currentPage) { diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/reader/viewer/base/BaseReader.java b/app/src/main/java/eu/kanade/mangafeed/ui/reader/viewer/base/BaseReader.java index 261f896be5..3a518a4d3c 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/reader/viewer/base/BaseReader.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/reader/viewer/base/BaseReader.java @@ -33,10 +33,6 @@ public abstract class BaseReader { return getCurrentPageIndex(currentPosition); } - public void retryPage(Page page) { - activity.getPresenter().retryPage(page); - } - public void requestNextChapter() { activity.getPresenter().setCurrentPage(getCurrentPosition()); activity.getPresenter().loadNextChapter(); diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/reader/viewer/common/ViewPagerReaderFragment.java b/app/src/main/java/eu/kanade/mangafeed/ui/reader/viewer/common/ViewPagerReaderFragment.java index aac1636cee..720b89094c 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/reader/viewer/common/ViewPagerReaderFragment.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/reader/viewer/common/ViewPagerReaderFragment.java @@ -5,6 +5,7 @@ import android.support.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.Button; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; @@ -17,8 +18,11 @@ import java.util.concurrent.atomic.AtomicInteger; import butterknife.Bind; import butterknife.ButterKnife; +import butterknife.OnClick; +import de.greenrobot.event.EventBus; import eu.kanade.mangafeed.R; import eu.kanade.mangafeed.data.source.model.Page; +import eu.kanade.mangafeed.event.RetryPageEvent; import eu.kanade.mangafeed.ui.base.fragment.BaseFragment; import eu.kanade.mangafeed.ui.reader.ReaderActivity; import rx.Observable; @@ -34,6 +38,7 @@ public class ViewPagerReaderFragment extends BaseFragment { @Bind(R.id.progress) ProgressBar progressBar; @Bind(R.id.progress_text) TextView progressText; @Bind(R.id.image_error) TextView errorText; + @Bind(R.id.retry_button) Button retryButton; private Page page; private Subscription progressSubscription; @@ -81,6 +86,11 @@ public class ViewPagerReaderFragment extends BaseFragment { this.page = page; } + @OnClick(R.id.retry_button) + void retry() { + EventBus.getDefault().postSticky(new RetryPageEvent(page)); + } + private void showImage() { if (page == null || page.getImagePath() == null) return; @@ -90,10 +100,12 @@ public class ViewPagerReaderFragment extends BaseFragment { } private void showDownloading() { + progressContainer.setVisibility(View.VISIBLE); progressText.setVisibility(View.VISIBLE); } private void showLoading() { + progressContainer.setVisibility(View.VISIBLE); progressText.setVisibility(View.VISIBLE); progressText.setText(R.string.downloading); } @@ -101,10 +113,19 @@ public class ViewPagerReaderFragment extends BaseFragment { private void showError() { progressContainer.setVisibility(View.GONE); errorText.setVisibility(View.VISIBLE); + retryButton.setVisibility(View.VISIBLE); + } + + private void hideError() { + errorText.setVisibility(View.GONE); + retryButton.setVisibility(View.GONE); } private void processStatus(int status) { switch (status) { + case Page.QUEUE: + hideError(); + break; case Page.LOAD_PAGE: showLoading(); break; diff --git a/app/src/main/res/layout/fragment_page.xml b/app/src/main/res/layout/fragment_page.xml index 0768b9ce2c..0232702eac 100644 --- a/app/src/main/res/layout/fragment_page.xml +++ b/app/src/main/res/layout/fragment_page.xml @@ -39,6 +39,14 @@ android:textSize="32sp" android:visibility="gone"/> +