소스 검색

Allow to start/stop queue from download queue fragment. DownloadQueue now extends from ArrayList.

inorichi 9 년 전
부모
커밋
3c87b4cba9

+ 20 - 21
app/src/main/java/eu/kanade/mangafeed/data/download/DownloadManager.java

@@ -42,11 +42,11 @@ public class DownloadManager {
 
     private PublishSubject<Download> downloadsQueueSubject;
     private BehaviorSubject<Integer> threadsNumber;
+    private BehaviorSubject<Boolean> runningSubject;
     private Subscription downloadsSubscription;
     private Subscription threadsNumberSubscription;
 
     private DownloadQueue queue;
-    private volatile boolean isQueuePaused;
     private volatile boolean isRunning;
 
     public static final String PAGE_LIST_FILE = "index.json";
@@ -61,9 +61,10 @@ public class DownloadManager {
 
         downloadsQueueSubject = PublishSubject.create();
         threadsNumber = BehaviorSubject.create();
+        runningSubject = BehaviorSubject.create();
     }
 
-    public void initializeSubscriptions() {
+    private void initializeSubscriptions() {
         if (downloadsSubscription != null && !downloadsSubscription.isUnsubscribed())
             downloadsSubscription.unsubscribe();
 
@@ -71,8 +72,6 @@ public class DownloadManager {
             threadsNumberSubscription.unsubscribe();
 
         threadsNumberSubscription = preferences.getDownloadTheadsObservable()
-                .filter(n -> !isQueuePaused)
-                .doOnNext(n -> isQueuePaused = (n == 0))
                 .subscribe(threadsNumber::onNext);
 
         downloadsSubscription = downloadsQueueSubject
@@ -86,11 +85,17 @@ public class DownloadManager {
                     }
                 }, e -> Timber.e(e.getCause(), e.getMessage()));
 
-        isRunning = true;
+        if (!isRunning) {
+            isRunning = true;
+            runningSubject.onNext(true);
+        }
     }
 
     public void destroySubscriptions() {
-        isRunning = false;
+        if (isRunning) {
+            isRunning = false;
+            runningSubject.onNext(false);
+        }
 
         if (downloadsSubscription != null && !downloadsSubscription.isUnsubscribed()) {
             downloadsSubscription.unsubscribe();
@@ -131,7 +136,7 @@ public class DownloadManager {
     // Prepare the download. Returns true if the chapter is already downloaded
     private boolean prepareDownload(Download download) {
         // If the chapter is already queued, don't add it again
-        for (Download queuedDownload : queue.get()) {
+        for (Download queuedDownload : queue) {
             if (download.chapter.id.equals(queuedDownload.chapter.id))
                 return true;
         }
@@ -376,28 +381,22 @@ public class DownloadManager {
     }
 
     public boolean areAllDownloadsFinished() {
-        for (Download download : queue.get()) {
+        for (Download download : queue) {
             if (download.getStatus() <= Download.DOWNLOADING)
                 return false;
         }
         return true;
     }
 
-    public void resumeDownloads() {
-        isQueuePaused = false;
-        threadsNumber.onNext(preferences.getDownloadThreads());
-    }
-
-    public void pauseDownloads() {
-        threadsNumber.onNext(0);
-    }
-
     public boolean startDownloads() {
+        if (queue.isEmpty())
+            return false;
+
         boolean hasPendingDownloads = false;
         if (downloadsSubscription == null || threadsNumberSubscription == null)
             initializeSubscriptions();
 
-        for (Download download : queue.get()) {
+        for (Download download : queue) {
             if (download.getStatus() != Download.DOWNLOADED) {
                 if (download.getStatus() != Download.QUEUE) download.setStatus(Download.QUEUE);
                 if (!hasPendingDownloads) hasPendingDownloads = true;
@@ -409,15 +408,15 @@ public class DownloadManager {
 
     public void stopDownloads() {
         destroySubscriptions();
-        for (Download download : queue.get()) {
+        for (Download download : queue) {
             if (download.getStatus() == Download.DOWNLOADING) {
                 download.setStatus(Download.ERROR);
             }
         }
     }
 
-    public boolean isRunning() {
-        return isRunning;
+    public BehaviorSubject<Boolean> getRunningSubject() {
+        return runningSubject;
     }
 
 }

+ 13 - 5
app/src/main/java/eu/kanade/mangafeed/data/download/DownloadService.java

@@ -24,6 +24,7 @@ public class DownloadService extends Service {
 
     private PowerManager.WakeLock wakeLock;
     private Subscription networkChangeSubscription;
+    private Subscription queueRunningSubscription;
 
     public static void start(Context context) {
         context.startService(new Intent(context, DownloadService.class));
@@ -40,6 +41,7 @@ public class DownloadService extends Service {
 
         createWakeLock();
 
+        listenQueueRunningChanges();
         EventBus.getDefault().registerSticky(this);
         listenNetworkChanges();
     }
@@ -52,6 +54,7 @@ public class DownloadService extends Service {
     @Override
     public void onDestroy() {
         EventBus.getDefault().unregister(this);
+        queueRunningSubscription.unsubscribe();
         networkChangeSubscription.unsubscribe();
         downloadManager.destroySubscriptions();
         destroyWakeLock();
@@ -67,8 +70,6 @@ public class DownloadService extends Service {
     public void onEvent(DownloadChaptersEvent event) {
         EventBus.getDefault().removeStickyEvent(event);
         downloadManager.onDownloadChaptersEvent(event);
-        if (downloadManager.isRunning())
-            acquireWakeLock();
     }
 
     private void listenNetworkChanges() {
@@ -79,15 +80,22 @@ public class DownloadService extends Service {
                         // If there are no remaining downloads, destroy the service
                         if (!downloadManager.startDownloads())
                             stopSelf();
-                        else
-                            acquireWakeLock();
                     } else {
                         downloadManager.stopDownloads();
-                        releaseWakeLock();
                     }
                 });
     }
 
+    private void listenQueueRunningChanges() {
+        queueRunningSubscription = downloadManager.getRunningSubject()
+                .subscribe(running -> {
+                    if (running)
+                        acquireWakeLock();
+                    else
+                        releaseWakeLock();
+                });
+    }
+
     private void createWakeLock() {
         wakeLock = ((PowerManager)getSystemService(POWER_SERVICE)).newWakeLock(
                 PowerManager.PARTIAL_WAKE_LOCK, "DownloadService:WakeLock");

+ 7 - 12
app/src/main/java/eu/kanade/mangafeed/data/download/model/DownloadQueue.java

@@ -8,29 +8,28 @@ import eu.kanade.mangafeed.data.source.model.Page;
 import rx.Observable;
 import rx.subjects.PublishSubject;
 
-public class DownloadQueue {
+public class DownloadQueue extends ArrayList<Download> {
 
-    private List<Download> queue;
     private PublishSubject<Download> statusSubject;
 
     public DownloadQueue() {
-        queue = new ArrayList<>();
+        super();
         statusSubject = PublishSubject.create();
     }
 
-    public void add(Download download) {
+    public boolean add(Download download) {
         download.setStatusSubject(statusSubject);
         download.setStatus(Download.QUEUE);
-        queue.add(download);
+        return super.add(download);
     }
 
     public void remove(Download download) {
-        queue.remove(download);
+        super.remove(download);
         download.setStatusSubject(null);
     }
 
     public void remove(Chapter chapter) {
-        for (Download download : queue) {
+        for (Download download : this) {
             if (download.chapter.id.equals(chapter.id)) {
                 remove(download);
                 break;
@@ -38,12 +37,8 @@ public class DownloadQueue {
         }
     }
 
-    public List<Download> get() {
-        return queue;
-    }
-
     public Observable<Download> getActiveDownloads() {
-        return Observable.from(queue)
+        return Observable.from(this)
                 .filter(download -> download.getStatus() == Download.DOWNLOADING);
     }
 

+ 62 - 0
app/src/main/java/eu/kanade/mangafeed/ui/download/DownloadFragment.java

@@ -5,6 +5,9 @@ import android.support.annotation.Nullable;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -13,9 +16,11 @@ import java.util.List;
 import butterknife.Bind;
 import butterknife.ButterKnife;
 import eu.kanade.mangafeed.R;
+import eu.kanade.mangafeed.data.download.DownloadService;
 import eu.kanade.mangafeed.data.download.model.Download;
 import eu.kanade.mangafeed.ui.base.fragment.BaseRxFragment;
 import nucleus.factory.RequiresPresenter;
+import rx.Subscription;
 
 @RequiresPresenter(DownloadPresenter.class)
 public class DownloadFragment extends BaseRxFragment<DownloadPresenter> {
@@ -23,10 +28,22 @@ public class DownloadFragment extends BaseRxFragment<DownloadPresenter> {
     @Bind(R.id.download_list) RecyclerView recyclerView;
     private DownloadAdapter adapter;
 
+    private MenuItem startButton;
+    private MenuItem stopButton;
+
+    private Subscription queueStatusSubscription;
+    private boolean isRunning;
+
     public static DownloadFragment newInstance() {
         return new DownloadFragment();
     }
 
+    @Override
+    public void onCreate(Bundle bundle) {
+        super.onCreate(bundle);
+        setHasOptionsMenu(true);
+    }
+
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
                              Bundle savedInstanceState) {
@@ -43,6 +60,51 @@ public class DownloadFragment extends BaseRxFragment<DownloadPresenter> {
         return view;
     }
 
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        inflater.inflate(R.menu.download_queue, menu);
+        startButton = menu.findItem(R.id.start_queue);
+        stopButton = menu.findItem(R.id.stop_queue);
+
+        // Menu seems to be inflated after onResume in fragments, so we initialize them here
+        startButton.setVisible(!isRunning && !getPresenter().downloadManager.getQueue().isEmpty());
+        stopButton.setVisible(isRunning);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.start_queue:
+                DownloadService.start(getActivity());
+                break;
+            case R.id.stop_queue:
+                DownloadService.stop(getActivity());
+                break;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        queueStatusSubscription = getPresenter().downloadManager.getRunningSubject()
+                .subscribe(this::onRunningChange);
+    }
+
+    @Override
+    public void onPause() {
+        queueStatusSubscription.unsubscribe();
+        super.onPause();
+    }
+
+    private void onRunningChange(boolean running) {
+        isRunning = running;
+        if (startButton != null)
+            startButton.setVisible(!running && !getPresenter().downloadManager.getQueue().isEmpty());
+        if (stopButton != null)
+            stopButton.setVisible(running);
+    }
+
     private void createAdapter() {
         adapter = new DownloadAdapter(getActivity());
         recyclerView.setAdapter(adapter);

+ 1 - 1
app/src/main/java/eu/kanade/mangafeed/ui/download/DownloadPresenter.java

@@ -37,7 +37,7 @@ public class DownloadPresenter extends BasePresenter<DownloadFragment> {
         progressSubscriptions = new HashMap<>();
 
         restartableLatestCache(GET_DOWNLOAD_QUEUE,
-                () -> Observable.just(downloadQueue.get()),
+                () -> Observable.just(downloadQueue),
                 DownloadFragment::onNextDownloads,
                 (view, error) -> Timber.e(error.getMessage()));
 

+ 1 - 1
app/src/main/java/eu/kanade/mangafeed/ui/manga/chapter/ChaptersPresenter.java

@@ -148,7 +148,7 @@ public class ChaptersPresenter extends BasePresenter<ChaptersFragment> {
     }
 
     private void setChapterStatus(Chapter chapter) {
-        for (Download download : downloadManager.getQueue().get()) {
+        for (Download download : downloadManager.getQueue()) {
             if (chapter.id.equals(download.chapter.id)) {
                 chapter.status = download.getStatus();
                 return;

BIN
app/src/main/res/drawable-hdpi/ic_play_arrow.png


BIN
app/src/main/res/drawable-hdpi/ic_stop.png


BIN
app/src/main/res/drawable-ldpi/ic_play_arrow.png


BIN
app/src/main/res/drawable-ldpi/ic_stop.png


BIN
app/src/main/res/drawable-mdpi/ic_play_arrow.png


BIN
app/src/main/res/drawable-mdpi/ic_stop.png


BIN
app/src/main/res/drawable-xhdpi/ic_play_arrow.png


BIN
app/src/main/res/drawable-xhdpi/ic_stop.png


BIN
app/src/main/res/drawable-xxhdpi/ic_play_arrow.png


BIN
app/src/main/res/drawable-xxhdpi/ic_stop.png


BIN
app/src/main/res/drawable-xxxhdpi/ic_play_arrow.png


BIN
app/src/main/res/drawable-xxxhdpi/ic_stop.png


+ 17 - 0
app/src/main/res/menu/download_queue.xml

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+      xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <item android:title="@string/action_start"
+          android:id="@+id/start_queue"
+          android:icon="@drawable/ic_play_arrow"
+          android:visible="false"
+          app:showAsAction="ifRoom"/>
+
+    <item android:title="@string/action_stop"
+          android:id="@+id/stop_queue"
+          android:icon="@drawable/ic_stop"
+          android:visible="false"
+          app:showAsAction="ifRoom"/>
+
+</menu>

+ 2 - 0
app/src/main/res/values/strings.xml

@@ -24,6 +24,8 @@
     <string name="action_show_unread">Unread</string>
     <string name="action_show_downloaded">Downloaded</string>
     <string name="action_next_unread">Next unread</string>
+    <string name="action_start">Start</string>
+    <string name="action_stop">Stop</string>
 
     <!-- Buttons -->
     <string name="button_ok">OK</string>