选择书源时可搜素
This commit is contained in:
@@ -34,7 +34,6 @@ import androidx.compose.material.icons.outlined.Image
|
||||
import androidx.compose.material.icons.outlined.Settings
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.LinearProgressIndicator
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -71,6 +70,7 @@ import io.legado.app.ui.book.changesource.ChangeBookSourceComposeViewModel
|
||||
import io.legado.app.ui.book.changesource.ChangeSourceConfig
|
||||
import io.legado.app.ui.book.changesource.ChangeSourceMigrationOptionsSheet
|
||||
import io.legado.app.ui.book.group.GroupEditSheet
|
||||
import io.legado.app.ui.book.search.ScopeSelectSheet
|
||||
import io.legado.app.ui.book.source.edit.BookSourceEditActivity
|
||||
import io.legado.app.ui.book.source.manage.BookSourceActivity
|
||||
import io.legado.app.ui.theme.LegadoTheme
|
||||
@@ -298,7 +298,6 @@ fun ChangeSourceSheet(
|
||||
var loadingAction by remember { mutableStateOf(false) }
|
||||
var showOptionsMenu by rememberSaveable { mutableStateOf(false) }
|
||||
var showFilterSheet by rememberSaveable { mutableStateOf(false) }
|
||||
var scopeSheetTab by rememberSaveable { mutableIntStateOf(0) }
|
||||
val bookAddedToShelfText = stringResource(R.string.book_added_to_shelf)
|
||||
|
||||
val editSourceResult = rememberLauncherForActivityResult(StartActivityContract(BookSourceEditActivity::class.java)) {
|
||||
@@ -603,93 +602,22 @@ fun ChangeSourceSheet(
|
||||
}
|
||||
)
|
||||
|
||||
AppModalBottomSheet(
|
||||
ScopeSelectSheet(
|
||||
show = showFilterSheet,
|
||||
onDismissRequest = { showFilterSheet = false },
|
||||
title = stringResource(R.string.search_select_group),
|
||||
endAction = {
|
||||
MediumIconButton(
|
||||
onClick = {
|
||||
viewModel.startSearch()
|
||||
showFilterSheet = false
|
||||
},
|
||||
imageVector = Icons.Default.Check
|
||||
)
|
||||
isAll = scopeState.isAll,
|
||||
onSelectAll = { viewModel.selectAllScope() },
|
||||
groups = groups,
|
||||
selectedGroups = scopeState.displayNames,
|
||||
onToggleGroup = { viewModel.toggleScopeGroup(it) },
|
||||
sources = enabledSources,
|
||||
selectedSources = scopeState.sourceUrls,
|
||||
onToggleSource = { viewModel.toggleScopeSource(it) },
|
||||
isSourceScope = scopeState.isSource,
|
||||
onConfirm = {
|
||||
viewModel.startSearch()
|
||||
showFilterSheet = false
|
||||
}
|
||||
) {
|
||||
Column {
|
||||
SelectionItemCard(
|
||||
title = stringResource(R.string.all_source),
|
||||
isSelected = scopeState.isAll,
|
||||
containerColor = LegadoTheme.colorScheme.surface.copy(alpha = 0.6f),
|
||||
inSelectionMode = true,
|
||||
onToggleSelection = {
|
||||
viewModel.selectAllScope()
|
||||
}
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
AppTabRow(
|
||||
tabTitles = listOf(
|
||||
stringResource(R.string.group),
|
||||
stringResource(R.string.book_source),
|
||||
),
|
||||
selectedTabIndex = scopeSheetTab,
|
||||
onTabSelected = { scopeSheetTab = it },
|
||||
)
|
||||
Spacer(modifier = Modifier.height(6.dp))
|
||||
|
||||
if (scopeSheetTab == 0) {
|
||||
LazyColumn(
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
items(groups, key = { it }) {
|
||||
val selected = !scopeState.isSource && scopeState.displayNames.contains(it)
|
||||
SelectionItemCard(
|
||||
title = it,
|
||||
isSelected = selected,
|
||||
containerColor = LegadoTheme.colorScheme.surface.copy(alpha = 0.6f),
|
||||
inSelectionMode = true,
|
||||
onToggleSelection = {
|
||||
viewModel.toggleScopeGroup(it)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (enabledSources.isEmpty()) {
|
||||
Text(
|
||||
text = stringResource(R.string.search_empty),
|
||||
style = LegadoTheme.typography.bodyMedium,
|
||||
color = LegadoTheme.colorScheme.onSurfaceVariant,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 12.dp),
|
||||
)
|
||||
} else {
|
||||
LazyColumn(
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
items(enabledSources, key = { it.bookSourceUrl }) {
|
||||
val selected = scopeState.sourceUrls.contains(it.bookSourceUrl)
|
||||
SelectionItemCard(
|
||||
title = it.bookSourceName,
|
||||
subtitle = it.bookSourceGroup?.takeIf { group -> group.isNotBlank() },
|
||||
containerColor = LegadoTheme.colorScheme.surface.copy(alpha = 0.6f),
|
||||
isSelected = selected,
|
||||
inSelectionMode = true,
|
||||
onToggleSelection = {
|
||||
viewModel.toggleScopeSource(it)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
package io.legado.app.ui.book.search
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Check
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.legado.app.R
|
||||
import io.legado.app.data.entities.BookSourcePart
|
||||
import io.legado.app.ui.theme.LegadoTheme
|
||||
import io.legado.app.ui.widget.components.SearchBar
|
||||
import io.legado.app.ui.widget.components.button.MediumIconButton
|
||||
import io.legado.app.ui.widget.components.card.SelectionItemCard
|
||||
import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
|
||||
import io.legado.app.ui.widget.components.tabRow.AppTabRow
|
||||
|
||||
@Composable
|
||||
fun ScopeSelectSheet(
|
||||
show: Boolean,
|
||||
onDismissRequest: () -> Unit,
|
||||
isAll: Boolean,
|
||||
onSelectAll: () -> Unit,
|
||||
groups: List<String>,
|
||||
selectedGroups: Collection<String>,
|
||||
onToggleGroup: (String) -> Unit,
|
||||
sources: List<BookSourcePart>,
|
||||
selectedSources: Collection<String>,
|
||||
onToggleSource: (BookSourcePart) -> Unit,
|
||||
isSourceScope: Boolean = false,
|
||||
title: String = stringResource(R.string.search_select_group),
|
||||
onConfirm: (() -> Unit)? = null,
|
||||
) {
|
||||
var scopeSheetTab by rememberSaveable(show) { mutableIntStateOf(if (isSourceScope) 1 else 0) }
|
||||
var filterText by rememberSaveable(show) { mutableStateOf("") }
|
||||
|
||||
val filteredGroups = remember(groups, filterText) {
|
||||
if (filterText.isBlank()) groups else groups.filter { it.contains(filterText, ignoreCase = true) }
|
||||
}
|
||||
val filteredSources = remember(sources, filterText) {
|
||||
if (filterText.isBlank()) sources else sources.filter {
|
||||
it.bookSourceName.contains(filterText, ignoreCase = true) ||
|
||||
it.bookSourceGroup?.contains(filterText, ignoreCase = true) == true ||
|
||||
it.bookSourceUrl.contains(filterText, ignoreCase = true)
|
||||
}
|
||||
}
|
||||
|
||||
AppModalBottomSheet(
|
||||
show = show,
|
||||
onDismissRequest = onDismissRequest,
|
||||
title = title,
|
||||
endAction = onConfirm?.let {
|
||||
{
|
||||
MediumIconButton(
|
||||
onClick = it,
|
||||
imageVector = Icons.Default.Check
|
||||
)
|
||||
}
|
||||
}
|
||||
) {
|
||||
Column {
|
||||
|
||||
SearchBar(
|
||||
query = filterText,
|
||||
onQueryChange = { filterText = it },
|
||||
placeholder = stringResource(R.string.screen),
|
||||
autoFocus = false
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
SelectionItemCard(
|
||||
title = stringResource(R.string.all_source),
|
||||
isSelected = isAll,
|
||||
containerColor = LegadoTheme.colorScheme.surface.copy(alpha = 0.6f),
|
||||
inSelectionMode = true,
|
||||
onToggleSelection = {
|
||||
onSelectAll()
|
||||
}
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
AppTabRow(
|
||||
tabTitles = listOf(
|
||||
stringResource(R.string.group),
|
||||
stringResource(R.string.book_source),
|
||||
),
|
||||
selectedTabIndex = scopeSheetTab,
|
||||
onTabSelected = { scopeSheetTab = it },
|
||||
)
|
||||
Spacer(modifier = Modifier.height(6.dp))
|
||||
|
||||
if (scopeSheetTab == 0) {
|
||||
LazyColumn(
|
||||
modifier = Modifier.heightIn(max = 480.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
items(filteredGroups, key = { it }) { groupName ->
|
||||
val selected = !isSourceScope && selectedGroups.contains(groupName)
|
||||
SelectionItemCard(
|
||||
title = groupName,
|
||||
isSelected = selected,
|
||||
containerColor = LegadoTheme.colorScheme.surface.copy(alpha = 0.6f),
|
||||
inSelectionMode = true,
|
||||
onToggleSelection = {
|
||||
onToggleGroup(groupName)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (filteredSources.isEmpty()) {
|
||||
Text(
|
||||
text = stringResource(R.string.search_empty),
|
||||
style = LegadoTheme.typography.bodyMedium,
|
||||
color = LegadoTheme.colorScheme.onSurfaceVariant,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 12.dp),
|
||||
)
|
||||
} else {
|
||||
LazyColumn(
|
||||
modifier = Modifier.heightIn(max = 480.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
items(filteredSources, key = { it.bookSourceUrl }) { source ->
|
||||
val selected = selectedSources.contains(source.bookSourceUrl)
|
||||
SelectionItemCard(
|
||||
title = source.bookSourceName,
|
||||
subtitle = source.bookSourceGroup?.takeIf { group -> group.isNotBlank() },
|
||||
containerColor = LegadoTheme.colorScheme.surface.copy(alpha = 0.6f),
|
||||
isSelected = selected,
|
||||
inSelectionMode = true,
|
||||
onToggleSelection = {
|
||||
onToggleSource(source)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,6 @@ import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
@@ -80,6 +79,7 @@ import io.legado.app.ui.widget.components.topbar.TopBarAnimatedActionButton
|
||||
import io.legado.app.ui.widget.components.topbar.TopBarNavigationButton
|
||||
import io.legado.app.ui.widget.components.icon.AppIcon
|
||||
import io.legado.app.ui.widget.components.icon.AppIcons
|
||||
import io.legado.app.ui.book.search.ScopeSelectSheet
|
||||
import io.legado.app.ui.widget.components.list.TopFloatingStickyItem
|
||||
import io.legado.app.ui.widget.components.tabRow.AppTabRow
|
||||
import io.legado.app.ui.widget.components.text.AppText
|
||||
@@ -104,7 +104,6 @@ fun SearchScreen(
|
||||
val listState = rememberLazyListState()
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
var queryInput by rememberSaveable { mutableStateOf(state.query) }
|
||||
var scopeSheetTab by rememberSaveable { mutableIntStateOf(0) }
|
||||
var ignoreNextDebouncedQuery by rememberSaveable { mutableStateOf<String?>(null) }
|
||||
val showSuggestionPanel = state.showSuggestions
|
||||
val latestQuery by rememberUpdatedState(state.query)
|
||||
@@ -128,12 +127,6 @@ fun SearchScreen(
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(state.showScopeSheet, state.isSourceScope) {
|
||||
if (state.showScopeSheet) {
|
||||
scopeSheetTab = if (state.isSourceScope) 1 else 0
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
snapshotFlow { queryInput }
|
||||
.distinctUntilChanged()
|
||||
@@ -505,85 +498,19 @@ fun SearchScreen(
|
||||
}
|
||||
)
|
||||
|
||||
AppModalBottomSheet(
|
||||
ScopeSelectSheet(
|
||||
show = state.showScopeSheet,
|
||||
onDismissRequest = { viewModel.onIntent(SearchIntent.SetScopeSheetVisible(false)) },
|
||||
title = stringResource(R.string.search_select_group),
|
||||
) {
|
||||
Column {
|
||||
SelectionItemCard(
|
||||
title = stringResource(R.string.all_source),
|
||||
isSelected = state.isAllScope,
|
||||
containerColor = LegadoTheme.colorScheme.surface.copy(alpha = 0.6f),
|
||||
inSelectionMode = true,
|
||||
onToggleSelection = {
|
||||
viewModel.onIntent(SearchIntent.SelectAllScope)
|
||||
}
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
AppTabRow(
|
||||
tabTitles = listOf(
|
||||
stringResource(R.string.group),
|
||||
stringResource(R.string.book_source),
|
||||
),
|
||||
selectedTabIndex = scopeSheetTab,
|
||||
onTabSelected = { scopeSheetTab = it },
|
||||
)
|
||||
Spacer(modifier = Modifier.height(6.dp))
|
||||
|
||||
if (scopeSheetTab == 0) {
|
||||
LazyColumn(
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
items(state.enabledGroups, key = { it }) {
|
||||
val selected = !state.isSourceScope && state.scopeDisplayNames.contains(it)
|
||||
SelectionItemCard(
|
||||
title = it,
|
||||
isSelected = selected,
|
||||
containerColor = LegadoTheme.colorScheme.surface.copy(alpha = 0.6f),
|
||||
inSelectionMode = true,
|
||||
onToggleSelection = {
|
||||
viewModel.onIntent(SearchIntent.ToggleScopeGroup(it))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (state.enabledSources.isEmpty()) {
|
||||
Text(
|
||||
text = stringResource(R.string.search_empty),
|
||||
style = LegadoTheme.typography.bodyMedium,
|
||||
color = LegadoTheme.colorScheme.onSurfaceVariant,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 12.dp),
|
||||
)
|
||||
} else {
|
||||
LazyColumn(
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
items(state.enabledSources, key = { it.bookSourceUrl }) {
|
||||
val selected = state.selectedScopeSourceUrls.contains(it.bookSourceUrl)
|
||||
SelectionItemCard(
|
||||
title = it.bookSourceName,
|
||||
subtitle = it.bookSourceGroup?.takeIf { group -> group.isNotBlank() },
|
||||
containerColor = LegadoTheme.colorScheme.surface.copy(alpha = 0.6f),
|
||||
isSelected = selected,
|
||||
inSelectionMode = true,
|
||||
onToggleSelection = {
|
||||
viewModel.onIntent(SearchIntent.ToggleScopeSource(it))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
}
|
||||
}
|
||||
isAll = state.isAllScope,
|
||||
onSelectAll = { viewModel.onIntent(SearchIntent.SelectAllScope) },
|
||||
groups = state.enabledGroups,
|
||||
selectedGroups = state.scopeDisplayNames,
|
||||
onToggleGroup = { viewModel.onIntent(SearchIntent.ToggleScopeGroup(it)) },
|
||||
sources = state.enabledSources,
|
||||
selectedSources = state.selectedScopeSourceUrls,
|
||||
onToggleSource = { viewModel.onIntent(SearchIntent.ToggleScopeSource(it)) },
|
||||
isSourceScope = state.isSourceScope
|
||||
)
|
||||
|
||||
AppModalBottomSheet(
|
||||
show = state.showTypeSheet,
|
||||
|
||||
@@ -26,6 +26,7 @@ sealed interface BookshelfOverlay {
|
||||
data object LogSheet : BookshelfOverlay
|
||||
data object GroupMenu : BookshelfOverlay
|
||||
data object GroupSelectSheet : BookshelfOverlay
|
||||
data class GroupEditSheet(val groupId: Long) : BookshelfOverlay
|
||||
data object BatchDownloadConfirmDialog : BookshelfOverlay
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user