Update number of downloaded images in the queue, and improve the way the view refreshes the data

This commit is contained in:
inorichi 2015-11-09 03:31:50 +01:00
parent 7c37262a9f
commit ceb56e2c8a
6 changed files with 88 additions and 27 deletions

View file

@ -77,7 +77,6 @@ public class DownloadManager {
.subscribe(threadsNumber::onNext); .subscribe(threadsNumber::onNext);
downloadsSubscription = downloadsQueueSubject downloadsSubscription = downloadsQueueSubject
.observeOn(Schedulers.newThread())
.lift(new DynamicConcurrentMergeOperator<>(this::downloadChapter, threadsNumber)) .lift(new DynamicConcurrentMergeOperator<>(this::downloadChapter, threadsNumber))
.onBackpressureBuffer() .onBackpressureBuffer()
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
@ -167,6 +166,8 @@ public class DownloadManager {
Observable.just(download.pages); Observable.just(download.pages);
return pageListObservable return pageListObservable
.subscribeOn(Schedulers.io())
.doOnNext(pages -> download.downloadedImages = 0)
.doOnNext(pages -> download.setStatus(Download.DOWNLOADING)) .doOnNext(pages -> download.setStatus(Download.DOWNLOADING))
// Get all the URLs to the source images, fetch pages if necessary // Get all the URLs to the source images, fetch pages if necessary
.flatMap(pageList -> Observable.merge( .flatMap(pageList -> Observable.merge(
@ -174,6 +175,7 @@ public class DownloadManager {
download.source.getRemainingImageUrlsFromPageList(pageList))) download.source.getRemainingImageUrlsFromPageList(pageList)))
// Start downloading images, consider we can have downloaded images already // Start downloading images, consider we can have downloaded images already
.concatMap(page -> getDownloadedImage(page, download.source, download.directory)) .concatMap(page -> getDownloadedImage(page, download.source, download.directory))
.doOnNext(p -> download.downloadedImages++)
// Do after download completes // Do after download completes
.doOnCompleted(() -> onDownloadCompleted(download)) .doOnCompleted(() -> onDownloadCompleted(download))
.toList() .toList()
@ -363,6 +365,11 @@ public class DownloadManager {
public void stopDownloads() { public void stopDownloads() {
destroySubscriptions(); destroySubscriptions();
for (Download download : queue.get()) {
if (download.getStatus() == Download.DOWNLOADING) {
download.setStatus(Download.ERROR);
}
}
} }
public boolean isRunning() { public boolean isRunning() {

View file

@ -14,6 +14,7 @@ public class Download {
public File directory; public File directory;
public transient volatile int totalProgress; public transient volatile int totalProgress;
public transient volatile int downloadedImages;
private transient volatile int status; private transient volatile int status;
private transient PublishSubject<Download> statusSubject; private transient PublishSubject<Download> statusSubject;

View file

@ -4,7 +4,6 @@ import android.os.Bundle;
import java.util.HashMap; import java.util.HashMap;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import javax.inject.Inject; import javax.inject.Inject;
@ -76,12 +75,17 @@ public class DownloadQueuePresenter extends BasePresenter<DownloadQueueFragment>
unsubscribeProgress(download); unsubscribeProgress(download);
unsubscribePagesStatus(download); unsubscribePagesStatus(download);
view.updateProgress(download); view.updateProgress(download);
view.updateDownloadedPages(download);
break;
case Download.ERROR:
unsubscribeProgress(download);
unsubscribePagesStatus(download);
break; break;
} }
} }
private void observeProgress(Download download, DownloadQueueFragment view) { 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) .flatMap(tick -> Observable.from(download.pages)
.map(Page::getProgress) .map(Page::getProgress)
.reduce((x, y) -> x + y)) .reduce((x, y) -> x + y))
@ -93,26 +97,31 @@ public class DownloadQueuePresenter extends BasePresenter<DownloadQueueFragment>
} }
}); });
// Avoid leaking subscriptions
Subscription oldSubscription = progressSubscriptions.remove(download);
if (oldSubscription != null) oldSubscription.unsubscribe();
progressSubscriptions.put(download, subscription); progressSubscriptions.put(download, subscription);
} }
private void observePagesStatus(Download download, DownloadQueueFragment view) { private void observePagesStatus(Download download, DownloadQueueFragment view) {
PublishSubject<Integer> pageStatusSubject = PublishSubject.create(); PublishSubject<Integer> pageStatusSubject = PublishSubject.create();
for (Page page : download.pages) for (Page page : download.pages) {
if (page.getStatus() != Page.READY)
page.setStatusSubject(pageStatusSubject); page.setStatusSubject(pageStatusSubject);
}
final AtomicInteger downloadedPages = new AtomicInteger(0);
Subscription subscription = pageStatusSubject Subscription subscription = pageStatusSubject
.startWith(Observable.from(download.pages)
.filter(page -> page.getStatus() == Page.READY)
.map(page -> Page.READY))
.filter(status -> status == Page.READY) .filter(status -> status == Page.READY)
.map(status -> downloadedPages.incrementAndGet()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(count -> { .subscribe(status -> {
// TODO view.updateDownloadedPages(download);
}); });
// Avoid leaking subscriptions
Subscription oldSubscription = progressSubscriptions.remove(download);
if (oldSubscription != null) oldSubscription.unsubscribe();
pageStatusSubscriptions.put(download, subscription); pageStatusSubscriptions.put(download, subscription);
} }
@ -123,8 +132,10 @@ public class DownloadQueuePresenter extends BasePresenter<DownloadQueueFragment>
} }
private void unsubscribePagesStatus(Download download) { private void unsubscribePagesStatus(Download download) {
if (download.pages != null) {
for (Page page : download.pages) for (Page page : download.pages)
page.setStatusSubject(null); page.setStatusSubject(null);
}
Subscription subscription = pageStatusSubscriptions.remove(download); Subscription subscription = pageStatusSubscriptions.remove(download);
if (subscription != null) if (subscription != null)
@ -136,7 +147,6 @@ public class DownloadQueuePresenter extends BasePresenter<DownloadQueueFragment>
for (Page page : download.pages) for (Page page : download.pages)
page.setStatusSubject(null); page.setStatusSubject(null);
} }
for (Subscription subscription : pageStatusSubscriptions.values()) { for (Subscription subscription : pageStatusSubscriptions.values()) {
subscription.unsubscribe(); subscription.unsubscribe();
} }

