diff --git a/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt index 07caf826f..38fccbb9b 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt @@ -59,15 +59,20 @@ fun GlobalSearchScreen( when (result) { is SearchItemResult.Success -> { result.result.forEach { manga -> - if (!bulkFavoriteState.selection.contains(manga)) { - bulkFavoriteScreenModel.select(manga) - } + bulkFavoriteScreenModel.select(manga) } } else -> {} } } }, + onReverseSelection = { + bulkFavoriteScreenModel.reverseSelection( + state.filteredItems.values + .filterIsInstance() + .flatMap { it.result }, + ) + }, ) } else { // KMK <-- diff --git a/app/src/main/java/eu/kanade/presentation/browse/MigrateSearchScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/MigrateSearchScreen.kt index 57600595f..c10438b49 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/MigrateSearchScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/MigrateSearchScreen.kt @@ -49,15 +49,20 @@ fun MigrateSearchScreen( when (result) { is SearchItemResult.Success -> { result.result.forEach { manga -> - if (!bulkFavoriteState.selection.contains(manga)) { - bulkFavoriteScreenModel.select(manga) - } + bulkFavoriteScreenModel.select(manga) } } else -> {} } } }, + onReverseSelection = { + bulkFavoriteScreenModel.reverseSelection( + state.filteredItems.values + .filterIsInstance() + .flatMap { it.result }, + ) + }, ) } else { // KMK <-- diff --git a/app/src/main/java/eu/kanade/presentation/browse/SourceFeedScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/SourceFeedScreen.kt index ddf41ed7e..e1ea7441b 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/SourceFeedScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/SourceFeedScreen.kt @@ -126,12 +126,16 @@ fun SourceFeedScreen( onSelectAll = { items.forEach { it.results?.forEach { manga -> - if (!bulkFavoriteState.selection.contains(manga)) { - bulkFavoriteScreenModel.select(manga) - } + bulkFavoriteScreenModel.select(manga) } } }, + onReverseSelection = { + bulkFavoriteScreenModel.reverseSelection( + items.mapNotNull { it.results } + .flatten(), + ) + }, ) } else { // KMK <-- diff --git a/app/src/main/java/eu/kanade/presentation/components/BulkSelectionToolbar.kt b/app/src/main/java/eu/kanade/presentation/components/BulkSelectionToolbar.kt index 0534c8852..6d2aa0b54 100644 --- a/app/src/main/java/eu/kanade/presentation/components/BulkSelectionToolbar.kt +++ b/app/src/main/java/eu/kanade/presentation/components/BulkSelectionToolbar.kt @@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.BookmarkAdd import androidx.compose.material.icons.filled.SelectAll +import androidx.compose.material.icons.outlined.FlipToBack import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -23,6 +24,7 @@ fun BulkSelectionToolbar( onClickClearSelection: () -> Unit, onChangeCategoryClick: () -> Unit, onSelectAll: (() -> Unit)? = null, + onReverseSelection: (() -> Unit)? = null, ) { AppBar( titleContent = { Text(text = "$selectedCount") }, @@ -36,9 +38,16 @@ fun BulkSelectionToolbar( AppBar.Action( title = stringResource(MR.strings.action_select_all), icon = Icons.Filled.SelectAll, - onClick = { - onSelectAll() - }, + onClick = onSelectAll, + ), + ) + } + if (onReverseSelection != null) { + add( + AppBar.Action( + title = stringResource(MR.strings.action_select_inverse), + icon = Icons.Outlined.FlipToBack, + onClick = onReverseSelection, ), ) } diff --git a/app/src/main/java/eu/kanade/presentation/components/TabbedScreen.kt b/app/src/main/java/eu/kanade/presentation/components/TabbedScreen.kt index 46494c645..c473eb0a5 100644 --- a/app/src/main/java/eu/kanade/presentation/components/TabbedScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/components/TabbedScreen.kt @@ -74,12 +74,16 @@ fun TabbedScreen( onSelectAll = { feedState.items?.forEach { it.results?.forEach { manga -> - if (!bulkFavoriteState.selection.contains(manga)) { - bulkFavoriteScreenModel.select(manga) - } + bulkFavoriteScreenModel.select(manga) } } }, + onReverseSelection = { + feedState.items + ?.mapNotNull { it.results } + ?.flatten() + ?.let { bulkFavoriteScreenModel.reverseSelection(it) } + }, ) } else { // KMK <-- diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/BulkFavoriteScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/BulkFavoriteScreenModel.kt index 339717018..7a338646f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/BulkFavoriteScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/BulkFavoriteScreenModel.kt @@ -34,6 +34,7 @@ import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.mutate import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList +import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch @@ -89,10 +90,6 @@ class BulkFavoriteScreenModel( toggleSelection(manga, toSelectedState = true) } - fun unselect(manga: Manga) { - toggleSelection(manga, toSelectedState = false) - } - /** * @param toSelectedState set to true to only Select, set to false to only Unselect */ @@ -105,11 +102,22 @@ class BulkFavoriteScreenModel( list.add(manga) } } - state.copy(selection = newSelection) - }.also { - if (state.value.selection.isEmpty()) { - toggleSelectionMode() - } + state.copy( + selection = newSelection, + selectionMode = newSelection.isNotEmpty(), + ) + } + } + + fun reverseSelection(mangas: List) { + mutableState.update { state -> + val newSelection = mangas.filterNot { manga -> + state.selection.contains(manga) + }.toPersistentList() + state.copy( + selection = newSelection, + selectionMode = newSelection.isNotEmpty(), + ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SourceSearchScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SourceSearchScreen.kt index 448295283..a3e8807a1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SourceSearchScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SourceSearchScreen.kt @@ -83,11 +83,12 @@ data class SourceSearchScreen( onChangeCategoryClick = bulkFavoriteScreenModel::addFavorite, onSelectAll = { state.mangaDisplayingList.forEach { manga -> - if (!bulkFavoriteState.selection.contains(manga)) { - bulkFavoriteScreenModel.select(manga) - } + bulkFavoriteScreenModel.select(manga) } }, + onReverseSelection = { + bulkFavoriteScreenModel.reverseSelection(state.mangaDisplayingList.toList()) + }, ) } else { // KMK <-- diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt index 98a5739aa..99c40287a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt @@ -183,11 +183,12 @@ data class BrowseSourceScreen( onChangeCategoryClick = bulkFavoriteScreenModel::addFavorite, onSelectAll = { state.mangaDisplayingList.forEach { manga -> - if (!bulkFavoriteState.selection.contains(manga)) { - bulkFavoriteScreenModel.select(manga) - } + bulkFavoriteScreenModel.select(manga) } }, + onReverseSelection = { + bulkFavoriteScreenModel.reverseSelection(state.mangaDisplayingList.toList()) + }, ) } else { // KMK <-- diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/RelatedMangasScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/RelatedMangasScreen.kt index 80f6e08cb..8941994e9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/RelatedMangasScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/RelatedMangasScreen.kt @@ -57,12 +57,16 @@ fun RelatedMangasScreen( successState.relatedMangasSorted?.forEach { val relatedManga = it as RelatedManga.Success relatedManga.mangaList.forEach { manga -> - if (!bulkFavoriteState.selection.contains(manga)) { - bulkFavoriteScreenModel.select(manga) - } + bulkFavoriteScreenModel.select(manga) } } }, + onReverseSelection = { + successState.relatedMangasSorted + ?.map { it as RelatedManga.Success } + ?.flatMap { it.mangaList } + ?.let { bulkFavoriteScreenModel.reverseSelection(it) } + }, ) } else { BrowseSourceSimpleToolbar( diff --git a/app/src/main/java/exh/md/follows/MangaDexFollowsScreen.kt b/app/src/main/java/exh/md/follows/MangaDexFollowsScreen.kt index 50c24d11b..1ccfaae82 100644 --- a/app/src/main/java/exh/md/follows/MangaDexFollowsScreen.kt +++ b/app/src/main/java/exh/md/follows/MangaDexFollowsScreen.kt @@ -76,11 +76,12 @@ class MangaDexFollowsScreen(private val sourceId: Long) : Screen() { onChangeCategoryClick = bulkFavoriteScreenModel::addFavorite, onSelectAll = { state.mangaDisplayingList.forEach { manga -> - if (!bulkFavoriteState.selection.contains(manga)) { - bulkFavoriteScreenModel.select(manga) - } + bulkFavoriteScreenModel.select(manga) } }, + onReverseSelection = { + bulkFavoriteScreenModel.reverseSelection(state.mangaDisplayingList.toList()) + }, ) } else { // KMK <-- diff --git a/app/src/main/java/exh/md/similar/MangaDexSimilarScreen.kt b/app/src/main/java/exh/md/similar/MangaDexSimilarScreen.kt index 9c9664477..9dc9d2cdc 100644 --- a/app/src/main/java/exh/md/similar/MangaDexSimilarScreen.kt +++ b/app/src/main/java/exh/md/similar/MangaDexSimilarScreen.kt @@ -72,11 +72,12 @@ class MangaDexSimilarScreen(val mangaId: Long, val sourceId: Long) : Screen() { onChangeCategoryClick = bulkFavoriteScreenModel::addFavorite, onSelectAll = { state.mangaDisplayingList.forEach { manga -> - if (!bulkFavoriteState.selection.contains(manga)) { - bulkFavoriteScreenModel.select(manga) - } + bulkFavoriteScreenModel.select(manga) } }, + onReverseSelection = { + bulkFavoriteScreenModel.reverseSelection(state.mangaDisplayingList.toList()) + }, ) } else { // KMK <-- diff --git a/app/src/main/java/exh/recs/RecommendsScreen.kt b/app/src/main/java/exh/recs/RecommendsScreen.kt index 43bb14596..944fb6003 100644 --- a/app/src/main/java/exh/recs/RecommendsScreen.kt +++ b/app/src/main/java/exh/recs/RecommendsScreen.kt @@ -71,11 +71,12 @@ class RecommendsScreen(val mangaId: Long, val sourceId: Long) : Screen() { onChangeCategoryClick = bulkFavoriteScreenModel::addFavorite, onSelectAll = { state.mangaDisplayingList.forEach { manga -> - if (!bulkFavoriteState.selection.contains(manga)) { - bulkFavoriteScreenModel.select(manga) - } + bulkFavoriteScreenModel.select(manga) } }, + onReverseSelection = { + bulkFavoriteScreenModel.reverseSelection(state.mangaDisplayingList.toList()) + }, ) } else { // KMK <--