Make HistoryViewModel collect history only while subscribed (#3728)
Assisted-by: Claude:claude-opus-5
This commit is contained in:
@@ -7,9 +7,9 @@ import androidx.compose.animation.graphics.vector.AnimatedImageVector
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.Navigator
|
||||
@@ -63,7 +63,7 @@ data object HistoryTab : Tab {
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
val context = LocalContext.current
|
||||
val viewModel = viewModel<HistoryViewModel>()
|
||||
val state by viewModel.state.collectAsState()
|
||||
val state by viewModel.state.collectAsStateWithLifecycle()
|
||||
|
||||
HistoryScreen(
|
||||
state = state,
|
||||
|
||||
@@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.history
|
||||
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import eu.kanade.core.util.insertSeparators
|
||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||
@@ -11,16 +12,21 @@ import eu.kanade.tachiyomi.util.lang.toLocalDate
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
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.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import logcat.LogPriority
|
||||
import mihon.core.viewmodel.StateViewModel
|
||||
import tachiyomi.core.common.preference.CheckboxState
|
||||
import tachiyomi.core.common.preference.mapAsCheckboxState
|
||||
import tachiyomi.core.common.util.lang.launchIO
|
||||
@@ -42,6 +48,7 @@ import tachiyomi.domain.manga.model.MangaWithChapterCount
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
class HistoryViewModel(
|
||||
private val addTracks: AddTracks = Injekt.get(),
|
||||
@@ -56,15 +63,16 @@ class HistoryViewModel(
|
||||
private val updateManga: UpdateManga = Injekt.get(),
|
||||
val snackbarHostState: SnackbarHostState = SnackbarHostState(),
|
||||
private val sourceManager: SourceManager = Injekt.get(),
|
||||
) : StateViewModel<HistoryViewModel.State>(State()) {
|
||||
) : ViewModel() {
|
||||
|
||||
private val _events: Channel<Event> = Channel(Channel.UNLIMITED)
|
||||
val events: Flow<Event> = _events.receiveAsFlow()
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
state.map { it.searchQuery }
|
||||
.distinctUntilChanged()
|
||||
private val searchQuery = MutableStateFlow<String?>(null)
|
||||
|
||||
private val dialog = MutableStateFlow<Dialog?>(null)
|
||||
|
||||
private val history = searchQuery
|
||||
.flatMapLatest { query ->
|
||||
getHistory.subscribe(query ?: "")
|
||||
.distinctUntilChanged()
|
||||
@@ -75,9 +83,16 @@ class HistoryViewModel(
|
||||
.map { it.toHistoryUiModels() }
|
||||
.flowOn(Dispatchers.IO)
|
||||
}
|
||||
.collect { newList -> mutableState.update { it.copy(list = newList) } }
|
||||
}
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5.seconds), emptyList())
|
||||
|
||||
val state: StateFlow<State> = combine(
|
||||
searchQuery,
|
||||
history,
|
||||
dialog,
|
||||
) { searchQuery, history, dialog ->
|
||||
State(searchQuery = searchQuery, list = history, dialog = dialog)
|
||||
}
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5.seconds), State())
|
||||
|
||||
private fun List<HistoryWithRelations>.toHistoryUiModels(): List<HistoryUiModel> {
|
||||
return map { HistoryUiModel.Item(it) }
|
||||
@@ -128,11 +143,11 @@ class HistoryViewModel(
|
||||
}
|
||||
|
||||
fun updateSearchQuery(query: String?) {
|
||||
mutableState.update { it.copy(searchQuery = query) }
|
||||
searchQuery.update { query }
|
||||
}
|
||||
|
||||
fun setDialog(dialog: Dialog?) {
|
||||
mutableState.update { it.copy(dialog = dialog) }
|
||||
this.dialog.update { dialog }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -175,7 +190,7 @@ class HistoryViewModel(
|
||||
|
||||
val duplicates = getDuplicateLibraryManga(manga)
|
||||
if (duplicates.isNotEmpty()) {
|
||||
mutableState.update { it.copy(dialog = Dialog.DuplicateManga(manga, duplicates)) }
|
||||
dialog.update { Dialog.DuplicateManga(manga, duplicates) }
|
||||
return@launchIO
|
||||
}
|
||||
|
||||
@@ -215,21 +230,17 @@ class HistoryViewModel(
|
||||
}
|
||||
|
||||
fun showMigrateDialog(target: Manga, current: Manga) {
|
||||
mutableState.update { currentState ->
|
||||
currentState.copy(dialog = Dialog.Migrate(target = target, current = current))
|
||||
}
|
||||
dialog.update { Dialog.Migrate(target = target, current = current) }
|
||||
}
|
||||
|
||||
fun showChangeCategoryDialog(manga: Manga) {
|
||||
viewModelScope.launch {
|
||||
val categories = getCategories()
|
||||
val selection = getMangaCategoryIds(manga)
|
||||
mutableState.update { currentState ->
|
||||
currentState.copy(
|
||||
dialog = Dialog.ChangeCategory(
|
||||
dialog.update {
|
||||
Dialog.ChangeCategory(
|
||||
manga = manga,
|
||||
initialSelection = categories.mapAsCheckboxState { it.id in selection },
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user