From 18f9e5ba6b080a74805db553e22f15412ddeab12 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. --- .../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 7b2019501c..b37eed762a 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 fe89516d64..f9eaa93df6 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 @@ -28,6 +36,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 f0c84dc505..bd98f1a1e2 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 @@ -18,6 +18,7 @@ import eu.kanade.domain.manga.interactor.UpdateManga import eu.kanade.domain.manga.model.toDomainManga import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.domain.track.model.toDomainTrack +import eu.kanade.presentation.util.ioCoroutineScope import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.track.EnhancedTrackService import eu.kanade.tachiyomi.data.track.TrackManager @@ -125,12 +126,12 @@ class BrowseSourceScreenModel( .filter { localManga -> !sourcePreferences.hideInLibraryItems().get() || !localManga.favorite } - .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 4979ac72bc..78238b21b8 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 @@ -94,7 +93,7 @@ abstract class SearchScreenModel( abstract fun getItems(): Map - fun getAndUpdateItems(function: (Map) -> Map) { + private fun getAndUpdateItems(function: (Map) -> Map) { updateItems(function(getItems())) } @@ -106,7 +105,7 @@ abstract class SearchScreenModel( val initialItems = getSelectedSources().associateWith { SearchItemResult.Loading } updateItems(initialItems) - coroutineScope.launch { + ioCoroutineScope.launch { sources .map { source -> async { @@ -115,10 +114,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 -> @@ -129,7 +126,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)) } }