Make MigrateSourceViewModel collect sources only while subscribed (#3723)

Assisted-by: Claude:claude-opus-5
This commit is contained in:
AntsyLich
2026-08-08 11:59:17 +06:00
committed by GitHub
parent fab4cbd279
commit 3cb9883d62
2 changed files with 35 additions and 43 deletions
@@ -3,9 +3,9 @@ package eu.kanade.tachiyomi.ui.browse.migration.sources
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.HelpOutline
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.platform.LocalUriHandler
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.navigator.LocalNavigator
@@ -22,7 +22,7 @@ fun Screen.migrateSourceTab(): TabContent {
val uriHandler = LocalUriHandler.current
val navigator = LocalNavigator.currentOrThrow
val viewModel = viewModel<MigrateSourceViewModel>()
val state by viewModel.state.collectAsState()
val state by viewModel.state.collectAsStateWithLifecycle()
return TabContent(
titleRes = MR.strings.label_migration,
@@ -1,79 +1,71 @@
package eu.kanade.tachiyomi.ui.browse.migration.sources
import androidx.compose.runtime.Immutable
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import eu.kanade.domain.source.interactor.GetSourcesWithFavoriteCount
import eu.kanade.domain.source.interactor.SetMigrateSorting
import eu.kanade.domain.source.service.SourcePreferences
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.WhileSubscribed
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.flow.stateIn
import logcat.LogPriority
import mihon.core.viewmodel.StateViewModel
import tachiyomi.core.common.util.lang.launchIO
import tachiyomi.core.common.preference.getAndSet
import tachiyomi.core.common.util.system.logcat
import tachiyomi.domain.source.model.Source
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import kotlin.time.Duration.Companion.seconds
class MigrateSourceViewModel(
preferences: SourcePreferences = Injekt.get(),
private val preferences: SourcePreferences = Injekt.get(),
private val getSourcesWithFavoriteCount: GetSourcesWithFavoriteCount = Injekt.get(),
private val setMigrateSorting: SetMigrateSorting = Injekt.get(),
) : StateViewModel<MigrateSourceViewModel.State>(State()) {
) : ViewModel() {
private val _channel = Channel<Event>(Int.MAX_VALUE)
val channel = _channel.receiveAsFlow()
init {
viewModelScope.launchIO {
getSourcesWithFavoriteCount.subscribe()
.catch {
logcat(LogPriority.ERROR, it)
_channel.send(Event.FailedFetchingSourcesWithCount)
}
.collectLatest { sources ->
mutableState.update {
it.copy(
isLoading = false,
items = sources,
)
}
}
}
preferences.migrationSortingDirection.changes()
.onEach { mutableState.update { state -> state.copy(sortingDirection = it) } }
.launchIn(viewModelScope)
preferences.migrationSortingMode.changes()
.onEach { mutableState.update { state -> state.copy(sortingMode = it) } }
.launchIn(viewModelScope)
val state: StateFlow<State> = combine(
getSourcesWithFavoriteCount.subscribe()
.catch {
logcat(LogPriority.ERROR, it)
_channel.send(Event.FailedFetchingSourcesWithCount)
},
preferences.migrationSortingMode.changes(),
preferences.migrationSortingDirection.changes(),
) { sources, sortingMode, sortingDirection ->
State(
isLoading = false,
items = sources,
sortingMode = sortingMode,
sortingDirection = sortingDirection,
)
}
.flowOn(Dispatchers.IO)
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5.seconds), State())
fun toggleSortingMode() {
with(state.value) {
val newMode = when (sortingMode) {
preferences.migrationSortingMode.getAndSet { mode ->
when (mode) {
SetMigrateSorting.Mode.ALPHABETICAL -> SetMigrateSorting.Mode.TOTAL
SetMigrateSorting.Mode.TOTAL -> SetMigrateSorting.Mode.ALPHABETICAL
}
setMigrateSorting.await(newMode, sortingDirection)
}
}
fun toggleSortingDirection() {
with(state.value) {
val newDirection = when (sortingDirection) {
preferences.migrationSortingDirection.getAndSet { direction ->
when (direction) {
SetMigrateSorting.Direction.ASCENDING -> SetMigrateSorting.Direction.DESCENDING
SetMigrateSorting.Direction.DESCENDING -> SetMigrateSorting.Direction.ASCENDING
}
setMigrateSorting.await(sortingMode, newDirection)
}
}