Replace some usages of RxJava
This commit is contained in:
parent
cbcab5a545
commit
788583e66f
6 changed files with 144 additions and 145 deletions
|
@ -1,10 +1,12 @@
|
||||||
package eu.kanade.tachiyomi.data.download.model
|
package eu.kanade.tachiyomi.data.download.model
|
||||||
|
|
||||||
import com.jakewharton.rxrelay.PublishRelay
|
import com.jakewharton.rxrelay.PublishRelay
|
||||||
|
import eu.kanade.core.util.asFlow
|
||||||
import eu.kanade.domain.manga.model.Manga
|
import eu.kanade.domain.manga.model.Manga
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadStore
|
import eu.kanade.tachiyomi.data.download.DownloadStore
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.subjects.PublishSubject
|
import rx.subjects.PublishSubject
|
||||||
import java.util.concurrent.CopyOnWriteArrayList
|
import java.util.concurrent.CopyOnWriteArrayList
|
||||||
|
@ -72,8 +74,11 @@ class DownloadQueue(
|
||||||
fun getActiveDownloads(): Observable<Download> =
|
fun getActiveDownloads(): Observable<Download> =
|
||||||
Observable.from(this).filter { download -> download.status == Download.State.DOWNLOADING }
|
Observable.from(this).filter { download -> download.status == Download.State.DOWNLOADING }
|
||||||
|
|
||||||
|
@Deprecated("Use getStatusAsFlow instead")
|
||||||
fun getStatusObservable(): Observable<Download> = statusSubject.onBackpressureBuffer()
|
fun getStatusObservable(): Observable<Download> = statusSubject.onBackpressureBuffer()
|
||||||
|
|
||||||
|
fun getStatusAsFlow(): Flow<Download> = getStatusObservable().asFlow()
|
||||||
|
|
||||||
fun getUpdatedObservable(): Observable<List<Download>> = updatedRelay.onBackpressureBuffer()
|
fun getUpdatedObservable(): Observable<List<Download>> = updatedRelay.onBackpressureBuffer()
|
||||||
.startWith(Unit)
|
.startWith(Unit)
|
||||||
.map { this }
|
.map { this }
|
||||||
|
@ -84,6 +89,7 @@ class DownloadQueue(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated("Use getProgressAsFlow instead")
|
||||||
fun getProgressObservable(): Observable<Download> {
|
fun getProgressObservable(): Observable<Download> {
|
||||||
return statusSubject.onBackpressureBuffer()
|
return statusSubject.onBackpressureBuffer()
|
||||||
.startWith(getActiveDownloads())
|
.startWith(getActiveDownloads())
|
||||||
|
@ -103,6 +109,10 @@ class DownloadQueue(
|
||||||
.filter { it.status == Download.State.DOWNLOADING }
|
.filter { it.status == Download.State.DOWNLOADING }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getProgressAsFlow(): Flow<Download> {
|
||||||
|
return getProgressObservable().asFlow()
|
||||||
|
}
|
||||||
|
|
||||||
private fun setPagesSubject(pages: List<Page>?, subject: PublishSubject<Int>?) {
|
private fun setPagesSubject(pages: List<Page>?, subject: PublishSubject<Int>?) {
|
||||||
pages?.forEach { it.setStatusSubject(subject) }
|
pages?.forEach { it.setStatusSubject(subject) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,13 +57,4 @@ open class BasePresenter<V> : RxPresenter<V>() {
|
||||||
* @param onError function to execute when the observable throws an error.
|
* @param onError function to execute when the observable throws an error.
|
||||||
*/
|
*/
|
||||||
fun <T> Observable<T>.subscribeLatestCache(onNext: (V, T) -> Unit, onError: ((V, Throwable) -> Unit) = { _, _ -> }) = compose(deliverLatestCache<T>()).subscribe(split(onNext, onError)).apply { add(this) }
|
fun <T> Observable<T>.subscribeLatestCache(onNext: (V, T) -> Unit, onError: ((V, Throwable) -> Unit) = { _, _ -> }) = compose(deliverLatestCache<T>()).subscribe(split(onNext, onError)).apply { add(this) }
|
||||||
|
|
||||||
/**
|
|
||||||
* Subscribes an observable with [deliverReplay] and adds it to the presenter's lifecycle
|
|
||||||
* subscription list.
|
|
||||||
*
|
|
||||||
* @param onNext function to execute when the observable emits an item.
|
|
||||||
* @param onError function to execute when the observable throws an error.
|
|
||||||
*/
|
|
||||||
fun <T> Observable<T>.subscribeReplay(onNext: (V, T) -> Unit, onError: ((V, Throwable) -> Unit) = { _, _ -> }) = compose(deliverReplay<T>()).subscribe(split(onNext, onError)).apply { add(this) }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,15 +51,13 @@ import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.asFlow
|
import kotlinx.coroutines.flow.asFlow
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.flow.firstOrNull
|
import kotlinx.coroutines.flow.firstOrNull
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import rx.Subscription
|
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
|
||||||
import rx.schedulers.Schedulers
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
@ -112,7 +110,7 @@ open class BrowseSourcePresenter(
|
||||||
/**
|
/**
|
||||||
* Subscription for the pager.
|
* Subscription for the pager.
|
||||||
*/
|
*/
|
||||||
private var pagerSubscription: Subscription? = null
|
private var pagerJob: Job? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subscription for one request from the pager.
|
* Subscription for one request from the pager.
|
||||||
|
@ -129,7 +127,6 @@ open class BrowseSourcePresenter(
|
||||||
super.onCreate(savedState)
|
super.onCreate(savedState)
|
||||||
|
|
||||||
source = sourceManager.get(sourceId) as? CatalogueSource ?: return
|
source = sourceManager.get(sourceId) as? CatalogueSource ?: return
|
||||||
|
|
||||||
sourceFilters = source.getFilterList()
|
sourceFilters = source.getFilterList()
|
||||||
|
|
||||||
if (savedState != null) {
|
if (savedState != null) {
|
||||||
|
@ -158,25 +155,37 @@ open class BrowseSourcePresenter(
|
||||||
pager = createPager(query, filters)
|
pager = createPager(query, filters)
|
||||||
|
|
||||||
val sourceId = source.id
|
val sourceId = source.id
|
||||||
|
|
||||||
val sourceDisplayMode = prefs.sourceDisplayMode()
|
val sourceDisplayMode = prefs.sourceDisplayMode()
|
||||||
|
|
||||||
// Prepare the pager.
|
pagerJob?.cancel()
|
||||||
pagerSubscription?.let { remove(it) }
|
pagerJob = presenterScope.launchIO {
|
||||||
pagerSubscription = pager.results()
|
pager.asFlow()
|
||||||
.observeOn(Schedulers.io())
|
.map { (first, second) ->
|
||||||
.map { (first, second) -> first to second.map { networkToLocalManga(it, sourceId).toDomainManga()!! } }
|
first to second.map {
|
||||||
.doOnNext { initializeMangas(it.second) }
|
networkToLocalManga(
|
||||||
.map { (first, second) -> first to second.map { SourceItem(it, sourceDisplayMode) } }
|
it,
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
sourceId,
|
||||||
.subscribeReplay(
|
).toDomainManga()!!
|
||||||
{ view, (page, mangas) ->
|
}
|
||||||
view.onAddPage(page, mangas)
|
}
|
||||||
},
|
.onEach { initializeMangas(it.second) }
|
||||||
{ _, error ->
|
.map { (first, second) ->
|
||||||
logcat(LogPriority.ERROR, error)
|
first to second.map {
|
||||||
},
|
SourceItem(
|
||||||
|
it,
|
||||||
|
sourceDisplayMode,
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.catch { error ->
|
||||||
|
logcat(LogPriority.ERROR, error)
|
||||||
|
}
|
||||||
|
.collectLatest { (page, mangas) ->
|
||||||
|
withUIContext {
|
||||||
|
view?.onAddPage(page, mangas)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Request first page.
|
// Request first page.
|
||||||
requestNext()
|
requestNext()
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package eu.kanade.tachiyomi.ui.browse.source.browse
|
package eu.kanade.tachiyomi.ui.browse.source.browse
|
||||||
|
|
||||||
import com.jakewharton.rxrelay.PublishRelay
|
import com.jakewharton.rxrelay.PublishRelay
|
||||||
|
import eu.kanade.core.util.asFlow
|
||||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import rx.Observable
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A general pager for source requests (latest updates, popular, search)
|
* A general pager for source requests (latest updates, popular, search)
|
||||||
|
@ -15,8 +16,8 @@ abstract class Pager(var currentPage: Int = 1) {
|
||||||
|
|
||||||
protected val results: PublishRelay<Pair<Int, List<SManga>>> = PublishRelay.create()
|
protected val results: PublishRelay<Pair<Int, List<SManga>>> = PublishRelay.create()
|
||||||
|
|
||||||
fun results(): Observable<Pair<Int, List<SManga>>> {
|
fun asFlow(): Flow<Pair<Int, List<SManga>>> {
|
||||||
return results.asObservable()
|
return results.asObservable().asFlow()
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract suspend fun requestNextPage()
|
abstract suspend fun requestNextPage()
|
||||||
|
|
|
@ -59,6 +59,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
|
@ -66,9 +67,6 @@ import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.supervisorScope
|
import kotlinx.coroutines.supervisorScope
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import rx.Subscription
|
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
|
||||||
import rx.schedulers.Schedulers
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
|
@ -119,8 +117,8 @@ class MangaPresenter(
|
||||||
/**
|
/**
|
||||||
* Subscription to observe download status changes.
|
* Subscription to observe download status changes.
|
||||||
*/
|
*/
|
||||||
private var observeDownloadsStatusSubscription: Subscription? = null
|
private var observeDownloadsStatusJob: Job? = null
|
||||||
private var observeDownloadsPageSubscription: Subscription? = null
|
private var observeDownloadsPageJob: Job? = null
|
||||||
|
|
||||||
private var _trackList: List<TrackItem> = emptyList()
|
private var _trackList: List<TrackItem> = emptyList()
|
||||||
val trackList get() = _trackList
|
val trackList get() = _trackList
|
||||||
|
@ -401,29 +399,29 @@ class MangaPresenter(
|
||||||
// Chapters list - start
|
// Chapters list - start
|
||||||
|
|
||||||
private fun observeDownloads() {
|
private fun observeDownloads() {
|
||||||
observeDownloadsStatusSubscription?.let { remove(it) }
|
observeDownloadsStatusJob?.cancel()
|
||||||
observeDownloadsStatusSubscription = downloadManager.queue.getStatusObservable()
|
observeDownloadsStatusJob = presenterScope.launchIO {
|
||||||
.observeOn(Schedulers.io())
|
downloadManager.queue.getStatusAsFlow()
|
||||||
.onBackpressureBuffer()
|
.filter { it.manga.id == successState?.manga?.id }
|
||||||
.filter { download -> download.manga.id == successState?.manga?.id }
|
.catch { error -> logcat(LogPriority.ERROR, error) }
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.collectLatest {
|
||||||
.subscribeLatestCache(
|
withUIContext {
|
||||||
{ _, it -> updateDownloadState(it) },
|
updateDownloadState(it)
|
||||||
{ _, error ->
|
}
|
||||||
logcat(LogPriority.ERROR, error)
|
}
|
||||||
},
|
}
|
||||||
)
|
|
||||||
|
|
||||||
observeDownloadsPageSubscription?.let { remove(it) }
|
observeDownloadsPageJob?.cancel()
|
||||||
observeDownloadsPageSubscription = downloadManager.queue.getProgressObservable()
|
observeDownloadsPageJob = presenterScope.launchIO {
|
||||||
.observeOn(Schedulers.io())
|
downloadManager.queue.getProgressAsFlow()
|
||||||
.onBackpressureBuffer()
|
.filter { it.manga.id == successState?.manga?.id }
|
||||||
.filter { download -> download.manga.id == successState?.manga?.id }
|
.catch { error -> logcat(LogPriority.ERROR, error) }
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.collectLatest {
|
||||||
.subscribeLatestCache(
|
withUIContext {
|
||||||
{ _, download -> updateDownloadState(download) },
|
updateDownloadState(it)
|
||||||
{ _, error -> logcat(LogPriority.ERROR, error) },
|
}
|
||||||
)
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateDownloadState(download: Download) {
|
private fun updateDownloadState(download: Download) {
|
||||||
|
|
|
@ -17,31 +17,30 @@ import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||||
import eu.kanade.tachiyomi.ui.recent.DateSectionItem
|
import eu.kanade.tachiyomi.ui.recent.DateSectionItem
|
||||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||||
import eu.kanade.tachiyomi.util.lang.toDateKey
|
import eu.kanade.tachiyomi.util.lang.toDateKey
|
||||||
|
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||||
import eu.kanade.tachiyomi.util.system.logcat
|
import eu.kanade.tachiyomi.util.system.logcat
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import rx.Observable
|
import uy.kohesive.injekt.Injekt
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import uy.kohesive.injekt.api.get
|
||||||
import rx.schedulers.Schedulers
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.TreeMap
|
import java.util.TreeMap
|
||||||
|
|
||||||
class UpdatesPresenter : BasePresenter<UpdatesController>() {
|
class UpdatesPresenter(
|
||||||
|
private val preferences: PreferencesHelper = Injekt.get(),
|
||||||
val preferences: PreferencesHelper by injectLazy()
|
private val downloadManager: DownloadManager = Injekt.get(),
|
||||||
private val downloadManager: DownloadManager by injectLazy()
|
private val sourceManager: SourceManager = Injekt.get(),
|
||||||
private val sourceManager: SourceManager by injectLazy()
|
private val handler: DatabaseHandler = Injekt.get(),
|
||||||
|
private val updateChapter: UpdateChapter = Injekt.get(),
|
||||||
private val handler: DatabaseHandler by injectLazy()
|
private val setReadStatus: SetReadStatus = Injekt.get(),
|
||||||
private val updateChapter: UpdateChapter by injectLazy()
|
) : BasePresenter<UpdatesController>() {
|
||||||
private val setReadStatus: SetReadStatus by injectLazy()
|
|
||||||
|
|
||||||
private val relativeTime: Int = preferences.relativeTime().get()
|
private val relativeTime: Int = preferences.relativeTime().get()
|
||||||
private val dateFormat: DateFormat = preferences.dateFormat()
|
private val dateFormat: DateFormat = preferences.dateFormat()
|
||||||
|
@ -52,39 +51,33 @@ class UpdatesPresenter : BasePresenter<UpdatesController>() {
|
||||||
override fun onCreate(savedState: Bundle?) {
|
override fun onCreate(savedState: Bundle?) {
|
||||||
super.onCreate(savedState)
|
super.onCreate(savedState)
|
||||||
|
|
||||||
getUpdatesObservable()
|
presenterScope.launchIO {
|
||||||
|
subscribeToUpdates()
|
||||||
|
|
||||||
downloadManager.queue.getStatusObservable()
|
downloadManager.queue.getStatusAsFlow()
|
||||||
.observeOn(Schedulers.io())
|
.catch { error -> logcat(LogPriority.ERROR, error) }
|
||||||
.onBackpressureBuffer()
|
.collectLatest {
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
withUIContext {
|
||||||
.subscribeLatestCache(
|
|
||||||
{ view, it ->
|
|
||||||
onDownloadStatusChange(it)
|
onDownloadStatusChange(it)
|
||||||
view.onChapterDownloadUpdate(it)
|
view?.onChapterDownloadUpdate(it)
|
||||||
},
|
}
|
||||||
{ _, error ->
|
}
|
||||||
logcat(LogPriority.ERROR, error)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
downloadManager.queue.getProgressObservable()
|
downloadManager.queue.getProgressAsFlow()
|
||||||
.observeOn(Schedulers.io())
|
.catch { error -> logcat(LogPriority.ERROR, error) }
|
||||||
.onBackpressureBuffer()
|
.collectLatest {
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
withUIContext {
|
||||||
.subscribeLatestCache(UpdatesController::onChapterDownloadUpdate) { _, error ->
|
view?.onChapterDownloadUpdate(it)
|
||||||
logcat(LogPriority.ERROR, error)
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get observable containing recent chapters and date
|
* Get observable containing recent chapters and date
|
||||||
*
|
|
||||||
* @return observable containing recent chapters and date
|
|
||||||
*/
|
*/
|
||||||
private fun getUpdatesObservable() {
|
private suspend fun subscribeToUpdates() {
|
||||||
// Set date limit for recent chapters
|
// Set date limit for recent chapters
|
||||||
presenterScope.launchIO {
|
|
||||||
val cal = Calendar.getInstance().apply {
|
val cal = Calendar.getInstance().apply {
|
||||||
time = Date()
|
time = Date()
|
||||||
add(Calendar.MONTH, -3)
|
add(Calendar.MONTH, -3)
|
||||||
|
@ -123,7 +116,6 @@ class UpdatesPresenter : BasePresenter<UpdatesController>() {
|
||||||
preferences.unreadUpdatesCount().set(list.count { !it.chapter.read })
|
preferences.unreadUpdatesCount().set(list.count { !it.chapter.read })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds and assigns the list of downloaded chapters.
|
* Finds and assigns the list of downloaded chapters.
|
||||||
|
@ -184,16 +176,14 @@ class UpdatesPresenter : BasePresenter<UpdatesController>() {
|
||||||
* @param chapters list of chapters
|
* @param chapters list of chapters
|
||||||
*/
|
*/
|
||||||
fun deleteChapters(chapters: List<UpdatesItem>) {
|
fun deleteChapters(chapters: List<UpdatesItem>) {
|
||||||
Observable.just(chapters)
|
launchIO {
|
||||||
.doOnNext { deleteChaptersInternal(it) }
|
try {
|
||||||
.subscribeOn(Schedulers.io())
|
deleteChaptersInternal(chapters)
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
withUIContext { view?.onChaptersDeleted() }
|
||||||
.subscribeFirst(
|
} catch (e: Throwable) {
|
||||||
{ view, _ ->
|
withUIContext { view?.onChaptersDeletedError(e) }
|
||||||
view.onChaptersDeleted()
|
}
|
||||||
},
|
}
|
||||||
UpdatesController::onChaptersDeletedError,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Reference in a new issue