BulkSelection: “Select all” for all screens

(cherry picked from commit bddcc089df738e23331b351cc20c8425cb316c74)
This commit is contained in:
Cuong Tran 2024-04-26 01:05:28 +07:00 committed by Cuong M. Tran
parent 45553eb096
commit f6be3a494c
No known key found for this signature in database
GPG key ID: 733AA7624B9315C2
13 changed files with 97 additions and 7 deletions

View file

@ -12,6 +12,7 @@ import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.SnackbarResult import androidx.compose.material3.SnackbarResult
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.paging.LoadState 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.components.AppBar
import eu.kanade.presentation.util.formattedMessage import eu.kanade.presentation.util.formattedMessage
import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreenModel
import exh.metadata.metadata.RaisedSearchMetadata import exh.metadata.metadata.RaisedSearchMetadata
import exh.source.isEhBasedSource import exh.source.isEhBasedSource
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
@ -60,6 +62,7 @@ fun BrowseSourceContent(
onMangaLongClick: (Manga) -> Unit, onMangaLongClick: (Manga) -> Unit,
// KMK --> // KMK -->
selection: List<Manga>, selection: List<Manga>,
browseSourceState: BrowseSourceScreenModel.State,
// KMK <-- // KMK <--
) { ) {
val context = LocalContext.current val context = LocalContext.current
@ -135,9 +138,22 @@ fun BrowseSourceContent(
LoadingScreen( LoadingScreen(
modifier = Modifier.padding(contentPadding), modifier = Modifier.padding(contentPadding),
) )
// KMK -->
browseSourceState.mangaDisplayingList.clear()
// KMK <--
return return
} }
// KMK -->
for (idx in browseSourceState.mangaDisplayingList.size..<mangaList.itemCount) {
mangaList[idx]?.collectAsState()?.value?.first?.let { manga ->
if (!browseSourceState.mangaDisplayingList.map { it.id }.contains(manga.id)) {
browseSourceState.mangaDisplayingList.add(manga)
}
}
}
// KMK <--
// SY --> // SY -->
if (source?.isEhBasedSource() == true && ehentaiBrowseDisplayMode) { if (source?.isEhBasedSource() == true && ehentaiBrowseDisplayMode) {
BrowseSourceEHentaiList( BrowseSourceEHentaiList(

View file

@ -8,6 +8,7 @@ import eu.kanade.presentation.browse.components.GlobalSearchToolbar
import eu.kanade.presentation.components.SelectionToolbar import eu.kanade.presentation.components.SelectionToolbar
import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.CatalogueSource
import eu.kanade.tachiyomi.ui.browse.BulkFavoriteScreenModel 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.SearchScreenModel
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SourceFilter import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SourceFilter
import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.Manga
@ -42,6 +43,19 @@ fun MigrateSearchScreen(
selectedCount = bulkFavoriteState.selection.size, selectedCount = bulkFavoriteState.selection.size,
onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode, onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode,
onChangeCategoryClicked = bulkFavoriteScreenModel::addFavorite, 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 { } else {
// KMK <-- // KMK <--

View file

@ -122,6 +122,14 @@ fun SourceFeedScreen(
selectedCount = bulkFavoriteState.selection.size, selectedCount = bulkFavoriteState.selection.size,
onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode, onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode,
onChangeCategoryClicked = bulkFavoriteScreenModel::addFavorite, onChangeCategoryClicked = bulkFavoriteScreenModel::addFavorite,
onSelectAll = {
items.forEach {
it.results?.forEach { manga ->
if (!bulkFavoriteState.selection.contains(manga))
bulkFavoriteScreenModel.select(manga)
}
}
},
) )
} else { } else {
// KMK <-- // KMK <--

View file

@ -29,7 +29,7 @@ fun SelectionToolbar(
title = stringResource(MR.strings.action_select_all), title = stringResource(MR.strings.action_select_all),
icon = Icons.Filled.SelectAll, icon = Icons.Filled.SelectAll,
onClick = { onClick = {
onSelectAll.invoke() onSelectAll()
}, },
), ),
) )

View file

@ -25,6 +25,7 @@ import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.zIndex import androidx.compose.ui.zIndex
import dev.icerock.moko.resources.StringResource import dev.icerock.moko.resources.StringResource
import eu.kanade.tachiyomi.ui.browse.BulkFavoriteScreenModel import eu.kanade.tachiyomi.ui.browse.BulkFavoriteScreenModel
import eu.kanade.tachiyomi.ui.browse.feed.FeedScreenModel
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -40,6 +41,7 @@ fun TabbedScreen(
searchQuery: String? = null, searchQuery: String? = null,
onChangeSearchQuery: (String?) -> Unit = {}, onChangeSearchQuery: (String?) -> Unit = {},
// KMK --> // KMK -->
feedScreenModel: FeedScreenModel,
bulkFavoriteScreenModel: BulkFavoriteScreenModel, bulkFavoriteScreenModel: BulkFavoriteScreenModel,
// KMK <-- // KMK <--
) { ) {
@ -48,6 +50,7 @@ fun TabbedScreen(
val snackbarHostState = remember { SnackbarHostState() } val snackbarHostState = remember { SnackbarHostState() }
// KMK --> // KMK -->
val feedState by feedScreenModel.state.collectAsState()
val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState() val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState()
// KMK <-- // KMK <--
@ -67,6 +70,14 @@ fun TabbedScreen(
selectedCount = bulkFavoriteState.selection.size, selectedCount = bulkFavoriteState.selection.size,
onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode, onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode,
onChangeCategoryClicked = bulkFavoriteScreenModel::addFavorite, onChangeCategoryClicked = bulkFavoriteScreenModel::addFavorite,
onSelectAll = {
feedState.items?.forEach {
it.results?.forEach { manga ->
if (!bulkFavoriteState.selection.contains(manga))
bulkFavoriteScreenModel.select(manga)
}
}
},
) )
} else { } else {
// KMK <-- // KMK <--

View file

@ -21,6 +21,7 @@ import eu.kanade.presentation.util.Tab
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.browse.extension.ExtensionsScreenModel import eu.kanade.tachiyomi.ui.browse.extension.ExtensionsScreenModel
import eu.kanade.tachiyomi.ui.browse.extension.extensionsTab 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.feed.feedTab
import eu.kanade.tachiyomi.ui.browse.migration.sources.migrateSourceTab import eu.kanade.tachiyomi.ui.browse.migration.sources.migrateSourceTab
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchScreen import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchScreen
@ -66,6 +67,7 @@ data class BrowseTab(
val extensionsState by extensionsScreenModel.state.collectAsState() val extensionsState by extensionsScreenModel.state.collectAsState()
// KMK --> // KMK -->
val feedScreenModel = rememberScreenModel { FeedScreenModel() }
val bulkFavoriteScreenModel = rememberScreenModel { BulkFavoriteScreenModel() } val bulkFavoriteScreenModel = rememberScreenModel { BulkFavoriteScreenModel() }
// KMK <-- // KMK <--
@ -80,7 +82,7 @@ data class BrowseTab(
) )
} else if (feedTabInFront) { } else if (feedTabInFront) {
persistentListOf( persistentListOf(
feedTab(bulkFavoriteScreenModel), feedTab(/* KMK --> */feedScreenModel, bulkFavoriteScreenModel/* KMK <-- */),
sourcesTab(), sourcesTab(),
extensionsTab(extensionsScreenModel), extensionsTab(extensionsScreenModel),
migrateSourceTab(), migrateSourceTab(),
@ -88,7 +90,7 @@ data class BrowseTab(
} else { } else {
persistentListOf( persistentListOf(
sourcesTab(), sourcesTab(),
feedTab(bulkFavoriteScreenModel), feedTab(/* KMK --> */feedScreenModel, bulkFavoriteScreenModel/* KMK <-- */),
extensionsTab(extensionsScreenModel), extensionsTab(extensionsScreenModel),
migrateSourceTab(), migrateSourceTab(),
) )
@ -98,6 +100,7 @@ data class BrowseTab(
searchQuery = extensionsState.searchQuery, searchQuery = extensionsState.searchQuery,
onChangeSearchQuery = extensionsScreenModel::search, onChangeSearchQuery = extensionsScreenModel::search,
// KMK --> // KMK -->
feedScreenModel = feedScreenModel,
bulkFavoriteScreenModel = bulkFavoriteScreenModel, bulkFavoriteScreenModel = bulkFavoriteScreenModel,
// KMK <-- // KMK <--
) )

View file

@ -9,8 +9,6 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.ui.platform.LocalHapticFeedback 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.core.stack.StackEvent
import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow import cafe.adriel.voyager.navigator.currentOrThrow
@ -39,13 +37,13 @@ import tachiyomi.i18n.sy.SYMR
import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.i18n.stringResource
@Composable @Composable
fun Screen.feedTab( fun feedTab(
// KMK --> // KMK -->
screenModel: FeedScreenModel,
bulkFavoriteScreenModel: BulkFavoriteScreenModel, bulkFavoriteScreenModel: BulkFavoriteScreenModel,
// KMK <-- // KMK <--
): TabContent { ): TabContent {
val navigator = LocalNavigator.currentOrThrow val navigator = LocalNavigator.currentOrThrow
val screenModel = rememberScreenModel { FeedScreenModel() }
val state by screenModel.state.collectAsState() val state by screenModel.state.collectAsState()
// KMK --> // KMK -->

View file

@ -75,6 +75,12 @@ data class SourceSearchScreen(
selectedCount = bulkFavoriteState.selection.size, selectedCount = bulkFavoriteState.selection.size,
onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode, onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode,
onChangeCategoryClicked = bulkFavoriteScreenModel::addFavorite, onChangeCategoryClicked = bulkFavoriteScreenModel::addFavorite,
onSelectAll = {
state.mangaDisplayingList.forEach { manga ->
if (!bulkFavoriteState.selection.contains(manga))
bulkFavoriteScreenModel.select(manga)
}
},
) )
} else { } else {
// KMK <-- // KMK <--
@ -150,6 +156,7 @@ data class SourceSearchScreen(
onMangaLongClick = { navigator.push(MangaScreen(it.id, true)) }, onMangaLongClick = { navigator.push(MangaScreen(it.id, true)) },
// KMK --> // KMK -->
selection = bulkFavoriteState.selection, selection = bulkFavoriteState.selection,
browseSourceState = state,
// KMK <-- // KMK <--
) )
} }

View file

@ -171,6 +171,12 @@ data class BrowseSourceScreen(
selectedCount = bulkFavoriteState.selection.size, selectedCount = bulkFavoriteState.selection.size,
onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode, onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode,
onChangeCategoryClicked = bulkFavoriteScreenModel::addFavorite, onChangeCategoryClicked = bulkFavoriteScreenModel::addFavorite,
onSelectAll = {
state.mangaDisplayingList.forEach { manga ->
if (!bulkFavoriteState.selection.contains(manga))
bulkFavoriteScreenModel.select(manga)
}
},
) )
} else { } else {
// KMK <-- // KMK <--
@ -317,6 +323,7 @@ data class BrowseSourceScreen(
}, },
// KMK --> // KMK -->
selection = bulkFavoriteState.selection, selection = bulkFavoriteState.selection,
browseSourceState = state,
// KMK <-- // KMK <--
) )
} }

