diff --git a/app/src/main/java/eu/kanade/presentation/browse/BrowseSourceScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/BrowseSourceScreen.kt index 5494801d18..a6eda94c34 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/BrowseSourceScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/BrowseSourceScreen.kt @@ -12,6 +12,7 @@ import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarResult import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.paging.LoadState @@ -23,6 +24,7 @@ import eu.kanade.presentation.browse.components.BrowseSourceList import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.util.formattedMessage import eu.kanade.tachiyomi.source.Source +import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreenModel import exh.metadata.metadata.RaisedSearchMetadata import exh.source.isEhBasedSource import kotlinx.collections.immutable.persistentListOf @@ -60,6 +62,7 @@ fun BrowseSourceContent( onMangaLongClick: (Manga) -> Unit, // KMK --> selection: List, + browseSourceState: BrowseSourceScreenModel.State, // KMK <-- ) { val context = LocalContext.current @@ -135,9 +138,22 @@ fun BrowseSourceContent( LoadingScreen( modifier = Modifier.padding(contentPadding), ) + // KMK --> + browseSourceState.mangaDisplayingList.clear() + // KMK <-- return } + // KMK --> + for (idx in browseSourceState.mangaDisplayingList.size.. + if (!browseSourceState.mangaDisplayingList.map { it.id }.contains(manga.id)) { + browseSourceState.mangaDisplayingList.add(manga) + } + } + } + // KMK <-- + // SY --> if (source?.isEhBasedSource() == true && ehentaiBrowseDisplayMode) { BrowseSourceEHentaiList( 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 953defc695..0547a6bbc8 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt @@ -52,6 +52,19 @@ fun GlobalSearchScreen( selectedCount = bulkFavoriteState.selection.size, onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode, onChangeCategoryClicked = bulkFavoriteScreenModel::addFavorite, + onSelectAll = { + state.filteredItems.forEach { (_, result) -> + when (result) { + is SearchItemResult.Success -> { + result.result.forEach { manga -> + if (!bulkFavoriteState.selection.contains(manga)) + bulkFavoriteScreenModel.select(manga) + } + } + else -> {} + } + } + }, ) } 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 7817189723..440075d992 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/MigrateSearchScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/MigrateSearchScreen.kt @@ -8,6 +8,7 @@ import eu.kanade.presentation.browse.components.GlobalSearchToolbar import eu.kanade.presentation.components.SelectionToolbar import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.ui.browse.BulkFavoriteScreenModel +import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchItemResult import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchScreenModel import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SourceFilter import tachiyomi.domain.manga.model.Manga @@ -42,6 +43,19 @@ fun MigrateSearchScreen( selectedCount = bulkFavoriteState.selection.size, onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode, onChangeCategoryClicked = bulkFavoriteScreenModel::addFavorite, + onSelectAll = { + state.filteredItems.forEach { (_, result) -> + when (result) { + is SearchItemResult.Success -> { + result.result.forEach { manga -> + if (!bulkFavoriteState.selection.contains(manga)) + bulkFavoriteScreenModel.select(manga) + } + } + else -> {} + } + } + }, ) } 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 40cf05828c..66cee34911 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/SourceFeedScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/SourceFeedScreen.kt @@ -122,6 +122,14 @@ fun SourceFeedScreen( selectedCount = bulkFavoriteState.selection.size, onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode, onChangeCategoryClicked = bulkFavoriteScreenModel::addFavorite, + onSelectAll = { + items.forEach { + it.results?.forEach { manga -> + if (!bulkFavoriteState.selection.contains(manga)) + bulkFavoriteScreenModel.select(manga) + } + } + }, ) } else { // KMK <-- diff --git a/app/src/main/java/eu/kanade/presentation/components/SelectionToolbar.kt b/app/src/main/java/eu/kanade/presentation/components/SelectionToolbar.kt index ae25a406ad..258c5aa711 100644 --- a/app/src/main/java/eu/kanade/presentation/components/SelectionToolbar.kt +++ b/app/src/main/java/eu/kanade/presentation/components/SelectionToolbar.kt @@ -2,6 +2,7 @@ package eu.kanade.presentation.components import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.BookmarkAdd +import androidx.compose.material.icons.filled.SelectAll import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.Preview @@ -14,22 +15,38 @@ fun SelectionToolbar( selectedCount: Int, onClickClearSelection: () -> Unit, onChangeCategoryClicked: () -> Unit, + onSelectAll: (() -> Unit)? = null, ) { AppBar( titleContent = { Text(text = "$selectedCount") }, actions = { AppBarActions( - persistentListOf( - AppBar.Action( - title = stringResource(MR.strings.action_bookmark), - icon = Icons.Filled.BookmarkAdd, - onClick = { - if (selectedCount > 0) { - onChangeCategoryClicked() - } - }, - ), - ), + actions = persistentListOf().builder() + .apply { + if (onSelectAll != null) { + add( + AppBar.Action( + title = stringResource(MR.strings.action_select_all), + icon = Icons.Filled.SelectAll, + onClick = { + onSelectAll() + }, + ), + ) + } + add( + AppBar.Action( + title = stringResource(MR.strings.action_bookmark), + icon = Icons.Filled.BookmarkAdd, + onClick = { + if (selectedCount > 0) { + onChangeCategoryClicked() + } + }, + ), + ) + } + .build(), ) }, isActionMode = true, 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 4ed9a519da..adddec7b72 100644 --- a/app/src/main/java/eu/kanade/presentation/components/TabbedScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/components/TabbedScreen.kt @@ -25,6 +25,7 @@ import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.zIndex import dev.icerock.moko.resources.StringResource import eu.kanade.tachiyomi.ui.browse.BulkFavoriteScreenModel +import eu.kanade.tachiyomi.ui.browse.feed.FeedScreenModel import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.launch @@ -40,6 +41,7 @@ fun TabbedScreen( searchQuery: String? = null, onChangeSearchQuery: (String?) -> Unit = {}, // KMK --> + feedScreenModel: FeedScreenModel, bulkFavoriteScreenModel: BulkFavoriteScreenModel, // KMK <-- ) { @@ -48,6 +50,7 @@ fun TabbedScreen( val snackbarHostState = remember { SnackbarHostState() } // KMK --> + val feedState by feedScreenModel.state.collectAsState() val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState() // KMK <-- @@ -67,6 +70,14 @@ fun TabbedScreen( selectedCount = bulkFavoriteState.selection.size, onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode, onChangeCategoryClicked = bulkFavoriteScreenModel::addFavorite, + onSelectAll = { + feedState.items?.forEach { + it.results?.forEach { manga -> + if (!bulkFavoriteState.selection.contains(manga)) + bulkFavoriteScreenModel.select(manga) + } + } + }, ) } else { // KMK <-- diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/BrowseTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/BrowseTab.kt index e256e116f2..96397144c0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/BrowseTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/BrowseTab.kt @@ -21,6 +21,7 @@ import eu.kanade.presentation.util.Tab import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.browse.extension.ExtensionsScreenModel import eu.kanade.tachiyomi.ui.browse.extension.extensionsTab +import eu.kanade.tachiyomi.ui.browse.feed.FeedScreenModel import eu.kanade.tachiyomi.ui.browse.feed.feedTab import eu.kanade.tachiyomi.ui.browse.migration.sources.migrateSourceTab import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchScreen @@ -66,6 +67,7 @@ data class BrowseTab( val extensionsState by extensionsScreenModel.state.collectAsState() // KMK --> + val feedScreenModel = rememberScreenModel { FeedScreenModel() } val bulkFavoriteScreenModel = rememberScreenModel { BulkFavoriteScreenModel() } // KMK <-- @@ -80,7 +82,7 @@ data class BrowseTab( ) } else if (feedTabInFront) { persistentListOf( - feedTab(bulkFavoriteScreenModel), + feedTab(/* KMK --> */feedScreenModel, bulkFavoriteScreenModel/* KMK <-- */), sourcesTab(), extensionsTab(extensionsScreenModel), migrateSourceTab(), @@ -88,7 +90,7 @@ data class BrowseTab( } else { persistentListOf( sourcesTab(), - feedTab(bulkFavoriteScreenModel), + feedTab(/* KMK --> */feedScreenModel, bulkFavoriteScreenModel/* KMK <-- */), extensionsTab(extensionsScreenModel), migrateSourceTab(), ) @@ -98,6 +100,7 @@ data class BrowseTab( searchQuery = extensionsState.searchQuery, onChangeSearchQuery = extensionsScreenModel::search, // KMK --> + feedScreenModel = feedScreenModel, bulkFavoriteScreenModel = bulkFavoriteScreenModel, // 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 491d057cbd..a043b936da 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 @@ -84,12 +84,23 @@ class BulkFavoriteScreenModel( mutableState.update { it.copy(selection = persistentListOf()) } } - fun toggleSelection(manga: Manga) { + fun select(manga: Manga) { + 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 + */ + fun toggleSelection(manga: Manga, toSelectedState: Boolean? = null) { mutableState.update { state -> val newSelection = state.selection.mutate { list -> - if (list.fastAny { it.id == manga.id }) { + if (toSelectedState != true && list.fastAny { it.id == manga.id }) { list.removeAll { it.id == manga.id } - } else { + } else if (toSelectedState != false) { list.add(manga) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/feed/FeedTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/feed/FeedTab.kt index 242fba8748..b959e9b5a4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/feed/FeedTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/feed/FeedTab.kt @@ -9,8 +9,6 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.platform.LocalHapticFeedback -import cafe.adriel.voyager.core.model.rememberScreenModel -import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.core.stack.StackEvent import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.currentOrThrow @@ -39,13 +37,13 @@ import tachiyomi.i18n.sy.SYMR import tachiyomi.presentation.core.i18n.stringResource @Composable -fun Screen.feedTab( +fun feedTab( // KMK --> + screenModel: FeedScreenModel, bulkFavoriteScreenModel: BulkFavoriteScreenModel, // KMK <-- ): TabContent { val navigator = LocalNavigator.currentOrThrow - val screenModel = rememberScreenModel { FeedScreenModel() } val state by screenModel.state.collectAsState() // KMK --> 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 0236869208..61ddfdf3d8 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 @@ -75,6 +75,12 @@ data class SourceSearchScreen( selectedCount = bulkFavoriteState.selection.size, onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode, onChangeCategoryClicked = bulkFavoriteScreenModel::addFavorite, + onSelectAll = { + state.mangaDisplayingList.forEach { manga -> + if (!bulkFavoriteState.selection.contains(manga)) + bulkFavoriteScreenModel.select(manga) + } + }, ) } else { // KMK <-- @@ -150,6 +156,7 @@ data class SourceSearchScreen( onMangaLongClick = { navigator.push(MangaScreen(it.id, true)) }, // KMK --> selection = bulkFavoriteState.selection, + browseSourceState = state, // 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 4ef59ac815..ef30073639 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 @@ -171,6 +171,12 @@ data class BrowseSourceScreen( selectedCount = bulkFavoriteState.selection.size, onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode, onChangeCategoryClicked = bulkFavoriteScreenModel::addFavorite, + onSelectAll = { + state.mangaDisplayingList.forEach { manga -> + if (!bulkFavoriteState.selection.contains(manga)) + bulkFavoriteScreenModel.select(manga) + } + }, ) } else { // KMK <-- @@ -317,6 +323,7 @@ data class BrowseSourceScreen( }, // KMK --> selection = bulkFavoriteState.selection, + browseSourceState = state, // KMK <-- ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt index 9a0a85c04d..94820b7274 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt @@ -473,6 +473,9 @@ open class BrowseSourceScreenModel( val savedSearches: ImmutableList = persistentListOf(), val filterable: Boolean = true, // SY <-- + // KMK --> + val mangaDisplayingList: MutableSet = emptySet().toMutableSet() + // KMK <-- ) { val isUserQuery get() = listing is Listing.Search && !listing.query.isNullOrEmpty() } diff --git a/app/src/main/java/exh/md/follows/MangaDexFollowsScreen.kt b/app/src/main/java/exh/md/follows/MangaDexFollowsScreen.kt index 5371417cf3..63b8643184 100644 --- a/app/src/main/java/exh/md/follows/MangaDexFollowsScreen.kt +++ b/app/src/main/java/exh/md/follows/MangaDexFollowsScreen.kt @@ -73,6 +73,12 @@ class MangaDexFollowsScreen(private val sourceId: Long) : Screen() { selectedCount = bulkFavoriteState.selection.size, onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode, onChangeCategoryClicked = bulkFavoriteScreenModel::addFavorite, + onSelectAll = { + state.mangaDisplayingList.forEach { manga -> + if (!bulkFavoriteState.selection.contains(manga)) + bulkFavoriteScreenModel.select(manga) + } + }, ) } else { // KMK <-- @@ -142,6 +148,7 @@ class MangaDexFollowsScreen(private val sourceId: Long) : Screen() { }, // KMK --> selection = bulkFavoriteState.selection, + browseSourceState = state, // KMK <-- ) } diff --git a/app/src/main/java/exh/md/similar/MangaDexSimilarScreen.kt b/app/src/main/java/exh/md/similar/MangaDexSimilarScreen.kt index 33cd209c50..9a03d6a0d5 100644 --- a/app/src/main/java/exh/md/similar/MangaDexSimilarScreen.kt +++ b/app/src/main/java/exh/md/similar/MangaDexSimilarScreen.kt @@ -44,6 +44,7 @@ class MangaDexSimilarScreen(val mangaId: Long, val sourceId: Long) : Screen() { val navigator = LocalNavigator.currentOrThrow // KMK --> + val state by screenModel.state.collectAsState() val bulkFavoriteScreenModel = rememberScreenModel { BulkFavoriteScreenModel() } val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState() @@ -68,6 +69,12 @@ class MangaDexSimilarScreen(val mangaId: Long, val sourceId: Long) : Screen() { selectedCount = bulkFavoriteState.selection.size, onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode, onChangeCategoryClicked = bulkFavoriteScreenModel::addFavorite, + onSelectAll = { + state.mangaDisplayingList.forEach { manga -> + if (!bulkFavoriteState.selection.contains(manga)) + bulkFavoriteScreenModel.select(manga) + } + }, ) } else { // KMK <-- @@ -120,6 +127,7 @@ class MangaDexSimilarScreen(val mangaId: Long, val sourceId: Long) : Screen() { }, // KMK --> selection = bulkFavoriteState.selection, + browseSourceState = state, // KMK <-- ) } diff --git a/app/src/main/java/exh/recs/RecommendsScreen.kt b/app/src/main/java/exh/recs/RecommendsScreen.kt index 0aa37cb333..11144cf62c 100644 --- a/app/src/main/java/exh/recs/RecommendsScreen.kt +++ b/app/src/main/java/exh/recs/RecommendsScreen.kt @@ -43,6 +43,7 @@ class RecommendsScreen(val mangaId: Long, val sourceId: Long) : Screen() { val navigator = LocalNavigator.currentOrThrow // KMK --> + val state by screenModel.state.collectAsState() val bulkFavoriteScreenModel = rememberScreenModel { BulkFavoriteScreenModel() } val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState() @@ -67,6 +68,12 @@ class RecommendsScreen(val mangaId: Long, val sourceId: Long) : Screen() { selectedCount = bulkFavoriteState.selection.size, onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode, onChangeCategoryClicked = bulkFavoriteScreenModel::addFavorite, + onSelectAll = { + state.mangaDisplayingList.forEach { manga -> + if (!bulkFavoriteState.selection.contains(manga)) + bulkFavoriteScreenModel.select(manga) + } + }, ) } else { // KMK <-- @@ -119,6 +126,7 @@ class RecommendsScreen(val mangaId: Long, val sourceId: Long) : Screen() { }, // KMK --> selection = bulkFavoriteState.selection, + browseSourceState = state, // KMK <-- ) }