diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 52aecde..70da39c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -68,6 +68,9 @@ dependencies { implementation("androidx.compose.material3:material3-window-size-class:1.3.0") implementation("com.github.Dimezis:BlurView:version-3.2.0") + implementation("com.google.code.gson:gson:2.10.1") + implementation("com.squareup.okhttp3:okhttp:4.12.0") + implementation("com.google.android.gms:play-services-location:21.0.1") debugImplementation("com.squareup.leakcanary:leakcanary-android:2.12") diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3a337ce..59794e9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,8 +1,13 @@ + + + + + diff --git a/app/src/main/java/com/example/smarthome/ui/MainScaffold.kt b/app/src/main/java/com/example/smarthome/ui/MainScaffold.kt index 40958df..48da923 100644 --- a/app/src/main/java/com/example/smarthome/ui/MainScaffold.kt +++ b/app/src/main/java/com/example/smarthome/ui/MainScaffold.kt @@ -66,6 +66,8 @@ import androidx.compose.animation.core.infiniteRepeatable import androidx.compose.animation.core.tween import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.RepeatMode +import com.example.smarthome.data.WeatherService +import com.example.smarthome.data.WeatherInfo @Composable fun MainScaffold( @@ -86,6 +88,10 @@ fun MainScaffold( // 根据选中的导航项显示不同的内容 when (selectedNavItem) { 0 -> DashboardContent(selectedRoom, onRoomSelect, rooms, onAddRoom, onDeleteRoom) + 1 -> SceneScreen() + 2 -> AutomationScreen() + 3 -> StatisticsScreen() + 4 -> SecurityScreen() 5 -> SettingsContent() else -> DashboardContent(selectedRoom, onRoomSelect, rooms, onAddRoom, onDeleteRoom) } @@ -394,7 +400,7 @@ fun RoomTab( val mod = if (selected) { base.background(brush = Brush.linearGradient(listOf(Color(0xFFA9F0FF), Color(0xFFB89CFF)))) } else { - base.background(color = Color(0x22121212)) + base.background(color = Color(0x50121212)) } Box( @@ -454,7 +460,13 @@ data class Device(val name: String, val sub: String, val icon: Int, val on: Bool @Composable fun DeviceCard(d: Device) { var active by remember { mutableStateOf(d.on) } - Box(modifier = Modifier.height(120.dp).clip(RoundedCornerShape(24.dp)).background(Color(0x26121212)).shadow(12.dp, RoundedCornerShape(24.dp), true).padding(16.dp)) { + Box( + modifier = Modifier + .height(120.dp) + .clip(RoundedCornerShape(24.dp)) + .background(Color(0x50121212)) + .padding(16.dp) + ) { Column(verticalArrangement = Arrangement.spacedBy(12.dp)) { Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(12.dp)) { Image(painter = painterResource(id = d.icon), contentDescription = null, modifier = Modifier.size(40.dp)) @@ -483,7 +495,7 @@ fun Toggle(on: Boolean, change: (Boolean) -> Unit) { @Composable fun BottomNav() { - Row(modifier = Modifier.fillMaxWidth().padding(16.dp).clip(RoundedCornerShape(28.dp)).background(Color(0x33121212)).padding(8.dp), horizontalArrangement = Arrangement.SpaceEvenly) { + Row(modifier = Modifier.fillMaxWidth().padding(16.dp).clip(RoundedCornerShape(28.dp)).background(Color(0x50121212)).padding(8.dp), horizontalArrangement = Arrangement.SpaceEvenly) { NavItem("首页", true) NavItem("设备", false) NavItem("我的", false) @@ -502,10 +514,10 @@ fun SideNavRail(selectedNavItem: Int = 0, onNavItemSelect: (Int) -> Unit = {}) { Column(modifier = Modifier.width(120.dp).fillMaxHeight().padding(12.dp), verticalArrangement = Arrangement.spacedBy(16.dp)) { Spacer(modifier = Modifier.height(48.dp)) NavRailItem("控制台", R.drawable.ic_dashboard, selectedNavItem == 0, onClick = { onNavItemSelect(0) }) - NavRailItem("最近", R.drawable.ic_recent, selectedNavItem == 1, onClick = { onNavItemSelect(1) }) - NavRailItem("收藏", R.drawable.ic_bookmark, selectedNavItem == 2, onClick = { onNavItemSelect(2) }) - NavRailItem("下载", R.drawable.ic_download, selectedNavItem == 3, onClick = { onNavItemSelect(3) }) - NavRailItem("支持", R.drawable.ic_support, selectedNavItem == 4, onClick = { onNavItemSelect(4) }) + NavRailItem("场景", R.drawable.ic_scene, selectedNavItem == 1, onClick = { onNavItemSelect(1) }) + NavRailItem("自动化", R.drawable.ic_automation, selectedNavItem == 2, onClick = { onNavItemSelect(2) }) + NavRailItem("统计", R.drawable.ic_statistics, selectedNavItem == 3, onClick = { onNavItemSelect(3) }) + NavRailItem("安全", R.drawable.ic_security, selectedNavItem == 4, onClick = { onNavItemSelect(4) }) NavRailItem("设置", R.drawable.ic_settings, selectedNavItem == 5, onClick = { onNavItemSelect(5) }) } } @@ -568,17 +580,117 @@ fun NavRailItem(text: String, iconRes: Int, selected: Boolean, onClick: () -> Un @Composable fun TopBar() { + var weatherInfo by remember { mutableStateOf(WeatherService.getSimulatedWeather()) } + var isLoading by remember { mutableStateOf(true) } + + LaunchedEffect(Unit) { + try { + weatherInfo = WeatherService.getWeather() + } catch (e: Exception) { + // 使用模拟数据 + } + isLoading = false + } + Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically) { Text(text = "控制台", style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold, color = Color.White) Row(horizontalArrangement = Arrangement.spacedBy(12.dp), verticalAlignment = Alignment.CenterVertically) { - Box(modifier = Modifier.width(280.dp).height(40.dp).clip(RoundedCornerShape(20.dp)).background(Color(0x22121212)).padding(horizontal = 16.dp), contentAlignment = Alignment.CenterStart) { - Text(text = "搜索关键词", color = Color(0xFF9AA0A6)) - } + // 天气信息卡片 + WeatherCard(weatherInfo = weatherInfo, isLoading = isLoading) GradientButton("+ 添加设备") } } } +@Composable +fun WeatherCard(weatherInfo: WeatherInfo, isLoading: Boolean) { + Box( + modifier = Modifier + .clip(RoundedCornerShape(16.dp)) + .background(Color(0x50121212)) + .padding(horizontal = 16.dp, vertical = 8.dp) + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + // 温度和天气 + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Text( + text = if (isLoading) "--" else "${weatherInfo.temperature}°C", + fontSize = 18.sp, + fontWeight = FontWeight.Bold, + color = Color.White + ) + Text( + text = if (isLoading) "加载中" else weatherInfo.weather, + fontSize = 12.sp, + color = Color(0xFF9AA0A6) + ) + } + + // 分隔线 + Box( + modifier = Modifier + .width(1.dp) + .height(30.dp) + .background(Color(0x33FFFFFF)) + ) + + // 湿度 + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Text( + text = if (isLoading) "--" else "${weatherInfo.humidity}%", + fontSize = 14.sp, + fontWeight = FontWeight.Medium, + color = Color.White + ) + Text( + text = "湿度", + fontSize = 11.sp, + color = Color(0xFF9AA0A6) + ) + } + + // 分隔线 + Box( + modifier = Modifier + .width(1.dp) + .height(30.dp) + .background(Color(0x33FFFFFF)) + ) + + // 空气质量 + Column(horizontalAlignment = Alignment.CenterHorizontally) { + val aqiColor = when { + weatherInfo.aqi <= 50 -> Color(0xFF00E676) + weatherInfo.aqi <= 100 -> Color(0xFFFFEB3B) + weatherInfo.aqi <= 150 -> Color(0xFFFF9800) + else -> Color(0xFFFF5252) + } + Text( + text = if (isLoading) "--" else weatherInfo.airQuality, + fontSize = 14.sp, + fontWeight = FontWeight.Medium, + color = aqiColor + ) + Text( + text = if (isLoading) "AQI" else "AQI ${weatherInfo.aqi}", + fontSize = 11.sp, + color = Color(0xFF9AA0A6) + ) + } + + // 城市 + Text( + text = weatherInfo.city, + fontSize = 12.sp, + color = Color(0xFFB0B0B0) + ) + } + } +} + @Composable fun GradientButton(text: String, onClick: () -> Unit = {}) { Box(modifier = Modifier.height(36.dp).clip(RoundedCornerShape(20.dp)).background(Brush.linearGradient(listOf(Color(0xFFA9F0FF), Color(0xFFB89CFF)))).clickable(indication = null, interactionSource = remember { MutableInteractionSource() }) { onClick() }.padding(horizontal = 16.dp), contentAlignment = Alignment.Center) { @@ -641,30 +753,246 @@ fun MyDevicesGrid(selectedRoom: Int, modifier: Modifier = Modifier) { fun UsageStatusChart(modifier: Modifier = Modifier, roomName: String = "房间") { // 根据房间生成不同的数据 val values = remember(roomName) { - List(10) { (10..35).random().toFloat() } + List(12) { (15..45).random().toFloat() } } - val totalPower = remember(roomName) { (15.0 + Math.random() * 30).toString().take(5) } + val maxValue = remember(values) { values.maxOrNull() ?: 45f } + val totalPower = remember(roomName) { (15.0 + Math.random() * 30).toString().take(4) } val totalHours = remember(roomName) { (10 + (Math.random() * 40).toInt()) } + val activeDevices = remember(roomName) { (3 + (Math.random() * 8).toInt()) } + val trend = remember(roomName) { if (Math.random() > 0.5) "↑" else "↓" } + val trendPercent = remember(roomName) { (5 + (Math.random() * 15).toInt()) } - Box(modifier = modifier.height(220.dp).clip(RoundedCornerShape(24.dp)).background(Color(0x26121212)).padding(16.dp)) { - Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { - Column { - Text(text = "使用状态", fontWeight = FontWeight.SemiBold, color = Color.White) - Text(text = roomName, fontSize = 12.sp, color = Color(0xFF9AA0A6)) - } - Row(horizontalArrangement = Arrangement.spacedBy(24.dp)) { - Column { - Text(text = "${totalPower}kWh", color = Color.White) - Text(text = "总消耗", color = Color(0xFF9AA0A6), fontSize = 12.sp) + Box( + modifier = modifier + .height(220.dp) + .clip(RoundedCornerShape(24.dp)) + .background( + Brush.linearGradient( + colors = listOf( + Color(0x60121212), + Color(0x50121212) + ) + ) + ) + .border( + width = 1.dp, + brush = Brush.linearGradient( + colors = listOf( + Color(0x22FFFFFF), + Color(0x0AFFFFFF) + ) + ), + shape = RoundedCornerShape(24.dp) + ) + .padding(16.dp) + ) { + Column( + verticalArrangement = Arrangement.spacedBy(12.dp), + modifier = Modifier.fillMaxSize() + ) { + // 标题区域 + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Column { + Text( + text = "能耗统计", + fontWeight = FontWeight.Bold, + color = Color.White, + fontSize = 16.sp + ) + Text( + text = roomName, + fontSize = 12.sp, + color = Color(0xFF9AA0A6) + ) } - Column { - Text(text = "${totalHours}h", color = Color.White) - Text(text = "总时长", color = Color(0xFF9AA0A6), fontSize = 12.sp) + + // 趋势指示器 + Box( + modifier = Modifier + .clip(RoundedCornerShape(12.dp)) + .background( + if (trend == "↑") Color(0x33FF5252) else Color(0x3300E676) + ) + .padding(horizontal = 10.dp, vertical = 6.dp) + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(4.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = trend, + color = if (trend == "↑") Color(0xFFFF5252) else Color(0xFF00E676), + fontSize = 14.sp, + fontWeight = FontWeight.Bold + ) + Text( + text = "${trendPercent}%", + color = if (trend == "↑") Color(0xFFFF5252) else Color(0xFF00E676), + fontSize = 12.sp, + fontWeight = FontWeight.Medium + ) + } } } - Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(8.dp), verticalAlignment = Alignment.Bottom) { - values.forEach { v -> - Box(modifier = Modifier.weight(1f).height(v.dp).clip(RoundedCornerShape(6.dp)).background(Color(0xFF2A2A2A))) + + // 数据指标区域 + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(16.dp) + ) { + // 总消耗 + Column( + modifier = Modifier.weight(1f) + ) { + Row( + verticalAlignment = Alignment.Bottom, + horizontalArrangement = Arrangement.spacedBy(4.dp) + ) { + Text( + text = totalPower, + color = Color(0xFFA9F0FF), + fontSize = 20.sp, + fontWeight = FontWeight.Bold + ) + Text( + text = "kWh", + color = Color(0xFF9AA0A6), + fontSize = 12.sp, + modifier = Modifier.padding(bottom = 2.dp) + ) + } + Text( + text = "总消耗", + color = Color(0xFF9AA0A6), + fontSize = 11.sp + ) + } + + // 运行时长 + Column( + modifier = Modifier.weight(1f) + ) { + Row( + verticalAlignment = Alignment.Bottom, + horizontalArrangement = Arrangement.spacedBy(4.dp) + ) { + Text( + text = "$totalHours", + color = Color(0xFFB89CFF), + fontSize = 20.sp, + fontWeight = FontWeight.Bold + ) + Text( + text = "小时", + color = Color(0xFF9AA0A6), + fontSize = 12.sp, + modifier = Modifier.padding(bottom = 2.dp) + ) + } + Text( + text = "运行时长", + color = Color(0xFF9AA0A6), + fontSize = 11.sp + ) + } + + // 活跃设备 + Column( + modifier = Modifier.weight(1f) + ) { + Row( + verticalAlignment = Alignment.Bottom, + horizontalArrangement = Arrangement.spacedBy(4.dp) + ) { + Text( + text = "$activeDevices", + color = Color(0xFF00E676), + fontSize = 20.sp, + fontWeight = FontWeight.Bold + ) + Text( + text = "台", + color = Color(0xFF9AA0A6), + fontSize = 12.sp, + modifier = Modifier.padding(bottom = 2.dp) + ) + } + Text( + text = "活跃设备", + color = Color(0xFF9AA0A6), + fontSize = 11.sp + ) + } + } + + Spacer(modifier = Modifier.height(4.dp)) + + // 图表区域 + Box( + modifier = Modifier + .fillMaxWidth() + .weight(1f) + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.BottomCenter), + horizontalArrangement = Arrangement.spacedBy(6.dp), + verticalAlignment = Alignment.Bottom + ) { + values.forEachIndexed { index, v -> + val normalizedHeight = (v / maxValue) * 60 + val isHighlight = index == values.size - 1 + + Box( + modifier = Modifier + .weight(1f) + .height(normalizedHeight.dp) + .clip(RoundedCornerShape(topStart = 4.dp, topEnd = 4.dp)) + .background( + if (isHighlight) { + Brush.verticalGradient( + colors = listOf( + Color(0xFFA9F0FF), + Color(0xFF00D1FF) + ) + ) + } else { + Brush.verticalGradient( + colors = listOf( + Color(0xFF3A3A3A), + Color(0xFF2A2A2A) + ) + ) + } + ) + ) + } + } + + // 时间标签 + Row( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.BottomCenter) + .offset(y = 16.dp), + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + text = "12h前", + fontSize = 10.sp, + color = Color(0xFF666666) + ) + Text( + text = "现在", + fontSize = 10.sp, + color = Color(0xFFA9F0FF), + fontWeight = FontWeight.Medium + ) } } } @@ -676,7 +1004,7 @@ fun AirConditionerCard(modifier: Modifier = Modifier, roomName: String = "房间 var temp by remember { mutableStateOf(24f) } var isOn by remember { mutableStateOf(true) } - Box(modifier = modifier.height(220.dp).clip(RoundedCornerShape(24.dp)).background(Color(0x26121212)).padding(16.dp)) { + Box(modifier = modifier.height(220.dp).clip(RoundedCornerShape(24.dp)).background(Color(0x50121212)).padding(16.dp)) { Column(verticalArrangement = Arrangement.spacedBy(16.dp)) { Row(horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) { Column { @@ -704,7 +1032,7 @@ fun AirConditionerCard(modifier: Modifier = Modifier, roomName: String = "房间 modifier = Modifier .size(40.dp) .clip(RoundedCornerShape(12.dp)) - .background(Color(0x33FFFFFF)) + .background(Color(0x55FFFFFF)) .clickable(enabled = isOn && temp > 16f) { if (temp > 16f) temp -= 1f }, @@ -718,7 +1046,7 @@ fun AirConditionerCard(modifier: Modifier = Modifier, roomName: String = "房间 modifier = Modifier .size(40.dp) .clip(RoundedCornerShape(12.dp)) - .background(Color(0x33FFFFFF)) + .background(Color(0x55FFFFFF)) .clickable(enabled = isOn && temp < 32f) { if (temp < 32f) temp += 1f }, @@ -777,10 +1105,10 @@ fun CustomSlider( activeTrackColor = Brush.linearGradient( listOf(Color(0xFF00D1FF), Color(0xFFA9F0FF)) ).let { Color(0xFF00D1FF) }, - inactiveTrackColor = Color(0x33FFFFFF), + inactiveTrackColor = Color(0x55FFFFFF), disabledThumbColor = Color(0x66FFFFFF), - disabledActiveTrackColor = Color(0x33FFFFFF), - disabledInactiveTrackColor = Color(0x22FFFFFF) + disabledActiveTrackColor = Color(0x55FFFFFF), + disabledInactiveTrackColor = Color(0x55FFFFFF) ), modifier = Modifier .fillMaxWidth() @@ -806,7 +1134,7 @@ fun CustomSlider( Box( modifier = Modifier .fillMaxSize() - .background(if (enabled) Color(0x33FFFFFF) else Color(0x22FFFFFF)) + .background(if (enabled) Color(0x55FFFFFF) else Color(0x55FFFFFF)) ) // 激活轨道 Box( @@ -820,7 +1148,7 @@ fun CustomSlider( ) } else { Brush.linearGradient( - listOf(Color(0x33FFFFFF), Color(0x33FFFFFF)) + listOf(Color(0x55FFFFFF), Color(0x55FFFFFF)) ) } ) @@ -843,9 +1171,9 @@ fun LightList(modifier: Modifier = Modifier) { Column(modifier = modifier.fillMaxHeight(), verticalArrangement = Arrangement.spacedBy(12.dp)) { Text(text = "灯光", fontWeight = FontWeight.SemiBold) lights.forEach { (name, percent) -> - Row(horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, modifier = Modifier.clip(RoundedCornerShape(16.dp)).background(Color(0x26121212)).padding(12.dp)) { + Row(horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, modifier = Modifier.clip(RoundedCornerShape(16.dp)).background(Color(0x50121212)).padding(12.dp)) { Row(horizontalArrangement = Arrangement.spacedBy(12.dp), verticalAlignment = Alignment.CenterVertically) { - Box(modifier = Modifier.size(36.dp).clip(RoundedCornerShape(10.dp)).background(Color(0x22121212))) + Box(modifier = Modifier.size(36.dp).clip(RoundedCornerShape(10.dp)).background(Color(0x50121212))) Column { Text(text = name); Text(text = "${(percent * 100).toInt()}%", color = Color(0xFF9AA0A6)) } } DotsProgress(percent) @@ -965,6 +1293,14 @@ fun ModeButton( val interaction = remember { MutableInteractionSource() } var pressed by remember { mutableStateOf(false) } + // 根据文本确定图标 + val iconRes = when (text) { + "回家" -> R.drawable.ic_mode_home + "出门" -> R.drawable.ic_mode_away + "玩乐" -> R.drawable.ic_mode_fun + else -> R.drawable.ic_dashboard + } + val scale by androidx.compose.animation.core.animateFloatAsState( targetValue = if (pressed) 0.96f else 1f, animationSpec = androidx.compose.animation.core.spring( @@ -980,6 +1316,14 @@ fun ModeButton( label = "elevation" ) + val iconScale by androidx.compose.animation.core.animateFloatAsState( + targetValue = if (selected) 1.1f else 1f, + animationSpec = androidx.compose.animation.core.spring( + dampingRatio = androidx.compose.animation.core.Spring.DampingRatioMediumBouncy + ), + label = "icon_scale" + ) + val view = LocalView.current LaunchedEffect(interaction) { @@ -995,38 +1339,25 @@ fun ModeButton( modifier = modifier .height(height) .scale(scale) - .shadow(elevation, shape) - .background( + .clip(shape) + .then( if (selected) { - brush + Modifier + .shadow(elevation, shape, clip = false) + .background(brush, shape) + .border( + width = 2.dp, + brush = Brush.linearGradient( + listOf( + Color(0x99FFFFFF), + Color(0x66FFFFFF) + ) + ), + shape = shape + ) } else { - Brush.linearGradient( - listOf( - Color(0x40FFFFFF), - Color(0x20FFFFFF) - ) - ) - }, - shape = shape - ) - .border( - width = if (selected) 2.dp else 1.dp, - brush = if (selected) { - Brush.linearGradient( - listOf( - Color(0x99FFFFFF), - Color(0x66FFFFFF) - ) - ) - } else { - Brush.linearGradient( - listOf( - Color(0x33FFFFFF), - Color(0x11FFFFFF) - ) - ) - }, - shape = shape + Modifier.background(Color(0x50121212)) + } ) .clickable(indication = null, interactionSource = interaction) { view.playSoundEffect(SoundEffectConstants.CLICK) @@ -1035,13 +1366,95 @@ fun ModeButton( .padding(24.dp), contentAlignment = Alignment.Center ) { - Text( - text = text, - color = if (selected) Color.White else Color(0xFFB0B0B0), - fontWeight = if (selected) FontWeight.Bold else FontWeight.Medium, - fontSize = if (selected) 22.sp else 20.sp, - style = MaterialTheme.typography.titleLarge - ) + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + // 图标容器 + Box( + modifier = Modifier + .size(if (selected) 72.dp else 64.dp) + .scale(iconScale), + contentAlignment = Alignment.Center + ) { + // 外层光晕效果(仅选中时) + if (selected) { + Box( + modifier = Modifier + .fillMaxSize() + .clip(RoundedCornerShape(20.dp)) + .background( + Brush.radialGradient( + colors = listOf( + Color.White.copy(alpha = 0.2f), + Color.Transparent + ), + radius = 100f + ) + ) + ) + } + + // 图标背景 + Box( + modifier = Modifier + .size(if (selected) 64.dp else 56.dp) + .clip(RoundedCornerShape(18.dp)) + .background( + if (selected) { + Brush.linearGradient( + colors = listOf( + Color.White.copy(alpha = 0.25f), + Color.White.copy(alpha = 0.15f) + ) + ) + } else { + Brush.linearGradient( + colors = listOf( + Color(0x55FFFFFF), + Color(0x55FFFFFF) + ) + ) + } + ) + .then( + if (selected) { + Modifier.border( + width = 1.dp, + brush = Brush.linearGradient( + colors = listOf( + Color.White.copy(alpha = 0.4f), + Color.White.copy(alpha = 0.1f) + ) + ), + shape = RoundedCornerShape(18.dp) + ) + } else { + Modifier + } + ), + contentAlignment = Alignment.Center + ) { + Image( + painter = painterResource(id = iconRes), + contentDescription = text, + modifier = Modifier.size(if (selected) 38.dp else 34.dp), + colorFilter = androidx.compose.ui.graphics.ColorFilter.tint( + Color.White + ) + ) + } + } + + // 文字 + Text( + text = text, + color = Color.White, + fontWeight = if (selected) FontWeight.Bold else FontWeight.Medium, + fontSize = if (selected) 20.sp else 18.sp, + style = MaterialTheme.typography.titleMedium + ) + } } } @@ -1065,7 +1478,7 @@ fun LightRow(modifier: Modifier = Modifier, roomName: String = "房间") { fun LightCard(name: String, percent: Float, modifier: Modifier = Modifier) { var brightness by remember { mutableStateOf(percent) } - Box(modifier = modifier.height(100.dp).clip(RoundedCornerShape(16.dp)).background(Color(0x26121212)).padding(12.dp)) { + Box(modifier = modifier.height(100.dp).clip(RoundedCornerShape(16.dp)).background(Color(0x50121212)).padding(12.dp)) { Row(horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) { Row(horizontalArrangement = Arrangement.spacedBy(12.dp), verticalAlignment = Alignment.CenterVertically) { // 灯光图标 - 带发光效果 @@ -1142,7 +1555,6 @@ fun AddRoomDialog( Box( modifier = Modifier .fillMaxSize() - .background(Color(0x80000000)) .clickable( indication = null, interactionSource = remember { MutableInteractionSource() } @@ -1176,8 +1588,8 @@ fun AddRoomDialog( placeholder = { Text("请输入房间名称", color = Color(0xFF9AA0A6)) }, modifier = Modifier.fillMaxWidth(), colors = androidx.compose.material3.TextFieldDefaults.colors( - focusedContainerColor = Color(0x22FFFFFF), - unfocusedContainerColor = Color(0x22FFFFFF), + focusedContainerColor = Color(0x55FFFFFF), + unfocusedContainerColor = Color(0x55FFFFFF), focusedTextColor = Color.White, unfocusedTextColor = Color.White, cursorColor = Color(0xFFA9F0FF), @@ -1197,7 +1609,7 @@ fun AddRoomDialog( .weight(1f) .height(48.dp) .clip(RoundedCornerShape(12.dp)) - .background(Color(0x22FFFFFF)) + .background(Color(0x55FFFFFF)) .clickable( indication = null, interactionSource = remember { MutableInteractionSource() } diff --git a/app/src/main/java/com/example/smarthome/ui/SettingsScreen.kt b/app/src/main/java/com/example/smarthome/ui/SettingsScreen.kt index 74763a4..e65a45e 100644 --- a/app/src/main/java/com/example/smarthome/ui/SettingsScreen.kt +++ b/app/src/main/java/com/example/smarthome/ui/SettingsScreen.kt @@ -130,7 +130,7 @@ fun SettingsTopBar(onBack: () -> Unit) { modifier = Modifier .size(40.dp) .clip(RoundedCornerShape(12.dp)) - .background(Color(0x22FFFFFF)) + .background(Color(0x50121212)) .clickable( indication = null, interactionSource = remember { MutableInteractionSource() } @@ -167,7 +167,7 @@ fun SettingsSection(title: String, content: @Composable ColumnScope.() -> Unit) modifier = Modifier .fillMaxWidth() .clip(RoundedCornerShape(24.dp)) - .background(Color(0x26FFFFFF)) + .background(Color(0x50121212)) .padding(8.dp) ) { Column( @@ -190,7 +190,7 @@ fun SettingsItem( modifier = Modifier .fillMaxWidth() .clip(RoundedCornerShape(16.dp)) - .background(Color(0x11FFFFFF)) + .background(Color(0x33121212)) .clickable( indication = null, interactionSource = remember { MutableInteractionSource() } @@ -237,7 +237,7 @@ fun SettingsSwitchItem( modifier = Modifier .fillMaxWidth() .clip(RoundedCornerShape(16.dp)) - .background(Color(0x11FFFFFF)) + .background(Color(0x33121212)) .padding(16.dp) ) { Row( @@ -312,13 +312,13 @@ fun LogoutButton(onClick: () -> Unit) { modifier = Modifier .fillMaxWidth() .height(56.dp) + .shadow(8.dp, RoundedCornerShape(24.dp)) .clip(RoundedCornerShape(24.dp)) .background( Brush.linearGradient( listOf(Color(0xFFFF6B6B), Color(0xFFFF5252)) ) ) - .shadow(8.dp, RoundedCornerShape(24.dp), clip = false) .clickable( indication = null, interactionSource = remember { MutableInteractionSource() } diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml index 318eab8..e43158f 100644 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -1,3 +1,22 @@ - - - + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml index 66a9344..76ff253 100644 --- a/app/src/main/res/drawable/ic_launcher_foreground.xml +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -1,4 +1,46 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml deleted file mode 100644 index d9f94e6..0000000 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - -