[优化] 优化了一些界面布局
This commit is contained in:
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user