[优化] 优化了一些界面布局

This commit is contained in:
HapeLee
2025-12-28 15:53:32 +08:00
parent 841c3df172
commit 925c7ad913
9 changed files with 149 additions and 201 deletions
@@ -45,6 +45,7 @@ abstract class BaseComposeActivity(
super.onCreate(savedInstanceState)
setupSystemBar()
// Compose 入口
setContent {
AppTheme {
@@ -54,8 +55,6 @@ abstract class BaseComposeActivity(
}
}
setupSystemBar()
if (imageBg) {
upBackgroundImage()
}
@@ -43,6 +43,7 @@ class AboutActivity : BaseComposeActivity() {
@Composable
override fun Content() {
AboutScreen(
onBack = { finish() },
onCheckUpdate = { checkUpdate() },
onOpenUrl = { openUrl(it) },
onShowMdFile = { title, file -> showMdFile(title, file) },
@@ -1,6 +1,5 @@
package io.legado.app.ui.about
import android.content.res.Configuration
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
@@ -25,7 +24,6 @@ import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MediumTopAppBar
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
@@ -36,11 +34,9 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import io.legado.app.R
import io.legado.app.base.AppTheme
import io.legado.app.constant.AppConst.appInfo
import io.legado.app.ui.widget.components.SettingItem
import io.legado.app.ui.widget.components.SplicedColumnGroup
@@ -50,7 +46,7 @@ import io.legado.app.ui.widget.components.TextCard
@Composable
fun AboutScreen(
versionName: String = appInfo.versionName,
onNavigateBack: () -> Unit = {},
onBack: () -> Unit = {},
onCheckUpdate: () -> Unit = {},
onOpenUrl: (String) -> Unit = {},
onShowMdFile: (String, String) -> Unit = { _, _ -> },
@@ -68,7 +64,7 @@ fun AboutScreen(
MediumTopAppBar(
title = { Text(stringResource(R.string.about)) },
navigationIcon = {
IconButton(onClick = onNavigateBack) {
IconButton(onClick = onBack) {
Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = stringResource(R.string.back)
@@ -82,7 +78,6 @@ fun AboutScreen(
Column(
modifier = Modifier
.padding(padding)
.padding(horizontal = 16.dp)
.verticalScroll(rememberScrollState())
) {
Image(
@@ -145,63 +140,60 @@ fun AboutScreen(
}
SplicedColumnGroup(
title = "",
content = listOf(
{
SettingItem(
modifier = Modifier.background(colorScheme.surfaceBright),
title = stringResource(R.string.contributors),
description = null,
option = null,
onClick = {
onOpenUrl("https://github.com/gedoor/legado/graphs/contributors")
}
)
SettingItem(
title = stringResource(R.string.privacy_policy),
description = null,
option = null,
onClick = {
onShowMdFile("隐私政策", "privacyPolicy.md")
}
)
SettingItem(
title = stringResource(R.string.license),
description = null,
option = null,
onClick = {
onShowMdFile("许可证", "LICENSE.md")
}
)
SettingItem(
title = stringResource(R.string.disclaimer),
description = null,
option = null,
onClick = {
onShowMdFile("免责声明", "disclaimer.md")
}
)
SettingItem(
title = stringResource(R.string.crash_log),
description = null,
option = null,
onClick = onShowCrashLogs
)
SettingItem(
title = stringResource(R.string.save_log),
description = null,
option = null,
onClick = onSaveLog
)
SettingItem(
title = stringResource(R.string.create_heap_dump),
description = null,
option = null,
onClick = onCreateHeapDump
)
modifier = Modifier.padding(horizontal = 16.dp),
title = ""
){
SettingItem(
title = stringResource(R.string.contributors),
description = null,
option = null,
onClick = {
onOpenUrl("https://github.com/gedoor/legado/graphs/contributors")
}
)
)
SettingItem(
title = stringResource(R.string.privacy_policy),
description = null,
option = null,
onClick = {
onShowMdFile("隐私政策", "privacyPolicy.md")
}
)
SettingItem(
title = stringResource(R.string.license),
description = null,
option = null,
onClick = {
onShowMdFile("许可证", "LICENSE.md")
}
)
SettingItem(
title = stringResource(R.string.disclaimer),
description = null,
option = null,
onClick = {
onShowMdFile("免责声明", "disclaimer.md")
}
)
SettingItem(
title = stringResource(R.string.crash_log),
description = null,
option = null,
onClick = onShowCrashLogs
)
SettingItem(
title = stringResource(R.string.save_log),
description = null,
option = null,
onClick = onSaveLog
)
SettingItem(
title = stringResource(R.string.create_heap_dump),
description = null,
option = null,
onClick = onCreateHeapDump
)
}
}
}
}
@@ -1,9 +1,9 @@
package io.legado.app.ui.book.readRecord
import android.os.Bundle
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.lifecycle.lifecycleScope
import io.legado.app.base.AppTheme
import io.legado.app.data.appDb
import io.legado.app.utils.startActivityForBook
import kotlinx.coroutines.Dispatchers
@@ -22,10 +22,8 @@ class ReadRecordActivity : BaseComposeActivity() {
@Composable
override fun Content() {
MaterialTheme {
val viewModel: ReadRecordViewModel = koinViewModel()
AppTheme {
ReadRecordScreen(
viewModel = viewModel,
onBackClick = { finish() },
onBookClick = { bookName ->
lifecycleScope.launch {
@@ -66,6 +66,7 @@ import io.legado.app.ui.widget.components.SearchBarSection
import io.legado.app.ui.widget.components.SectionHeader
import io.legado.app.utils.StringUtils.formatFriendlyDate
import kotlinx.coroutines.delay
import org.koin.androidx.compose.koinViewModel
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.util.Date
@@ -78,7 +79,7 @@ import kotlin.collections.sumOf
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ReadRecordScreen(
viewModel: ReadRecordViewModel,
viewModel: ReadRecordViewModel = koinViewModel(),
onBackClick: () -> Unit,
onBookClick: (String) -> Unit
) {
@@ -3,17 +3,21 @@ package io.legado.app.ui.replace
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.runtime.Composable
import io.legado.app.base.AppTheme
import io.legado.app.base.BaseComposeActivity
class ReplaceRuleActivity : AppCompatActivity() {
class ReplaceRuleActivity : BaseComposeActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
AppTheme {
ReplaceRuleScreen(onBackClick = { finish() })
}
@Composable
override fun Content() {
AppTheme {
ReplaceRuleScreen(onBackClick = { finish() })
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
}
@@ -330,15 +330,15 @@ fun ReplaceRuleScreen(
snackbarHost = { SnackbarHost(snackbarHostState) },
topBar = {
Column {
val titleText = remember(isUploading, inSelectionMode, selectedRuleIds.size, rules.size) {
when {
isUploading -> "正在上传..."
inSelectionMode -> "已选择 ${selectedRuleIds.size}/${rules.size}"
else -> "替换规则"
}
}
MediumTopAppBar(
title = {
val titleText = remember(isUploading, inSelectionMode, selectedRuleIds.size, rules.size) {
when {
isUploading -> "正在上传..."
inSelectionMode -> "已选择 ${selectedRuleIds.size}/${rules.size}"
else -> "替换规则"
}
}
AnimatedText(
text = titleText
)
@@ -485,12 +485,12 @@ fun ReplaceRuleScreen(
) { padding ->
Box(
modifier = Modifier
.padding(padding)
.fillMaxSize()
) {
FastScrollLazyColumn(
state = listState,
modifier = Modifier
.padding(padding)
.fillMaxSize(),
contentPadding = PaddingValues(
top = 8.dp,
@@ -561,7 +561,6 @@ fun ReplaceRuleScreen(
onSelectionChange = viewModel::setSelection,
haptic = haptic,
modifier = Modifier
.padding(padding)
.fillMaxHeight()
.width(60.dp)
.align(Alignment.TopStart)
@@ -1,5 +1,6 @@
package io.legado.app.ui.widget.components
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@@ -15,6 +16,8 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ChevronRight
import androidx.compose.material.icons.filled.Info
import androidx.compose.material3.Icon
import androidx.compose.material3.ListItem
import androidx.compose.material3.ListItemDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.Text
@@ -95,85 +98,64 @@ fun SettingItem(
painter: Painter? = null,
imageVector: ImageVector? = null,
title: String,
description: String? = null,
option: String? = null,
trailingContent: @Composable (() -> Unit)? = null,
description: String? = null,
onClick: () -> Unit
) {
Row(
modifier = Modifier
ListItem(
modifier = modifier
.clip(RoundedCornerShape(4.dp))
.then(modifier)
.fillMaxWidth()
.clickable { onClick() }
.padding(horizontal = 8.dp)
.padding(vertical = 12.dp)
.heightIn(min = 56.dp),
verticalAlignment = Alignment.CenterVertically
) {
painter?.let {
Icon(
modifier = Modifier.padding(end = 8.dp).size(24.dp),
painter = it,
tint = colorScheme.onSurfaceVariant,
contentDescription = "Icon"
)
}
imageVector?.let {
Icon(
imageVector = it,
contentDescription = null,
modifier = Modifier
.padding(end = 8.dp)
.size(24.dp),
tint = colorScheme.onSurfaceVariant
)
}
Column(
modifier = Modifier.weight(1f),
verticalArrangement = if (description == null)
Arrangement.Center
else
Arrangement.spacedBy(3.dp)
) {
.clickable(onClick = onClick),
leadingContent = {
when {
painter != null -> {
Icon(
painter = painter,
contentDescription = null,
tint = MaterialTheme.colorScheme.onSurfaceVariant
)
}
imageVector != null -> {
Icon(
imageVector = imageVector,
contentDescription = null,
tint = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
},
headlineContent = {
Text(
text = title,
color = colorScheme.onSurface,
style = AppTypography.titleMedium,
fontWeight = FontWeight.Normal
style = MaterialTheme.typography.titleMedium
)
},
supportingContent = {
Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
description?.let {
Text(
text = it,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
description?.let {
Text(
text = it,
color = colorScheme.onSurfaceVariant,
style = AppTypography.labelMedium
)
option?.let {
AnimatedTextLine(
text = it,
style = MaterialTheme.typography.labelMedium,
color = MaterialTheme.colorScheme.primary,
maxLines = 3,
overflow = TextOverflow.Ellipsis
)
}
}
option?.let {
AnimatedTextLine(
text = it,
style = AppTypography.labelMedium,
color = colorScheme.primary,
maxLines = 3,
overflow = TextOverflow.Ellipsis
)
}
}
trailingContent?.let { composable ->
Box(
modifier = Modifier
.width(55.dp),
contentAlignment = Alignment.Center
) {
composable()
}
}
}
},
trailingContent = trailingContent,
colors = ListItemDefaults.colors(
containerColor = MaterialTheme.colorScheme.surfaceContainerLow
)
)
}
@@ -3,8 +3,12 @@ package io.legado.app.ui.widget.components
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -14,7 +18,7 @@ import androidx.compose.ui.unit.dp
/**
* Settings Group Container by https://github.com/wxxsfxyzm/InstallerX-Revived
*
* Edit by @Kudomaga
* @param title the title of the group
* @param content a list of composable that will be displayed in the group
* @param modifier Modifier
@@ -23,61 +27,29 @@ import androidx.compose.ui.unit.dp
fun SplicedColumnGroup(
modifier: Modifier = Modifier,
title: String = "",
content: List<@Composable () -> Unit>,
content: @Composable ColumnScope.() -> Unit,
) {
if (content.isEmpty()) return
val cornerRadius = 16.dp
val connectionRadius = 5.dp
// Define shapes for different positions.
val topShape = RoundedCornerShape(
topStart = cornerRadius,
topEnd = cornerRadius,
bottomStart = connectionRadius,
bottomEnd = connectionRadius
)
val middleShape = RoundedCornerShape(connectionRadius)
val bottomShape = RoundedCornerShape(
topStart = connectionRadius,
topEnd = connectionRadius,
bottomStart = cornerRadius,
bottomEnd = cornerRadius
)
val singleShape = RoundedCornerShape(cornerRadius)
Column(modifier = modifier.padding(vertical = 8.dp)) {
// Group title
if (title != "")
if (title.isNotEmpty()) {
Text(
text = title,
style = MaterialTheme.typography.titleSmall,
style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.primary,
modifier = Modifier.padding(start = 16.dp, bottom = 8.dp)
)
}
// The container for setting items.
Column(
modifier = Modifier.clip(
// Clip the whole column to ensure content stays within the rounded bounds.
if (content.size == 1) singleShape else RoundedCornerShape(cornerRadius)
Card(
shape = RoundedCornerShape(16.dp),
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surface
),
verticalArrangement = Arrangement.spacedBy(2.dp)
modifier = Modifier.fillMaxWidth()
) {
content.forEachIndexed { index, itemContent ->
// Determine the shape based on the pkg's position.
val shape = when {
content.size == 1 -> singleShape
index == 0 -> topShape
index == content.size - 1 -> bottomShape
else -> middleShape
}
// Apply background with the correct shape to the pkg.
Column(
modifier = Modifier.background(MaterialTheme.colorScheme.surfaceBright, shape)
) {
itemContent()
}
Column(
verticalArrangement = Arrangement.spacedBy(4.dp)
) {
content()
}
}
}