feat: Implement "About" screen
This commit introduces a new "About" screen that displays application information, including version, development team credits, and other acknowledgments.
**Key Changes:**
* **feat(AboutScreen):**
* Added a new `AboutScreen.kt` Composable to display app logo, version, development team roles, and other details.
* Created modular `InfoSection` and `InfoItem` components to structure the content.
* The screen features a top app bar with a back button.
* **feat(Navigation):**
* Added a new `Screen.About` destination to the navigation graph.
* The "About" option in the `UserScreen` now navigates to the newly created `AboutScreen`.
This commit is contained in:
parent
46588259dd
commit
a5041db384
@ -20,6 +20,7 @@ import com.qingshuige.tangyuan.navigation.Screen
|
|||||||
import com.qingshuige.tangyuan.ui.components.PageLevel
|
import com.qingshuige.tangyuan.ui.components.PageLevel
|
||||||
import com.qingshuige.tangyuan.ui.components.TangyuanBottomAppBar
|
import com.qingshuige.tangyuan.ui.components.TangyuanBottomAppBar
|
||||||
import com.qingshuige.tangyuan.ui.components.TangyuanTopBar
|
import com.qingshuige.tangyuan.ui.components.TangyuanTopBar
|
||||||
|
import com.qingshuige.tangyuan.ui.screens.AboutScreen
|
||||||
import com.qingshuige.tangyuan.ui.screens.PostDetailScreen
|
import com.qingshuige.tangyuan.ui.screens.PostDetailScreen
|
||||||
import com.qingshuige.tangyuan.ui.screens.ImageDetailScreen
|
import com.qingshuige.tangyuan.ui.screens.ImageDetailScreen
|
||||||
import com.qingshuige.tangyuan.ui.screens.TalkScreen
|
import com.qingshuige.tangyuan.ui.screens.TalkScreen
|
||||||
@ -50,6 +51,7 @@ fun App() {
|
|||||||
onAuthorClick = { authorId ->
|
onAuthorClick = { authorId ->
|
||||||
navController.navigate(Screen.UserDetail.createRoute(authorId))
|
navController.navigate(Screen.UserDetail.createRoute(authorId))
|
||||||
},
|
},
|
||||||
|
onAboutClick = { navController.navigate(Screen.About.route) },
|
||||||
sharedTransitionScope = this@SharedTransitionLayout,
|
sharedTransitionScope = this@SharedTransitionLayout,
|
||||||
animatedContentScope = this@composable
|
animatedContentScope = this@composable
|
||||||
)
|
)
|
||||||
@ -169,6 +171,12 @@ fun App() {
|
|||||||
animatedContentScope = this@composable
|
animatedContentScope = this@composable
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
composable(Screen.About.route) {
|
||||||
|
AboutScreen(
|
||||||
|
onBackClick = { navController.popBackStack() }
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -180,6 +188,7 @@ fun MainFlow(
|
|||||||
onPostClick: (Int) -> Unit,
|
onPostClick: (Int) -> Unit,
|
||||||
onImageClick: (Int, Int) -> Unit = { _, _ -> },
|
onImageClick: (Int, Int) -> Unit = { _, _ -> },
|
||||||
onAuthorClick: (Int) -> Unit = {},
|
onAuthorClick: (Int) -> Unit = {},
|
||||||
|
onAboutClick: () -> Unit,
|
||||||
sharedTransitionScope: SharedTransitionScope? = null,
|
sharedTransitionScope: SharedTransitionScope? = null,
|
||||||
animatedContentScope: AnimatedContentScope? = null,
|
animatedContentScope: AnimatedContentScope? = null,
|
||||||
userViewModel: UserViewModel = hiltViewModel()
|
userViewModel: UserViewModel = hiltViewModel()
|
||||||
@ -269,9 +278,7 @@ fun MainFlow(
|
|||||||
onSettings = {
|
onSettings = {
|
||||||
// TODO: 导航到设置页面
|
// TODO: 导航到设置页面
|
||||||
},
|
},
|
||||||
onAbout = {
|
onAbout = onAboutClick
|
||||||
// TODO: 导航到关于页面
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ sealed class Screen(val route: String, val title: String) {
|
|||||||
object Topic : Screen("topic", "侃一侃")
|
object Topic : Screen("topic", "侃一侃")
|
||||||
object Message : Screen("message", "消息")
|
object Message : Screen("message", "消息")
|
||||||
object User : Screen("settings", "我的")
|
object User : Screen("settings", "我的")
|
||||||
|
object About : Screen("about", "关于")
|
||||||
object PostDetail : Screen("post_detail/{postId}", "帖子详情") {
|
object PostDetail : Screen("post_detail/{postId}", "帖子详情") {
|
||||||
fun createRoute(postId: Int) = "post_detail/$postId"
|
fun createRoute(postId: Int) = "post_detail/$postId"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,206 @@
|
|||||||
|
package com.qingshuige.tangyuan.ui.screens
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.ColumnScope
|
||||||
|
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.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
|
import androidx.compose.material.icons.filled.MoreVert
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
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
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.qingshuige.tangyuan.R
|
||||||
|
import com.qingshuige.tangyuan.ui.components.AuroraBackground
|
||||||
|
import com.qingshuige.tangyuan.ui.theme.LiteraryFontFamily
|
||||||
|
import com.qingshuige.tangyuan.ui.theme.TangyuanGeneralFontFamily
|
||||||
|
import com.qingshuige.tangyuan.ui.theme.TangyuanTheme
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun AboutScreen(
|
||||||
|
onBackClick: () -> Unit = {}
|
||||||
|
) {
|
||||||
|
|
||||||
|
Scaffold(topBar = {
|
||||||
|
TopAppBar(
|
||||||
|
title = {
|
||||||
|
Text(
|
||||||
|
text = "关于",
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
},
|
||||||
|
navigationIcon = {
|
||||||
|
IconButton(onClick = onBackClick) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.ArrowBack,
|
||||||
|
contentDescription = "返回",
|
||||||
|
tint = MaterialTheme.colorScheme.onSurface
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions = {
|
||||||
|
IconButton(onClick = {}) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.MoreVert,
|
||||||
|
contentDescription = "其他",
|
||||||
|
tint = MaterialTheme.colorScheme.onSurface
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
colors = TopAppBarDefaults.topAppBarColors(
|
||||||
|
containerColor = MaterialTheme.colorScheme.surfaceVariant
|
||||||
|
),
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
)
|
||||||
|
}) { contentPadding ->
|
||||||
|
AuroraBackground {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(contentPadding),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
// App Logo and Name
|
||||||
|
Spacer(modifier = Modifier.height(32.dp))
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(R.drawable.ic_launcher_foreground),
|
||||||
|
contentDescription = "App Logo",
|
||||||
|
modifier = Modifier.size(100.dp),
|
||||||
|
tint = MaterialTheme.colorScheme.primary
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
Text(
|
||||||
|
text = "糖原",
|
||||||
|
style = MaterialTheme.typography.headlineMedium.copy(
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontFamily = LiteraryFontFamily
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "Version 1.0.0", // Placeholder
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(48.dp))
|
||||||
|
|
||||||
|
// Info Sections
|
||||||
|
InfoSection(title = "开发团队") {
|
||||||
|
InfoItem(label = "Lead Developer", value = "线粒体 XianliticCN")
|
||||||
|
InfoItem(label = "Algorithm", value = "南木, 浩瀚之渺, Legend")
|
||||||
|
InfoItem(label = "Business Manager", value = "なかのみく")
|
||||||
|
InfoItem(label = "Test", value = "NukeCirno, 嘉木, 猕猴桃教教主")
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
Text(
|
||||||
|
text = "所有成员皆参与了开发过程的全部工作。",
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
InfoSection(title = "Logo 设计") {
|
||||||
|
InfoItem(value = "南木")
|
||||||
|
}
|
||||||
|
|
||||||
|
InfoSection(title = "代号设计") {
|
||||||
|
InfoItem(value = "NukeCirno")
|
||||||
|
}
|
||||||
|
|
||||||
|
InfoSection(title = "特别纪念") {
|
||||||
|
Text(
|
||||||
|
text = "糖原在一台序列号为 6a34145e 的小米5上完成调试。",
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(32.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun InfoSection(
|
||||||
|
title: String,
|
||||||
|
content: @Composable ColumnScope.() -> Unit
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = 12.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
style = MaterialTheme.typography.titleLarge,
|
||||||
|
fontFamily = TangyuanGeneralFontFamily,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
modifier = Modifier.padding(bottom = 8.dp)
|
||||||
|
)
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun InfoItem(label: String? = null, value: String) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.padding(vertical = 4.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
if (label != null) {
|
||||||
|
Text(
|
||||||
|
text = "$label: ",
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
color = MaterialTheme.colorScheme.onSurface
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
text = value,
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(showBackground = true)
|
||||||
|
@Composable
|
||||||
|
fun AboutScreenPreview() {
|
||||||
|
TangyuanTheme {
|
||||||
|
Surface {
|
||||||
|
AboutScreen()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user