Add category filters to Upcoming calendar (#3607)
This commit is contained in:
@@ -1,12 +1,16 @@
|
||||
package mihon.feature.upcoming
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.ui.util.fastMap
|
||||
import androidx.compose.ui.util.fastMapIndexedNotNull
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import eu.kanade.core.util.insertSeparatorsReversed
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.YearMonth
|
||||
@@ -14,27 +18,46 @@ 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
|
||||
import tachiyomi.domain.upcoming.service.UpcomingPreferences
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import kotlin.time.Clock
|
||||
|
||||
class UpcomingViewModel(
|
||||
private val getUpcomingManga: GetUpcomingManga = Injekt.get(),
|
||||
val getCategories: GetCategories = Injekt.get(),
|
||||
val upcomingPreferences: UpcomingPreferences = Injekt.get(),
|
||||
) : StateViewModel<UpcomingViewModel.State>(State()) {
|
||||
|
||||
val excludedCategories = upcomingPreferences.filterExcludedCategories
|
||||
val includedCategories = upcomingPreferences.filterIncludedCategories
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
getUpcomingManga.subscribe().collectLatest {
|
||||
mutableState.update { state ->
|
||||
val upcomingItems = it.toUpcomingUIModels()
|
||||
state.copy(
|
||||
items = upcomingItems,
|
||||
events = upcomingItems.toEvents(),
|
||||
headerIndexes = upcomingItems.getHeaderIndexes(),
|
||||
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(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +104,44 @@ class UpcomingViewModel(
|
||||
mutableState.update { it.copy(selectedYearMonth = yearMonth) }
|
||||
}
|
||||
|
||||
private fun getUpcomingItemPreferenceFlow(): Flow<ItemPreferences> {
|
||||
return combine(
|
||||
upcomingPreferences.filterExcludedCategories.changes(),
|
||||
upcomingPreferences.filterIncludedCategories.changes(),
|
||||
) { excluded, included ->
|
||||
ItemPreferences(
|
||||
filterExcludedCategories = excluded,
|
||||
filterIncludedCategories = included,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun resetDialog() {
|
||||
mutableState.update { it.copy(dialog = null) }
|
||||
}
|
||||
|
||||
fun showFilterDialog() {
|
||||
mutableState.update { it.copy(dialog = Dialog.FilterSheet) }
|
||||
}
|
||||
|
||||
fun cycleCategory(category: Category) {
|
||||
when (category.id) {
|
||||
in includedCategories.get() -> {
|
||||
includedCategories.getAndSet { it - category.id }
|
||||
excludedCategories.getAndSet { it + category.id }
|
||||
}
|
||||
|
||||
in excludedCategories.get() -> excludedCategories.getAndSet { it - category.id }
|
||||
else -> includedCategories.getAndSet { it + category.id }
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
private data class ItemPreferences(
|
||||
val filterExcludedCategories: List<Long>,
|
||||
val filterIncludedCategories: List<Long>,
|
||||
)
|
||||
|
||||
data class State(
|
||||
val selectedYearMonth: YearMonth = Clock.System.now()
|
||||
.toLocalDateTime(TimeZone.currentSystemDefault())
|
||||
@@ -89,5 +150,11 @@ class UpcomingViewModel(
|
||||
val items: List<UpcomingUIModel> = listOf(),
|
||||
val events: Map<LocalDate, Int> = mapOf(),
|
||||
val headerIndexes: Map<LocalDate, Int> = mapOf(),
|
||||
val hasActiveFilters: Boolean = false,
|
||||
val dialog: Dialog? = null,
|
||||
)
|
||||
|
||||
sealed interface Dialog {
|
||||
data object FilterSheet : Dialog
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user