Downloads view now uses a copy of the original queue. Fixes #351 and some crashes while scrolling and removing a download from the queue

This commit is contained in:
len 2016-07-01 18:30:46 +02:00
parent 06786322ca
commit ce7118084a
5 changed files with 51 additions and 30 deletions

View File

@ -6,29 +6,41 @@ import rx.Observable
import rx.subjects.PublishSubject import rx.subjects.PublishSubject
import java.util.concurrent.CopyOnWriteArrayList import java.util.concurrent.CopyOnWriteArrayList
class DownloadQueue : CopyOnWriteArrayList<Download>() { class DownloadQueue(private val queue: MutableList<Download> = CopyOnWriteArrayList<Download>())
: List<Download> by queue {
private val statusSubject = PublishSubject.create<Download>() private val statusSubject = PublishSubject.create<Download>()
override fun add(download: Download): Boolean { private val removeSubject = PublishSubject.create<Download>()
fun add(download: Download): Boolean {
download.setStatusSubject(statusSubject) download.setStatusSubject(statusSubject)
download.status = Download.QUEUE download.status = Download.QUEUE
return super.add(download) return queue.add(download)
} }
fun del(download: Download) { fun del(download: Download) {
super.remove(download) val removed = queue.remove(download)
download.setStatusSubject(null) download.setStatusSubject(null)
if (removed) {
removeSubject.onNext(download)
}
} }
fun del(chapter: Chapter) { fun del(chapter: Chapter) {
find { it.chapter.id == chapter.id }?.let { del(it) } find { it.chapter.id == chapter.id }?.let { del(it) }
} }
fun getActiveDownloads() = fun clear() {
queue.forEach { del(it) }
}
fun getActiveDownloads(): Observable<Download> =
Observable.from(this).filter { download -> download.status == Download.DOWNLOADING } Observable.from(this).filter { download -> download.status == Download.DOWNLOADING }
fun getStatusObservable() = statusSubject.onBackpressureBuffer() fun getStatusObservable(): Observable<Download> = statusSubject.onBackpressureBuffer()
fun getRemovedObservable(): Observable<Download> = removeSubject.onBackpressureBuffer()
fun getProgressObservable(): Observable<Download> { fun getProgressObservable(): Observable<Download> {
return statusSubject.onBackpressureBuffer() return statusSubject.onBackpressureBuffer()

View File

@ -1,5 +1,6 @@
package eu.kanade.tachiyomi.data.glide package eu.kanade.tachiyomi.data.glide
import android.support.v4.util.AtomicFile
import com.bumptech.glide.Priority import com.bumptech.glide.Priority
import com.bumptech.glide.load.data.DataFetcher import com.bumptech.glide.load.data.DataFetcher
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
@ -27,16 +28,14 @@ class MangaDataFetcher(private val networkFetcher: DataFetcher<InputStream>,
override fun loadData(priority: Priority): InputStream? { override fun loadData(priority: Priority): InputStream? {
if (manga.favorite) { if (manga.favorite) {
if (!file.exists()) { if (!file.exists()) {
file.parentFile.mkdirs() networkFetcher.loadData(priority)?.let { input ->
networkFetcher.loadData(priority)?.let { val atomicFile = AtomicFile(file)
val output = atomicFile.startWrite()
try { try {
it.use { input -> input.use { it.copyTo(output) }
file.outputStream().use { output -> atomicFile.finishWrite(output)
input.copyTo(output)
}
}
} catch (e: Exception) { } catch (e: Exception) {
file.delete() atomicFile.failWrite(output)
throw e throw e
} }
} }

View File

@ -236,6 +236,10 @@ class DownloadFragment : BaseRxFragment<DownloadPresenter>() {
adapter.setItems(downloads) adapter.setItems(downloads)
} }
fun onDownloadRemoved(position: Int) {
adapter.notifyItemRemoved(position)
}
/** /**
* Called when the progress of a download changes. * Called when the progress of a download changes.
* *

View File

@ -6,21 +6,16 @@ import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.data.download.model.DownloadQueue import eu.kanade.tachiyomi.data.download.model.DownloadQueue
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import rx.Observable import rx.Observable
import rx.android.schedulers.AndroidSchedulers
import timber.log.Timber import timber.log.Timber
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.util.*
/** /**
* Presenter of [DownloadFragment]. * Presenter of [DownloadFragment].
*/ */
class DownloadPresenter : BasePresenter<DownloadFragment>() { class DownloadPresenter : BasePresenter<DownloadFragment>() {
companion object {
/**
* Id of the restartable that returns the download queue.
*/
const val GET_DOWNLOAD_QUEUE = 1
}
/** /**
* Download manager. * Download manager.
*/ */
@ -35,14 +30,27 @@ class DownloadPresenter : BasePresenter<DownloadFragment>() {
override fun onCreate(savedState: Bundle?) { override fun onCreate(savedState: Bundle?) {
super.onCreate(savedState) super.onCreate(savedState)
restartableLatestCache(GET_DOWNLOAD_QUEUE, Observable.just(ArrayList(downloadQueue))
{ Observable.just(downloadQueue) }, .doOnNext { syncQueue(it) }
{ view, downloads -> view.onNextDownloads(downloads) }, .subscribeLatestCache({ view, downloads ->
{ view, error -> Timber.e(error.message) }) view.onNextDownloads(downloads)
}, { view, error ->
if (savedState == null) { Timber.e(error, error.message)
start(GET_DOWNLOAD_QUEUE) })
} }
private fun syncQueue(queue: MutableList<Download>) {
add(downloadQueue.getRemovedObservable()
.observeOn(AndroidSchedulers.mainThread())
.subscribe { download ->
val position = queue.indexOf(download)
if (position != -1) {
queue.removeAt(position)
@Suppress("DEPRECATION")
view?.onDownloadRemoved(position)
}
})
} }
fun getStatusObservable(): Observable<Download> { fun getStatusObservable(): Observable<Download> {
@ -60,7 +68,6 @@ class DownloadPresenter : BasePresenter<DownloadFragment>() {
*/ */
fun clearQueue() { fun clearQueue() {
downloadManager.clearQueue() downloadManager.clearQueue()
start(GET_DOWNLOAD_QUEUE)
} }
} }

View File

@ -47,7 +47,6 @@ class LibraryHolder(private val view: View,
.load(manga) .load(manga)
.diskCacheStrategy(DiskCacheStrategy.RESULT) .diskCacheStrategy(DiskCacheStrategy.RESULT)
.centerCrop() .centerCrop()
.placeholder(android.R.color.transparent)
.into(view.thumbnail) .into(view.thumbnail)
} }