Make UpcomingViewModel collect manga only while subscribed (#3725)

Assisted-by: Claude:claude-opus-5
This commit is contained in:
AntsyLich
2026-08-08 20:04:05 +06:00
committed by GitHub
parent 3cb9883d62
commit 62288c08fb
2 changed files with 55 additions and 33 deletions
@@ -3,23 +3,29 @@ package mihon.feature.upcoming
import androidx.compose.runtime.Immutable
import androidx.compose.ui.util.fastMap
import androidx.compose.ui.util.fastMapIndexedNotNull
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import eu.kanade.core.util.insertSeparatorsReversed
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.WhileSubscribed
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.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.datetime.LocalDate
import kotlinx.datetime.TimeZone
import kotlinx.datetime.YearMonth
import kotlinx.datetime.toLocalDateTime
import kotlinx.datetime.yearMonth
import mihon.core.viewmodel.StateViewModel
import mihon.domain.upcoming.interactor.GetUpcomingManga
import tachiyomi.core.common.preference.getAndSet
import tachiyomi.core.common.util.lang.launchIO
import tachiyomi.domain.category.interactor.GetCategories
import tachiyomi.domain.category.model.Category
import tachiyomi.domain.manga.model.Manga
@@ -27,39 +33,57 @@ import tachiyomi.domain.upcoming.service.UpcomingPreferences
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import kotlin.time.Clock
import kotlin.time.Duration.Companion.seconds
class UpcomingViewModel(
private val getUpcomingManga: GetUpcomingManga = Injekt.get(),
val getCategories: GetCategories = Injekt.get(),
val upcomingPreferences: UpcomingPreferences = Injekt.get(),
) : StateViewModel<UpcomingViewModel.State>(State()) {
) : ViewModel() {
val excludedCategories = upcomingPreferences.filterExcludedCategories
val includedCategories = upcomingPreferences.filterIncludedCategories
init {
viewModelScope.launchIO {
getUpcomingItemPreferenceFlow()
.distinctUntilChanged()
.flatMapLatest {
getUpcomingManga.subscribe(
excludedCategories = it.filterExcludedCategories,
includedCategories = it.filterIncludedCategories,
)
.distinctUntilChanged()
}
.collectLatest {
mutableState.update { state ->
val upcomingItems = it.toUpcomingUIModels()
state.copy(
items = upcomingItems,
events = upcomingItems.toEvents(),
headerIndexes = upcomingItems.getHeaderIndexes(),
)
}
}
private val selectedYearMonth = MutableStateFlow(
value = Clock.System.now()
.toLocalDateTime(TimeZone.currentSystemDefault())
.date
.yearMonth,
)
private val dialog = MutableStateFlow<Dialog?>(null)
private val upcoming = getUpcomingItemPreferenceFlow()
.distinctUntilChanged()
.flatMapLatest {
getUpcomingManga.subscribe(
excludedCategories = it.filterExcludedCategories,
includedCategories = it.filterIncludedCategories,
)
}
.distinctUntilChanged()
.map { it.toUpcomingUIModels() }
.flowOn(Dispatchers.IO)
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5.seconds), emptyList())
val state: StateFlow<State> = combine(
upcoming,
selectedYearMonth,
dialog,
) { upcoming, selectedYearMonth, dialog ->
State(
selectedYearMonth = selectedYearMonth,
items = upcoming,
events = upcoming.toEvents(),
headerIndexes = upcoming.getHeaderIndexes(),
dialog = dialog,
)
}
.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(5.seconds),
State(selectedYearMonth = selectedYearMonth.value),
)
private fun List<Manga>.toUpcomingUIModels(): List<UpcomingUIModel> {
var mangaCount = 0
@@ -101,7 +125,7 @@ class UpcomingViewModel(
}
fun setSelectedYearMonth(yearMonth: YearMonth) {
mutableState.update { it.copy(selectedYearMonth = yearMonth) }
selectedYearMonth.update { yearMonth }
}
private fun getUpcomingItemPreferenceFlow(): Flow<ItemPreferences> {
@@ -117,11 +141,11 @@ class UpcomingViewModel(
}
fun resetDialog() {
mutableState.update { it.copy(dialog = null) }
dialog.update { null }
}
fun showFilterDialog() {
mutableState.update { it.copy(dialog = Dialog.FilterSheet) }
dialog.update { Dialog.FilterSheet }
}
fun cycleCategory(category: Category) {
@@ -143,10 +167,7 @@ class UpcomingViewModel(
)
data class State(
val selectedYearMonth: YearMonth = Clock.System.now()
.toLocalDateTime(TimeZone.currentSystemDefault())
.date
.yearMonth,
val selectedYearMonth: YearMonth,
val items: List<UpcomingUIModel> = listOf(),
val events: Map<LocalDate, Int> = mapOf(),
val headerIndexes: Map<LocalDate, Int> = mapOf(),