View file

@ -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<Download> {
public DownloadAdapter(Context context) {
super(context, DownloadHolder.class);
}
public int getPositionForItem(Download item) {
return getItems() != null && getItems().size() > 0 ? getItems().indexOf(item) : -1;
}
}

View file

@ -6,6 +6,8 @@ import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;
import java.util.List; import java.util.List;
@ -14,16 +16,16 @@ import butterknife.ButterKnife;
import eu.kanade.mangafeed.R; import eu.kanade.mangafeed.R;
import eu.kanade.mangafeed.data.models.Download; import eu.kanade.mangafeed.data.models.Download;
import eu.kanade.mangafeed.presenter.DownloadQueuePresenter; 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.fragment.base.BaseRxFragment;
import eu.kanade.mangafeed.ui.holder.DownloadHolder;
import nucleus.factory.RequiresPresenter; import nucleus.factory.RequiresPresenter;
import uk.co.ribot.easyadapter.EasyRecyclerAdapter;
@RequiresPresenter(DownloadQueuePresenter.class) @RequiresPresenter(DownloadQueuePresenter.class)
public class DownloadQueueFragment extends BaseRxFragment<DownloadQueuePresenter> { public class DownloadQueueFragment extends BaseRxFragment<DownloadQueuePresenter> {
@Bind(R.id.download_list) RecyclerView downloadList; @Bind(R.id.download_list) RecyclerView downloadList;
private EasyRecyclerAdapter<Download> adapter; private LinearLayoutManager downloadListLayout;
private DownloadAdapter adapter;
public static DownloadQueueFragment newInstance() { public static DownloadQueueFragment newInstance() {
return new DownloadQueueFragment(); return new DownloadQueueFragment();
@ -38,14 +40,15 @@ public class DownloadQueueFragment extends BaseRxFragment<DownloadQueuePresenter
setToolbarTitle(R.string.download_title); setToolbarTitle(R.string.download_title);
downloadList.setLayoutManager(new LinearLayoutManager(getActivity())); downloadListLayout = new LinearLayoutManager(getActivity());
downloadList.setLayoutManager(downloadListLayout);
createAdapter(); createAdapter();
return view; return view;
} }
private void createAdapter() { private void createAdapter() {
adapter = new EasyRecyclerAdapter<>(getActivity(), DownloadHolder.class); adapter = new DownloadAdapter(getActivity());
downloadList.setAdapter(adapter); downloadList.setAdapter(adapter);
} }
@ -53,14 +56,32 @@ public class DownloadQueueFragment extends BaseRxFragment<DownloadQueuePresenter
adapter.setItems(downloads); adapter.setItems(downloads);
} }
// TODO use a better approach private View getDownloadRow(Download download) {
public void updateProgress(Download download) { int first = downloadListLayout.findFirstVisibleItemPosition();
for (int i = 0; i < adapter.getItems().size(); i++) { int last = downloadListLayout.findLastVisibleItemPosition();
if (adapter.getItem(i) == download) { int pos = adapter.getPositionForItem(download);
adapter.notifyItemChanged(i);
break; if (pos != -1 && pos >= first && pos <= last) {
return downloadListLayout.getChildAt(pos - first);
} }
return null;
}
public void updateProgress(Download download) {
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);
}
}
} }

View file

@ -28,9 +28,13 @@ public class DownloadHolder extends ItemViewHolder<Download> {
if (download.pages == null) { if (download.pages == null) {
downloadProgress.setProgress(0); downloadProgress.setProgress(0);
downloadProgress.setMax(1);
downloadProgressText.setText("");
} else { } else {
downloadProgress.setMax(download.pages.size() * 100); downloadProgress.setMax(download.pages.size() * 100);
downloadProgress.setProgress(download.totalProgress); downloadProgress.setProgress(download.totalProgress);
String progressText = download.downloadedImages + "/" + download.pages.size();
downloadProgressText.setText(progressText);
} }
} }