[优化] 优化了正文搜索的界面 #549
This commit is contained in:
2 files changed
+119
-32
No files matched your search
@@ -19,12 +19,13 @@ import androidx.compose.foundation.lazy.itemsIndexed
|
|||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||||
|
import androidx.compose.material.icons.filled.Code
|
||||||
|
import androidx.compose.material.icons.filled.FindReplace
|
||||||
import androidx.compose.material.icons.filled.Stop
|
import androidx.compose.material.icons.filled.Stop
|
||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.CardDefaults
|
import androidx.compose.material3.CardDefaults
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||||
import androidx.compose.material3.FilterChip
|
|
||||||
import androidx.compose.material3.FloatingActionButton
|
import androidx.compose.material3.FloatingActionButton
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
@@ -52,12 +53,14 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.toArgb
|
import androidx.compose.ui.graphics.toArgb
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.text.buildAnnotatedString
|
import androidx.compose.ui.text.buildAnnotatedString
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import io.legado.app.ui.widget.components.AnimatedText
|
import io.legado.app.ui.widget.components.AnimatedText
|
||||||
import io.legado.app.ui.widget.components.EmptyMessageView
|
import io.legado.app.ui.widget.components.EmptyMessageView
|
||||||
import io.legado.app.ui.widget.components.SearchBarSection
|
import io.legado.app.ui.widget.components.SearchBarSection
|
||||||
import io.legado.app.ui.widget.components.TextCard
|
import io.legado.app.ui.widget.components.TextCard
|
||||||
|
import io.legado.app.ui.widget.components.button.AnimatedActionButton
|
||||||
import io.legado.app.ui.widget.components.lazylist.FastScrollLazyColumn
|
import io.legado.app.ui.widget.components.lazylist.FastScrollLazyColumn
|
||||||
import org.koin.androidx.compose.koinViewModel
|
import org.koin.androidx.compose.koinViewModel
|
||||||
|
|
||||||
@@ -70,6 +73,7 @@ fun SearchContentScreen(
|
|||||||
viewModel: SearchContentViewModel = koinViewModel()
|
viewModel: SearchContentViewModel = koinViewModel()
|
||||||
) {
|
) {
|
||||||
val activity = LocalActivity.current
|
val activity = LocalActivity.current
|
||||||
|
val context = LocalContext.current
|
||||||
|
|
||||||
val uiState by viewModel.uiState.collectAsState()
|
val uiState by viewModel.uiState.collectAsState()
|
||||||
|
|
||||||
@@ -142,7 +146,46 @@ fun SearchContentScreen(
|
|||||||
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
|
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
scrollBehavior = scrollBehavior
|
actions = {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.padding(end = 16.dp),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(4.dp)
|
||||||
|
) {
|
||||||
|
AnimatedActionButton(
|
||||||
|
checked = replaceEnabled,
|
||||||
|
onCheckedChange = {
|
||||||
|
replaceEnabled = it
|
||||||
|
if (searchQuery.isNotBlank()) {
|
||||||
|
viewModel.startSearch(
|
||||||
|
searchQuery,
|
||||||
|
replaceEnabled,
|
||||||
|
regexReplace
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
icon = Icons.Default.FindReplace,
|
||||||
|
activeText = "替换开启",
|
||||||
|
inactiveText = "替换关闭"
|
||||||
|
)
|
||||||
|
|
||||||
|
AnimatedActionButton(
|
||||||
|
checked = regexReplace,
|
||||||
|
onCheckedChange = {
|
||||||
|
regexReplace = it
|
||||||
|
if (searchQuery.isNotBlank()) {
|
||||||
|
viewModel.startSearch(
|
||||||
|
searchQuery,
|
||||||
|
replaceEnabled,
|
||||||
|
regexReplace
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
icon = Icons.Default.Code,
|
||||||
|
activeText = "正则开启",
|
||||||
|
inactiveText = "正则关闭"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
SearchBarSection(
|
SearchBarSection(
|
||||||
query = searchQuery,
|
query = searchQuery,
|
||||||
@@ -151,36 +194,6 @@ fun SearchContentScreen(
|
|||||||
viewModel.startSearch(searchQuery, replaceEnabled, regexReplace)
|
viewModel.startSearch(searchQuery, replaceEnabled, regexReplace)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
AnimatedVisibility(visible = scrollBehavior.state.heightOffset == 0f) {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
FilterChip(
|
|
||||||
selected = replaceEnabled,
|
|
||||||
onClick = {
|
|
||||||
replaceEnabled = !replaceEnabled
|
|
||||||
if (searchQuery.isNotBlank()) {
|
|
||||||
viewModel.startSearch(searchQuery, replaceEnabled, regexReplace)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
label = { Text("启用替换") }
|
|
||||||
)
|
|
||||||
FilterChip(
|
|
||||||
selected = regexReplace,
|
|
||||||
onClick = {
|
|
||||||
regexReplace = !regexReplace
|
|
||||||
if (searchQuery.isNotBlank()) {
|
|
||||||
viewModel.startSearch(searchQuery, replaceEnabled, regexReplace)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
label = { Text("正则匹配") }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AnimatedVisibility(visible = contentState == SearchContentState.Loading) {
|
AnimatedVisibility(visible = contentState == SearchContentState.Loading) {
|
||||||
LinearProgressIndicator(
|
LinearProgressIndicator(
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package io.legado.app.ui.widget.components.button
|
||||||
|
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.ToggleButton
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
|
||||||
|
@Composable
|
||||||
|
fun AnimatedActionButton(
|
||||||
|
checked: Boolean,
|
||||||
|
onCheckedChange: (Boolean) -> Unit,
|
||||||
|
icon: ImageVector,
|
||||||
|
activeText: String,
|
||||||
|
inactiveText: String
|
||||||
|
) {
|
||||||
|
|
||||||
|
var showText by remember { mutableStateOf(false) }
|
||||||
|
LaunchedEffect(showText) {
|
||||||
|
if (showText) {
|
||||||
|
delay(1000)
|
||||||
|
showText = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleButton(
|
||||||
|
contentPadding = PaddingValues(4.dp),
|
||||||
|
checked = checked,
|
||||||
|
onCheckedChange = {
|
||||||
|
onCheckedChange(it)
|
||||||
|
showText = true
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.Center,
|
||||||
|
modifier = Modifier.padding(horizontal = 4.dp)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = icon,
|
||||||
|
contentDescription = null
|
||||||
|
)
|
||||||
|
|
||||||
|
AnimatedVisibility(
|
||||||
|
visible = showText
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = if (checked) activeText else inactiveText,
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
modifier = Modifier.padding(start = 8.dp),
|
||||||
|
maxLines = 1,
|
||||||
|
softWrap = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user