View file

@ -473,6 +473,9 @@ open class BrowseSourceScreenModel(
val savedSearches: ImmutableList<EXHSavedSearch> = persistentListOf(), val savedSearches: ImmutableList<EXHSavedSearch> = persistentListOf(),
val filterable: Boolean = true, val filterable: Boolean = true,
// SY <-- // SY <--
// KMK -->
val mangaDisplayingList: MutableSet<Manga> = emptySet<Manga>().toMutableSet()
// KMK <--
) { ) {
val isUserQuery get() = listing is Listing.Search && !listing.query.isNullOrEmpty() val isUserQuery get() = listing is Listing.Search && !listing.query.isNullOrEmpty()
} }

View file

@ -73,6 +73,12 @@ class MangaDexFollowsScreen(private val sourceId: Long) : Screen() {
selectedCount = bulkFavoriteState.selection.size, selectedCount = bulkFavoriteState.selection.size,
onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode, onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode,
onChangeCategoryClicked = bulkFavoriteScreenModel::addFavorite, onChangeCategoryClicked = bulkFavoriteScreenModel::addFavorite,
onSelectAll = {
state.mangaDisplayingList.forEach { manga ->
if (!bulkFavoriteState.selection.contains(manga))
bulkFavoriteScreenModel.select(manga)
}
},
) )
} else { } else {
// KMK <-- // KMK <--
@ -142,6 +148,7 @@ class MangaDexFollowsScreen(private val sourceId: Long) : Screen() {
}, },
// KMK --> // KMK -->
selection = bulkFavoriteState.selection, selection = bulkFavoriteState.selection,
browseSourceState = state,
// KMK <-- // KMK <--
) )
} }

