diff --git a/app/src/main/java/eu/kanade/mangafeed/data/helpers/DownloadManager.java b/app/src/main/java/eu/kanade/mangafeed/data/helpers/DownloadManager.java index 087eec65c8..b1cc6d4d98 100644 --- a/app/src/main/java/eu/kanade/mangafeed/data/helpers/DownloadManager.java +++ b/app/src/main/java/eu/kanade/mangafeed/data/helpers/DownloadManager.java @@ -77,7 +77,6 @@ public class DownloadManager { .subscribe(threadsNumber::onNext); downloadsSubscription = downloadsQueueSubject - .observeOn(Schedulers.newThread()) .lift(new DynamicConcurrentMergeOperator<>(this::downloadChapter, threadsNumber)) .onBackpressureBuffer() .observeOn(AndroidSchedulers.mainThread()) @@ -167,6 +166,8 @@ public class DownloadManager { Observable.just(download.pages); return pageListObservable + .subscribeOn(Schedulers.io()) + .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( @@ -174,6 +175,7 @@ public class DownloadManager { 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++) // Do after download completes .doOnCompleted(() -> onDownloadCompleted(download)) .toList() @@ -363,6 +365,11 @@ public class DownloadManager { public void stopDownloads() { destroySubscriptions(); + for (Download download : queue.get()) { + if (download.getStatus() == Download.DOWNLOADING) { + download.setStatus(Download.ERROR); + } + } } public boolean isRunning() { diff --git a/app/src/main/java/eu/kanade/mangafeed/data/models/Download.java b/app/src/main/java/eu/kanade/mangafeed/data/models/Download.java index 08e4f98a02..1a8369610a 100644 --- a/app/src/main/java/eu/kanade/mangafeed/data/models/Download.java +++ b/app/src/main/java/eu/kanade/mangafeed/data/models/Download.java @@ -14,6 +14,7 @@ public class Download { public File directory; public transient volatile int totalProgress; + public transient volatile int downloadedImages; private transient volatile int status; private transient PublishSubject statusSubject; diff --git a/app/src/main/java/eu/kanade/mangafeed/presenter/DownloadQueuePresenter.java b/app/src/main/java/eu/kanade/mangafeed/presenter/DownloadQueuePresenter.java index f272566736..dd931bf4f6 100644 --- a/app/src/main/java/eu/kanade/mangafeed/presenter/DownloadQueuePresenter.java +++ b/app/src/main/java/eu/kanade/mangafeed/presenter/DownloadQueuePresenter.java @@ -4,7 +4,6 @@ import android.os.Bundle; import java.util.HashMap; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; import javax.inject.Inject; @@ -76,12 +75,17 @@ public class DownloadQueuePresenter extends BasePresenter unsubscribeProgress(download); unsubscribePagesStatus(download); view.updateProgress(download); + view.updateDownloadedPages(download); + break; + case Download.ERROR: + unsubscribeProgress(download); + unsubscribePagesStatus(download); break; } } private void observeProgress(Download download, DownloadQueueFragment view) { - Subscription subscription = Observable.interval(75, TimeUnit.MILLISECONDS, Schedulers.newThread()) + Subscription subscription = Observable.interval(50, TimeUnit.MILLISECONDS, Schedulers.newThread()) .flatMap(tick -> Observable.from(download.pages) .map(Page::getProgress) .reduce((x, y) -> x + y)) @@ -93,26 +97,31 @@ public class DownloadQueuePresenter extends BasePresenter } }); + // Avoid leaking subscriptions + Subscription oldSubscription = progressSubscriptions.remove(download); + if (oldSubscription != null) oldSubscription.unsubscribe(); + progressSubscriptions.put(download, subscription); } private void observePagesStatus(Download download, DownloadQueueFragment view) { PublishSubject pageStatusSubject = PublishSubject.create(); - for (Page page : download.pages) - page.setStatusSubject(pageStatusSubject); - - final AtomicInteger downloadedPages = new AtomicInteger(0); + for (Page page : download.pages) { + if (page.getStatus() != Page.READY) + page.setStatusSubject(pageStatusSubject); + } Subscription subscription = pageStatusSubject - .startWith(Observable.from(download.pages) - .filter(page -> page.getStatus() == Page.READY) - .map(page -> Page.READY)) .filter(status -> status == Page.READY) - .map(status -> downloadedPages.incrementAndGet()) - .subscribe(count -> { - // TODO + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(status -> { + view.updateDownloadedPages(download); }); + // Avoid leaking subscriptions + Subscription oldSubscription = progressSubscriptions.remove(download); + if (oldSubscription != null) oldSubscription.unsubscribe(); + pageStatusSubscriptions.put(download, subscription); } @@ -123,8 +132,10 @@ public class DownloadQueuePresenter extends BasePresenter } private void unsubscribePagesStatus(Download download) { - for (Page page : download.pages) - page.setStatusSubject(null); + if (download.pages != null) { + for (Page page : download.pages) + page.setStatusSubject(null); + } Subscription subscription = pageStatusSubscriptions.remove(download); if (subscription != null) @@ -136,7 +147,6 @@ public class DownloadQueuePresenter extends BasePresenter for (Page page : download.pages) page.setStatusSubject(null); } - for (Subscription subscription : pageStatusSubscriptions.values()) { subscription.unsubscribe(); } diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/adapter/DownloadAdapter.java b/app/src/main/java/eu/kanade/mangafeed/ui/adapter/DownloadAdapter.java new file mode 100644 index 0000000000..ce0bbb6ce4 --- /dev/null +++ b/app/src/main/java/eu/kanade/mangafeed/ui/adapter/DownloadAdapter.java @@ -0,0 +1,18 @@ +package eu.kanade.mangafeed.ui.adapter; + +import android.content.Context; + +import eu.kanade.mangafeed.data.models.Download; +import eu.kanade.mangafeed.ui.holder.DownloadHolder; +import uk.co.ribot.easyadapter.EasyRecyclerAdapter; + +public class DownloadAdapter extends EasyRecyclerAdapter { + + public DownloadAdapter(Context context) { + super(context, DownloadHolder.class); + } + + public int getPositionForItem(Download item) { + return getItems() != null && getItems().size() > 0 ? getItems().indexOf(item) : -1; + } +} diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/fragment/DownloadQueueFragment.java b/app/src/main/java/eu/kanade/mangafeed/ui/fragment/DownloadQueueFragment.java index bca0e22ac1..6225e05278 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/fragment/DownloadQueueFragment.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/fragment/DownloadQueueFragment.java @@ -6,6 +6,8 @@ import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.ProgressBar; +import android.widget.TextView; import java.util.List; @@ -14,16 +16,16 @@ import butterknife.ButterKnife; import eu.kanade.mangafeed.R; import eu.kanade.mangafeed.data.models.Download; import eu.kanade.mangafeed.presenter.DownloadQueuePresenter; +import eu.kanade.mangafeed.ui.adapter.DownloadAdapter; import eu.kanade.mangafeed.ui.fragment.base.BaseRxFragment; -import eu.kanade.mangafeed.ui.holder.DownloadHolder; import nucleus.factory.RequiresPresenter; -import uk.co.ribot.easyadapter.EasyRecyclerAdapter; @RequiresPresenter(DownloadQueuePresenter.class) public class DownloadQueueFragment extends BaseRxFragment { @Bind(R.id.download_list) RecyclerView downloadList; - private EasyRecyclerAdapter adapter; + private LinearLayoutManager downloadListLayout; + private DownloadAdapter adapter; public static DownloadQueueFragment newInstance() { return new DownloadQueueFragment(); @@ -38,14 +40,15 @@ public class DownloadQueueFragment extends BaseRxFragment(getActivity(), DownloadHolder.class); + adapter = new DownloadAdapter(getActivity()); downloadList.setAdapter(adapter); } @@ -53,14 +56,32 @@ public class DownloadQueueFragment extends BaseRxFragment= first && pos <= last) { + return downloadListLayout.getChildAt(pos - first); + } + return null; + } + public void updateProgress(Download download) { - for (int i = 0; i < adapter.getItems().size(); i++) { - if (adapter.getItem(i) == download) { - adapter.notifyItemChanged(i); - break; - } + View row = getDownloadRow(download); + if (row != null) { + ProgressBar progress = (ProgressBar) row.findViewById(R.id.download_progress); + if (progress.getMax() == 1) progress.setMax(download.pages.size() * 100); + progress.setProgress(download.totalProgress); } } + public void updateDownloadedPages(Download download) { + View row = getDownloadRow(download); + if (row != null) { + TextView progress = (TextView) row.findViewById(R.id.download_progress_text); + String progressText = download.downloadedImages + "/" + download.pages.size(); + progress.setText(progressText); + } + } } diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/holder/DownloadHolder.java b/app/src/main/java/eu/kanade/mangafeed/ui/holder/DownloadHolder.java index 5e3e20228c..8843eb0fa4 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/holder/DownloadHolder.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/holder/DownloadHolder.java @@ -28,9 +28,13 @@ public class DownloadHolder extends ItemViewHolder { if (download.pages == null) { downloadProgress.setProgress(0); + downloadProgress.setMax(1); + downloadProgressText.setText(""); } else { downloadProgress.setMax(download.pages.size() * 100); downloadProgress.setProgress(download.totalProgress); + String progressText = download.downloadedImages + "/" + download.pages.size(); + downloadProgressText.setText(progressText); } }