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 2cc27b9..40958df 100644 --- a/app/src/main/java/com/example/smarthome/ui/MainScaffold.kt +++ b/app/src/main/java/com/example/smarthome/ui/MainScaffold.kt @@ -157,16 +157,18 @@ fun OverviewRoomContent() { AirConditionerCard(modifier = Modifier.weight(1f), roomName = "全屋") UsageStatusChart(modifier = Modifier.weight(1f), roomName = "全屋") } - LightRow(modifier = Modifier.fillMaxWidth().padding(bottom = 16.dp), roomName = "全屋") + LightRow(modifier = Modifier.fillMaxWidth().padding(top = 16.dp, bottom = 16.dp), roomName = "全屋") ModeButtonsRow(onModeSelected = { }) + Spacer(modifier = Modifier.height(24.dp)) + // 显示所有房间的设备摘要 Text( text = "所有设备", fontSize = 18.sp, fontWeight = FontWeight.Bold, color = Color.White, - modifier = Modifier.padding(vertical = 12.dp) + modifier = Modifier.padding(bottom = 12.dp) ) AllDevicesOverview(modifier = Modifier.fillMaxSize()) } @@ -179,14 +181,16 @@ fun SpecificRoomContent(selectedRoom: Int, roomName: String) { AirConditionerCard(modifier = Modifier.weight(1f), roomName = roomName) UsageStatusChart(modifier = Modifier.weight(1f), roomName = roomName) } - LightRow(modifier = Modifier.fillMaxWidth().padding(bottom = 16.dp), roomName = roomName) + LightRow(modifier = Modifier.fillMaxWidth().padding(top = 16.dp, bottom = 16.dp), roomName = roomName) + + Spacer(modifier = Modifier.height(24.dp)) Text( text = "$roomName 设备", fontSize = 18.sp, fontWeight = FontWeight.Bold, color = Color.White, - modifier = Modifier.padding(vertical = 12.dp) + modifier = Modifier.padding(bottom = 12.dp) ) MyDevicesGrid(selectedRoom = selectedRoom, modifier = Modifier.fillMaxSize()) } @@ -673,31 +677,160 @@ fun AirConditionerCard(modifier: Modifier = Modifier, roomName: String = "房间 var isOn by remember { mutableStateOf(true) } Box(modifier = modifier.height(220.dp).clip(RoundedCornerShape(24.dp)).background(Color(0x26121212)).padding(16.dp)) { - Column(verticalArrangement = Arrangement.spacedBy(12.dp)) { + Column(verticalArrangement = Arrangement.spacedBy(16.dp)) { Row(horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) { Column { - Text(text = "空调", fontWeight = FontWeight.SemiBold, color = Color.White) + Text(text = "空调", fontWeight = FontWeight.SemiBold, color = Color.White, fontSize = 18.sp) Text(text = roomName, fontSize = 12.sp, color = Color(0xFF9AA0A6)) } Switch(checked = isOn, onCheckedChange = { isOn = it }) } - Text(text = "${temp.toInt()}°C", style = MaterialTheme.typography.headlineMedium, color = Color.White) - Slider( + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "${temp.toInt()}°C", + style = MaterialTheme.typography.headlineLarge, + color = Color.White, + fontWeight = FontWeight.Bold + ) + + Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { + // 降温按钮 + Box( + modifier = Modifier + .size(40.dp) + .clip(RoundedCornerShape(12.dp)) + .background(Color(0x33FFFFFF)) + .clickable(enabled = isOn && temp > 16f) { + if (temp > 16f) temp -= 1f + }, + contentAlignment = Alignment.Center + ) { + Text(text = "−", color = Color.White, fontSize = 24.sp, fontWeight = FontWeight.Bold) + } + + // 升温按钮 + Box( + modifier = Modifier + .size(40.dp) + .clip(RoundedCornerShape(12.dp)) + .background(Color(0x33FFFFFF)) + .clickable(enabled = isOn && temp < 32f) { + if (temp < 32f) temp += 1f + }, + contentAlignment = Alignment.Center + ) { + Text(text = "+", color = Color.White, fontSize = 24.sp, fontWeight = FontWeight.Bold) + } + } + } + + // 自定义滑动条 + CustomSlider( value = temp, onValueChange = { temp = it }, valueRange = 16f..32f, enabled = isOn ) - Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) { - 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(0x22121212))) - 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(0x22121212))) + + // 温度标记 + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text(text = "16°C", fontSize = 12.sp, color = Color(0xFF9AA0A6)) + Text(text = "24°C", fontSize = 12.sp, color = Color(0xFF9AA0A6)) + Text(text = "32°C", fontSize = 12.sp, color = Color(0xFF9AA0A6)) } } } } +@OptIn(androidx.compose.material3.ExperimentalMaterial3Api::class) +@Composable +fun CustomSlider( + value: Float, + onValueChange: (Float) -> Unit, + valueRange: ClosedFloatingPointRange, + enabled: Boolean = true +) { + val interactionSource = remember { MutableInteractionSource() } + + Box( + modifier = Modifier + .fillMaxWidth() + .height(32.dp), + contentAlignment = Alignment.Center + ) { + Slider( + value = value, + onValueChange = onValueChange, + valueRange = valueRange, + enabled = enabled, + interactionSource = interactionSource, + colors = androidx.compose.material3.SliderDefaults.colors( + thumbColor = Color.White, + activeTrackColor = Brush.linearGradient( + listOf(Color(0xFF00D1FF), Color(0xFFA9F0FF)) + ).let { Color(0xFF00D1FF) }, + inactiveTrackColor = Color(0x33FFFFFF), + disabledThumbColor = Color(0x66FFFFFF), + disabledActiveTrackColor = Color(0x33FFFFFF), + disabledInactiveTrackColor = Color(0x22FFFFFF) + ), + modifier = Modifier + .fillMaxWidth() + .height(24.dp), + thumb = { + Box( + modifier = Modifier + .size(20.dp) + .shadow(4.dp, RoundedCornerShape(10.dp)) + .clip(RoundedCornerShape(10.dp)) + .background(Color.White) + ) + }, + track = { sliderState -> + val fraction = (sliderState.value - valueRange.start) / (valueRange.endInclusive - valueRange.start) + Box( + modifier = Modifier + .fillMaxWidth() + .height(6.dp) + .clip(RoundedCornerShape(3.dp)) + ) { + // 未激活轨道 + Box( + modifier = Modifier + .fillMaxSize() + .background(if (enabled) Color(0x33FFFFFF) else Color(0x22FFFFFF)) + ) + // 激活轨道 + Box( + modifier = Modifier + .fillMaxWidth(fraction) + .fillMaxHeight() + .background( + if (enabled) { + Brush.linearGradient( + listOf(Color(0xFF00D1FF), Color(0xFFA9F0FF)) + ) + } else { + Brush.linearGradient( + listOf(Color(0x33FFFFFF), Color(0x33FFFFFF)) + ) + } + ) + ) + } + } + ) + } +} + @Composable fun LightList(modifier: Modifier = Modifier) { val lights = listOf( @@ -722,12 +855,39 @@ fun LightList(modifier: Modifier = Modifier) { } @Composable -fun DotsProgress(percent: Float) { +fun DotsProgress(percent: Float, onPercentChange: (Float) -> Unit = {}, enabled: Boolean = true) { val total = 12 - Row(horizontalArrangement = Arrangement.spacedBy(4.dp), verticalAlignment = Alignment.CenterVertically) { + Row( + horizontalArrangement = Arrangement.spacedBy(4.dp), + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.pointerInput(enabled) { + if (enabled) { + detectTapGestures { offset -> + // 计算点击的是第几个点 + val dotWidth = 6.dp.toPx() + val spacing = 4.dp.toPx() + val totalWidth = (dotWidth + spacing) * total - spacing + val clickedIndex = ((offset.x / totalWidth) * total).toInt().coerceIn(0, total - 1) + // 更新百分比 + val newPercent = (clickedIndex + 1).toFloat() / total + onPercentChange(newPercent) + } + } + } + ) { repeat(total) { i -> val filled = i < (percent * total).toInt() - Box(modifier = Modifier.size(6.dp).clip(RoundedCornerShape(3.dp)).background(if (filled) Color(0xFFA9F0FF) else Color(0xFF3A3A3A))) + Box( + modifier = Modifier + .size(8.dp) + .clip(RoundedCornerShape(4.dp)) + .background(if (filled) Color(0xFFA9F0FF) else Color(0xFF3A3A3A)) + .clickable(enabled = enabled) { + // 点击某个点直接设置到该亮度 + val newPercent = (i + 1).toFloat() / total + onPercentChange(newPercent) + } + ) } } } @@ -903,13 +1063,70 @@ fun LightRow(modifier: Modifier = Modifier, roomName: String = "房间") { @Composable 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)) { Row(horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) { Row(horizontalArrangement = Arrangement.spacedBy(12.dp), verticalAlignment = Alignment.CenterVertically) { - Box(modifier = Modifier.size(36.dp).clip(RoundedCornerShape(10.dp)).background(Color(0x22121212))) - Column { Text(text = name); Text(text = "${(percent * 100).toInt()}%", color = Color(0xFF9AA0A6)) } + // 灯光图标 - 带发光效果 + Box( + modifier = Modifier + .size(40.dp) + .shadow( + elevation = if (brightness > 0.3f) (brightness * 12).dp else 0.dp, + shape = RoundedCornerShape(12.dp), + spotColor = Color(0xFFFFD54F).copy(alpha = brightness * 0.6f) + ) + .clip(RoundedCornerShape(12.dp)) + .background( + if (brightness > 0.1f) { + Brush.radialGradient( + colors = listOf( + Color(0xFFFFE082).copy(alpha = brightness), + Color(0xFFFFD54F).copy(alpha = brightness * 0.9f), + Color(0xFFFF8F00).copy(alpha = brightness * 0.7f) + ), + radius = 60f + ) + } else { + Brush.linearGradient( + listOf( + Color(0xFF3A3A3A), + Color(0xFF2A2A2A) + ) + ) + } + ), + contentAlignment = Alignment.Center + ) { + Image( + painter = painterResource(id = R.drawable.ic_light), + contentDescription = "灯光", + modifier = Modifier.size(24.dp), + colorFilter = androidx.compose.ui.graphics.ColorFilter.tint( + if (brightness > 0.1f) { + Color.White.copy(alpha = 0.95f) + } else { + Color(0xFF666666) + } + ) + ) + } + Column { + Text(text = name, color = Color.White, fontWeight = FontWeight.Medium) + Text( + text = "${(brightness * 100).toInt()}%", + color = if (brightness > 0.1f) Color(0xFFFFD54F) else Color(0xFF9AA0A6), + fontSize = 13.sp, + fontWeight = if (brightness > 0.5f) FontWeight.Medium else FontWeight.Normal + ) + } } - DotsProgress(percent) + DotsProgress( + percent = brightness, + onPercentChange = { brightness = it }, + enabled = true + ) } } } diff --git a/app/src/main/res/drawable/ic_light.xml b/app/src/main/res/drawable/ic_light.xml index 92c766e..ca7bace 100644 --- a/app/src/main/res/drawable/ic_light.xml +++ b/app/src/main/res/drawable/ic_light.xml @@ -1,4 +1,22 @@ - - - + + + + + + + + + +