Improvements for downloads fragment

This commit is contained in:
inorichi 2015-12-06 12:27:05 +01:00
parent 49a38821f2
commit 4aee1ca8a3
5 changed files with 91 additions and 101 deletions

View File

@ -84,7 +84,7 @@ public class DownloadManager {
if (finished) { if (finished) {
DownloadService.stop(context); DownloadService.stop(context);
} }
}, e -> Timber.e(e.fillInStackTrace(), e.getMessage())); }, e -> Timber.e(e.getCause(), e.getMessage()));
isRunning = true; isRunning = true;
} }
@ -238,10 +238,12 @@ public class DownloadManager {
try { try {
DiskUtils.saveBufferedSourceToDirectory(resp.body().source(), directory, filename); DiskUtils.saveBufferedSourceToDirectory(resp.body().source(), directory, filename);
} catch (Exception e) { } catch (Exception e) {
Timber.e(e.getCause(), e.getMessage());
return Observable.error(e); return Observable.error(e);
} }
return Observable.just(page); return Observable.just(page);
}); })
.retry(2);
} }
// Public method to get the image from the filesystem. It does NOT provide any way to download the image // Public method to get the image from the filesystem. It does NOT provide any way to download the image
@ -310,7 +312,7 @@ public class DownloadManager {
pages = gson.fromJson(reader, collectionType); pages = gson.fromJson(reader, collectionType);
} }
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
Timber.e(e.fillInStackTrace(), e.getMessage()); Timber.e(e.getCause(), e.getMessage());
} finally { } finally {
if (reader != null) try { reader.close(); } catch (IOException e) { /* Do nothing */ } if (reader != null) try { reader.close(); } catch (IOException e) { /* Do nothing */ }
} }
@ -333,7 +335,7 @@ public class DownloadManager {
out.write(gson.toJson(pages).getBytes()); out.write(gson.toJson(pages).getBytes());
out.flush(); out.flush();
} catch (IOException e) { } catch (IOException e) {
Timber.e(e.fillInStackTrace(), e.getMessage()); Timber.e(e.getCause(), e.getMessage());
} finally { } finally {
if (out != null) try { out.close(); } catch (IOException e) { /* Do nothing */ } if (out != null) try { out.close(); } catch (IOException e) { /* Do nothing */ }
} }

View File

@ -1,17 +1,50 @@
package eu.kanade.mangafeed.ui.download; package eu.kanade.mangafeed.ui.download;
import android.content.Context; import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.kanade.mangafeed.R;
import eu.kanade.mangafeed.data.download.model.Download; import eu.kanade.mangafeed.data.download.model.Download;
import uk.co.ribot.easyadapter.EasyRecyclerAdapter;
public class DownloadAdapter extends EasyRecyclerAdapter<Download> { public class DownloadAdapter extends FlexibleAdapter<DownloadHolder, Download> {
private Context context;
public DownloadAdapter(Context context) { public DownloadAdapter(Context context) {
super(context, DownloadHolder.class); this.context = context;
mItems = new ArrayList<>();
setHasStableIds(true);
} }
public int getPositionForItem(Download item) { @Override
return getItems() != null && getItems().size() > 0 ? getItems().indexOf(item) : -1; public DownloadHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.item_download, parent, false);
return new DownloadHolder(v);
} }
@Override
public void onBindViewHolder(DownloadHolder holder, int position) {
final Download download = getItem(position);
holder.onSetValues(download);
}
@Override
public long getItemId(int position) {
return getItem(position).chapter.id;
}
public void setItems(List<Download> downloads) {
mItems = downloads;
notifyDataSetChanged();
}
@Override
public void updateDataSet(String param) {}
} }

View File