View file

@ -44,6 +44,7 @@ class MangaDexSimilarScreen(val mangaId: Long, val sourceId: Long) : Screen() {
val navigator = LocalNavigator.currentOrThrow val navigator = LocalNavigator.currentOrThrow
// KMK --> // KMK -->
val state by screenModel.state.collectAsState()
val bulkFavoriteScreenModel = rememberScreenModel { BulkFavoriteScreenModel() } val bulkFavoriteScreenModel = rememberScreenModel { BulkFavoriteScreenModel() }
val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState() val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState()
@ -68,6 +69,12 @@ class MangaDexSimilarScreen(val mangaId: Long, val sourceId: Long) : Screen() {
selectedCount = bulkFavoriteState.selection.size, selectedCount = bulkFavoriteState.selection.size,
onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode, onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode,
onChangeCategoryClicked = bulkFavoriteScreenModel::addFavorite, onChangeCategoryClicked = bulkFavoriteScreenModel::addFavorite,
onSelectAll = {
state.mangaDisplayingList.forEach { manga ->
if (!bulkFavoriteState.selection.contains(manga))
bulkFavoriteScreenModel.select(manga)
}
},
) )
} else { } else {
// KMK <-- // KMK <--
@ -120,6 +127,7 @@ class MangaDexSimilarScreen(val mangaId: Long, val sourceId: Long) : Screen() {
}, },
// KMK --> // KMK -->
selection = bulkFavoriteState.selection, selection = bulkFavoriteState.selection,
browseSourceState = state,
// KMK <-- // KMK <--
) )
} }

