Make MigrateMangaViewModel collect favorites only while subscribed (#3722)
Assisted-by: Claude:claude-opus-5
This commit is contained in:
+2
-2
@@ -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()
|
||||||
|
|||||||
+33
-28
@@ -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>())
|
||||||
.catch {
|
|
||||||
logcat(LogPriority.ERROR, it)
|
private val favorites = getFavorites.subscribe(sourceId)
|
||||||
_events.send(MigrationMangaEvent.FailedFetchingFavorites)
|
.catch {
|
||||||
mutableState.update { state ->
|
logcat(LogPriority.ERROR, it)
|
||||||
state.copy(titleList = listOf())
|
_events.send(MigrationMangaEvent.FailedFetchingFavorites)
|
||||||
}
|
emit(listOf())
|
||||||
}
|
|
||||||
.map { manga ->
|
|
||||||
manga
|
|
||||||
.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.title })
|
|
||||||
}
|
|
||||||
.collectLatest { list ->
|
|
||||||
mutableState.update { it.copy(titleList = list) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
.map { manga ->
|
||||||
|
manga.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.title })
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|||||||
Reference in New Issue
Block a user