Make MigrateMangaViewModel collect favorites only while subscribed (#3722)

Assisted-by: Claude:claude-opus-5
This commit is contained in:
AntsyLich
2026-08-08 11:59:04 +06:00
committed by GitHub
parent 6c0058d230
commit fab4cbd279
2 changed files with 35 additions and 30 deletions
@@ -14,11 +14,11 @@ import androidx.compose.material3.Text
import androidx.compose.material3.animateFloatingActionButton import androidx.compose.material3.animateFloatingActionButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.CreationExtras import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.LocalNavigator
@@ -55,7 +55,7 @@ data class MigrateMangaScreen(
}, },
) )
val state by viewModel.state.collectAsState() val state by viewModel.state.collectAsStateWithLifecycle()
if (state.isLoading) { if (state.isLoading) {
LoadingScreen() LoadingScreen()
@@ -1,34 +1,41 @@
package eu.kanade.tachiyomi.ui.browse.migration.manga package eu.kanade.tachiyomi.ui.browse.migration.manga
import androidx.compose.runtime.Immutable import androidx.compose.runtime.Immutable
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.CreationExtras import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.initializer import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory import androidx.lifecycle.viewmodel.viewModelFactory
import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.Source
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.WhileSubscribed
import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import logcat.LogPriority import logcat.LogPriority
import mihon.core.common.utils.mutate import mihon.core.common.utils.mutate
import mihon.core.viewmodel.StateViewModel
import tachiyomi.core.common.util.system.logcat import tachiyomi.core.common.util.system.logcat
import tachiyomi.domain.manga.interactor.GetFavorites import tachiyomi.domain.manga.interactor.GetFavorites
import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.Manga
import tachiyomi.domain.source.service.SourceManager import tachiyomi.domain.source.service.SourceManager
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import kotlin.time.Duration.Companion.seconds
class MigrateMangaViewModel( class MigrateMangaViewModel(
private val sourceId: Long, private val sourceId: Long,
private val sourceManager: SourceManager = Injekt.get(), private val sourceManager: SourceManager = Injekt.get(),
private val getFavorites: GetFavorites = Injekt.get(), private val getFavorites: GetFavorites = Injekt.get(),
) : StateViewModel<MigrateMangaViewModel.State>(State()) { ) : ViewModel() {
companion object { companion object {
val SOURCE_ID_KEY = CreationExtras.Key<Long>() val SOURCE_ID_KEY = CreationExtras.Key<Long>()
@@ -45,41 +52,39 @@ class MigrateMangaViewModel(
private val _events: Channel<MigrationMangaEvent> = Channel() private val _events: Channel<MigrationMangaEvent> = Channel()
val events: Flow<MigrationMangaEvent> = _events.receiveAsFlow() val events: Flow<MigrationMangaEvent> = _events.receiveAsFlow()
init { private val source by lazy { sourceManager.getOrStub(sourceId) }
viewModelScope.launch {
mutableState.update { state ->
state.copy(source = sourceManager.getOrStub(sourceId))
}
getFavorites.subscribe(sourceId) private val selection = MutableStateFlow(emptySet<Long>())
private val favorites = getFavorites.subscribe(sourceId)
.catch { .catch {
logcat(LogPriority.ERROR, it) logcat(LogPriority.ERROR, it)
_events.send(MigrationMangaEvent.FailedFetchingFavorites) _events.send(MigrationMangaEvent.FailedFetchingFavorites)
mutableState.update { state -> emit(listOf())
state.copy(titleList = listOf())
}
} }
.map { manga -> .map { manga ->
manga manga.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.title })
.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.title })
}
.collectLatest { list ->
mutableState.update { it.copy(titleList = list) }
}
}
} }
val state: StateFlow<State> = combine(
favorites,
selection,
) { titleList, selection ->
State(source = source, selection = selection, titleList = titleList)
}
.flowOn(Dispatchers.IO)
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5.seconds), State())
fun toggleSelection(item: Manga) { fun toggleSelection(item: Manga) {
mutableState.update { state -> selection.update { selection ->
val selection = state.selection.mutate { list -> selection.mutate { list ->
if (!list.remove(item.id)) list.add(item.id) if (!list.remove(item.id)) list.add(item.id)
} }
state.copy(selection = selection)
} }
} }
fun clearSelection() { fun clearSelection() {
mutableState.update { it.copy(selection = emptySet()) } selection.update { emptySet() }
} }
@Immutable @Immutable