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:
parent
06786322ca
commit
ce7118084a
@ -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()
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
*
|
*
|
||||||
|
@ -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.
|
||||||
*/
|
*/
|
||||||
@ -34,15 +29,28 @@ class DownloadPresenter : BasePresenter<DownloadFragment>() {
|
|||||||
|
|
||||||
override fun onCreate(savedState: Bundle?) {
|
override fun onCreate(savedState: Bundle?) {
|
||||||
super.onCreate(savedState)
|
super.onCreate(savedState)
|
||||||
|
|
||||||
|
Observable.just(ArrayList(downloadQueue))
|
||||||
|
.doOnNext { syncQueue(it) }
|
||||||
|
.subscribeLatestCache({ view, downloads ->
|
||||||
|
view.onNextDownloads(downloads)
|
||||||
|
}, { view, error ->
|
||||||
|
Timber.e(error, error.message)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
restartableLatestCache(GET_DOWNLOAD_QUEUE,
|
private fun syncQueue(queue: MutableList<Download>) {
|
||||||
{ Observable.just(downloadQueue) },
|
add(downloadQueue.getRemovedObservable()
|
||||||
{ view, downloads -> view.onNextDownloads(downloads) },
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
{ view, error -> Timber.e(error.message) })
|
.subscribe { download ->
|
||||||
|
val position = queue.indexOf(download)
|
||||||
|
if (position != -1) {
|
||||||
|
queue.removeAt(position)
|
||||||
|
|
||||||
if (savedState == null) {
|
@Suppress("DEPRECATION")
|
||||||
start(GET_DOWNLOAD_QUEUE)
|
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user