@ -1,13 +1,12 @@
package eu.kanade.mangafeed.ui.download; package eu.kanade.mangafeed.ui.download;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; 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;
@ -21,8 +20,7 @@ import nucleus.factory.RequiresPresenter;
@RequiresPresenter(DownloadPresenter.class) @RequiresPresenter(DownloadPresenter.class)
public class DownloadFragment extends BaseRxFragment<DownloadPresenter> { public class DownloadFragment extends BaseRxFragment<DownloadPresenter> {
@Bind(R.id.download_list) RecyclerView downloadList; @Bind(R.id.download_list) RecyclerView recyclerView;
private LinearLayoutManager downloadListLayout;
private DownloadAdapter adapter; private DownloadAdapter adapter;
public static DownloadFragment newInstance() { public static DownloadFragment newInstance() {
@ -38,8 +36,8 @@ public class DownloadFragment extends BaseRxFragment<DownloadPresenter> {
setToolbarTitle(R.string.label_download_queue); setToolbarTitle(R.string.label_download_queue);
downloadListLayout = new LinearLayoutManager(getActivity()); recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
downloadList.setLayoutManager(downloadListLayout); recyclerView.setHasFixedSize(true);
createAdapter(); createAdapter();
return view; return view;
@ -47,39 +45,30 @@ public class DownloadFragment extends BaseRxFragment<DownloadPresenter> {
private void createAdapter() { private void createAdapter() {
adapter = new DownloadAdapter(getActivity()); adapter = new DownloadAdapter(getActivity());
downloadList.setAdapter(adapter); recyclerView.setAdapter(adapter);
} }
public void onNextDownloads(List<Download> downloads) { public void onNextDownloads(List<Download> downloads) {
adapter.setItems(downloads); adapter.setItems(downloads);
} }
private View getDownloadRow(Download download) {
int first = downloadListLayout.findFirstVisibleItemPosition();
int last = downloadListLayout.findLastVisibleItemPosition();
int pos = adapter.getPositionForItem(download);
if (pos != -1 && pos >= first && pos <= last) {
return downloadListLayout.getChildAt(pos - first);
}
return null;
}
public void updateProgress(Download download) { public void updateProgress(Download download) {
View row = getDownloadRow(download); DownloadHolder holder = getHolder(download);
if (row != null) { if (holder != null) {
ProgressBar progress = (ProgressBar) row.findViewById(R.id.download_progress); holder.setDownloadProgress(download);
if (progress.getMax() == 1) progress.setMax(download.pages.size() * 100);
progress.setProgress(download.totalProgress);
} }
} }
public void updateDownloadedPages(Download download) { public void updateDownloadedPages(Download download) {
View row = getDownloadRow(download); DownloadHolder holder = getHolder(download);
if (row != null) { if (holder != null) {
TextView progress = (TextView) row.findViewById(R.id.download_progress_text); holder.setDownloadedPages(download);
String progressText = download.downloadedImages + "/" + download.pages.size();
progress.setText(progressText);
} }
} }
@Nullable
private DownloadHolder getHolder(Download download) {
return (DownloadHolder) recyclerView.findViewHolderForItemId(download.chapter.id);
}
} }

View File

@ -1,29 +1,27 @@
package eu.kanade.mangafeed.ui.download; package eu.kanade.mangafeed.ui.download;
import android.support.v7.widget.RecyclerView;
import android.view.View; import android.view.View;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import butterknife.Bind;
import butterknife.ButterKnife;
import eu.kanade.mangafeed.R; import eu.kanade.mangafeed.R;
import eu.kanade.mangafeed.data.download.model.Download; import eu.kanade.mangafeed.data.download.model.Download;
import uk.co.ribot.easyadapter.ItemViewHolder;
import uk.co.ribot.easyadapter.PositionInfo;
import uk.co.ribot.easyadapter.annotations.LayoutId;
import uk.co.ribot.easyadapter.annotations.ViewId;
@LayoutId(R.layout.item_download) public class DownloadHolder extends RecyclerView.ViewHolder {
public class DownloadHolder extends ItemViewHolder<Download> {
@ViewId(R.id.download_title) TextView downloadTitle; @Bind(R.id.download_title) TextView downloadTitle;
@ViewId(R.id.download_progress) ProgressBar downloadProgress; @Bind(R.id.download_progress) ProgressBar downloadProgress;
@ViewId(R.id.download_progress_text) TextView downloadProgressText; @Bind(R.id.download_progress_text) TextView downloadProgressText;
public DownloadHolder(View view) { public DownloadHolder(View view) {
super(view); super(view);
ButterKnife.bind(this, view);
} }
@Override public void onSetValues(Download download) {
public void onSetValues(Download download, PositionInfo positionInfo) {
downloadTitle.setText(download.chapter.name); downloadTitle.setText(download.chapter.name);
if (download.pages == null) { if (download.pages == null) {
@ -32,10 +30,20 @@ public class DownloadHolder extends ItemViewHolder<Download> {
downloadProgressText.setText(""); downloadProgressText.setText("");
} else { } else {
downloadProgress.setMax(download.pages.size() * 100); downloadProgress.setMax(download.pages.size() * 100);
downloadProgress.setProgress(download.totalProgress); setDownloadProgress(download);
String progressText = download.downloadedImages + "/" + download.pages.size(); setDownloadedPages(download);
downloadProgressText.setText(progressText);
} }
} }
public void setDownloadedPages(Download download) {
String progressText = download.downloadedImages + "/" + download.pages.size();
downloadProgressText.setText(progressText);
}
public void setDownloadProgress(Download download) {
if (downloadProgress.getMax() == 1)
downloadProgress.setMax(download.pages.size() * 100);
downloadProgress.setProgress(download.totalProgress);
}
} }

View File

@ -16,7 +16,6 @@ import rx.Observable;
import rx.Subscription; import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers; import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers; import rx.schedulers.Schedulers;
import rx.subjects.PublishSubject;
import timber.log.Timber; import timber.log.Timber;
public class DownloadPresenter extends BasePresenter<DownloadFragment> { public class DownloadPresenter extends BasePresenter<DownloadFragment> {
@ -25,8 +24,8 @@ public class DownloadPresenter extends BasePresenter<DownloadFragment> {
private DownloadQueue downloadQueue; private DownloadQueue downloadQueue;
private Subscription statusSubscription; private Subscription statusSubscription;
private Subscription pageProgressSubscription;
private HashMap<Download, Subscription> progressSubscriptions; private HashMap<Download, Subscription> progressSubscriptions;
private HashMap<Download, Subscription> pageStatusSubscriptions;
public final static int GET_DOWNLOAD_QUEUE = 1; public final static int GET_DOWNLOAD_QUEUE = 1;
@ -36,7 +35,6 @@ public class DownloadPresenter extends BasePresenter<DownloadFragment> {
downloadQueue = downloadManager.getQueue(); downloadQueue = downloadManager.getQueue();
progressSubscriptions = new HashMap<>(); progressSubscriptions = new HashMap<>();
pageStatusSubscriptions = new HashMap<>();
restartableLatestCache(GET_DOWNLOAD_QUEUE, restartableLatestCache(GET_DOWNLOAD_QUEUE,
() -> Observable.just(downloadQueue.get()), () -> Observable.just(downloadQueue.get()),
@ -57,6 +55,10 @@ public class DownloadPresenter extends BasePresenter<DownloadFragment> {
.subscribe(download -> { .subscribe(download -> {
processStatus(download, view); processStatus(download, view);
})); }));
add(pageProgressSubscription = downloadQueue.getProgressObservable()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(view::updateDownloadedPages));
} }
@Override @Override
@ -69,17 +71,16 @@ public class DownloadPresenter extends BasePresenter<DownloadFragment> {
switch (download.getStatus()) { switch (download.getStatus()) {
case Download.DOWNLOADING: case Download.DOWNLOADING:
observeProgress(download, view); observeProgress(download, view);
observePagesStatus(download, view); // Initial update of the downloaded pages
view.updateDownloadedPages(download);
break; break;
case Download.DOWNLOADED: case Download.DOWNLOADED:
unsubscribeProgress(download); unsubscribeProgress(download);
unsubscribePagesStatus(download);
view.updateProgress(download); view.updateProgress(download);
view.updateDownloadedPages(download); view.updateDownloadedPages(download);
break; break;
case Download.ERROR: case Download.ERROR:
unsubscribeProgress(download); unsubscribeProgress(download);
unsubscribePagesStatus(download);
break; break;
} }
} }
@ -104,62 +105,19 @@ public class DownloadPresenter extends BasePresenter<DownloadFragment> {
progressSubscriptions.put(download, subscription); progressSubscriptions.put(download, subscription);
} }
private void observePagesStatus(Download download, DownloadFragment view) {
// Initial update of the downloaded pages
view.updateDownloadedPages(download);
PublishSubject<Integer> pageStatusSubject = PublishSubject.create();
for (Page page : download.pages) {
if (page.getStatus() != Page.READY)
page.setStatusSubject(pageStatusSubject);
}
Subscription subscription = pageStatusSubject
.filter(status -> status == Page.READY)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(status -> {
view.updateDownloadedPages(download);
});
// Avoid leaking subscriptions
Subscription oldSubscription = pageStatusSubscriptions.remove(download);
if (oldSubscription != null) oldSubscription.unsubscribe();
pageStatusSubscriptions.put(download, subscription);
}
private void unsubscribeProgress(Download download) { private void unsubscribeProgress(Download download) {
Subscription subscription = progressSubscriptions.remove(download); Subscription subscription = progressSubscriptions.remove(download);
if (subscription != null) if (subscription != null)
subscription.unsubscribe(); subscription.unsubscribe();
} }
private void unsubscribePagesStatus(Download download) {
if (download.pages != null) {
for (Page page : download.pages)
page.setStatusSubject(null);
}
Subscription subscription = pageStatusSubscriptions.remove(download);
if (subscription != null)
subscription.unsubscribe();
}
private void destroySubscriptions() { private void destroySubscriptions() {
for (Download download : pageStatusSubscriptions.keySet()) {
for (Page page : download.pages)
page.setStatusSubject(null);
}
for (Subscription subscription : pageStatusSubscriptions.values()) {
subscription.unsubscribe();
}
pageStatusSubscriptions.clear();
for (Subscription subscription : progressSubscriptions.values()) { for (Subscription subscription : progressSubscriptions.values()) {
subscription.unsubscribe(); subscription.unsubscribe();
} }
progressSubscriptions.clear(); progressSubscriptions.clear();
remove(pageProgressSubscription);
remove(statusSubscription); remove(statusSubscription);
} }