diff --git a/composeApp/src/commonMain/composeResources/drawable/bg_exercise_history.png b/composeApp/src/commonMain/composeResources/drawable/bg_exercise_history.png new file mode 100644 index 0000000..cd118b9 Binary files /dev/null and b/composeApp/src/commonMain/composeResources/drawable/bg_exercise_history.png differ diff --git a/composeApp/src/commonMain/composeResources/drawable/bg_score.png b/composeApp/src/commonMain/composeResources/drawable/bg_score.png new file mode 100644 index 0000000..622f526 Binary files /dev/null and b/composeApp/src/commonMain/composeResources/drawable/bg_score.png differ diff --git a/composeApp/src/commonMain/composeResources/drawable/ic_exercise_riding.png b/composeApp/src/commonMain/composeResources/drawable/ic_exercise_riding.png new file mode 100644 index 0000000..569fa76 Binary files /dev/null and b/composeApp/src/commonMain/composeResources/drawable/ic_exercise_riding.png differ diff --git a/composeApp/src/commonMain/composeResources/drawable/ic_exercise_running.png b/composeApp/src/commonMain/composeResources/drawable/ic_exercise_running.png new file mode 100644 index 0000000..c02a5af Binary files /dev/null and b/composeApp/src/commonMain/composeResources/drawable/ic_exercise_running.png differ diff --git a/composeApp/src/commonMain/composeResources/drawable/ic_exercise_swimming.png b/composeApp/src/commonMain/composeResources/drawable/ic_exercise_swimming.png new file mode 100644 index 0000000..7521a77 Binary files /dev/null and b/composeApp/src/commonMain/composeResources/drawable/ic_exercise_swimming.png differ diff --git a/composeApp/src/commonMain/composeResources/drawable/ic_free.png b/composeApp/src/commonMain/composeResources/drawable/ic_free.png new file mode 100644 index 0000000..7d83fbf Binary files /dev/null and b/composeApp/src/commonMain/composeResources/drawable/ic_free.png differ diff --git a/composeApp/src/commonMain/composeResources/drawable/ic_running.png b/composeApp/src/commonMain/composeResources/drawable/ic_running.png new file mode 100644 index 0000000..7bb52e9 Binary files /dev/null and b/composeApp/src/commonMain/composeResources/drawable/ic_running.png differ diff --git a/composeApp/src/commonMain/kotlin/com/whitefish/app/ui/home/exercise/ExerciseScreen.kt b/composeApp/src/commonMain/kotlin/com/whitefish/app/ui/home/exercise/ExerciseScreen.kt index 9aaf4f6..79a4535 100644 --- a/composeApp/src/commonMain/kotlin/com/whitefish/app/ui/home/exercise/ExerciseScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/whitefish/app/ui/home/exercise/ExerciseScreen.kt @@ -1,6 +1,7 @@ package com.whitefish.app.ui.home.exercise import androidx.compose.foundation.Canvas +import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn @@ -17,10 +18,24 @@ import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.StrokeCap import androidx.compose.ui.graphics.drawscope.Stroke +import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import org.jetbrains.compose.resources.DrawableResource +import org.jetbrains.compose.resources.painterResource +import org.jetbrains.compose.ui.tooling.preview.Preview +import ringappkmp.composeapp.generated.resources.Res +import ringappkmp.composeapp.generated.resources.bg +import ringappkmp.composeapp.generated.resources.bg_exercise_history +import ringappkmp.composeapp.generated.resources.bg_exercise_target +import ringappkmp.composeapp.generated.resources.bg_score +import ringappkmp.composeapp.generated.resources.ic_exercise_riding +import ringappkmp.composeapp.generated.resources.ic_exercise_running +import ringappkmp.composeapp.generated.resources.ic_exercise_swimming +import ringappkmp.composeapp.generated.resources.ic_free +import ringappkmp.composeapp.generated.resources.ic_running @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -96,22 +111,22 @@ fun ExerciseTypeCards() { item { ExerciseTypeCard( title = "跑步", - gradient = listOf(Color(0xFF4FC3F7), Color(0xFF29B6F6)), - modifier = Modifier.size(160.dp, 120.dp) + modifier = Modifier.size(154.dp, 154.dp), + background = Res.drawable.ic_exercise_running ) } item { ExerciseTypeCard( title = "骑行", - gradient = listOf(Color(0xFFFFB74D), Color(0xFFFF9800)), - modifier = Modifier.size(160.dp, 120.dp) + background = Res.drawable.ic_exercise_riding, + modifier = Modifier.size(154.dp, 154.dp) ) } item { ExerciseTypeCard( title = "游泳", - gradient = listOf(Color(0xFF4DD0E1), Color(0xFF00BCD4)), - modifier = Modifier.size(160.dp, 120.dp) + background = Res.drawable.ic_exercise_swimming, + modifier = Modifier.size(154.dp, 154.dp) ) } } @@ -120,7 +135,7 @@ fun ExerciseTypeCards() { @Composable fun ExerciseTypeCard( title: String, - gradient: List, + background: DrawableResource, modifier: Modifier = Modifier ) { Card( @@ -132,17 +147,24 @@ fun ExerciseTypeCard( modifier = Modifier .fillMaxSize() .background( - Brush.linearGradient(gradient), + Color.Transparent, RoundedCornerShape(16.dp) ), - contentAlignment = Alignment.Center + contentAlignment = Alignment.TopStart ) { - Text( - text = title, - fontSize = 18.sp, - color = Color.White, - fontWeight = FontWeight.Bold + Image( + painterResource(background), + contentDescription = null, + modifier = Modifier.fillMaxSize() ) + Row(modifier = Modifier.padding(top = 20.dp, start = 20.dp)) { + Text( + text = title, + fontSize = 24.sp, + color = Color.White, + fontWeight = FontWeight.Bold, + ) + } } } } @@ -158,7 +180,11 @@ fun AddExerciseButton() { shape = RoundedCornerShape(16.dp), elevation = CardDefaults.cardElevation(10.dp) ) { - Row(modifier = Modifier.fillMaxSize(),verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Center) { + Row( + modifier = Modifier.fillMaxSize(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { Text( text = "+ 添加运动记录", fontSize = 16.sp, @@ -173,58 +199,72 @@ fun AddExerciseButton() { fun ExerciseRecordsSection() { Card( modifier = Modifier.fillMaxWidth(), - shape = RoundedCornerShape(16.dp), - colors = CardDefaults.cardColors(Color.White.copy(alpha = 0.9f)) + shape = RoundedCornerShape(24.dp), + colors = CardDefaults.cardColors(containerColor = Color.Transparent) ) { - Column( - modifier = Modifier.padding(16.dp) - ) { - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically + Box(modifier = Modifier.fillMaxSize()){ + Image( + painterResource(Res.drawable.bg_exercise_history), + contentDescription = null, + modifier = Modifier.fillMaxSize(), + contentScale = ContentScale.Crop + ) + Column( + modifier = Modifier.padding(14.dp) ) { - Text( - text = "运动记录", - fontSize = 16.sp, - fontWeight = FontWeight.Bold, - color = Color(0xFF666666) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "运动记录", + fontSize = 16.sp, + fontWeight = FontWeight.Bold, + color = Color(0xffffffff) + ) + Text( + text = "查看更多", + fontSize = 14.sp, + color = Color(0xffffffff) + ) + } + + Spacer(modifier = Modifier.height(16.dp)) + + // 户外跑步记录 + ExerciseRecordItem( + iconColor = Color(0xFF2196F3), + iconRes = Res.drawable.ic_running, + title = "户外跑步", + distance = "2.85公里", + time = "00:20:36", + pace = "7'59\"公里" ) - Text( - text = "查看更多", - fontSize = 14.sp, - color = Color(0xFF9C27B0) + + Row(modifier = Modifier.height(16.dp).padding(start = 65.dp), verticalAlignment = Alignment.CenterVertically){ + Box(modifier = Modifier.background(Color.White).height(1.dp).fillMaxWidth()) + } + + // 自由训练记录 + ExerciseRecordItem( + iconColor = Color(0xFF4CAF50), + title = "自由训练", + distance = "161千卡", + time = "00:57:06", + pace = "104次/分钟", + iconRes = Res.drawable.ic_free ) } - - Spacer(modifier = Modifier.height(16.dp)) - - // 户外跑步记录 - ExerciseRecordItem( - iconColor = Color(0xFF2196F3), - title = "户外跑步", - distance = "2.85公里", - time = "00:20:36", - pace = "7'59\"公里" - ) - - Spacer(modifier = Modifier.height(12.dp)) - - // 自由训练记录 - ExerciseRecordItem( - iconColor = Color(0xFF4CAF50), - title = "自由训练", - distance = "161千卡", - time = "00:57:06", - pace = "104次/分钟" - ) } + } } @Composable fun ExerciseRecordItem( iconColor: Color, + iconRes: DrawableResource, title: String, distance: String, time: String, @@ -237,16 +277,11 @@ fun ExerciseRecordItem( // 运动图标占位 Box( modifier = Modifier - .size(40.dp) + .size(50.dp) .background(iconColor, CircleShape), contentAlignment = Alignment.Center ) { - Text( - text = title.first().toString(), - color = Color.White, - fontSize = 16.sp, - fontWeight = FontWeight.Bold - ) + Image(painterResource(iconRes),contentDescription = null) } Spacer(modifier = Modifier.width(12.dp)) @@ -254,28 +289,28 @@ fun ExerciseRecordItem( Column(modifier = Modifier.weight(1f)) { Text( text = title, - fontSize = 16.sp, + fontSize = 12.sp, fontWeight = FontWeight.Medium, - color = Color(0xFF333333) + color = Color(0xEFffffff), ) Spacer(modifier = Modifier.height(4.dp)) - Row { + Row(modifier = Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.SpaceBetween) { Text( text = distance, - fontSize = 14.sp, - color = Color(0xFF666666) + fontSize = 12.sp, + color = Color(0xFFffffff) ) Spacer(modifier = Modifier.width(16.dp)) Text( text = time, - fontSize = 14.sp, - color = Color(0xFF666666) + fontSize = 12.sp, + color = Color(0xFFffffff) ) Spacer(modifier = Modifier.width(16.dp)) Text( text = pace, - fontSize = 14.sp, - color = Color(0xFF666666) + fontSize = 12.sp, + color = Color(0xFFffffff) ) } } @@ -286,59 +321,62 @@ fun ExerciseRecordItem( fun ComprehensiveScoreSection() { Card( modifier = Modifier.fillMaxWidth(), - shape = RoundedCornerShape(16.dp), - colors = CardDefaults.cardColors(Color.White.copy(alpha = 0.9f)) + shape = RoundedCornerShape(24.dp), + colors = CardDefaults.cardColors(Color.Transparent) ) { - Column( - modifier = Modifier.padding(16.dp) - ) { - Text( - text = "综合评分", - fontSize = 16.sp, - fontWeight = FontWeight.Bold, - color = Color(0xFF333333) - ) - - Spacer(modifier = Modifier.height(20.dp)) - - // 圆形评分图表 - Box( - modifier = Modifier - .fillMaxWidth() - .height(200.dp), - contentAlignment = Alignment.Center + Box(modifier = Modifier.fillMaxSize()){ + Image(painterResource(Res.drawable.bg_score),contentDescription = null, modifier = Modifier.fillMaxSize(), contentScale = ContentScale.Crop) + Column( + modifier = Modifier.padding(16.dp) ) { - CircularScoreChart(score = 75) - } + Text( + text = "综合评分", + fontSize = 16.sp, + fontWeight = FontWeight.Bold, + color = Color(0xFF333333) + ) - Spacer(modifier = Modifier.height(20.dp)) + Spacer(modifier = Modifier.height(20.dp)) - // 评估指标 - Column(verticalArrangement = Arrangement.spacedBy(12.dp)) { - ScoreIndicator( - label = "活动小时数得分", - value = "佳", - progress = 0.8f, - color = Color(0xFFFF6B6B) - ) - ScoreIndicator( - label = "有氧活动评估", - value = "佳", - progress = 0.85f, - color = Color(0xFF4ECDC4) - ) - ScoreIndicator( - label = "运动强度审评估", - value = "优", - progress = 0.95f, - color = Color(0xFF45B7D1) - ) - ScoreIndicator( - label = "运动强度效率评估", - value = "优", - progress = 0.9f, - color = Color(0xFF96CEB4) - ) + // 圆形评分图表 + Box( + modifier = Modifier + .fillMaxWidth() + .height(140.dp), + contentAlignment = Alignment.Center + ) { + CircularScoreChart(score = 75) + } + + Spacer(modifier = Modifier.height(20.dp)) + + // 评估指标 + Column(verticalArrangement = Arrangement.spacedBy(12.dp)) { + ScoreIndicator( + label = "活动小时数得分", + value = "佳", + progress = 0.8f, + color = Color(0xFFFF6B6B) + ) + ScoreIndicator( + label = "有氧活动评估", + value = "佳", + progress = 0.85f, + color = Color(0xFF4ECDC4) + ) + ScoreIndicator( + label = "运动强度审评估", + value = "优", + progress = 0.95f, + color = Color(0xFF45B7D1) + ) + ScoreIndicator( + label = "运动强度效率评估", + value = "优", + progress = 0.9f, + color = Color(0xFF96CEB4) + ) + } } } } @@ -346,25 +384,28 @@ fun ComprehensiveScoreSection() { @Composable fun CircularScoreChart(score: Int) { - Box(contentAlignment = Alignment.Center) { - Canvas(modifier = Modifier.size(120.dp)) { + Box(contentAlignment = Alignment.BottomCenter) { + Canvas(modifier = Modifier.size(250.dp, 125.dp)) { val strokeWidth = 12.dp.toPx() - val radius = (size.minDimension - strokeWidth) / 2 - val center = Offset(size.width / 2, size.height / 2) + val radius = (size.width - strokeWidth) / 2 + val center = Offset(size.width / 2, size.height) - // 背景圆 - drawCircle( + // 背景半圆弧 + drawArc( color = Color(0xFFE0E0E0), - radius = radius, - center = center, - style = Stroke(strokeWidth) + startAngle = 180f, + sweepAngle = 180f, + useCenter = false, + style = Stroke(strokeWidth), + topLeft = Offset(center.x - radius, center.y - radius), + size = Size(radius * 2, radius * 2) ) - // 进度圆弧 - val sweepAngle = (score / 100f) * 360f + // 进度半圆弧 + val sweepAngle = (score / 100f) * 180f drawArc( color = Color(0xFF5E35B1), - startAngle = -90f, + startAngle = 180f, sweepAngle = sweepAngle, useCenter = false, style = Stroke(strokeWidth, cap = StrokeCap.Round), @@ -373,7 +414,10 @@ fun CircularScoreChart(score: Int) { ) } - Column(horizontalAlignment = Alignment.CenterHorizontally) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.padding(bottom = 8.dp) + ) { Text( text = score.toString(), fontSize = 36.sp, @@ -437,8 +481,8 @@ fun ScoreIndicator( fun InsightSection() { Card( modifier = Modifier.fillMaxWidth(), - shape = RoundedCornerShape(16.dp), - colors = CardDefaults.cardColors(Color(0xFF5E35B1)) + shape = RoundedCornerShape(24.dp), + colors = CardDefaults.cardColors(Color(0x80352764)) ) { Column( modifier = Modifier.padding(16.dp) @@ -460,4 +504,10 @@ fun InsightSection() { ) } } -} \ No newline at end of file +} + +@Preview +@Composable +fun ExerciseScreenPreview() { + ExerciseScreen() +} \ No newline at end of file