Ver Fonte

选择书源时可搜素

HapeLee há 5 meses atrás
pai
commit
4d3ae1e537

+ 15 - 87
app/src/main/java/io/legado/app/ui/book/info/BookInfoSheets.kt

@@ -34,7 +34,6 @@ import androidx.compose.material.icons.outlined.Image
 import androidx.compose.material.icons.outlined.Settings
 import androidx.compose.material.icons.outlined.Settings
 import androidx.compose.material3.CircularProgressIndicator
 import androidx.compose.material3.CircularProgressIndicator
 import androidx.compose.material3.Icon
 import androidx.compose.material3.Icon
-import androidx.compose.material3.IconButton
 import androidx.compose.material3.LinearProgressIndicator
 import androidx.compose.material3.LinearProgressIndicator
 import androidx.compose.material3.Text
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 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.ChangeSourceConfig
 import io.legado.app.ui.book.changesource.ChangeSourceMigrationOptionsSheet
 import io.legado.app.ui.book.changesource.ChangeSourceMigrationOptionsSheet
 import io.legado.app.ui.book.group.GroupEditSheet
 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.edit.BookSourceEditActivity
 import io.legado.app.ui.book.source.manage.BookSourceActivity
 import io.legado.app.ui.book.source.manage.BookSourceActivity
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.LegadoTheme
@@ -298,7 +298,6 @@ fun ChangeSourceSheet(
     var loadingAction by remember { mutableStateOf(false) }
     var loadingAction by remember { mutableStateOf(false) }
     var showOptionsMenu by rememberSaveable { mutableStateOf(false) }
     var showOptionsMenu by rememberSaveable { mutableStateOf(false) }
     var showFilterSheet 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 bookAddedToShelfText = stringResource(R.string.book_added_to_shelf)
 
 
     val editSourceResult = rememberLauncherForActivityResult(StartActivityContract(BookSourceEditActivity::class.java)) {
     val editSourceResult = rememberLauncherForActivityResult(StartActivityContract(BookSourceEditActivity::class.java)) {
@@ -603,93 +602,22 @@ fun ChangeSourceSheet(
         }
         }
     )
     )
 
 
-    AppModalBottomSheet(
+    ScopeSelectSheet(
         show = showFilterSheet,
         show = showFilterSheet,
         onDismissRequest = { showFilterSheet = false },
         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))
-        }
-    }
+    )
 }
 }
 
 

+ 165 - 0
app/src/main/java/io/legado/app/ui/book/search/ScopeSelectSheet.kt

@@ -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))
+        }
+    }
+}

+ 12 - 85
app/src/main/java/io/legado/app/ui/book/search/SearchScreen.kt

@@ -39,7 +39,6 @@ import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableIntStateOf
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberUpdatedState
 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.topbar.TopBarNavigationButton
 import io.legado.app.ui.widget.components.icon.AppIcon
 import io.legado.app.ui.widget.components.icon.AppIcon
 import io.legado.app.ui.widget.components.icon.AppIcons
 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.list.TopFloatingStickyItem
 import io.legado.app.ui.widget.components.tabRow.AppTabRow
 import io.legado.app.ui.widget.components.tabRow.AppTabRow
 import io.legado.app.ui.widget.components.text.AppText
 import io.legado.app.ui.widget.components.text.AppText
@@ -104,7 +104,6 @@ fun SearchScreen(
     val listState = rememberLazyListState()
     val listState = rememberLazyListState()
     val lifecycleOwner = LocalLifecycleOwner.current
     val lifecycleOwner = LocalLifecycleOwner.current
     var queryInput by rememberSaveable { mutableStateOf(state.query) }
     var queryInput by rememberSaveable { mutableStateOf(state.query) }
-    var scopeSheetTab by rememberSaveable { mutableIntStateOf(0) }
     var ignoreNextDebouncedQuery by rememberSaveable { mutableStateOf<String?>(null) }
     var ignoreNextDebouncedQuery by rememberSaveable { mutableStateOf<String?>(null) }
     val showSuggestionPanel = state.showSuggestions
     val showSuggestionPanel = state.showSuggestions
     val latestQuery by rememberUpdatedState(state.query)
     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) {
     LaunchedEffect(Unit) {
         snapshotFlow { queryInput }
         snapshotFlow { queryInput }
             .distinctUntilChanged()
             .distinctUntilChanged()
@@ -505,85 +498,19 @@ fun SearchScreen(
         }
         }
     )
     )
 
 
-    AppModalBottomSheet(
+    ScopeSelectSheet(
         show = state.showScopeSheet,
         show = state.showScopeSheet,
         onDismissRequest = { viewModel.onIntent(SearchIntent.SetScopeSheetVisible(false)) },
         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(
     AppModalBottomSheet(
         show = state.showTypeSheet,
         show = state.showTypeSheet,

+ 1 - 0
app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfUiState.kt

@@ -26,6 +26,7 @@ sealed interface BookshelfOverlay {
     data object LogSheet : BookshelfOverlay
     data object LogSheet : BookshelfOverlay
     data object GroupMenu : BookshelfOverlay
     data object GroupMenu : BookshelfOverlay
     data object GroupSelectSheet : BookshelfOverlay
     data object GroupSelectSheet : BookshelfOverlay
+    data class GroupEditSheet(val groupId: Long) : BookshelfOverlay
     data object BatchDownloadConfirmDialog : BookshelfOverlay
     data object BatchDownloadConfirmDialog : BookshelfOverlay
 }
 }