diff --git a/app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt b/app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt index 7a5d118de..24dd70072 100644 --- a/app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt +++ b/app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt @@ -31,7 +31,7 @@ fun LibraryContent( searchQuery: String?, selection: Set, contentPadding: PaddingValues, - currentPage: () -> Int, + currentPage: Int, hasActiveFilters: Boolean, showPageTabs: Boolean, onChangeCurrentPage: (Int) -> Unit, @@ -53,8 +53,7 @@ fun LibraryContent( end = contentPadding.calculateEndPadding(LocalLayoutDirection.current), ), ) { - val coercedCurrentPage = remember { currentPage().coerceAtMost(categories.lastIndex) } - val pagerState = rememberPagerState(coercedCurrentPage) { categories.size } + val pagerState = rememberPagerState(currentPage) { categories.size } val scope = rememberCoroutineScope() var isRefreshing by remember(pagerState.currentPage) { mutableStateOf(false) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt index 838d839b1..d07609340 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt @@ -1,8 +1,6 @@ package eu.kanade.tachiyomi.ui.library import androidx.compose.runtime.Immutable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.setValue import androidx.compose.ui.util.fastAny import androidx.compose.ui.util.fastFilter import androidx.compose.ui.util.fastMap @@ -39,6 +37,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.update +import kotlinx.coroutines.flow.updateAndGet import mihon.core.common.utils.mutate import tachiyomi.core.common.preference.CheckboxState import tachiyomi.core.common.preference.TriState @@ -86,10 +85,10 @@ class LibraryScreenModel( private val trackerManager: TrackerManager = Injekt.get(), ) : StateScreenModel(State()) { - var activeCategoryIndex: Int by libraryPreferences.lastUsedCategory().asState(screenModelScope) - val activeCategory: Category get() = state.value.displayedCategories[activeCategoryIndex] - init { + mutableState.update { state -> + state.copy(activeCategoryIndex = libraryPreferences.lastUsedCategory().get()) + } screenModelScope.launchIO { combine( state.map { it.searchQuery }.distinctUntilChanged().debounce(SEARCH_DEBOUNCE_MILLIS), @@ -98,12 +97,14 @@ class LibraryScreenModel( combine(getTracksPerManga.subscribe(), getTrackingFiltersFlow(), ::Pair), getLibraryItemPreferencesFlow(), ) { searchQuery, categories, favorites, (tracksMap, trackingFilters), itemPreferences -> + val showSystemCategory = favorites.any { it.libraryManga.categories.contains(0) } val filteredFavorites = favorites .applyFilters(tracksMap, trackingFilters, itemPreferences) .let { if (searchQuery == null) it else it.filter { m -> m.matches(searchQuery) } } LibraryData( isInitialized = true, + showSystemCategory = showSystemCategory, categories = categories, favorites = filteredFavorites, tracksMap = tracksMap, @@ -125,7 +126,7 @@ class LibraryScreenModel( .distinctUntilChanged() .map { data -> data.favorites - .applyGrouping(data.categories) + .applyGrouping(data.categories, data.showSystemCategory) .applySort(data.favoritesById, data.tracksMap, data.loggedInTrackerIds) } .collectLatest { @@ -256,6 +257,7 @@ class LibraryScreenModel( private fun List.applyGrouping( categories: List, + showSystemCategory: Boolean, ): Map> { val groupCache = mutableMapOf>() forEach { item -> @@ -263,7 +265,6 @@ class LibraryScreenModel( groupCache.getOrPut(categoryId) { mutableListOf() }.add(item.id) } } - val showSystemCategory = groupCache.containsKey(0L) return categories.filter { showSystemCategory || !it.isSystemCategory } .associateWith { groupCache[it.id]?.toList().orEmpty() } } @@ -571,7 +572,8 @@ class LibraryScreenModel( } fun getRandomLibraryItemForCurrentCategory(): LibraryItem? { - return state.value.getItemsForCategoryId(activeCategory.id).randomOrNull() + val state = state.value + return state.getItemsForCategoryId(state.activeCategory.id).randomOrNull() } fun showSettingsDialog() { @@ -629,7 +631,7 @@ class LibraryScreenModel( lastSelectionCategory = null mutableState.update { state -> val newSelection = state.selection.mutate { list -> - state.getItemsForCategoryId(activeCategory.id).map { it.id }.let(list::addAll) + state.getItemsForCategoryId(state.activeCategory.id).map { it.id }.let(list::addAll) } state.copy(selection = newSelection) } @@ -639,7 +641,7 @@ class LibraryScreenModel( lastSelectionCategory = null mutableState.update { state -> val newSelection = state.selection.mutate { list -> - val itemIds = state.getItemsForCategoryId(activeCategory.id).fastMap { it.id } + val itemIds = state.getItemsForCategoryId(state.activeCategory.id).fastMap { it.id } val (toRemove, toAdd) = itemIds.partition { it in list } list.removeAll(toRemove) list.addAll(toAdd) @@ -652,6 +654,15 @@ class LibraryScreenModel( mutableState.update { it.copy(searchQuery = query) } } + fun updateActiveCategoryIndex(index: Int) { + val newIndex = mutableState.updateAndGet { state -> + state.copy(activeCategoryIndex = index) + } + .coercedActiveCategoryIndex + + libraryPreferences.lastUsedCategory().set(newIndex) + } + fun openChangeCategoryDialog() { screenModelScope.launchIO { // Create a copy of selected manga @@ -714,6 +725,7 @@ class LibraryScreenModel( @Immutable data class LibraryData( val isInitialized: Boolean = false, + val showSystemCategory: Boolean = false, val categories: List = emptyList(), val favorites: List = emptyList(), val tracksMap: Map> = emptyMap(), @@ -734,16 +746,24 @@ class LibraryScreenModel( val showMangaContinueButton: Boolean = false, val dialog: Dialog? = null, val libraryData: LibraryData = LibraryData(), + private val activeCategoryIndex: Int = 0, private val groupedFavorites: Map> = emptyMap(), ) { + val displayedCategories: List = groupedFavorites.keys.toList() + + val coercedActiveCategoryIndex = activeCategoryIndex.coerceIn( + minimumValue = 0, + maximumValue = displayedCategories.lastIndex.coerceAtLeast(0), + ) + + val activeCategory: Category by lazy { displayedCategories[coercedActiveCategoryIndex] } + val isLibraryEmpty = libraryData.favorites.isEmpty() val selectionMode = selection.isNotEmpty() val selectedManga by lazy { selection.mapNotNull { libraryData.favoritesById[it]?.libraryManga?.manga } } - val displayedCategories = groupedFavorites.keys.toList() - fun getItemsForCategoryId(categoryId: Long): List { val category = displayedCategories.find { it.id == categoryId } ?: return emptyList() return getItemsForCategory(category) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryTab.kt index 8598bf393..fc0199d38 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryTab.kt @@ -111,7 +111,7 @@ data object LibraryTab : Tab { val title = state.getToolbarTitle( defaultTitle = stringResource(MR.strings.label_library), defaultCategoryTitle = stringResource(MR.strings.label_default), - page = screenModel.activeCategoryIndex, + page = state.coercedActiveCategoryIndex, ) LibraryToolbar( hasActiveFilters = state.hasActiveFilters, @@ -121,7 +121,7 @@ data object LibraryTab : Tab { onClickSelectAll = screenModel::selectAll, onClickInvertSelection = screenModel::invertSelection, onClickFilter = screenModel::showSettingsDialog, - onClickRefresh = { onClickRefresh(screenModel.activeCategory) }, + onClickRefresh = { onClickRefresh(state.activeCategory) }, onClickGlobalUpdate = { onClickRefresh(null) }, onClickOpenRandomManga = { scope.launch { @@ -183,10 +183,10 @@ data object LibraryTab : Tab { searchQuery = state.searchQuery, selection = state.selection, contentPadding = contentPadding, - currentPage = { screenModel.activeCategoryIndex }, + currentPage = state.coercedActiveCategoryIndex, hasActiveFilters = state.hasActiveFilters, showPageTabs = state.showCategoryTabs || !state.searchQuery.isNullOrEmpty(), - onChangeCurrentPage = { screenModel.activeCategoryIndex = it }, + onChangeCurrentPage = screenModel::updateActiveCategoryIndex, onClickManga = { navigator.push(MangaScreen(it)) }, onContinueReadingClicked = { it: LibraryManga -> scope.launchIO { @@ -206,7 +206,7 @@ data object LibraryTab : Tab { screenModel.toggleRangeSelection(category, manga) haptic.performHapticFeedback(HapticFeedbackType.LongPress) }, - onRefresh = { onClickRefresh(screenModel.activeCategory) }, + onRefresh = { onClickRefresh(state.activeCategory) }, onGlobalSearchClicked = { navigator.push(GlobalSearchScreen(screenModel.state.value.searchQuery ?: "")) }, @@ -225,7 +225,7 @@ data object LibraryTab : Tab { LibrarySettingsDialog( onDismissRequest = onDismissRequest, screenModel = settingsScreenModel, - category = screenModel.activeCategory, + category = state.activeCategory, ) } is LibraryScreenModel.Dialog.ChangeCategory -> {