[优化] 界面优化大师

This commit is contained in:
HapeLee
2026-01-05 01:49:05 +08:00
parent 8a0038fa7f
commit cc61742b5d
15 changed files with 226 additions and 95 deletions
@@ -1,7 +1,6 @@
package io.legado.app.ui.about package io.legado.app.ui.about
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
@@ -21,7 +20,7 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MaterialTheme.colorScheme import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MediumTopAppBar import androidx.compose.material3.MediumFlexibleTopAppBar
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarDefaults
@@ -61,7 +60,7 @@ fun AboutScreen(
Scaffold( Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = { topBar = {
MediumTopAppBar( MediumFlexibleTopAppBar(
title = { Text(stringResource(R.string.about)) }, title = { Text(stringResource(R.string.about)) },
navigationIcon = { navigationIcon = {
IconButton(onClick = onBack) { IconButton(onClick = onBack) {
@@ -14,7 +14,15 @@ import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
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.KeyboardArrowDown import androidx.compose.material.icons.filled.KeyboardArrowDown
@@ -22,8 +30,32 @@ import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.icons.filled.Search import androidx.compose.material.icons.filled.Search
import androidx.compose.material.icons.filled.UnfoldLess import androidx.compose.material.icons.filled.UnfoldLess
import androidx.compose.material.icons.filled.UnfoldMore import androidx.compose.material.icons.filled.UnfoldMore
import androidx.compose.material3.* import androidx.compose.material3.AlertDialog
import androidx.compose.runtime.* import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MediumFlexibleTopAppBar
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
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.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate import androidx.compose.ui.draw.rotate
@@ -35,9 +67,9 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.legado.app.data.entities.Bookmark import io.legado.app.data.entities.Bookmark
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.lazylist.FastScrollLazyColumn import io.legado.app.ui.widget.components.lazylist.FastScrollLazyColumn
import io.legado.app.ui.widget.components.lazylist.Scroller import io.legado.app.ui.widget.components.lazylist.Scroller
import io.legado.app.ui.widget.components.SearchBarSection
import org.koin.androidx.compose.koinViewModel import org.koin.androidx.compose.koinViewModel
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class, @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class,
@@ -77,11 +109,10 @@ fun AllBookmarkScreen(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = { topBar = {
Column { Column {
MediumTopAppBar( MediumFlexibleTopAppBar(
title = { title = {
Text( Text(
text = "所有书签", text = "所有书签"
style = MaterialTheme.typography.titleLarge
) )
}, },
scrollBehavior = scrollBehavior, scrollBehavior = scrollBehavior,
@@ -56,7 +56,7 @@ import androidx.compose.material3.FilterChip
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MediumTopAppBar import androidx.compose.material3.MediumFlexibleTopAppBar
import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
@@ -253,7 +253,8 @@ fun ExploreShowScreen(
} }
FlowRow( FlowRow(
modifier = Modifier.fillMaxWidth() modifier = Modifier
.fillMaxWidth()
.padding(16.dp) .padding(16.dp)
) { ) {
filteredKinds.forEach { kind -> filteredKinds.forEach { kind ->
@@ -393,7 +394,7 @@ fun KindListItem(
) )
} }
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@Composable @Composable
fun ExploreTopBar( fun ExploreTopBar(
title: String, title: String,
@@ -408,7 +409,7 @@ fun ExploreTopBar(
) { ) {
var showMenu by remember { mutableStateOf(false) } var showMenu by remember { mutableStateOf(false) }
MediumTopAppBar( MediumFlexibleTopAppBar(
title = { AnimatedTextLine(title, maxLines = 1, overflow = TextOverflow.Ellipsis) }, title = { AnimatedTextLine(title, maxLines = 1, overflow = TextOverflow.Ellipsis) },
navigationIcon = { navigationIcon = {
IconButton(onClick = onBack) { IconButton(onClick = onBack) {
@@ -3,13 +3,11 @@ package io.legado.app.ui.book.info.edit
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
@@ -34,15 +32,11 @@ import androidx.compose.material3.FilledTonalIconButton
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.IconButtonDefaults import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MediumFlexibleTopAppBar
import androidx.compose.material3.MediumTopAppBar
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedIconButton
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.OutlinedTextFieldDefaults
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
@@ -52,8 +46,6 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.Modifier.Companion
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@@ -79,7 +71,7 @@ fun BookInfoEditScreen(
Scaffold( Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = { topBar = {
MediumTopAppBar( MediumFlexibleTopAppBar(
title = { Text(text = stringResource(id = R.string.book_info_edit)) }, title = { Text(text = stringResource(id = R.string.book_info_edit)) },
navigationIcon = { navigationIcon = {
IconButton(onClick = onBack) { IconButton(onClick = onBack) {
@@ -28,10 +28,11 @@ import androidx.compose.material.icons.filled.Timeline
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.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MediumTopAppBar import androidx.compose.material3.MediumFlexibleTopAppBar
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
@@ -70,13 +71,8 @@ import org.koin.androidx.compose.koinViewModel
import java.time.LocalDate import java.time.LocalDate
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
import java.util.Date import java.util.Date
import kotlin.collections.component1
import kotlin.collections.component2
import kotlin.collections.isNotEmpty
import kotlin.collections.map
import kotlin.collections.sumOf
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@Composable @Composable
fun ReadRecordScreen( fun ReadRecordScreen(
viewModel: ReadRecordViewModel = koinViewModel(), viewModel: ReadRecordViewModel = koinViewModel(),
@@ -98,7 +94,7 @@ fun ReadRecordScreen(
} }
LaunchedEffect(searchText) { LaunchedEffect(searchText) {
if (showSearch) { if (showSearch && searchText.isNotBlank()) {
delay(100L) delay(100L)
viewModel.loadData(searchText) viewModel.loadData(searchText)
} }
@@ -108,24 +104,21 @@ fun ReadRecordScreen(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = { topBar = {
Column { Column {
MediumTopAppBar( MediumFlexibleTopAppBar(
title = { title = {
val (mainTitle, subTitle) = when (displayMode) { Text(
DisplayMode.AGGREGATE -> "阅读记录" to "汇总视图" text = "阅读记录"
DisplayMode.TIMELINE -> "阅读记录" to "时间线视图" )
DisplayMode.LATEST -> "阅读记录" to "最后阅读" },
} subtitle = {
Column { val subTitle = when (displayMode) {
Text( DisplayMode.AGGREGATE -> "汇总视图"
text = mainTitle, DisplayMode.TIMELINE -> "时间线视图"
style = MaterialTheme.typography.titleLarge, DisplayMode.LATEST -> "最后阅读"
)
AnimatedTextLine(
text = subTitle,
style = MaterialTheme.typography.titleMedium
)
} }
AnimatedTextLine(
text = subTitle
)
}, },
navigationIcon = { navigationIcon = {
IconButton(onClick = onBackClick) { IconButton(onClick = onBackClick) {
@@ -170,18 +163,20 @@ fun ReadRecordScreen(
selectedDate = state.selectedDate, selectedDate = state.selectedDate,
onDateSelected = { date -> onDateSelected = { date ->
viewModel.setSelectedDate(date) viewModel.setSelectedDate(date)
showCalendar = false // 选择后自动收起日历 showCalendar = false
}, },
onClearDate = { onClearDate = {
viewModel.setSelectedDate(null) viewModel.setSelectedDate(null)
showCalendar = false // 清除后自动收起 showCalendar = false
} }
) )
} }
} }
} }
) { padding -> ) { padding ->
Column(modifier = Modifier.padding(padding).fillMaxSize()) { Column(modifier = Modifier
.padding(padding)
.fillMaxSize()) {
val contentState = when { val contentState = when {
state.isLoading -> "LOADING" state.isLoading -> "LOADING"
(displayMode == DisplayMode.AGGREGATE && state.groupedRecords.isEmpty()) || (displayMode == DisplayMode.AGGREGATE && state.groupedRecords.isEmpty()) ||
@@ -31,7 +31,7 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MediumTopAppBar import androidx.compose.material3.MediumFlexibleTopAppBar
import androidx.compose.material3.PlainTooltip import androidx.compose.material3.PlainTooltip
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
@@ -126,7 +126,7 @@ fun SearchContentScreen(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = { topBar = {
Column { Column {
MediumTopAppBar( MediumFlexibleTopAppBar(
title = { title = {
val title = if (searchQuery.isNotBlank() && searchResults.isNotEmpty()) { val title = if (searchQuery.isNotBlank() && searchResults.isNotEmpty()) {
"${searchResults.size} 条结果" "${searchResults.size} 条结果"
@@ -26,9 +26,10 @@ import androidx.compose.material.icons.filled.Translate
import androidx.compose.material.icons.filled.Web import androidx.compose.material.icons.filled.Web
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MediumTopAppBar import androidx.compose.material3.MediumFlexibleTopAppBar
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Switch import androidx.compose.material3.Switch
import androidx.compose.material3.Text import androidx.compose.material3.Text
@@ -55,7 +56,7 @@ import io.legado.app.ui.widget.components.SettingItem
import io.legado.app.ui.widget.components.SplicedColumnGroup import io.legado.app.ui.widget.components.SplicedColumnGroup
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@Composable @Composable
fun MyScreen( fun MyScreen(
viewModel: MyViewModel, viewModel: MyViewModel,
@@ -70,7 +71,7 @@ fun MyScreen(
contentWindowInsets = WindowInsets.systemBars contentWindowInsets = WindowInsets.systemBars
.only(WindowInsetsSides.Horizontal + WindowInsetsSides.Top), .only(WindowInsetsSides.Horizontal + WindowInsetsSides.Top),
topBar = { topBar = {
MediumTopAppBar( MediumFlexibleTopAppBar(
title = { title = {
Text( Text(
text = stringResource(R.string.my) text = stringResource(R.string.my)
@@ -6,16 +6,63 @@ import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.ime
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
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.automirrored.filled.HelpOutline import androidx.compose.material.icons.automirrored.filled.HelpOutline
import androidx.compose.material.icons.filled.* import androidx.compose.material.icons.filled.Check
import androidx.compose.material3.* import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.runtime.* import androidx.compose.material.icons.filled.Save
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.AssistChip
import androidx.compose.material3.BottomAppBar
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Checkbox
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.ExposedDropdownMenuAnchorType
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.FilterChip
import androidx.compose.material3.FilterChipDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MediumFlexibleTopAppBar
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
@@ -32,7 +79,7 @@ fun keyboardAsState(): State<Boolean> {
return rememberUpdatedState(isImeVisible) return rememberUpdatedState(isImeVisible)
} }
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@Composable @Composable
fun ReplaceEditScreen( fun ReplaceEditScreen(
onBack: () -> Unit, onBack: () -> Unit,
@@ -48,7 +95,7 @@ fun ReplaceEditScreen(
Scaffold( Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = { topBar = {
MediumTopAppBar( MediumFlexibleTopAppBar(
title = { Text(if (state.id > 0) "编辑替换规则" else "新增替换规则") }, title = { Text(if (state.id > 0) "编辑替换规则" else "新增替换规则") },
navigationIcon = { navigationIcon = {
IconButton(onClick = onBack) { Icon(Icons.AutoMirrored.Filled.ArrowBack, "Back") } IconButton(onClick = onBack) { Icon(Icons.AutoMirrored.Filled.ArrowBack, "Back") }
@@ -111,7 +158,10 @@ fun ReplaceEditScreen(
label = { Text("规则名称") }, label = { Text("规则名称") },
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.onFocusChanged { if (it.isFocused) viewModel.activeField = ReplaceEditViewModel.ActiveField.Name }, .onFocusChanged {
if (it.isFocused) viewModel.activeField =
ReplaceEditViewModel.ActiveField.Name
},
singleLine = true singleLine = true
) )
@@ -129,7 +179,10 @@ fun ReplaceEditScreen(
placeholder = { Text("输入正则表达式或关键字") }, placeholder = { Text("输入正则表达式或关键字") },
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.onFocusChanged { if (it.isFocused) viewModel.activeField = ReplaceEditViewModel.ActiveField.Pattern } .onFocusChanged {
if (it.isFocused) viewModel.activeField =
ReplaceEditViewModel.ActiveField.Pattern
}
) )
OutlinedTextField( OutlinedTextField(
@@ -139,7 +192,10 @@ fun ReplaceEditScreen(
placeholder = { Text("输入替换内容或捕获组") }, placeholder = { Text("输入替换内容或捕获组") },
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.onFocusChanged { if (it.isFocused) viewModel.activeField = ReplaceEditViewModel.ActiveField.Replacement } .onFocusChanged {
if (it.isFocused) viewModel.activeField =
ReplaceEditViewModel.ActiveField.Replacement
}
) )
Row( Row(
@@ -187,7 +243,10 @@ fun ReplaceEditScreen(
placeholder = { Text("指定规则适用的范围") }, placeholder = { Text("指定规则适用的范围") },
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.onFocusChanged { if (it.isFocused) viewModel.activeField = ReplaceEditViewModel.ActiveField.Scope } .onFocusChanged {
if (it.isFocused) viewModel.activeField =
ReplaceEditViewModel.ActiveField.Scope
}
) )
OutlinedTextField( OutlinedTextField(
@@ -197,7 +256,10 @@ fun ReplaceEditScreen(
placeholder = { Text("指定规则不适用的范围") }, placeholder = { Text("指定规则不适用的范围") },
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.onFocusChanged { if (it.isFocused) viewModel.activeField = ReplaceEditViewModel.ActiveField.Exclude } .onFocusChanged {
if (it.isFocused) viewModel.activeField =
ReplaceEditViewModel.ActiveField.Exclude
}
) )
OutlinedTextField( OutlinedTextField(
@@ -261,13 +323,15 @@ fun GroupSelector(
value = currentGroup, value = currentGroup,
onValueChange = onGroupChange, onValueChange = onGroupChange,
label = { Text("分组") }, label = { Text("分组") },
placeholder = {Text("默认")}, placeholder = { Text("默认") },
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) }, trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
colors = ExposedDropdownMenuDefaults.outlinedTextFieldColors(), colors = ExposedDropdownMenuDefaults.outlinedTextFieldColors(),
modifier = Modifier.fillMaxWidth().menuAnchor( modifier = Modifier
ExposedDropdownMenuAnchorType.PrimaryEditable, .fillMaxWidth()
true .menuAnchor(
) ExposedDropdownMenuAnchorType.PrimaryEditable,
true
)
) )
ExposedDropdownMenu( ExposedDropdownMenu(
expanded = expanded, expanded = expanded,
@@ -1,11 +1,19 @@
package io.legado.app.ui.widget.components package io.legado.app.ui.widget.components
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Clear import androidx.compose.material.icons.filled.Clear
import androidx.compose.material.icons.filled.Search import androidx.compose.material.icons.filled.Search
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
@@ -15,6 +23,11 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextField import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
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.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@@ -25,8 +38,14 @@ fun SearchBarSection(
query: String, query: String,
onQueryChange: (String) -> Unit, onQueryChange: (String) -> Unit,
placeholder: String = "搜索书名", placeholder: String = "搜索书名",
backgroundColor: Color = MaterialTheme.colorScheme.surfaceContainerLow backgroundColor: Color = MaterialTheme.colorScheme.surfaceContainerLow,
//外部定义末尾的图标按钮
trailingIcon: @Composable (() -> Unit)? = null,
//外部定义下拉菜单的内容
dropdownMenu: (@Composable (onDismiss: () -> Unit) -> Unit)? = null
) { ) {
var showMenu by remember { mutableStateOf(false) }
Surface( Surface(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@@ -35,17 +54,47 @@ fun SearchBarSection(
color = backgroundColor color = backgroundColor
) { ) {
TextField( TextField(
value = query,
onValueChange = onQueryChange,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 4.dp), .padding(horizontal = 4.dp),
value = query,
onValueChange = onQueryChange,
placeholder = { Text(placeholder) }, placeholder = { Text(placeholder) },
leadingIcon = { Icon(Icons.Default.Search, null) }, leadingIcon = { Icon(Icons.Default.Search, null) },
trailingIcon = { trailingIcon = {
if (query.isNotEmpty()) { Row(
IconButton(onClick = { onQueryChange("") }) { verticalAlignment = Alignment.CenterVertically,
Icon(Icons.Default.Clear, null) modifier = Modifier.padding(end = 4.dp)
) {
AnimatedVisibility(
visible = query.isNotEmpty(),
enter = fadeIn() + scaleIn(initialScale = 0.8f),
exit = fadeOut() + scaleOut(targetScale = 0.8f)
) {
IconButton(onClick = {
onQueryChange("")
}) {
Icon(Icons.Default.Clear, "清空输入")
}
}
if (trailingIcon != null) {
Box {
IconButton(onClick = {
if (dropdownMenu != null) showMenu = true
}) {
trailingIcon()
}
if (dropdownMenu != null) {
DropdownMenu(
expanded = showMenu,
onDismissRequest = { showMenu = false }
) {
dropdownMenu { showMenu = false }
}
}
}
} }
} }
}, },
@@ -59,4 +108,4 @@ fun SearchBarSection(
) )
) )
} }
} }
@@ -1,8 +1,8 @@
package io.legado.app.ui.widget.components package io.legado.app.ui.widget.components
import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
@@ -10,6 +10,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ChevronRight import androidx.compose.material.icons.filled.ChevronRight
import androidx.compose.material.icons.filled.Info import androidx.compose.material.icons.filled.Info
import androidx.compose.material3.Card
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.ListItem import androidx.compose.material3.ListItem
@@ -22,7 +23,6 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
@@ -103,10 +103,14 @@ fun SettingItem(
) { ) {
var showMenu by remember { mutableStateOf(false) } var showMenu by remember { mutableStateOf(false) }
Box ( modifier = Modifier.fillMaxWidth() ){ Card(
modifier = Modifier
.fillMaxWidth()
.animateContentSize(),
shape = RoundedCornerShape(8.dp)
) {
ListItem( ListItem(
modifier = modifier modifier = modifier
.clip(RoundedCornerShape(4.dp))
.combinedClickable( .combinedClickable(
onClick = onClick, onClick = onClick,
onLongClick = { onLongClick = {
@@ -19,8 +19,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/collapsingToolbarLayoutMediumSize" android:layout_height="?attr/collapsingToolbarLayoutMediumSize"
style="?attr/collapsingToolbarLayoutMediumStyle" style="?attr/collapsingToolbarLayoutMediumStyle"
app:collapsedTitleTextAppearance="?attr/textAppearanceTitleLarge" app:expandedTitleTextAppearance="?attr/textAppearanceHeadlineMedium"
app:expandedTitleTextAppearance="?attr/textAppearanceHeadlineLarge"
app:titleCollapseMode="scale" app:titleCollapseMode="scale"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"> app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
@@ -18,8 +18,7 @@
style="?attr/collapsingToolbarLayoutMediumStyle" style="?attr/collapsingToolbarLayoutMediumStyle"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/collapsingToolbarLayoutMediumSize" android:layout_height="?attr/collapsingToolbarLayoutMediumSize"
app:collapsedTitleTextAppearance="?attr/textAppearanceTitleLarge" app:expandedTitleTextAppearance="?attr/textAppearanceHeadlineMedium"
app:expandedTitleTextAppearance="?attr/textAppearanceHeadlineLarge"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap" app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
app:titleCollapseMode="scale"> app:titleCollapseMode="scale">
@@ -19,8 +19,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/collapsingToolbarLayoutMediumSize" android:layout_height="?attr/collapsingToolbarLayoutMediumSize"
style="?attr/collapsingToolbarLayoutLargeStyle" style="?attr/collapsingToolbarLayoutLargeStyle"
app:collapsedTitleTextAppearance="?attr/textAppearanceTitleLarge" app:expandedTitleTextAppearance="?attr/textAppearanceHeadlineMedium"
app:expandedTitleTextAppearance="?attr/textAppearanceHeadlineLarge"
app:titleCollapseMode="scale" app:titleCollapseMode="scale"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"> app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
+2 -3
View File
@@ -17,10 +17,9 @@
<com.google.android.material.appbar.CollapsingToolbarLayout <com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/collapsingToolbarLayoutLargeSize" android:layout_height="?attr/collapsingToolbarLayoutMediumSize"
style="?attr/collapsingToolbarLayoutLargeSize" style="?attr/collapsingToolbarLayoutLargeSize"
app:collapsedTitleTextAppearance="?attr/textAppearanceTitleLarge" app:expandedTitleTextAppearance="?attr/textAppearanceHeadlineMedium"
app:expandedTitleTextAppearance="?attr/textAppearanceHeadlineLarge"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"> app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<com.google.android.material.appbar.MaterialToolbar <com.google.android.material.appbar.MaterialToolbar
+2 -3
View File
@@ -16,10 +16,9 @@
<com.google.android.material.appbar.CollapsingToolbarLayout <com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/collapsingToolbarLayoutLargeSize" android:layout_height="?attr/collapsingToolbarLayoutMediumSize"
style="?attr/collapsingToolbarLayoutLargeSize" style="?attr/collapsingToolbarLayoutLargeSize"
app:collapsedTitleTextAppearance="?attr/textAppearanceTitleLarge" app:expandedTitleTextAppearance="?attr/textAppearanceHeadlineMedium"
app:expandedTitleTextAppearance="?attr/textAppearanceHeadlineLarge"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"> app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<com.google.android.material.appbar.MaterialToolbar <com.google.android.material.appbar.MaterialToolbar