feat: 关于页面与开源许可声明
- 新增 AboutScreen:应用图标、名称、版本、开源许可入口 - 新增 LicensesScreen 与 Licenses 数据源,展示第三方依赖许可证 - App 内页面导航(Main/About/Licenses) - 双平台 getAppIconUri() 及 app_icon.png 资源 - 菜单"关于"项接入 AboutScreen 跳转 - iOS Info.plist 补充 CFBundleShortVersionString / CFBundleVersion Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e93d575f02
commit
43579b2866
BIN
androidApp/src/main/assets/app_icon.png
Normal file
BIN
androidApp/src/main/assets/app_icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
@ -4,5 +4,9 @@
|
||||
<dict>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@ -8,4 +8,6 @@ class AndroidPlatform : Platform {
|
||||
|
||||
actual fun getPlatform(): Platform = AndroidPlatform()
|
||||
|
||||
actual fun getGifUri(gifFile: String): String = "file:///android_asset/gifs/$gifFile"
|
||||
actual fun getGifUri(gifFile: String): String = "file:///android_asset/gifs/$gifFile"
|
||||
|
||||
actual fun getAppIconUri(): String = "file:///android_asset/app_icon.png"
|
||||
BIN
shared/src/commonMain/composeResources/files/app_icon.png
Normal file
BIN
shared/src/commonMain/composeResources/files/app_icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
@ -5,18 +5,40 @@ import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
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.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import plus.rua.project.ui.AboutScreen
|
||||
import plus.rua.project.ui.CalendarMonthView
|
||||
import plus.rua.project.ui.LicensesScreen
|
||||
|
||||
private enum class Screen { Main, About, Licenses }
|
||||
|
||||
/**
|
||||
* 应用入口 Composable,根据系统主题切换明暗 ColorScheme 并包裹 CalendarMonthView。
|
||||
* 应用入口 Composable,根据系统主题切换明暗 ColorScheme 并管理页面导航。
|
||||
*/
|
||||
@Composable
|
||||
@Preview(name = "Calendar App")
|
||||
fun App() {
|
||||
var currentScreen by remember { mutableStateOf(Screen.Main) }
|
||||
|
||||
val colorScheme = if (isSystemInDarkTheme()) darkColorScheme() else lightColorScheme()
|
||||
MaterialTheme(colorScheme = colorScheme) {
|
||||
CalendarMonthView(modifier = Modifier)
|
||||
when (currentScreen) {
|
||||
Screen.Main -> CalendarMonthView(
|
||||
modifier = Modifier,
|
||||
onNavigateToAbout = { currentScreen = Screen.About }
|
||||
)
|
||||
Screen.About -> AboutScreen(
|
||||
onBack = { currentScreen = Screen.Main },
|
||||
onNavigateToLicenses = { currentScreen = Screen.Licenses }
|
||||
)
|
||||
Screen.Licenses -> LicensesScreen(
|
||||
onBack = { currentScreen = Screen.About }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
9
shared/src/commonMain/kotlin/plus/rua/project/AppInfo.kt
Normal file
9
shared/src/commonMain/kotlin/plus/rua/project/AppInfo.kt
Normal file
@ -0,0 +1,9 @@
|
||||
package plus.rua.project
|
||||
|
||||
/**
|
||||
* 应用常量信息。
|
||||
*/
|
||||
object AppInfo {
|
||||
const val NAME = "鸭鸭日历"
|
||||
const val VERSION = "1.0"
|
||||
}
|
||||
@ -12,4 +12,6 @@ expect fun getPlatform(): Platform
|
||||
* @param gifFile GIF 文件名(如 "001.gif")
|
||||
* @return 平台特定的资源 URI
|
||||
*/
|
||||
expect fun getGifUri(gifFile: String): String
|
||||
expect fun getGifUri(gifFile: String): String
|
||||
|
||||
expect fun getAppIconUri(): String
|
||||
114
shared/src/commonMain/kotlin/plus/rua/project/ui/AboutScreen.kt
Normal file
114
shared/src/commonMain/kotlin/plus/rua/project/ui/AboutScreen.kt
Normal file
@ -0,0 +1,114 @@
|
||||
package plus.rua.project.ui
|
||||
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.StrokeCap
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.github.panpf.sketch.AsyncImage
|
||||
import plus.rua.project.AppInfo
|
||||
import plus.rua.project.getAppIconUri
|
||||
|
||||
/**
|
||||
* 关于页面,展示应用图标、名称、版本号及开源许可入口。
|
||||
*
|
||||
* @param onBack 返回回调
|
||||
* @param onNavigateToLicenses 跳转到开源许可页面回调
|
||||
* @param modifier 布局修饰符
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun AboutScreen(
|
||||
onBack: () -> Unit,
|
||||
onNavigateToLicenses: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = { Text("关于鸭鸭日历") },
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBack) {
|
||||
Canvas(modifier = Modifier.size(24.dp)) {
|
||||
val strokeWidth = 2.dp.toPx()
|
||||
drawLine(
|
||||
color = Color.White,
|
||||
start = Offset(size.width * 0.75f, size.height * 0.25f),
|
||||
end = Offset(size.width * 0.25f, size.height * 0.5f),
|
||||
strokeWidth = strokeWidth,
|
||||
cap = StrokeCap.Round
|
||||
)
|
||||
drawLine(
|
||||
color = Color.White,
|
||||
start = Offset(size.width * 0.25f, size.height * 0.5f),
|
||||
end = Offset(size.width * 0.75f, size.height * 0.75f),
|
||||
strokeWidth = strokeWidth,
|
||||
cap = StrokeCap.Round
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
modifier = modifier
|
||||
) { innerPadding ->
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(innerPadding)
|
||||
.padding(horizontal = 24.dp)
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(48.dp))
|
||||
|
||||
val appIconUri = remember { getAppIconUri() }
|
||||
AsyncImage(
|
||||
uri = appIconUri,
|
||||
contentDescription = "应用图标",
|
||||
modifier = Modifier
|
||||
.size(80.dp)
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
Text(
|
||||
text = AppInfo.NAME,
|
||||
style = MaterialTheme.typography.titleLarge
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Text(
|
||||
text = "版本:${AppInfo.VERSION}",
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(48.dp))
|
||||
|
||||
TextButton(onClick = onNavigateToLicenses) {
|
||||
Text("开放源代码许可")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -78,7 +78,8 @@ import kotlin.time.Clock
|
||||
*/
|
||||
@Composable
|
||||
fun CalendarMonthView(
|
||||
modifier: Modifier = Modifier
|
||||
modifier: Modifier = Modifier,
|
||||
onNavigateToAbout: () -> Unit = {}
|
||||
) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val viewModel = remember { CalendarViewModel(coroutineScope) }
|
||||
@ -468,7 +469,10 @@ fun CalendarMonthView(
|
||||
MenuItem(
|
||||
text = "关于",
|
||||
selected = false,
|
||||
onClick = { /* TODO: 后续接入设置页 */ }
|
||||
onClick = {
|
||||
isMenuExpanded = false
|
||||
onNavigateToAbout()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
27
shared/src/commonMain/kotlin/plus/rua/project/ui/Licenses.kt
Normal file
27
shared/src/commonMain/kotlin/plus/rua/project/ui/Licenses.kt
Normal file
@ -0,0 +1,27 @@
|
||||
package plus.rua.project.ui
|
||||
|
||||
/**
|
||||
* 许可证条目数据。
|
||||
*
|
||||
* @param library 库名称
|
||||
* @param license 许可证名称
|
||||
*/
|
||||
data class LicenseItem(
|
||||
val library: String,
|
||||
val license: String
|
||||
)
|
||||
|
||||
/**
|
||||
* 项目使用的第三方库及其许可证列表。
|
||||
*/
|
||||
val licenses = listOf(
|
||||
LicenseItem("Kotlin", "Apache-2.0"),
|
||||
LicenseItem("Compose Multiplatform", "Apache-2.0"),
|
||||
LicenseItem("Material 3", "Apache-2.0"),
|
||||
LicenseItem("kotlinx-datetime", "Apache-2.0"),
|
||||
LicenseItem("tyme4kt", "MIT"),
|
||||
LicenseItem("Sketch", "Apache-2.0"),
|
||||
LicenseItem("AndroidX Activity", "Apache-2.0"),
|
||||
LicenseItem("AndroidX Lifecycle", "Apache-2.0"),
|
||||
LicenseItem("JUnit", "EPL-1.0"),
|
||||
)
|
||||
@ -0,0 +1,98 @@
|
||||
package plus.rua.project.ui
|
||||
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.StrokeCap
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* 开放源代码许可页面,展示项目使用的第三方库及其许可证。
|
||||
*
|
||||
* @param onBack 返回回调
|
||||
* @param modifier 布局修饰符
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun LicensesScreen(
|
||||
onBack: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = { Text("开放源代码许可") },
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBack) {
|
||||
Canvas(modifier = Modifier.size(24.dp)) {
|
||||
val strokeWidth = 2.dp.toPx()
|
||||
drawLine(
|
||||
color = Color.White,
|
||||
start = Offset(size.width * 0.75f, size.height * 0.25f),
|
||||
end = Offset(size.width * 0.25f, size.height * 0.5f),
|
||||
strokeWidth = strokeWidth,
|
||||
cap = StrokeCap.Round
|
||||
)
|
||||
drawLine(
|
||||
color = Color.White,
|
||||
start = Offset(size.width * 0.25f, size.height * 0.5f),
|
||||
end = Offset(size.width * 0.75f, size.height * 0.75f),
|
||||
strokeWidth = strokeWidth,
|
||||
cap = StrokeCap.Round
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
modifier = modifier
|
||||
) { innerPadding ->
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(innerPadding)
|
||||
) {
|
||||
items(licenses) { item ->
|
||||
Column {
|
||||
ListItem(
|
||||
modifier = Modifier.clickable { },
|
||||
headlineContent = {
|
||||
Text(
|
||||
text = item.library,
|
||||
style = MaterialTheme.typography.bodyLarge
|
||||
)
|
||||
},
|
||||
trailingContent = {
|
||||
Text(
|
||||
text = item.license,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
)
|
||||
HorizontalDivider(
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
color = MaterialTheme.colorScheme.outlineVariant
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9,4 +9,6 @@ class IOSPlatform : Platform {
|
||||
|
||||
actual fun getPlatform(): Platform = IOSPlatform()
|
||||
|
||||
actual fun getGifUri(gifFile: String): String = "compose.resource://files/$gifFile"
|
||||
actual fun getGifUri(gifFile: String): String = "compose.resource://files/$gifFile"
|
||||
|
||||
actual fun getAppIconUri(): String = "compose.resource://files/app_icon.png"
|
||||
Loading…
x
Reference in New Issue
Block a user