From dde1bff9ffafc01902eae1b0e8c201e03a1a4d50 Mon Sep 17 00:00:00 2001 From: arkon Date: Tue, 28 Mar 2023 22:52:30 -0400 Subject: [PATCH] Use IO dispatcher for some screen model work Not sure if this is an ideal approach. If it is, we could migrate more usages to this. (cherry picked from commit 18f9e5ba6b080a74805db553e22f15412ddeab12) # Conflicts: # app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt --- .../more/settings/screen/WorkerInfoScreen.kt | 8 ++++---- .../eu/kanade/presentation/util/Navigator.kt | 20 +++++++++++++++++++ .../source/browse/BrowseSourceScreenModel.kt | 7 ++++--- .../source/globalsearch/SearchScreenModel.kt | 15 ++++++-------- 4 files changed, 34 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/WorkerInfoScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/WorkerInfoScreen.kt index 7b2019501..b37eed762 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/WorkerInfoScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/WorkerInfoScreen.kt @@ -31,11 +31,11 @@ import androidx.lifecycle.asFlow import androidx.work.WorkInfo import androidx.work.WorkQuery import cafe.adriel.voyager.core.model.ScreenModel -import cafe.adriel.voyager.core.model.coroutineScope import cafe.adriel.voyager.core.model.rememberScreenModel import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.currentOrThrow import eu.kanade.presentation.util.Screen +import eu.kanade.presentation.util.ioCoroutineScope import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.util.system.workManager import kotlinx.coroutines.flow.SharingStarted @@ -128,19 +128,19 @@ object WorkerInfoScreen : Screen() { .getWorkInfosLiveData(WorkQuery.fromStates(WorkInfo.State.SUCCEEDED, WorkInfo.State.FAILED, WorkInfo.State.CANCELLED)) .asFlow() .map(::constructString) - .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), "") + .stateIn(ioCoroutineScope, SharingStarted.WhileSubscribed(), "") val running = workManager .getWorkInfosLiveData(WorkQuery.fromStates(WorkInfo.State.RUNNING)) .asFlow() .map(::constructString) - .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), "") + .stateIn(ioCoroutineScope, SharingStarted.WhileSubscribed(), "") val enqueued = workManager .getWorkInfosLiveData(WorkQuery.fromStates(WorkInfo.State.ENQUEUED)) .asFlow() .map(::constructString) - .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), "") + .stateIn(ioCoroutineScope, SharingStarted.WhileSubscribed(), "") private fun constructString(list: List) = buildString { if (list.isEmpty()) { diff --git a/app/src/main/java/eu/kanade/presentation/util/Navigator.kt b/app/src/main/java/eu/kanade/presentation/util/Navigator.kt index 9fe2083d9..adefc29df 100644 --- a/app/src/main/java/eu/kanade/presentation/util/Navigator.kt +++ b/app/src/main/java/eu/kanade/presentation/util/Navigator.kt @@ -3,12 +3,20 @@ package eu.kanade.presentation.util import androidx.compose.runtime.Composable import androidx.compose.runtime.ProvidableCompositionLocal import androidx.compose.runtime.staticCompositionLocalOf +import cafe.adriel.voyager.core.model.ScreenModel +import cafe.adriel.voyager.core.model.ScreenModelStore import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.core.screen.ScreenKey import cafe.adriel.voyager.core.screen.uniqueScreenKey import cafe.adriel.voyager.core.stack.StackEvent import cafe.adriel.voyager.navigator.Navigator import cafe.adriel.voyager.transitions.ScreenTransition +import kotlinx.coroutines.CoroutineName +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel +import kotlinx.coroutines.plus import soup.compose.material.motion.animation.materialSharedAxisX import soup.compose.material.motion.animation.rememberSlideDistance @@ -33,6 +41,18 @@ abstract class Screen : Screen { override val key: ScreenKey = uniqueScreenKey } +/** + * A variant of ScreenModel.coroutineScope except with the IO dispatcher instead of the + * main dispatcher. + */ +val ScreenModel.ioCoroutineScope: CoroutineScope + get() = ScreenModelStore.getOrPutDependency( + screenModel = this, + name = "ScreenModelIoCoroutineScope", + factory = { key -> CoroutineScope(Dispatchers.IO + SupervisorJob()) + CoroutineName(key) }, + onDispose = { scope -> scope.cancel() }, + ) + interface AssistContentScreen { fun onProvideAssistUrl(): String? } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt index 25a84db20..f79e3807d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt @@ -20,6 +20,7 @@ import eu.kanade.domain.source.interactor.GetExhSavedSearch import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.domain.track.model.toDomainTrack import eu.kanade.domain.ui.UiPreferences +import eu.kanade.presentation.util.ioCoroutineScope import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.track.EnhancedTrackService @@ -208,12 +209,12 @@ open class BrowseSourceScreenModel( // SY --> .combineMetadata(metadata) // SY <-- - .stateIn(coroutineScope) + .stateIn(ioCoroutineScope) } } - .cachedIn(coroutineScope) + .cachedIn(ioCoroutineScope) } - .stateIn(coroutineScope, SharingStarted.Lazily, emptyFlow()) + .stateIn(ioCoroutineScope, SharingStarted.Lazily, emptyFlow()) fun getColumnsPreference(orientation: Int): GridCells { val isLandscape = orientation == Configuration.ORIENTATION_LANDSCAPE diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt index 1631cd41f..d17933356 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt @@ -4,10 +4,10 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.runtime.produceState import cafe.adriel.voyager.core.model.StateScreenModel -import cafe.adriel.voyager.core.model.coroutineScope import eu.kanade.domain.manga.interactor.UpdateManga import eu.kanade.domain.manga.model.toDomainManga import eu.kanade.domain.source.service.SourcePreferences +import eu.kanade.presentation.util.ioCoroutineScope import eu.kanade.tachiyomi.extension.ExtensionManager import eu.kanade.tachiyomi.source.CatalogueSource import kotlinx.coroutines.asCoroutineDispatcher @@ -17,7 +17,6 @@ import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import tachiyomi.core.util.lang.awaitSingle -import tachiyomi.core.util.lang.withIOContext import tachiyomi.domain.manga.interactor.GetManga import tachiyomi.domain.manga.interactor.NetworkToLocalManga import tachiyomi.domain.manga.model.Manga @@ -90,7 +89,7 @@ abstract class SearchScreenModel( abstract fun getItems(): Map - fun getAndUpdateItems(function: (Map) -> Map) { + private fun getAndUpdateItems(function: (Map) -> Map) { updateItems(function(getItems())) } @@ -102,7 +101,7 @@ abstract class SearchScreenModel( val initialItems = getSelectedSources().associateWith { SearchItemResult.Loading } updateItems(initialItems) - coroutineScope.launch { + ioCoroutineScope.launch { sources .map { source -> async { @@ -111,10 +110,8 @@ abstract class SearchScreenModel( source.fetchSearchManga(1, query, source.getFilterList()).awaitSingle() } - val titles = withIOContext { - page.mangas.map { - networkToLocalManga.await(it.toDomainManga(source.id)) - } + val titles = page.mangas.map { + networkToLocalManga.await(it.toDomainManga(source.id)) } getAndUpdateItems { items -> @@ -125,7 +122,7 @@ abstract class SearchScreenModel( } catch (e: Exception) { getAndUpdateItems { items -> val mutableMap = items.toMutableMap() - mutableMap[source] = SearchItemResult.Error(throwable = e) + mutableMap[source] = SearchItemResult.Error(e) mutableMap.toSortedMap(sortComparator(mutableMap)) } }