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.
This commit is contained in:
arkon 2023-03-28 22:52:30 -04:00
parent d1bf857079
commit 18f9e5ba6b
4 changed files with 34 additions and 16 deletions

View file

@ -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<WorkInfo>) = buildString {
if (list.isEmpty()) {

View file

@ -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?
}

View file

@ -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

View file

@ -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<T>(
abstract fun getItems(): Map<CatalogueSource, SearchItemResult>
fun getAndUpdateItems(function: (Map<CatalogueSource, SearchItemResult>) -> Map<CatalogueSource, SearchItemResult>) {
private fun getAndUpdateItems(function: (Map<CatalogueSource, SearchItemResult>) -> Map<CatalogueSource, SearchItemResult>) {
updateItems(function(getItems()))
}
@ -106,7 +105,7 @@ abstract class SearchScreenModel<T>(
val initialItems = getSelectedSources().associateWith { SearchItemResult.Loading }
updateItems(initialItems)
coroutineScope.launch {
ioCoroutineScope.launch {
sources
.map { source ->
async {
@ -115,10 +114,8 @@ abstract class SearchScreenModel<T>(
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<T>(
} catch (e: Exception) {
getAndUpdateItems { items ->
val mutableMap = items.toMutableMap()
mutableMap[source] = SearchItemResult.Error(throwable = e)
mutableMap[source] = SearchItemResult.Error(e)
mutableMap.toSortedMap(sortComparator(mutableMap))
}
}