Use Coroutines for Feed

This commit is contained in:
Jobobby04 2022-11-30 14:12:20 -05:00
parent c14b7879a4
commit 07f0e73d6c

View File

@ -21,7 +21,7 @@ import eu.kanade.presentation.browse.FeedItemUI
import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.CatalogueSource
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.util.lang.awaitSingle
import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.util.lang.launchIO
import eu.kanade.tachiyomi.util.lang.launchNonCancellable import eu.kanade.tachiyomi.util.lang.launchNonCancellable
import eu.kanade.tachiyomi.util.lang.withIOContext import eu.kanade.tachiyomi.util.lang.withIOContext
@ -30,6 +30,7 @@ import eu.kanade.tachiyomi.util.system.LocaleHelper
import eu.kanade.tachiyomi.util.system.logcat import eu.kanade.tachiyomi.util.system.logcat
import exh.savedsearches.models.FeedSavedSearch import exh.savedsearches.models.FeedSavedSearch
import exh.savedsearches.models.SavedSearch import exh.savedsearches.models.SavedSearch
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
@ -37,17 +38,15 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.serialization.decodeFromString import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import logcat.LogPriority import logcat.LogPriority
import rx.Observable
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 xyz.nulldev.ts.api.http.serializer.FilterSerializer import xyz.nulldev.ts.api.http.serializer.FilterSerializer
import java.util.concurrent.Executors
import eu.kanade.domain.manga.model.Manga as DomainManga import eu.kanade.domain.manga.model.Manga as DomainManga
/** /**
@ -70,10 +69,7 @@ open class FeedScreenModel(
private val _events = Channel<Event>(Int.MAX_VALUE) private val _events = Channel<Event>(Int.MAX_VALUE)
val events = _events.receiveAsFlow() val events = _events.receiveAsFlow()
/** private val coroutineDispatcher = Executors.newFixedThreadPool(1).asCoroutineDispatcher()
* Fetches the different sources by user settings.
*/
private var fetchSourcesSubscription: Subscription? = null
init { init {
getFeedSavedSearchGlobal.subscribe() getFeedSavedSearchGlobal.subscribe()
@ -205,44 +201,43 @@ open class FeedScreenModel(
* Initiates get manga per feed. * Initiates get manga per feed.
*/ */
private fun getFeed(feedSavedSearch: List<FeedItemUI>) { private fun getFeed(feedSavedSearch: List<FeedItemUI>) {
fetchSourcesSubscription?.unsubscribe() coroutineScope.launch {
fetchSourcesSubscription = Observable.from(feedSavedSearch) feedSavedSearch.forEach { itemUI ->
.flatMap( val page = try {
{ itemUI ->
if (itemUI.source != null) { if (itemUI.source != null) {
Observable.defer { withContext(coroutineDispatcher) {
if (itemUI.savedSearch == null) { if (itemUI.savedSearch == null) {
itemUI.source.fetchLatestUpdates(1) itemUI.source.fetchLatestUpdates(1)
} else { } else {
itemUI.source.fetchSearchManga(1, itemUI.savedSearch.query.orEmpty(), getFilterList(itemUI.savedSearch, itemUI.source)) itemUI.source.fetchSearchManga(
} 1,
} itemUI.savedSearch.query.orEmpty(),
.subscribeOn(Schedulers.io()) getFilterList(itemUI.savedSearch, itemUI.source),
.onErrorReturn { MangasPage(emptyList(), false) } // Ignore timeouts or other exceptions )
.map { it.mangas } // Get manga from search result. }.awaitSingle()
.map { list -> runBlocking { list.map { networkToLocalManga.await(it.toDomainManga(itemUI.source.id)) } } } // Convert to local manga. }.mangas
.map { list -> itemUI.copy(results = list) }
} else { } else {
Observable.just(itemUI.copy(results = emptyList())) emptyList()
} }
}, } catch (e: Exception) {
5, emptyList()
) }
.observeOn(AndroidSchedulers.mainThread())
// Update matching source with the obtained results val result = itemUI.copy(
.doOnNext { result -> results = page.map {
withIOContext {
networkToLocalManga.await(it.toDomainManga(itemUI.source!!.id))
}
},
)
mutableState.update { state -> mutableState.update { state ->
state.copy( state.copy(
items = state.items?.map { if (it.feed.id == result.feed.id) result else it }, items = state.items?.map { if (it.feed.id == result.feed.id) result else it },
) )
} }
} }
.subscribe( }
{},
{ error ->
logcat(LogPriority.ERROR, error)
},
)
} }
private val filterSerializer = FilterSerializer() private val filterSerializer = FilterSerializer()
@ -295,7 +290,7 @@ open class FeedScreenModel(
override fun onDispose() { override fun onDispose() {
super.onDispose() super.onDispose()
fetchSourcesSubscription?.unsubscribe() coroutineDispatcher.close()
} }
fun dismissDialog() { fun dismissDialog() {