View file

@ -43,6 +43,7 @@ class RecommendsScreen(val mangaId: Long, val sourceId: Long) : Screen() {
val navigator = LocalNavigator.currentOrThrow val navigator = LocalNavigator.currentOrThrow
// KMK --> // KMK -->
val state by screenModel.state.collectAsState()
val bulkFavoriteScreenModel = rememberScreenModel { BulkFavoriteScreenModel() } val bulkFavoriteScreenModel = rememberScreenModel { BulkFavoriteScreenModel() }
val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState() val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState()
@ -67,6 +68,12 @@ class RecommendsScreen(val mangaId: Long, val sourceId: Long) : Screen() {
selectedCount = bulkFavoriteState.selection.size, selectedCount = bulkFavoriteState.selection.size,
onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode, onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode,
onChangeCategoryClicked = bulkFavoriteScreenModel::addFavorite, onChangeCategoryClicked = bulkFavoriteScreenModel::addFavorite,
onSelectAll = {
state.mangaDisplayingList.forEach { manga ->
if (!bulkFavoriteState.selection.contains(manga))
bulkFavoriteScreenModel.select(manga)
}
},
) )
} else { } else {
// KMK <-- // KMK <--
@ -119,6 +126,7 @@ class RecommendsScreen(val mangaId: Long, val sourceId: Long) : Screen() {
}, },
// KMK --> // KMK -->
selection = bulkFavoriteState.selection, selection = bulkFavoriteState.selection,
browseSourceState = state,
// KMK <-- // KMK <--
) )
} }