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 a0e6095f3..af766bae9 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), ), ) { - // SY --> - val coercedCurrentPage = remember(categories) { currentPage().coerceIn(0, categories.lastIndex) } + val coercedCurrentPage = remember(categories, currentPage) { currentPage.coerceIn(0, categories.lastIndex) } // SY <-- val pagerState = rememberPagerState(coercedCurrentPage) { categories.size } 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 9178f3ba6..de1c7f8b4 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt @@ -74,6 +74,7 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.toList import kotlinx.coroutines.flow.update +import kotlinx.coroutines.flow.updateAndGet import kotlinx.coroutines.runBlocking import mihon.core.common.utils.mutate import tachiyomi.core.common.i18n.stringResource @@ -115,6 +116,7 @@ import tachiyomi.source.local.LocalSource import tachiyomi.source.local.isLocal import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get +import kotlin.collections.map import kotlin.random.Random class LibraryScreenModel( @@ -149,9 +151,6 @@ class LibraryScreenModel( // SY <-- ) : StateScreenModel(State()) { - var activeCategoryIndex: Int by libraryPreferences.lastUsedCategory().asState(screenModelScope) - val activeCategory: Category get() = state.value.displayedCategories[activeCategoryIndex] - // SY --> val favoritesSync = FavoritesSyncHelper(preferences.context) val recommendationSearch = RecommendationSearchHelper(preferences.context) @@ -160,6 +159,9 @@ class LibraryScreenModel( // SY <-- init { + mutableState.update { state -> + state.copy(activeCategoryIndex = libraryPreferences.lastUsedCategory().get()) + } screenModelScope.launchIO { combine( combine( @@ -182,6 +184,7 @@ class LibraryScreenModel( // SY <-- getLibraryItemPreferencesFlow(), ) { (searchQuery, categories, favorites), (tracksMap, trackingFilters), /* SY --> */ (groupType, sortingMode) /* <-- SY */, itemPreferences -> + val showSystemCategory = favorites.any { it.libraryManga.categories.contains(0) } val filteredFavorites = favorites .applyFilters(tracksMap, trackingFilters, itemPreferences) .let { @@ -197,6 +200,7 @@ class LibraryScreenModel( LibraryData( isInitialized = true, + showSystemCategory = showSystemCategory, categories = categories, favorites = filteredFavorites, tracksMap = tracksMap, @@ -227,6 +231,7 @@ class LibraryScreenModel( data.favorites .applyGrouping( data.categories, + data.showSystemCategory, // SY --> groupType, // SY <-- @@ -428,6 +433,7 @@ class LibraryScreenModel( private fun List.applyGrouping( categories: List, + showSystemCategory: Boolean, // SY --> groupType: Int, // <-- SY @@ -442,7 +448,7 @@ 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() } } @@ -850,7 +856,7 @@ class LibraryScreenModel( } clearSelection() } - // SY <-- +// SY <-- /** * Marks mangas' chapters read status. @@ -941,7 +947,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() { @@ -1129,7 +1136,7 @@ class LibraryScreenModel( } } } - // SY <-- +// SY <-- private var lastSelectionCategory: Long? = null @@ -1182,7 +1189,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) } @@ -1192,7 +1199,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.toSet()) list.addAll(toAdd) @@ -1205,6 +1212,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 @@ -1256,7 +1272,7 @@ class LibraryScreenModel( // SY <-- } - // SY --> +// SY --> /** Returns first unread chapter of a manga */ suspend fun getFirstUnread(manga: Manga): Chapter? { @@ -1380,7 +1396,7 @@ class LibraryScreenModel( ) } } - // SY <-- +// SY <-- @Immutable private data class ItemPreferences( @@ -1405,6 +1421,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(), @@ -1425,6 +1442,7 @@ class LibraryScreenModel( val showMangaContinueButton: Boolean = false, val dialog: Dialog? = null, val libraryData: LibraryData = LibraryData(), + private val activeCategoryIndex: Int = 0, private val groupedFavorites: Map> = emptyMap(), // SY --> val showSyncExh: Boolean = false, @@ -1432,18 +1450,21 @@ class LibraryScreenModel( val groupType: Int = LibraryGroup.BY_DEFAULT, // SY <-- ) { + 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 } } - /** - * The grouped tabs which is displayed above the library screen. - * They can be actual [Category] or [Source], [Track]... - */ - val displayedCategories = groupedFavorites.keys.toList() - // SY --> val showCleanTitles: Boolean by lazy { selectedManga.fastAny { 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 e3976d41e..6b0755dfa 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 @@ -137,7 +137,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, @@ -147,7 +147,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 { @@ -238,10 +238,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 { @@ -261,7 +261,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 ?: "")) }, @@ -280,7 +280,7 @@ data object LibraryTab : Tab { LibrarySettingsDialog( onDismissRequest = onDismissRequest, screenModel = settingsScreenModel, - category = screenModel.activeCategory, + category = state.activeCategory, // SY --> hasCategories = state.libraryData.categories.fastAny { !it.isSystemCategory }, // SY <--