|
|
@ -1,22 +1,44 @@ |
|
|
|
package com.whitefish.ring.ui.home.setting |
|
|
|
|
|
|
|
import androidx.compose.foundation.Image |
|
|
|
import androidx.compose.foundation.background |
|
|
|
import androidx.compose.foundation.clickable |
|
|
|
import androidx.compose.foundation.layout.* |
|
|
|
import androidx.compose.foundation.layout.Arrangement |
|
|
|
import androidx.compose.foundation.layout.Box |
|
|
|
import androidx.compose.foundation.layout.Column |
|
|
|
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.layout.width |
|
|
|
import androidx.compose.foundation.lazy.LazyColumn |
|
|
|
import androidx.compose.foundation.lazy.items |
|
|
|
import androidx.compose.foundation.shape.CircleShape |
|
|
|
import androidx.compose.foundation.shape.RoundedCornerShape |
|
|
|
import androidx.compose.material3.* |
|
|
|
import androidx.compose.runtime.* |
|
|
|
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 |
|
|
|
import androidx.compose.runtime.collectAsState |
|
|
|
import androidx.compose.runtime.getValue |
|
|
|
import androidx.compose.ui.Alignment |
|
|
|
import androidx.compose.ui.Modifier |
|
|
|
import androidx.compose.ui.draw.clip |
|
|
|
import androidx.compose.ui.graphics.Brush |
|
|
|
import androidx.compose.ui.graphics.Color |
|
|
|
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 androidx.lifecycle.viewmodel.compose.viewModel |
|
|
|
import org.jetbrains.compose.resources.painterResource |
|
|
|
import org.jetbrains.compose.ui.tooling.preview.Preview |
|
|
|
import kotlin.invoke |
|
|
|
import ring.shared.generated.resources.Res |
|
|
|
import ring.shared.generated.resources.ic_ring |
|
|
|
|
|
|
|
@Composable |
|
|
|
fun SettingScreen( |
|
|
@ -25,93 +47,356 @@ fun SettingScreen( |
|
|
|
) { |
|
|
|
val uiState by viewModel.uiState.collectAsState() |
|
|
|
|
|
|
|
Box( |
|
|
|
modifier = modifier.fillMaxSize() |
|
|
|
) { |
|
|
|
LazyColumn( |
|
|
|
modifier = modifier |
|
|
|
modifier = Modifier |
|
|
|
.fillMaxSize() |
|
|
|
.background(Color(0xFF1A1A1A)) |
|
|
|
.padding(horizontal = 16.dp), |
|
|
|
contentPadding = PaddingValues(vertical = 16.dp), |
|
|
|
verticalArrangement = Arrangement.spacedBy(8.dp) |
|
|
|
verticalArrangement = Arrangement.spacedBy(16.dp) |
|
|
|
) { |
|
|
|
items(uiState.settingItems) { setting -> |
|
|
|
SettingItem( |
|
|
|
setting = setting, |
|
|
|
onItemClick = { viewModel.onSettingClick(setting) } |
|
|
|
item { |
|
|
|
Spacer(modifier = Modifier.height(40.dp)) |
|
|
|
} |
|
|
|
|
|
|
|
// 顶部标题和头像 |
|
|
|
item { |
|
|
|
TopSection( |
|
|
|
deviceName = uiState.deviceName, |
|
|
|
modifier = Modifier.fillMaxWidth() |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
// 戒指图像 |
|
|
|
item { |
|
|
|
RingImageSection( |
|
|
|
modifier = Modifier.fillMaxWidth() |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
// 连接状态和电池 |
|
|
|
item { |
|
|
|
ConnectionStatusSection( |
|
|
|
isConnected = uiState.isConnected, |
|
|
|
batteryLevel = uiState.batteryLevel, |
|
|
|
modifier = Modifier.fillMaxWidth().height(102.dp) |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
// 功能网格 - 使用分块显示而不是嵌套LazyGrid |
|
|
|
item { |
|
|
|
FeatureGridSection( |
|
|
|
features = uiState.featureItems, |
|
|
|
onFeatureClick = viewModel::onFeatureClick, |
|
|
|
modifier = Modifier.fillMaxWidth() |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
// 其他设置 |
|
|
|
item { |
|
|
|
OtherSettingsSection( |
|
|
|
settingItems = uiState.settingItems, |
|
|
|
onSettingClick = viewModel::onSettingClick, |
|
|
|
modifier = Modifier.fillMaxWidth() |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@Composable |
|
|
|
private fun SettingItem( |
|
|
|
setting: SettingItemData, |
|
|
|
onItemClick: () -> Unit, |
|
|
|
private fun TopSection( |
|
|
|
deviceName: String, |
|
|
|
modifier: Modifier = Modifier |
|
|
|
) { |
|
|
|
Row( |
|
|
|
modifier = modifier, |
|
|
|
horizontalArrangement = Arrangement.SpaceBetween, |
|
|
|
verticalAlignment = Alignment.CenterVertically |
|
|
|
) { |
|
|
|
Text( |
|
|
|
text = deviceName, |
|
|
|
fontSize = 20.sp, |
|
|
|
fontWeight = FontWeight.Medium, |
|
|
|
color = Color.White |
|
|
|
) |
|
|
|
|
|
|
|
// 头像占位符 |
|
|
|
Box( |
|
|
|
modifier = Modifier |
|
|
|
.size(40.dp) |
|
|
|
.clip(CircleShape) |
|
|
|
.background(Color.White.copy(alpha = 0.3f)), |
|
|
|
contentAlignment = Alignment.Center |
|
|
|
) { |
|
|
|
// Icon( |
|
|
|
// imageVector = Icons.Default.Person, |
|
|
|
// contentDescription = "用户头像", |
|
|
|
// tint = Color.White, |
|
|
|
// modifier = Modifier.size(24.dp) |
|
|
|
// ) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@Composable |
|
|
|
private fun RingImageSection( |
|
|
|
modifier: Modifier = Modifier |
|
|
|
) { |
|
|
|
Box( |
|
|
|
modifier = modifier, |
|
|
|
contentAlignment = Alignment.Center |
|
|
|
) { |
|
|
|
// 戒指图像占位符 |
|
|
|
Box( |
|
|
|
modifier = Modifier |
|
|
|
.size(160.dp) |
|
|
|
.clip(CircleShape), |
|
|
|
contentAlignment = Alignment.Center |
|
|
|
) { |
|
|
|
Image( |
|
|
|
painter = painterResource(Res.drawable.ic_ring), |
|
|
|
contentDescription = null, |
|
|
|
modifier = Modifier.fillMaxSize() |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@Composable |
|
|
|
private fun ConnectionStatusSection( |
|
|
|
isConnected: Boolean, |
|
|
|
batteryLevel: Int, |
|
|
|
modifier: Modifier = Modifier |
|
|
|
) { |
|
|
|
Card( |
|
|
|
modifier = modifier |
|
|
|
.fillMaxWidth() |
|
|
|
.clickable { onItemClick() }, |
|
|
|
shape = RoundedCornerShape(12.dp), |
|
|
|
modifier = modifier, |
|
|
|
shape = RoundedCornerShape(15.dp), |
|
|
|
colors = CardDefaults.cardColors( |
|
|
|
containerColor = Color(0xFF2A2A2A) |
|
|
|
containerColor = Color.White.copy(alpha = 0.9f) |
|
|
|
) |
|
|
|
) { |
|
|
|
Row( |
|
|
|
modifier = Modifier |
|
|
|
.fillMaxWidth() |
|
|
|
.fillMaxSize() |
|
|
|
.padding(16.dp), |
|
|
|
horizontalArrangement = Arrangement.SpaceBetween, |
|
|
|
verticalAlignment = Alignment.CenterVertically |
|
|
|
) { |
|
|
|
Text( |
|
|
|
text = if (isConnected) "已连接" else "未连接", |
|
|
|
fontSize = 16.sp, |
|
|
|
fontWeight = FontWeight.Medium, |
|
|
|
color = Color.Black |
|
|
|
) |
|
|
|
|
|
|
|
Row( |
|
|
|
verticalAlignment = Alignment.CenterVertically, |
|
|
|
horizontalArrangement = Arrangement.spacedBy(8.dp) |
|
|
|
) { |
|
|
|
// 电池图标占位符 |
|
|
|
Box( |
|
|
|
modifier = Modifier |
|
|
|
.size(20.dp, 12.dp) |
|
|
|
.background( |
|
|
|
color = if (batteryLevel > 20) Color.Green else Color.Red, |
|
|
|
shape = RoundedCornerShape(2.dp) |
|
|
|
) |
|
|
|
) |
|
|
|
Text( |
|
|
|
text = "$batteryLevel%", |
|
|
|
fontSize = 16.sp, |
|
|
|
fontWeight = FontWeight.Medium, |
|
|
|
color = Color.Black |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@Composable |
|
|
|
private fun FeatureGridSection( |
|
|
|
features: List<FeatureItemData>, |
|
|
|
onFeatureClick: (FeatureItemData) -> Unit, |
|
|
|
modifier: Modifier = Modifier |
|
|
|
) { |
|
|
|
// 将features按每行2个分组 |
|
|
|
val chunkedFeatures = features.chunked(2) |
|
|
|
|
|
|
|
Column( |
|
|
|
modifier = modifier, |
|
|
|
verticalArrangement = Arrangement.spacedBy(12.dp) |
|
|
|
) { |
|
|
|
chunkedFeatures.forEach { rowFeatures -> |
|
|
|
Row( |
|
|
|
modifier = Modifier.fillMaxWidth(), |
|
|
|
horizontalArrangement = Arrangement.spacedBy(12.dp) |
|
|
|
) { |
|
|
|
rowFeatures.forEach { feature -> |
|
|
|
FeatureCard( |
|
|
|
feature = feature, |
|
|
|
onClick = { onFeatureClick(feature) }, |
|
|
|
modifier = Modifier.weight(1f) |
|
|
|
) |
|
|
|
} |
|
|
|
// 如果行中只有一个元素,添加一个空的spacer保持布局对称 |
|
|
|
if (rowFeatures.size == 1) { |
|
|
|
Spacer(modifier = Modifier.weight(1f)) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@Composable |
|
|
|
private fun FeatureCard( |
|
|
|
feature: FeatureItemData, |
|
|
|
onClick: () -> Unit, |
|
|
|
modifier: Modifier = Modifier |
|
|
|
) { |
|
|
|
Card( |
|
|
|
modifier = modifier |
|
|
|
.height(85.dp) |
|
|
|
.clickable { onClick() }, |
|
|
|
shape = RoundedCornerShape(16.dp), |
|
|
|
colors = CardDefaults.cardColors( |
|
|
|
containerColor = Color.White.copy(alpha = 0.9f) |
|
|
|
) |
|
|
|
) { |
|
|
|
|
|
|
|
Row(modifier = Modifier.fillMaxSize(), verticalAlignment = Alignment.CenterVertically) { |
|
|
|
Spacer(Modifier.width(12.dp)) |
|
|
|
Column { |
|
|
|
Text("Title", fontSize = 18.sp, color = Color(0xff394298)) |
|
|
|
Text("Subtitle", fontSize = 11.sp, color = Color(0xff978CB9)) |
|
|
|
} |
|
|
|
Spacer(modifier = Modifier.weight(1f)) |
|
|
|
Column { |
|
|
|
// 功能图标占位符 |
|
|
|
Box( |
|
|
|
modifier = Modifier |
|
|
|
.size(32.dp) |
|
|
|
.clip(CircleShape) |
|
|
|
.background(getFeatureIconColor(feature.id)), |
|
|
|
contentAlignment = Alignment.Center |
|
|
|
) { |
|
|
|
Text( |
|
|
|
text = setting.title, |
|
|
|
color = Color.White, |
|
|
|
text = getFeatureIconText(feature.id), |
|
|
|
fontSize = 16.sp, |
|
|
|
fontWeight = FontWeight.Medium |
|
|
|
color = Color.White, |
|
|
|
fontWeight = FontWeight.Bold |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
Spacer(Modifier.width(22.dp)) |
|
|
|
|
|
|
|
if (setting.subtitle.isNotEmpty()) { |
|
|
|
Spacer(modifier = Modifier.height(4.dp)) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@Composable |
|
|
|
private fun OtherSettingsSection( |
|
|
|
settingItems: List<SettingItemData>, |
|
|
|
onSettingClick: (SettingItemData) -> Unit, |
|
|
|
modifier: Modifier = Modifier |
|
|
|
) { |
|
|
|
Column( |
|
|
|
modifier = modifier, |
|
|
|
verticalArrangement = Arrangement.spacedBy(8.dp) |
|
|
|
) { |
|
|
|
Text( |
|
|
|
text = setting.subtitle, |
|
|
|
color = Color.Gray, |
|
|
|
fontSize = 14.sp |
|
|
|
text = "其他", |
|
|
|
fontSize = 16.sp, |
|
|
|
fontWeight = FontWeight.Medium, |
|
|
|
color = Color.White, |
|
|
|
modifier = Modifier.padding(horizontal = 4.dp) |
|
|
|
) |
|
|
|
|
|
|
|
Column( |
|
|
|
verticalArrangement = Arrangement.spacedBy(4.dp) |
|
|
|
) { |
|
|
|
settingItems.forEach { setting -> |
|
|
|
SettingItem( |
|
|
|
setting = setting, |
|
|
|
onClick = { onSettingClick(setting) }, |
|
|
|
modifier = Modifier.height(65.dp) |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (setting.hasSwitch) { |
|
|
|
Switch( |
|
|
|
checked = setting.isEnabled, |
|
|
|
onCheckedChange = { /* Handle switch change */ }, |
|
|
|
colors = SwitchDefaults.colors( |
|
|
|
checkedThumbColor = Color.White, |
|
|
|
checkedTrackColor = Color(0xFF352764), |
|
|
|
uncheckedThumbColor = Color.Gray, |
|
|
|
uncheckedTrackColor = Color.DarkGray |
|
|
|
) |
|
|
|
@Composable |
|
|
|
private fun SettingItem( |
|
|
|
setting: SettingItemData, |
|
|
|
onClick: () -> Unit, |
|
|
|
modifier: Modifier = Modifier |
|
|
|
) { |
|
|
|
Card( |
|
|
|
modifier = modifier |
|
|
|
.fillMaxWidth() |
|
|
|
.clickable { onClick() }, |
|
|
|
shape = RoundedCornerShape(20.dp), |
|
|
|
colors = CardDefaults.cardColors( |
|
|
|
containerColor = Color(0xff352764) |
|
|
|
) |
|
|
|
} else { |
|
|
|
) { |
|
|
|
Row( |
|
|
|
modifier = Modifier |
|
|
|
.fillMaxSize() |
|
|
|
.padding(start = 12.dp,end = 16.dp), |
|
|
|
horizontalArrangement = Arrangement.SpaceBetween, |
|
|
|
verticalAlignment = Alignment.CenterVertically |
|
|
|
) { |
|
|
|
Text( |
|
|
|
text = ">", |
|
|
|
color = Color.Gray, |
|
|
|
fontSize = 18.sp |
|
|
|
text = setting.title, |
|
|
|
fontSize = 16.sp, |
|
|
|
fontWeight = FontWeight.Medium, |
|
|
|
color = Color.White |
|
|
|
) |
|
|
|
|
|
|
|
if (setting.hasArrow) { |
|
|
|
// Icon( |
|
|
|
// imageVector = Icons.Default.ArrowForwardIos, |
|
|
|
// contentDescription = "前往", |
|
|
|
// tint = Color.White, |
|
|
|
// modifier = Modifier.size(16.dp) |
|
|
|
// ) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
data class SettingItemData( |
|
|
|
val title: String, |
|
|
|
val subtitle: String = "", |
|
|
|
val hasSwitch: Boolean = false, |
|
|
|
val isEnabled: Boolean = false |
|
|
|
) |
|
|
|
// 辅助函数:获取功能图标颜色 |
|
|
|
private fun getFeatureIconColor(featureId: String): Color { |
|
|
|
return when (featureId) { |
|
|
|
"smart_life" -> Color(0xFF4CAF50) |
|
|
|
"wallet" -> Color(0xFFFF5722) |
|
|
|
"message_notification" -> Color(0xFFFFC107) |
|
|
|
"find_device" -> Color(0xFF2196F3) |
|
|
|
"alarm" -> Color(0xFFFF9800) |
|
|
|
"message_reminder" -> Color(0xFF9C27B0) |
|
|
|
"wechat" -> Color(0xFF4CAF50) |
|
|
|
"manual" -> Color(0xFF795548) |
|
|
|
else -> Color.Gray |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 辅助函数:获取功能图标文本 |
|
|
|
private fun getFeatureIconText(featureId: String): String { |
|
|
|
return when (featureId) { |
|
|
|
"smart_life" -> "🏠" |
|
|
|
"wallet" -> "💰" |
|
|
|
"message_notification" -> "📧" |
|
|
|
"find_device" -> "🔍" |
|
|
|
"alarm" -> "⏰" |
|
|
|
"message_reminder" -> "💡" |
|
|
|
"wechat" -> "💬" |
|
|
|
"manual" -> "📖" |
|
|
|
else -> "?" |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@Preview |
|
|
|
@Composable |
|
|
|