From 8051ff242a40f11a5ff1b4a6e9aa2f1696d18b88 Mon Sep 17 00:00:00 2001 From: zzh Date: Tue, 24 Feb 2026 13:44:25 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 14 +- app/src/main/AndroidManifest.xml | 3 + .../com/example/smarthome/MainActivity.kt | 16 +- .../smarthome/MainActivityAlternative.kt | 12 + .../example/smarthome/MainActivityCompose.kt | 176 ++ .../com/example/smarthome/MainActivityHaze.kt | 215 ++ .../com/example/smarthome/ui/MainScaffold.kt | 1858 ++++++----------- .../com/example/smarthome/ui/RoomDialog.kt | 613 ++++++ .../example/smarthome/ui/SettingsScreen.kt | 42 +- .../example/smarthome/ui/SmartHomeScreen.kt | 345 +++ app/src/main/res/layout/activity_main.xml | 14 - build.gradle.kts | 5 +- settings.gradle.kts | 2 +- 13 files changed, 2087 insertions(+), 1228 deletions(-) create mode 100644 app/src/main/java/com/example/smarthome/MainActivityAlternative.kt create mode 100644 app/src/main/java/com/example/smarthome/MainActivityCompose.kt create mode 100644 app/src/main/java/com/example/smarthome/MainActivityHaze.kt create mode 100644 app/src/main/java/com/example/smarthome/ui/RoomDialog.kt create mode 100644 app/src/main/java/com/example/smarthome/ui/SmartHomeScreen.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 8c973cc..1a2432b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,16 +1,17 @@ plugins { id("com.android.application") id("org.jetbrains.kotlin.android") + id("org.jetbrains.kotlin.plugin.compose") } android { namespace = "com.example.smarthome" - compileSdk = 35 + compileSdk = 36 defaultConfig { applicationId = "com.example.smarthome" - minSdk = 24 - targetSdk = 35 + minSdk = 33 // Android 13+ + targetSdk = 36 versionCode = 1 versionName = "1.0" vectorDrawables { @@ -36,9 +37,6 @@ android { compose = true viewBinding = true } - composeOptions { - kotlinCompilerExtensionVersion = "1.5.14" - } compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 @@ -67,7 +65,9 @@ dependencies { implementation("androidx.compose.material3:material3") implementation("androidx.compose.material3:material3-window-size-class:1.3.0") - implementation("com.github.Dimezis:BlurView:version-3.2.0") + // Haze - 现代毛玻璃效果库 + implementation("dev.chrisbanes.haze:haze:1.7.1") + 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") diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 59794e9..63a8267 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -16,5 +16,8 @@ + + + diff --git a/app/src/main/java/com/example/smarthome/MainActivity.kt b/app/src/main/java/com/example/smarthome/MainActivity.kt index 5377337..91c3caa 100644 --- a/app/src/main/java/com/example/smarthome/MainActivity.kt +++ b/app/src/main/java/com/example/smarthome/MainActivity.kt @@ -7,8 +7,6 @@ import com.example.smarthome.ui.theme.SmartHomeTheme import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.ViewCompositionStrategy -import eightbitlab.com.blurview.BlurTarget -import eightbitlab.com.blurview.BlurView import androidx.compose.material3.Surface import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.ui.Modifier @@ -31,6 +29,7 @@ import androidx.compose.runtime.collectAsState import com.example.smarthome.data.BackgroundManager import com.example.smarthome.data.LanguageManager import com.example.smarthome.data.UserManager +import com.example.smarthome.ui.SmartHomeScreen class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { @@ -53,14 +52,6 @@ class MainActivity : ComponentActivity() { } } - val decorView = window.decorView - val blurTarget = findViewById(R.id.blurTarget) - val blurView = findViewById(R.id.blurView) - val windowBackground: Drawable? = decorView.background - blurView.setupWith(blurTarget) - .setFrameClearDrawable(windowBackground) - .setBlurRadius(20f) - } private fun hideStatusBar() { // 设置全屏模式,让内容延伸到系统栏区域 @@ -174,7 +165,10 @@ fun MainContent() { Box(modifier = Modifier.fillMaxSize()) { MainScaffold( selectedRoom = selectedRoom, - onRoomSelect = { selectedRoom = it }, + onRoomSelect = { roomIndex -> + selectedRoom = roomIndex + selectedNavItem = 0 // 切换到控制台页面 + }, selectedNavItem = selectedNavItem, onNavItemSelect = { selectedNavItem = it }, rooms = rooms, diff --git a/app/src/main/java/com/example/smarthome/MainActivityAlternative.kt b/app/src/main/java/com/example/smarthome/MainActivityAlternative.kt new file mode 100644 index 0000000..9c7631c --- /dev/null +++ b/app/src/main/java/com/example/smarthome/MainActivityAlternative.kt @@ -0,0 +1,12 @@ +package com.example.smarthome + +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity + +class MainActivityAlternative : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + // 简单的空 Activity + } +} diff --git a/app/src/main/java/com/example/smarthome/MainActivityCompose.kt b/app/src/main/java/com/example/smarthome/MainActivityCompose.kt new file mode 100644 index 0000000..448fec9 --- /dev/null +++ b/app/src/main/java/com/example/smarthome/MainActivityCompose.kt @@ -0,0 +1,176 @@ +package com.example.smarthome + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.blur +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.unit.dp +import androidx.compose.ui.unit.sp +import com.example.smarthome.ui.theme.SmartHomeTheme + +class MainActivityCompose : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + SmartHomeTheme { + Surface( + modifier = Modifier.fillMaxSize(), + color = Color(0xFF1A1A2E) + ) { + SmartHomeScreen() + } + } + } + } +} + +@Composable +fun SmartHomeScreen() { + Box( + modifier = Modifier + .fillMaxSize() + .background( + Brush.verticalGradient( + colors = listOf( + Color(0xFF1A1A2E), + Color(0xFF16213E), + Color(0xFF0F3460) + ) + ) + ) + ) { + Row( + modifier = Modifier.fillMaxSize() + ) { + // 左侧毛玻璃边栏 + GlassSidebar( + modifier = Modifier + .width(260.dp) + .padding(24.dp) + ) + + // 主内容区域 + Box( + modifier = Modifier + .fillMaxSize() + .padding(24.dp), + contentAlignment = Alignment.Center + ) { + GlassCard() + } + } + } +} + +@Composable +fun GlassSidebar( + modifier: Modifier = Modifier +) { + Box( + modifier = modifier + .fillMaxHeight() + .clip(RoundedCornerShape(32.dp)) + .background( + Brush.linearGradient( + colors = listOf( + Color.White.copy(alpha = 0.15f), + Color.White.copy(alpha = 0.08f) + ) + ) + ) + .blur(20.dp) + .padding(32.dp) + ) { + Column( + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + Text( + text = "Lumina", + color = Color.White, + fontSize = 32.sp, + fontWeight = FontWeight.Bold + ) + + Text( + text = "Smart Home", + color = Color.White.copy(alpha = 0.6f), + fontSize = 14.sp + ) + + Spacer(modifier = Modifier.height(32.dp)) + + listOf("🏠 首页", "🌡️ 温控", "💡 照明", "🔒 安全").forEach { item -> + Text( + text = item, + color = if (item == "🏠 首页") Color.White else Color.White.copy(alpha = 0.6f), + fontSize = 16.sp, + modifier = Modifier.padding(vertical = 8.dp) + ) + } + } + } +} + +@Composable +fun GlassCard() { + Box( + modifier = Modifier + .width(400.dp) + .height(250.dp) + .clip(RoundedCornerShape(24.dp)) + .background( + Brush.linearGradient( + colors = listOf( + Color.White.copy(alpha = 0.20f), + Color.White.copy(alpha = 0.12f), + Color.White.copy(alpha = 0.06f) + ) + ) + ) + .blur(25.dp) + .padding(32.dp), + contentAlignment = Alignment.CenterStart + ) { + Column( + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + Text( + text = "智能家居控制中心", + color = Color.White, + fontSize = 24.sp, + fontWeight = FontWeight.Bold + ) + + Text( + text = "当前温度: 26°C", + color = Color.White.copy(alpha = 0.8f), + fontSize = 16.sp + ) + + Text( + text = "湿度: 65%", + color = Color.White.copy(alpha = 0.8f), + fontSize = 16.sp + ) + + Text( + text = "空气质量: 优", + color = Color.White.copy(alpha = 0.8f), + fontSize = 16.sp + ) + } + } +} diff --git a/app/src/main/java/com/example/smarthome/MainActivityHaze.kt b/app/src/main/java/com/example/smarthome/MainActivityHaze.kt new file mode 100644 index 0000000..753edea --- /dev/null +++ b/app/src/main/java/com/example/smarthome/MainActivityHaze.kt @@ -0,0 +1,215 @@ +package com.example.smarthome + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +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.unit.dp +import androidx.compose.ui.unit.sp +import dev.chrisbanes.haze.HazeState +import dev.chrisbanes.haze.HazeStyle +import dev.chrisbanes.haze.HazeTint +import dev.chrisbanes.haze.haze +import dev.chrisbanes.haze.hazeChild +import dev.chrisbanes.haze.hazeEffect +import dev.chrisbanes.haze.hazeSource +import com.example.smarthome.ui.theme.SmartHomeTheme +import androidx.compose.ui.platform.LocalDensity + +class MainActivityHaze : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + SmartHomeTheme { + Surface( + modifier = Modifier.fillMaxSize(), + color = Color(0xFF1A1A2E) + ) { + SmartHomeScreenWithHaze() + } + } + } + } +} + +@Composable +fun SmartHomeScreenWithHaze() { + val hazeState = HazeState() + val density = LocalDensity.current + + Box( + modifier = Modifier + .fillMaxSize() + .background( + Brush.verticalGradient( + colors = listOf( + Color(0xFF1A1A2E), + Color(0xFF16213E), + Color(0xFF0F3460) + ) + ) + ) + .hazeSource(state = hazeState) + ) { + // 背景装饰内容 + Column( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.SpaceEvenly, + horizontalAlignment = Alignment.CenterHorizontally + ) { + repeat(5) { index -> + with(density) { + val sizeDp = (100 + index * 20).dp + Box( + modifier = Modifier + .size(sizeDp) + .clip(RoundedCornerShape(50)) + .background( + Brush.radialGradient( + colors = listOf( + Color(0xFF6C5CE7), + Color(0xFFA29BFE), + Color.Transparent + ) + ) + ) + ) + } + } + } + + Row( + modifier = Modifier.fillMaxSize() + ) { + // 左侧毛玻璃边栏 + HazeSidebar( + modifier = Modifier + .width(260.dp) + .padding(24.dp), + hazeState = hazeState + ) + + // 主内容区域 + Box( + modifier = Modifier + .fillMaxSize() + .padding(24.dp), + contentAlignment = Alignment.Center + ) { + HazeCard(hazeState = hazeState) + } + } + } +} + +@Composable +fun HazeSidebar( + modifier: Modifier = Modifier, + hazeState: HazeState +) { + Box( + modifier = modifier + .fillMaxHeight() + .clip(RoundedCornerShape(32.dp)) + .hazeEffect( + state = hazeState, + style = HazeStyle( + blurRadius = 20.dp, + tint = HazeTint(Color.White.copy(alpha = 0.15f)), + noiseFactor = 0.0f + ) + ) + .padding(32.dp) + ) { + Column( + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + Text( + text = "Lumina", + color = Color.White, + fontSize = 32.sp, + fontWeight = FontWeight.Bold + ) + + Text( + text = "Smart Home", + color = Color.White.copy(alpha = 0.6f), + fontSize = 14.sp + ) + + Spacer(modifier = Modifier.height(32.dp)) + + listOf("🏠 首页", "🌡️ 温控", "💡 照明", "🔒 安全").forEach { item -> + Text( + text = item, + color = if (item == "🏠 首页") Color.White else Color.White.copy(alpha = 0.6f), + fontSize = 16.sp, + modifier = Modifier.padding(vertical = 8.dp) + ) + } + } + } +} + +@Composable +fun HazeCard( + hazeState: HazeState +) { + Box( + modifier = Modifier + .width(400.dp) + .height(250.dp) + .clip(RoundedCornerShape(24.dp)) + .hazeEffect( + state = hazeState, + style = HazeStyle( + blurRadius = 25.dp, + tint = HazeTint(Color.White.copy(alpha = 0.2f)), + noiseFactor = 0.0f + ) + ) + .padding(32.dp), + contentAlignment = Alignment.CenterStart + ) { + Column( + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + Text( + text = "智能家居控制中心", + color = Color.White, + fontSize = 24.sp, + fontWeight = FontWeight.Bold + ) + + Text( + text = "当前温度: 26°C", + color = Color.White.copy(alpha = 0.8f), + fontSize = 16.sp + ) + + Text( + text = "湿度: 65%", + color = Color.White.copy(alpha = 0.8f), + fontSize = 16.sp + ) + + Text( + text = "空气质量: 优", + color = Color.White.copy(alpha = 0.8f), + fontSize = 16.sp + ) + } + } +} 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 210da54..4025617 100644 --- a/app/src/main/java/com/example/smarthome/ui/MainScaffold.kt +++ b/app/src/main/java/com/example/smarthome/ui/MainScaffold.kt @@ -1,5 +1,6 @@ package com.example.smarthome.ui +import androidx.compose.foundation.Canvas import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -19,10 +20,13 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.shadow import androidx.compose.ui.draw.scale import androidx.compose.ui.draw.alpha +import androidx.compose.ui.draw.blur +import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Shadow +import androidx.compose.ui.graphics.drawscope.DrawScope import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign @@ -32,13 +36,16 @@ import androidx.compose.foundation.border import com.example.smarthome.R import com.example.smarthome.data.WeatherInfo import com.example.smarthome.data.WeatherService +import com.example.smarthome.data.BackgroundManager import com.example.smarthome.data.LanguageManager +import com.example.smarthome.data.UserManager import com.example.smarthome.data.tr import kotlinx.coroutines.launch import kotlinx.coroutines.delay import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalView +import androidx.compose.ui.platform.LocalContext import android.view.SoundEffectConstants import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.verticalScroll @@ -51,6 +58,23 @@ import androidx.compose.ui.draw.rotate import androidx.compose.ui.layout.ContentScale import androidx.compose.foundation.text.BasicTextField import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.Path +import android.os.Build +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import androidx.compose.ui.viewinterop.AndroidView +import android.content.Context +import android.view.LayoutInflater +import android.app.Activity +import android.content.ContextWrapper +import dev.chrisbanes.haze.HazeState +import dev.chrisbanes.haze.HazeStyle +import dev.chrisbanes.haze.HazeTint +import dev.chrisbanes.haze.haze +import dev.chrisbanes.haze.hazeChild +import dev.chrisbanes.haze.hazeSource +import dev.chrisbanes.haze.hazeEffect @Composable fun MainScaffold( @@ -66,120 +90,28 @@ fun MainScaffold( // 编辑房间对话框状态 - 提升到这里以控制菜单栏显示 var showEditRoomsDialog by remember { mutableStateOf(false) } + // Haze state for blur effects + val hazeState = remember { HazeState() } + Box(modifier = Modifier.fillMaxSize()) { - // 内容区域 - 全屏显示 - Box( - modifier = Modifier.fillMaxSize() - ) { - // 根据选中的导航项显示不同的内容 - // 底部导航: 0-Dashboard, 1-Scene, 2-Automation, 3-Security, 4-Settings - when (selectedNavItem) { - 0 -> DashboardContent( - selectedRoom = selectedRoom, - onRoomSelect = onRoomSelect, - rooms = rooms, - onAddRoom = onAddRoom, - onDeleteRoom = onDeleteRoom, - onRenameRoom = onRenameRoom, - showEditRoomsDialog = showEditRoomsDialog, - onShowEditRoomsDialog = { showEditRoomsDialog = it } - ) - 1 -> SceneScreen() - 2 -> AutomationScreen() - 3 -> SecurityScreen() - 4 -> SettingsContent() - else -> DashboardContent( - selectedRoom = selectedRoom, - onRoomSelect = onRoomSelect, - rooms = rooms, - onAddRoom = onAddRoom, - onDeleteRoom = onDeleteRoom, - onRenameRoom = onRenameRoom, - showEditRoomsDialog = showEditRoomsDialog, - onShowEditRoomsDialog = { showEditRoomsDialog = it } - ) - } - } - - // 底部渐变遮罩 - 让内容优雅淡出 + // 背景作为模糊源 Box( modifier = Modifier - .align(Alignment.BottomCenter) - .fillMaxWidth() - .height(120.dp) - .background( - Brush.verticalGradient( - colors = listOf( - Color.Transparent, - Color(0xFF0A0A0A).copy(alpha = 0.8f) - ) - ) - ) - ) - - // 底部悬浮导航栏 - 置于内容之上,编辑房间时隐藏 - if (!showEditRoomsDialog) { - FloatingBottomNav( - selectedNavItem = selectedNavItem, - onNavItemSelect = onNavItemSelect, - modifier = Modifier - .align(Alignment.BottomCenter) - .padding(bottom = 24.dp) - ) - } - } -} - -@Composable -fun DashboardContent( - selectedRoom: Int, - onRoomSelect: (Int) -> Unit, - rooms: List = listOf("总览", "客厅", "厨房", "卧室", "影音室", "游戏房"), - onAddRoom: (String) -> Unit = {}, - onDeleteRoom: (Int) -> Unit = {}, - onRenameRoom: (Int, String) -> Unit = { _, _ -> }, - showEditRoomsDialog: Boolean = false, - onShowEditRoomsDialog: (Boolean) -> Unit = {} -) { - var showAddRoomDialog by remember { mutableStateOf(false) } - - // 根据房间选择壁纸 - val roomName = rooms.getOrNull(selectedRoom) ?: "总览" - val wallpaperRes = when { - selectedRoom == 0 -> R.drawable.room_wallpaper_default // 总览 - roomName == "客厅" -> R.drawable.room_wallpaper_default - roomName == "厨房" -> R.drawable.zenhome_wallpaper_1764420980064 - roomName == "卧室" -> R.drawable.zenhome_wallpaper_1764420805752 - else -> null - } - - Box( - modifier = Modifier - .fillMaxSize() - ) { - // 房间壁纸背景 - 放在最底层 - if (wallpaperRes != null) { - // 先添加深色底层,避免与全局背景重叠 - Box( - modifier = Modifier - .fillMaxSize() - .clip(RoundedCornerShape(24.dp)) - .background(Color(0xFF0D0D0D)) - ) + .fillMaxSize() + .hazeSource(state = hazeState) + ) { + // 背景图片 Image( - painter = painterResource(id = wallpaperRes), + painter = painterResource(id = R.drawable.background), contentDescription = null, - modifier = Modifier - .fillMaxSize() - .clip(RoundedCornerShape(24.dp)), + modifier = Modifier.fillMaxSize(), contentScale = ContentScale.Crop, - alpha = 0.6f + alpha = 0.8f ) // 添加渐变遮罩层增强可读性 Box( modifier = Modifier .fillMaxSize() - .clip(RoundedCornerShape(24.dp)) .background( Brush.verticalGradient( colors = listOf( @@ -192,20 +124,105 @@ fun DashboardContent( ) } - Column(modifier = Modifier.fillMaxSize().padding(horizontal = 16.dp, vertical = 16.dp)) { - TopBar() - RoomTabs( + Row(modifier = Modifier.fillMaxSize()) { + // 左侧毛玻璃边栏 + GlassSidebar( selectedRoom = selectedRoom, onRoomSelect = onRoomSelect, - rooms = rooms, - onAddRoomClick = { showAddRoomDialog = true }, - onDeleteRoom = onDeleteRoom, - onRenameRoom = onRenameRoom, - showEditRoomsDialog = showEditRoomsDialog, - onShowEditRoomsDialog = onShowEditRoomsDialog + selectedNavItem = selectedNavItem, + onNavItemSelect = onNavItemSelect, + modifier = Modifier.fillMaxHeight(), + hazeState = hazeState ) + + // 间距 + Spacer(modifier = Modifier.width(24.dp)) + + // 主内容区域 + Box(modifier = Modifier.weight(1f)) { + // 内容区域 - 全屏显示 + Box( + modifier = Modifier.fillMaxSize() + ) { + // 根据选中的导航项显示不同的内容 + // 底部导航: 0-Dashboard, 1-Scene, 2-Automation, 3-Settings + when (selectedNavItem) { + 0 -> DashboardContent( + selectedRoom = selectedRoom, + onRoomSelect = onRoomSelect, + rooms = rooms, + onAddRoom = onAddRoom, + onDeleteRoom = onDeleteRoom, + onRenameRoom = onRenameRoom, + showEditRoomsDialog = showEditRoomsDialog, + onShowEditRoomsDialog = { showEditRoomsDialog = it }, + hazeState = hazeState + ) + 1 -> SceneScreen() + 2 -> AutomationScreen() + 3 -> SettingsContent( + rooms = rooms, + onAddRoom = onAddRoom, + onDeleteRoom = onDeleteRoom, + onRenameRoom = onRenameRoom + ) + else -> DashboardContent( + selectedRoom = selectedRoom, + onRoomSelect = onRoomSelect, + rooms = rooms, + onAddRoom = onAddRoom, + onDeleteRoom = onDeleteRoom, + onRenameRoom = onRenameRoom, + showEditRoomsDialog = showEditRoomsDialog, + onShowEditRoomsDialog = { showEditRoomsDialog = it }, + hazeState = hazeState + ) + } + } + } + } + } +} + +@Composable +fun DashboardContent( + selectedRoom: Int, + onRoomSelect: (Int) -> Unit, + rooms: List = listOf("总览", "客厅", "厨房", "卧室", "影音室", "游戏房"), + onAddRoom: (String) -> Unit = {}, + onDeleteRoom: (Int) -> Unit = {}, + onRenameRoom: (Int, String) -> Unit = { _, _ -> }, + showEditRoomsDialog: Boolean = false, + onShowEditRoomsDialog: (Boolean) -> Unit = {}, + hazeState: HazeState +) { + var showAddRoomDialog by remember { mutableStateOf(false) } + + val roomName = rooms.getOrNull(selectedRoom) ?: "总览" + + Box( + modifier = Modifier + .fillMaxSize() + ) { + + Column(modifier = Modifier.fillMaxSize().padding(start = 8.dp, end = 16.dp, top = 16.dp, bottom = 16.dp)) { + TopBar() + + Spacer(modifier = Modifier.height(16.dp)) + // 根据选中的房间显示不同的内容 - RoomContent(selectedRoom = selectedRoom, roomName = roomName) + RoomContent(selectedRoom = selectedRoom, roomName = roomName, hazeState = hazeState) + } + + // 编辑房间对话框 + if (showEditRoomsDialog) { + EditRoomsDialog( + rooms = rooms, + onDismiss = { onShowEditRoomsDialog(false) }, + onRenameRoom = onRenameRoom, + onDeleteRoom = onDeleteRoom, + onAddRoom = { /* 添加房间逻辑已移到右上角按钮 */ } + ) } if (showAddRoomDialog) { @@ -221,16 +238,16 @@ fun DashboardContent( } @Composable -fun RoomContent(selectedRoom: Int, roomName: String) { +fun RoomContent(selectedRoom: Int, roomName: String, hazeState: HazeState) { // 根据房间索引显示不同的内容 when (selectedRoom) { - 0 -> OverviewRoomContent() // 总览 - else -> SpecificRoomContent(selectedRoom, roomName) // 具体房间 + 0 -> OverviewRoomContent(hazeState) // 总览 + else -> SpecificRoomContent(selectedRoom, roomName, hazeState) // 具体房间 } } @Composable -fun OverviewRoomContent() { +fun OverviewRoomContent(hazeState: HazeState) { Column( modifier = Modifier .fillMaxSize() @@ -242,8 +259,20 @@ fun OverviewRoomContent() { .height(IntrinsicSize.Max), horizontalArrangement = Arrangement.spacedBy(16.dp) ) { - AirConditionerCard(modifier = Modifier.weight(1f).fillMaxHeight(), roomName = tr("room_all")) - UsageStatusChart(modifier = Modifier.weight(1f).fillMaxHeight(), roomName = tr("room_all")) + AirConditionerCard( + modifier = Modifier + .weight(2f) + .fillMaxHeight(), + roomName = tr("room_all"), + hazeState = hazeState + ) + UsageStatusChart( + modifier = Modifier + .weight(1f) + .fillMaxHeight(), + roomName = tr("room_all"), + hazeState = hazeState + ) } Spacer(modifier = Modifier.height(16.dp)) ModeButtonsRow(onModeSelected = { }) @@ -267,15 +296,30 @@ fun OverviewRoomContent() { } @Composable -fun SpecificRoomContent(selectedRoom: Int, roomName: String) { +fun SpecificRoomContent(selectedRoom: Int, roomName: String, hazeState: HazeState) { Column( modifier = Modifier .fillMaxSize() .verticalScroll(rememberScrollState()) ) { - Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(16.dp)) { - AirConditionerCard(modifier = Modifier.weight(1f), roomName = roomName) - UsageStatusChart(modifier = Modifier.weight(1f), roomName = roomName) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(16.dp) + ) { + AirConditionerCard( + modifier = Modifier + .weight(2f) + .fillMaxHeight(), + roomName = roomName, + hazeState = hazeState + ) + UsageStatusChart( + modifier = Modifier + .weight(1f) + .fillMaxHeight(), + roomName = roomName, + hazeState = hazeState + ) } LightRow(modifier = Modifier.fillMaxWidth().padding(top = 16.dp, bottom = 16.dp), roomName = roomName) @@ -1328,7 +1372,7 @@ private data class RoomEnergy( ) @Composable -fun UsageStatusChart(modifier: Modifier = Modifier, roomName: String = "房间") { +fun UsageStatusChart(modifier: Modifier = Modifier, roomName: String = "房间", hazeState: HazeState) { // 判断是否为总览 val isOverview = roomName == tr("room_all") || roomName == "总览" || roomName == "全部" @@ -1346,16 +1390,13 @@ fun UsageStatusChart(modifier: Modifier = Modifier, roomName: String = "房间") peakWatt = allRooms.maxOf { it.peakWatt } // 取最大峰值 ) } else { - roomEnergyData[roomName] ?: RoomEnergy(2.0, 5, 4, "↓", 8, 1.2, 200) + roomEnergyData[roomName] ?: RoomEnergy(13.1, 5, 4, "↑", 11, 7.5, 200) } val totalPower = String.format("%.1f", roomData.power) - val totalHours = roomData.hours - val activeDevices = roomData.devices val trend = roomData.trend val trendPercent = roomData.trendPercent val costToday = String.format("%.1f", roomData.cost) - val peakWatt = roomData.peakWatt // 主题色 val accentColor = Color(0xFF00D1FF) @@ -1363,17 +1404,22 @@ fun UsageStatusChart(modifier: Modifier = Modifier, roomName: String = "房间") Box( modifier = modifier .clip(RoundedCornerShape(24.dp)) - .background(Color(0xFF1A1A1A).copy(alpha = 0.65f)) + .hazeEffect( + state = hazeState, + style = HazeStyle( + blurRadius = 40.dp, + tint = HazeTint(Color.White.copy(alpha = 0.15f)), + noiseFactor = 0.0f + ) + ) .border( - width = 2.dp, - color = Color.White.copy(alpha = 0.25f), + width = 1.dp, + color = Color.White.copy(alpha = 0.3f), shape = RoundedCornerShape(24.dp) ) - .padding(16.dp) + .padding(20.dp) ) { - Column( - verticalArrangement = Arrangement.spacedBy(12.dp) - ) { + Column { // 标题区域 Row( modifier = Modifier.fillMaxWidth(), @@ -1384,411 +1430,372 @@ fun UsageStatusChart(modifier: Modifier = Modifier, roomName: String = "房间") // 图标 Box( modifier = Modifier - .size(36.dp) - .clip(RoundedCornerShape(10.dp)) - .background(accentColor.copy(alpha = 0.2f)), + .size(32.dp) + .clip(RoundedCornerShape(8.dp)) + .background(Color(0xFFFFB74D).copy(alpha = 0.2f)), contentAlignment = Alignment.Center ) { - Text(text = "⚡", fontSize = 18.sp) - } - Column { - Text( - text = "能耗统计", - fontWeight = FontWeight.SemiBold, - color = Color.White, - fontSize = 16.sp - ) - Text( - text = roomName, - fontSize = 11.sp, - color = Color(0xFF9AA0A6) - ) + Text(text = "⚡", fontSize = 16.sp) } + Text( + text = "能耗统计", + fontWeight = FontWeight.Medium, + color = Color.White, + fontSize = 16.sp + ) } // 趋势指示器 Box( modifier = Modifier - .clip(RoundedCornerShape(8.dp)) - .background( - if (trend == "↑") Color(0x33FF5252) else Color(0x3300E676) - ) + .clip(RoundedCornerShape(12.dp)) + .background(Color(0x33FF5252)) .padding(horizontal = 8.dp, vertical = 4.dp) ) { Text( - text = "$trend${trendPercent}%", - color = if (trend == "↑") Color(0xFFFF5252) else Color(0xFF00E676), - fontSize = 12.sp, - fontWeight = FontWeight.Bold + text = "$trend $trendPercent% vs Prev Day", + color = Color(0xFFFF5252), + fontSize = 11.sp, + fontWeight = FontWeight.Medium ) } } + Spacer(modifier = Modifier.height(16.dp)) + // 主数据显示 - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.Bottom - ) { - // 今日用电 - Column { - Row(verticalAlignment = Alignment.Top) { - Text( - text = totalPower, - fontSize = 42.sp, - color = Color.White, - fontWeight = FontWeight.Light - ) - Text( - text = "kWh", - fontSize = 14.sp, - color = Color.White.copy(alpha = 0.6f), - modifier = Modifier.padding(top = 10.dp, start = 4.dp) - ) - } + Column { + Row( + verticalAlignment = Alignment.Top + ) { Text( - text = "今日用电", - fontSize = 12.sp, - color = Color(0xFF9AA0A6) + text = totalPower, + fontSize = 32.sp, + color = Color.White, + fontWeight = FontWeight.Light + ) + Text( + text = "KWH", + fontSize = 14.sp, + color = Color.White.copy(alpha = 0.6f), + modifier = Modifier.padding(top = 8.dp, start = 4.dp) ) } + Spacer(modifier = Modifier.height(8.dp)) + // 预计费用 - Column(horizontalAlignment = Alignment.End) { - Text( - text = "¥$costToday", - fontSize = 20.sp, - color = accentColor, - fontWeight = FontWeight.Bold - ) - Text( - text = "预计费用", - fontSize = 11.sp, - color = Color(0xFF9AA0A6) + Text( + text = "EST. COST", + fontSize = 12.sp, + color = Color.White.copy(alpha = 0.5f) + ) + Text( + text = "¥$costToday", + fontSize = 20.sp, + color = accentColor, + fontWeight = FontWeight.Medium + ) + } + + Spacer(modifier = Modifier.height(20.dp)) + + // 折线图 + EnergyTrendChart() + } + } +} + +@Composable +fun EnergyTrendChart() { + // 模拟数据点 - 7天的能耗数据 + val dataPoints = listOf(0.3f, 0.5f, 0.4f, 0.7f, 0.6f, 0.8f, 0.9f) + + Box( + modifier = Modifier + .fillMaxWidth() + .height(60.dp) + ) { + Canvas(modifier = Modifier.fillMaxSize()) { + val canvasWidth = size.width + val canvasHeight = size.height + val stepX = canvasWidth / (dataPoints.size - 1) + + // 绘制渐变填充区域 + val fillPath = Path().apply { + moveTo(0f, canvasHeight) + + dataPoints.forEachIndexed { index, value -> + val x = index * stepX + val y = canvasHeight - (value * canvasHeight) + if (index == 0) { + lineTo(x, y) + } else { + // 使用二次贝塞尔曲线使线条更平滑 + val prevX = (index - 1) * stepX + val prevY = canvasHeight - (dataPoints[index - 1] * canvasHeight) + val controlX = (prevX + x) / 2 + quadraticBezierTo(controlX, prevY, x, y) + } + } + + lineTo(canvasWidth, canvasHeight) + close() + } + + // 绘制渐变填充 + drawPath( + path = fillPath, + brush = Brush.verticalGradient( + colors = listOf( + Color(0xFF00D1FF).copy(alpha = 0.3f), + Color(0xFF00D1FF).copy(alpha = 0.05f) ) + ) + ) + + // 绘制线条 + val linePath = Path().apply { + dataPoints.forEachIndexed { index, value -> + val x = index * stepX + val y = canvasHeight - (value * canvasHeight) + if (index == 0) { + moveTo(x, y) + } else { + val prevX = (index - 1) * stepX + val prevY = canvasHeight - (dataPoints[index - 1] * canvasHeight) + val controlX = (prevX + x) / 2 + quadraticBezierTo(controlX, prevY, x, y) + } } } - // 详细数据行 - Row( - modifier = Modifier - .fillMaxWidth() - .height(56.dp) - .clip(RoundedCornerShape(12.dp)) - .background(Color(0xFF2A2A2A).copy(alpha = 0.4f)) - .padding(horizontal = 12.dp), - horizontalArrangement = Arrangement.SpaceEvenly, - verticalAlignment = Alignment.CenterVertically - ) { - // 运行时长 - Column(horizontalAlignment = Alignment.CenterHorizontally) { - Text( - text = "$totalHours", - color = Color(0xFFB89CFF), - fontSize = 18.sp, - fontWeight = FontWeight.Bold - ) - Text(text = "小时", fontSize = 10.sp, color = Color(0xFF9AA0A6)) - } - - // 分隔线 - Box( - modifier = Modifier - .width(1.dp) - .height(30.dp) - .background(Color(0xFF3A3A3A).copy(alpha = 0.5f)) + drawPath( + path = linePath, + color = Color(0xFF00D1FF), + style = androidx.compose.ui.graphics.drawscope.Stroke( + width = 2.dp.toPx(), + cap = androidx.compose.ui.graphics.StrokeCap.Round ) - - // 活跃设备 - Column(horizontalAlignment = Alignment.CenterHorizontally) { - Text( - text = "$activeDevices", - color = Color(0xFF00E676), - fontSize = 18.sp, - fontWeight = FontWeight.Bold - ) - Text(text = "设备", fontSize = 10.sp, color = Color(0xFF9AA0A6)) - } - - // 分隔线 - Box( - modifier = Modifier - .width(1.dp) - .height(30.dp) - .background(Color(0xFF3A3A3A).copy(alpha = 0.5f)) + ) + + // 绘制数据点 + dataPoints.forEachIndexed { index, value -> + val x = index * stepX + val y = canvasHeight - (value * canvasHeight) + drawCircle( + color = Color(0xFF00D1FF), + radius = 3.dp.toPx(), + center = Offset(x, y) + ) + drawCircle( + color = Color.White, + radius = 1.5.dp.toPx(), + center = Offset(x, y) ) - - // 峰值功率 - Column(horizontalAlignment = Alignment.CenterHorizontally) { - Text( - text = "$peakWatt", - color = Color(0xFFFFB74D), - fontSize = 18.sp, - fontWeight = FontWeight.Bold - ) - Text(text = "W峰值", fontSize = 10.sp, color = Color(0xFF9AA0A6)) - } } } } } @Composable -fun AirConditionerCard(modifier: Modifier = Modifier, roomName: String = "房间") { - var temp by remember { mutableStateOf(24f) } - var isOn by remember { mutableStateOf(true) } - var selectedMode by remember { mutableStateOf(0) } // 0:制冷 1:制热 2:除湿 3:送风 - var fanSpeed by remember { mutableStateOf(1) } // 0:自动 1:低 2:中 3:高 - - // 模式emoji图标 - val modeIcons = listOf( - "❄️" to tr("ac_mode_cool"), - "☀️" to tr("ac_mode_heat"), - "💧" to tr("ac_mode_dry"), - "🌀" to tr("ac_mode_fan") - ) - - // 风速旋转速度(根据档位变化) - val fanRotationDuration = when (fanSpeed) { - 0 -> 2000 // 自动 - 1 -> 3000 // 低速 - 2 -> 1500 // 中速 - else -> 800 // 高速 - } - - // 图标动画 - val infiniteTransition = rememberInfiniteTransition(label = "ac_icon") - - // 旋转动画(制冷、制热、送风) - val iconRotation by infiniteTransition.animateFloat( - initialValue = 0f, - targetValue = 360f, - animationSpec = infiniteRepeatable( - animation = tween(durationMillis = 3000, easing = LinearEasing), - repeatMode = RepeatMode.Restart - ), - label = "icon_rotation" - ) - - // 水滴下落动画(除湿) - val dropOffset by infiniteTransition.animateFloat( - initialValue = -2f, - targetValue = 2f, - animationSpec = infiniteRepeatable( - animation = tween(durationMillis = 800, easing = androidx.compose.animation.core.EaseInOut), - repeatMode = RepeatMode.Reverse - ), - label = "drop_offset" - ) - - // 风扇旋转动画 - val fanRotation by infiniteTransition.animateFloat( - initialValue = 0f, - targetValue = 360f, - animationSpec = infiniteRepeatable( - animation = tween(durationMillis = fanRotationDuration, easing = LinearEasing), - repeatMode = RepeatMode.Restart - ), - label = "fan_rotation" - ) - - // 风速标签 - val fanSpeedLabel = when (fanSpeed) { - 0 -> tr("ac_fan_auto") - 1 -> tr("ac_fan_low") - 2 -> tr("ac_fan_medium") - else -> tr("ac_fan_high") - } - - // 根据模式决定主题色 - val accentColor = when (selectedMode) { - 0 -> Color(0xFF4FC3F7) // 制冷 - 蓝色 - 1 -> Color(0xFFFF8A65) // 制热 - 橙色 - 2 -> Color(0xFF81C784) // 除湿 - 绿色 - else -> Color(0xFFB0BEC5) // 送风 - 灰色 - } - - // 当前模式的emoji - val currentEmoji = modeIcons[selectedMode].first +fun AirConditionerCard( + modifier: Modifier = Modifier, + roomName: String = "房间", + hazeState: HazeState +) { + // 模拟环境数据 + val currentTemp = remember { mutableStateOf(24) } + val humidity = remember { mutableStateOf(65) } + val pm25 = remember { mutableStateOf(35) } + val co2 = remember { mutableStateOf(420) } + // 外层大卡片 - 使用 Haze 毛玻璃效果 Box( modifier = modifier .clip(RoundedCornerShape(24.dp)) - .background(Color(0xFF1A1A1A).copy(alpha = 0.65f)) + .hazeEffect( + state = hazeState, + style = HazeStyle( + blurRadius = 40.dp, + tint = HazeTint(Color.White.copy(alpha = 0.15f)), + noiseFactor = 0.0f + ) + ) .border( - width = 2.dp, - color = Color.White.copy(alpha = 0.25f), + width = 1.dp, + color = Color.White.copy(alpha = 0.3f), shape = RoundedCornerShape(24.dp) ) - .padding(16.dp) + .padding(20.dp) ) { - Column(verticalArrangement = Arrangement.spacedBy(12.dp)) { - // 顶部:标题和开关 + Column( + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + // 标题 Row( - horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.fillMaxWidth() + horizontalArrangement = Arrangement.spacedBy(8.dp) ) { - Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp)) { - // 空调图标 - 根据模式应用不同动画 - Box( - modifier = Modifier - .size(36.dp) - .clip(RoundedCornerShape(10.dp)) - .background(accentColor.copy(alpha = if (isOn) 0.3f else 0.1f)), - contentAlignment = Alignment.Center - ) { - // 根据模式选择动画:除湿用上下移动,其他用旋转 - val emojiModifier = when { - !isOn -> Modifier - selectedMode == 2 -> Modifier.offset(y = dropOffset.dp) // 除湿:上下移动 - else -> Modifier.rotate(iconRotation) // 其他:旋转 - } - Text( - text = currentEmoji, - fontSize = 18.sp, - modifier = emojiModifier - ) - } - Column { - Text(text = tr("ac_title"), fontWeight = FontWeight.SemiBold, color = Color.White, fontSize = 16.sp) - Text(text = roomName, fontSize = 11.sp, color = Color(0xFF9AA0A6)) - } - } - Switch( - checked = isOn, - onCheckedChange = { isOn = it }, - colors = SwitchDefaults.colors( - checkedThumbColor = Color.White, - checkedTrackColor = accentColor, - uncheckedThumbColor = Color.Gray, - uncheckedTrackColor = Color(0xFF3A3A4E) - ) + Text( + text = "环境监测", + fontWeight = FontWeight.Bold, + color = Color.White, + fontSize = 18.sp + ) + Box( + modifier = Modifier + .size(8.dp) + .clip(RoundedCornerShape(4.dp)) + .background(Color(0xFF00E676)) ) } - // 温度显示和调节 + Text( + text = "Real-time sensor data across $roomName", + color = Color(0xFF9AA0A6), + fontSize = 12.sp + ) + + // 4个横向排列的竖条卡片 + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + // 温度 + EnvironmentCard( + icon = "🌡️", + iconColor = Color(0xFF00E676), + value = "${currentTemp.value}", + unit = "°C", + label = "TEMPERATURE", + modifier = Modifier.weight(1f) + ) + + // 湿度 + EnvironmentCard( + icon = "💧", + iconColor = Color(0xFF00E676), + value = "${humidity.value}", + unit = "%", + label = "HUMIDITY", + modifier = Modifier.weight(1f) + ) + + // PM2.5 + EnvironmentCard( + icon = "💨", + iconColor = Color(0xFFFFB74D), + value = "${pm25.value}", + unit = "μg/m³", + label = "PM 2.5", + modifier = Modifier.weight(1f) + ) + + // CO2 + EnvironmentCard( + icon = "😊", + iconColor = Color(0xFF00E676), + value = "${co2.value}", + unit = "ppm", + label = "CO2", + modifier = Modifier.weight(1f) + ) + } + } + } +} + +@Composable +private fun EnvironmentCard( + icon: String, + iconColor: Color, + value: String, + unit: String, + label: String, + modifier: Modifier = Modifier +) { + Box( + modifier = modifier + .aspectRatio(0.7f) + .clip(RoundedCornerShape(20.dp)) + .background( + Brush.linearGradient( + listOf( + Color.Black.copy(alpha = 0.5f), + Color.Black.copy(alpha = 0.4f) + ) + ) + ) + .border( + width = 0.5.dp, + color = Color.White.copy(alpha = 0.15f), + shape = RoundedCornerShape(20.dp) + ) + .padding(16.dp) + ) { + Column( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.SpaceBetween + ) { + // 顶部:图标和指示灯 Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically + verticalAlignment = Alignment.Top ) { - // 大温度显示 - Row(verticalAlignment = Alignment.Top) { + // 图标 + Box( + modifier = Modifier + .size(44.dp) + .clip(RoundedCornerShape(12.dp)) + .background(iconColor.copy(alpha = 0.15f)), + contentAlignment = Alignment.Center + ) { Text( - text = "${temp.toInt()}", - fontSize = 52.sp, - color = if (isOn) Color.White else Color.Gray, - fontWeight = FontWeight.Light - ) - Text( - text = "°C", - fontSize = 20.sp, - color = if (isOn) Color.White.copy(alpha = 0.7f) else Color.Gray, - modifier = Modifier.padding(top = 8.dp) + text = icon, + fontSize = 22.sp ) } - // 风速按钮 + 温度调节按钮 - Row( - horizontalArrangement = Arrangement.spacedBy(8.dp), - verticalAlignment = Alignment.CenterVertically - ) { - // 风速按钮(点击循环切换) - Column( - horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier - .clip(RoundedCornerShape(12.dp)) - .background(if (isOn) accentColor.copy(alpha = 0.2f) else Color(0xFF2A2A2A).copy(alpha = 0.4f)) - .clickable(enabled = isOn) { fanSpeed = (fanSpeed + 1) % 4 } - .padding(horizontal = 12.dp, vertical = 8.dp) - ) { - // 风扇图标(根据风速显示不同图片,带旋转动画) - val fanIconRes = when (fanSpeed) { - 1 -> R.drawable.fan_low // 低速 - 3叶片 - 2 -> R.drawable.fan_medium // 中速 - 4叶片 - 3 -> R.drawable.fan_high // 高速 - 5叶片 - else -> R.drawable.fan_medium // 自动 - 默认4叶片 - } - Image( - painter = painterResource(id = fanIconRes), - contentDescription = "Fan Speed", - modifier = Modifier - .size(24.dp) - .then(if (isOn) Modifier.rotate(fanRotation) else Modifier) - ) - Text( - text = fanSpeedLabel, - fontSize = 10.sp, - color = if (isOn) Color.White else Color.Gray, - maxLines = 1 - ) - } - - // 温度调节按钮 - Column(verticalArrangement = Arrangement.spacedBy(4.dp)) { - // 升温按钮 - Box( - modifier = Modifier - .size(36.dp) - .clip(RoundedCornerShape(10.dp)) - .background(if (isOn) accentColor.copy(alpha = 0.3f) else Color(0xFF2A2A2A).copy(alpha = 0.4f)) - .clickable(enabled = isOn && temp < 32f) { temp += 1f }, - contentAlignment = Alignment.Center - ) { - Text(text = "▲", color = if (isOn) Color.White else Color.Gray, fontSize = 14.sp) - } - // 降温按钮 - Box( - modifier = Modifier - .size(36.dp) - .clip(RoundedCornerShape(10.dp)) - .background(if (isOn) accentColor.copy(alpha = 0.3f) else Color(0xFF2A2A2A).copy(alpha = 0.4f)) - .clickable(enabled = isOn && temp > 16f) { temp -= 1f }, - contentAlignment = Alignment.Center - ) { - Text(text = "▼", color = if (isOn) Color.White else Color.Gray, fontSize = 14.sp) - } - } - } + // 指示灯 + Box( + modifier = Modifier + .size(8.dp) + .clip(RoundedCornerShape(4.dp)) + .background(iconColor) + ) } - // 模式选择 - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(8.dp) + // 中间:数值 + Column( + verticalArrangement = Arrangement.spacedBy(4.dp) ) { - modeIcons.forEachIndexed { index, (emoji, name) -> - val isSelected = selectedMode == index - val modeColor = when (index) { - 0 -> Color(0xFF4FC3F7) - 1 -> Color(0xFFFF8A65) - 2 -> Color(0xFF81C784) - else -> Color(0xFFB0BEC5) - } - Box( - modifier = Modifier - .weight(1f) - .height(56.dp) - .clip(RoundedCornerShape(12.dp)) - .background( - if (isSelected && isOn) modeColor.copy(alpha = 0.4f) - else Color(0xFF2A2A2A).copy(alpha = 0.4f) - ) - .clickable(enabled = isOn) { selectedMode = index }, - contentAlignment = Alignment.Center - ) { - Column(horizontalAlignment = Alignment.CenterHorizontally) { - Text(text = emoji, fontSize = 14.sp) - Text( - text = name, - fontSize = 10.sp, - color = if (isSelected && isOn) Color.White else Color(0xFF9AA0A6), - maxLines = 1 - ) - } - } + Row( + verticalAlignment = Alignment.Bottom, + horizontalArrangement = Arrangement.spacedBy(4.dp) + ) { + Text( + text = value, + fontSize = 36.sp, + fontWeight = FontWeight.Light, + color = Color.White + ) + Text( + text = unit, + fontSize = 14.sp, + color = Color(0xFF9AA0A6), + modifier = Modifier.padding(bottom = 6.dp) + ) } + + // 底部:标签 + Text( + text = label, + fontSize = 11.sp, + color = Color(0xFF9AA0A6), + letterSpacing = 0.5.sp + ) } } } @@ -2434,767 +2441,238 @@ fun WeatherEffectLayer(weather: String, modifier: Modifier = Modifier) { } } - +// 使用 Haze 的毛玻璃效果组件 @Composable -fun AddRoomDialog( - onDismiss: () -> Unit, - onConfirm: (String) -> Unit +fun BlurGlassCard( + modifier: Modifier = Modifier, + blurRadius: Float = 25f, + overlayColor: String = "#40FFFFFF", + content: @Composable () -> Unit ) { - var roomName by remember { mutableStateOf("") } - var selectedIcon by remember { mutableStateOf(0) } + val hazeState = remember { HazeState() } - // 预设房间图标 - val roomIcons = listOf("🛋️", "🍳", "🛏️", "🎬", "🎮", "📚", "🛁", "🌿") - val roomSuggestions = listOf("书房", "阳台", "浴室", "储物间", "健身房", "儿童房") - - // 背景遮罩(点击关闭) Box( - modifier = Modifier - .fillMaxSize() - .clickable( - indication = null, - interactionSource = remember { MutableInteractionSource() } - ) { onDismiss() }, - contentAlignment = Alignment.Center + modifier = modifier + .clip(RoundedCornerShape(24.dp)) + .hazeEffect( + state = hazeState, + style = HazeStyle( + blurRadius = blurRadius.dp, + tint = HazeTint(Color.White.copy(alpha = 0.2f)), + noiseFactor = 0.0f + ) + ) ) { - // 对话框主体 Box( - modifier = Modifier - .width(420.dp) - .clip(RoundedCornerShape(28.dp)) - .background( - Brush.verticalGradient( - listOf( - Color(0xFF2A2A3E), - Color(0xFF1A1A2E) - ) - ) - ) - .border( - width = 1.dp, - brush = Brush.linearGradient( - listOf(Color(0xFF00D1FF).copy(alpha = 0.3f), Color(0xFFB89CFF).copy(alpha = 0.3f)) - ), - shape = RoundedCornerShape(28.dp) - ) - .clickable( - indication = null, - interactionSource = remember { MutableInteractionSource() } - ) { /* 阻止点击穿透 */ } - .padding(28.dp) + modifier = Modifier.padding(20.dp) ) { - Column( - verticalArrangement = Arrangement.spacedBy(24.dp) - ) { - // 标题区域 - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(12.dp) - ) { - // 图标 - Box( - modifier = Modifier - .size(44.dp) - .clip(RoundedCornerShape(12.dp)) - .background( - Brush.linearGradient( - listOf(Color(0xFF00D1FF).copy(alpha = 0.3f), Color(0xFFB89CFF).copy(alpha = 0.3f)) - ) - ), - contentAlignment = Alignment.Center - ) { - Text(text = "🏠", fontSize = 22.sp) - } - Column { - Text( - text = "添加新房间", - fontSize = 20.sp, - fontWeight = FontWeight.Bold, - color = Color.White - ) - Text( - text = "创建一个新的智能空间", - fontSize = 12.sp, - color = Color(0xFF9AA0A6) - ) - } - } - - // 关闭按钮 - Box( - modifier = Modifier - .size(32.dp) - .clip(RoundedCornerShape(8.dp)) - .background(Color(0x33FFFFFF)) - .clickable { onDismiss() }, - contentAlignment = Alignment.Center - ) { - Text(text = "✕", color = Color(0xFF9AA0A6), fontSize = 14.sp) - } - } - - // 房间名称输入 - Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { - Text( - text = "房间名称", - fontSize = 14.sp, - fontWeight = FontWeight.Medium, - color = Color(0xFFB0B0B0) - ) - androidx.compose.material3.TextField( - value = roomName, - onValueChange = { roomName = it }, - placeholder = { Text("例如:书房、阳台...", color = Color(0xFF6A6A7A)) }, - modifier = Modifier - .fillMaxWidth() - .height(56.dp), - colors = androidx.compose.material3.TextFieldDefaults.colors( - focusedContainerColor = Color(0xFF1A1A2E), - unfocusedContainerColor = Color(0xFF1A1A2E), - focusedTextColor = Color.White, - unfocusedTextColor = Color.White, - cursorColor = Color(0xFF00D1FF), - focusedIndicatorColor = Color.Transparent, - unfocusedIndicatorColor = Color.Transparent - ), - shape = RoundedCornerShape(14.dp), - singleLine = true, - textStyle = androidx.compose.ui.text.TextStyle(fontSize = 16.sp) - ) - } - - // 快速选择建议 - Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { - Text( - text = "快速选择", - fontSize = 14.sp, - fontWeight = FontWeight.Medium, - color = Color(0xFFB0B0B0) - ) - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(8.dp) - ) { - roomSuggestions.take(3).forEach { suggestion -> - Box( - modifier = Modifier - .clip(RoundedCornerShape(20.dp)) - .background( - if (roomName == suggestion) Color(0xFF00D1FF).copy(alpha = 0.3f) - else Color(0xFF1A1A2E) - ) - .border( - width = 1.dp, - color = if (roomName == suggestion) Color(0xFF00D1FF) else Color(0xFF3A3A4E), - shape = RoundedCornerShape(20.dp) - ) - .clickable { roomName = suggestion } - .padding(horizontal = 16.dp, vertical = 8.dp) - ) { - Text( - text = suggestion, - color = if (roomName == suggestion) Color.White else Color(0xFF9AA0A6), - fontSize = 13.sp - ) - } - } - } - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(8.dp) - ) { - roomSuggestions.drop(3).forEach { suggestion -> - Box( - modifier = Modifier - .clip(RoundedCornerShape(20.dp)) - .background( - if (roomName == suggestion) Color(0xFF00D1FF).copy(alpha = 0.3f) - else Color(0xFF1A1A2E) - ) - .border( - width = 1.dp, - color = if (roomName == suggestion) Color(0xFF00D1FF) else Color(0xFF3A3A4E), - shape = RoundedCornerShape(20.dp) - ) - .clickable { roomName = suggestion } - .padding(horizontal = 16.dp, vertical = 8.dp) - ) { - Text( - text = suggestion, - color = if (roomName == suggestion) Color.White else Color(0xFF9AA0A6), - fontSize = 13.sp - ) - } - } - } - } - - // 选择图标 - Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { - Text( - text = "选择图标", - fontSize = 14.sp, - fontWeight = FontWeight.Medium, - color = Color(0xFFB0B0B0) - ) - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceEvenly - ) { - roomIcons.forEachIndexed { index, icon -> - Box( - modifier = Modifier - .size(44.dp) - .clip(RoundedCornerShape(12.dp)) - .then( - if (selectedIcon == index) - Modifier.background(Brush.linearGradient(listOf(Color(0xFF00D1FF), Color(0xFFB89CFF)))) - else Modifier.background(Color(0xFF1A1A2E)) - ) - .border( - width = if (selectedIcon == index) 0.dp else 1.dp, - color = Color(0xFF3A3A4E), - shape = RoundedCornerShape(12.dp) - ) - .clickable { selectedIcon = index }, - contentAlignment = Alignment.Center - ) { - Text(text = icon, fontSize = 20.sp) - } - } - } - } - - // 按钮区域 - Row( - modifier = Modifier - .fillMaxWidth() - .padding(top = 8.dp), - horizontalArrangement = Arrangement.spacedBy(12.dp) - ) { - // 取消按钮 - Box( - modifier = Modifier - .weight(1f) - .height(52.dp) - .clip(RoundedCornerShape(14.dp)) - .background(Color(0xFF1A1A2E)) - .border( - width = 1.dp, - color = Color(0xFF3A3A4E), - shape = RoundedCornerShape(14.dp) - ) - .clickable { onDismiss() }, - contentAlignment = Alignment.Center - ) { - Text( - text = "取消", - color = Color(0xFFB0B0B0), - fontWeight = FontWeight.Medium, - fontSize = 15.sp - ) - } - - // 确定按钮 - Box( - modifier = Modifier - .weight(1f) - .height(52.dp) - .clip(RoundedCornerShape(14.dp)) - .background( - if (roomName.isNotBlank()) - Brush.linearGradient(listOf(Color(0xFF00D1FF), Color(0xFFB89CFF))) - else - Brush.linearGradient(listOf(Color(0xFF3A3A4E), Color(0xFF3A3A4E))) - ) - .clickable(enabled = roomName.isNotBlank()) { - if (roomName.isNotBlank()) { - onConfirm(roomName.trim()) - } - }, - contentAlignment = Alignment.Center - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(8.dp) - ) { - Text( - text = "✓", - color = if (roomName.isNotBlank()) Color.White else Color(0xFF6A6A7A), - fontSize = 16.sp - ) - Text( - text = "添加房间", - color = if (roomName.isNotBlank()) Color.White else Color(0xFF6A6A7A), - fontWeight = FontWeight.Bold, - fontSize = 15.sp - ) - } - } - } - } + content() } } } +// 毛玻璃效果左侧边栏 @Composable -fun RenameRoomDialog( - currentName: String, - onDismiss: () -> Unit, - onConfirm: (String) -> Unit +fun GlassSidebar( + selectedRoom: Int = 0, + onRoomSelect: (Int) -> Unit = {}, + selectedNavItem: Int = 0, + onNavItemSelect: (Int) -> Unit = {}, + modifier: Modifier = Modifier, + hazeState: HazeState ) { - var roomName by remember { mutableStateOf(currentName) } - // 背景遮罩(点击关闭) + // 房间列表 - 放在总览上面 + val roomNavItems = listOf( + "总览", + "客厅", + "厨房", + "卧室", + "影音室", + "游戏房" + ) + + // 导航项列表 + val navItems = listOf( + "首页", + "场景", + "自动化", + "设置" + ) + Box( - modifier = Modifier - .fillMaxSize() - .clickable( - indication = null, - interactionSource = remember { MutableInteractionSource() } - ) { onDismiss() }, - contentAlignment = Alignment.Center + modifier = modifier + .width(260.dp) + .padding(start = 24.dp, top = 24.dp, bottom = 24.dp) ) { - // 对话框主体 + // 毛玻璃背景 - 使用 Haze Box( modifier = Modifier - .width(380.dp) - .clip(RoundedCornerShape(28.dp)) - .background( - Brush.verticalGradient( - listOf( - Color(0xFF2A2A3E), - Color(0xFF1A1A2E) - ) + .fillMaxSize() + .clip(RoundedCornerShape(32.dp)) + .hazeEffect( + state = hazeState, + style = HazeStyle( + blurRadius = 40.dp, + tint = HazeTint(Color.White.copy(alpha = 0.15f)), + noiseFactor = 0.0f ) ) .border( width = 1.dp, - brush = Brush.linearGradient( - listOf(Color(0xFF00D1FF).copy(alpha = 0.3f), Color(0xFFB89CFF).copy(alpha = 0.3f)) - ), - shape = RoundedCornerShape(28.dp) + color = Color.White.copy(alpha = 0.3f), + shape = RoundedCornerShape(32.dp) ) - .clickable( - indication = null, - interactionSource = remember { MutableInteractionSource() } - ) { /* 阻止点击穿透 */ } - .padding(28.dp) + .padding(20.dp) ) { + // 内容 - 放在毛玻璃背景之上 Column( - verticalArrangement = Arrangement.spacedBy(24.dp) + modifier = Modifier + .fillMaxSize() + .padding(12.dp), + verticalArrangement = Arrangement.SpaceBetween ) { - // 标题区域 - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(12.dp) - ) { - Box( - modifier = Modifier - .size(44.dp) - .clip(RoundedCornerShape(12.dp)) - .background( - Brush.linearGradient( - listOf(Color(0xFF00D1FF).copy(alpha = 0.3f), Color(0xFFB89CFF).copy(alpha = 0.3f)) - ) - ), - contentAlignment = Alignment.Center - ) { - Text(text = "✏️", fontSize = 22.sp) - } - Column { - Text( - text = "重命名房间", - fontSize = 20.sp, - fontWeight = FontWeight.Bold, - color = Color.White - ) - Text( - text = "修改房间名称", - fontSize = 12.sp, - color = Color(0xFF9AA0A6) - ) - } - } - - Box( - modifier = Modifier - .size(32.dp) - .clip(RoundedCornerShape(8.dp)) - .background(Color(0x33FFFFFF)) - .clickable { onDismiss() }, - contentAlignment = Alignment.Center - ) { - Text(text = "✕", color = Color(0xFF9AA0A6), fontSize = 14.sp) - } - } - - // 房间名称输入 - Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { + // 可滚动的内容区域 + Column( + modifier = Modifier + .verticalScroll(rememberScrollState()) + .weight(1f), + verticalArrangement = Arrangement.spacedBy(32.dp) + ) { + // 品牌标题 + Column { Text( - text = "房间名称", + text = "HEMS", + color = Color.White, + fontSize = 32.sp, + fontWeight = FontWeight.Bold, + letterSpacing = 1.sp + ) + Text( + text = "Smart Home", + color = Color.White.copy(alpha = 0.6f), fontSize = 14.sp, - fontWeight = FontWeight.Medium, - color = Color(0xFFB0B0B0) - ) - TextField( - value = roomName, - onValueChange = { roomName = it }, - placeholder = { Text("输入新名称...", color = Color(0xFF6A6A7A)) }, - modifier = Modifier - .fillMaxWidth() - .height(56.dp), - colors = TextFieldDefaults.colors( - focusedContainerColor = Color(0xFF1A1A2E), - unfocusedContainerColor = Color(0xFF1A1A2E), - focusedTextColor = Color.White, - unfocusedTextColor = Color.White, - cursorColor = Color(0xFF00D1FF), - focusedIndicatorColor = Color.Transparent, - unfocusedIndicatorColor = Color.Transparent - ), - shape = RoundedCornerShape(14.dp), - singleLine = true, - textStyle = androidx.compose.ui.text.TextStyle(fontSize = 16.sp) + letterSpacing = 0.5.sp ) } - // 按钮区域 - Row( - modifier = Modifier - .fillMaxWidth() - .padding(top = 8.dp), - horizontalArrangement = Arrangement.spacedBy(12.dp) - ) { - Box( - modifier = Modifier - .weight(1f) - .height(52.dp) - .clip(RoundedCornerShape(14.dp)) - .background(Color(0xFF1A1A2E)) - .border( - width = 1.dp, - color = Color(0xFF3A3A4E), - shape = RoundedCornerShape(14.dp) - ) - .clickable { onDismiss() }, - contentAlignment = Alignment.Center - ) { - Text( - text = "取消", - color = Color(0xFFB0B0B0), - fontWeight = FontWeight.Medium, - fontSize = 15.sp - ) - } - - val canConfirm = roomName.isNotBlank() && roomName.trim() != currentName - Box( - modifier = Modifier - .weight(1f) - .height(52.dp) - .clip(RoundedCornerShape(14.dp)) - .background( - if (canConfirm) - Brush.linearGradient(listOf(Color(0xFF00D1FF), Color(0xFFB89CFF))) - else - Brush.linearGradient(listOf(Color(0xFF3A3A4E), Color(0xFF3A3A4E))) - ) - .clickable(enabled = canConfirm) { - onConfirm(roomName.trim()) - }, - contentAlignment = Alignment.Center - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(8.dp) - ) { - Text( - text = "✓", - color = if (canConfirm) Color.White else Color(0xFF6A6A7A), - fontSize = 16.sp - ) - Text( - text = "确认修改", - color = if (canConfirm) Color.White else Color(0xFF6A6A7A), - fontWeight = FontWeight.Bold, - fontSize = 15.sp - ) - } - } - } - } - } - } -} - -@Composable -fun EditRoomsDialog( - rooms: List, - onDismiss: () -> Unit, - onRenameRoom: (Int, String) -> Unit, - onDeleteRoom: (Int) -> Unit, - onAddRoom: () -> Unit = {} -) { - // 当前编辑的房间索引 - var editingIndex by remember { mutableStateOf(-1) } - var editingName by remember { mutableStateOf("") } - - // 背景遮罩 - Box( - modifier = Modifier - .fillMaxSize() - .clickable( - indication = null, - interactionSource = remember { MutableInteractionSource() } - ) { onDismiss() }, - contentAlignment = Alignment.TopCenter - ) { - // 对话框主体 - 往上挪,使用透明卡片风格 - Box( - modifier = Modifier - .padding(top = 60.dp, bottom = 60.dp) - .widthIn(max = 420.dp) - .fillMaxWidth(0.9f) - .clip(RoundedCornerShape(28.dp)) - .background(Color(0xFF1A1A1A).copy(alpha = 0.65f)) - .border( - width = 1.dp, - color = Color.White.copy(alpha = 0.15f), - shape = RoundedCornerShape(28.dp) - ) - .clickable( - indication = null, - interactionSource = remember { MutableInteractionSource() } - ) { /* 阻止点击穿透 */ } - .padding(28.dp) - ) { - Column( - verticalArrangement = Arrangement.spacedBy(20.dp) - ) { - // 标题区域 - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(12.dp) - ) { - Box( - modifier = Modifier - .size(44.dp) - .clip(RoundedCornerShape(12.dp)) - .background( - Brush.linearGradient( - listOf(Color(0xFF00D1FF).copy(alpha = 0.3f), Color(0xFFB89CFF).copy(alpha = 0.3f)) - ) - ), - contentAlignment = Alignment.Center - ) { - Text(text = "🏠", fontSize = 22.sp) - } - Column { - Text( - text = "编辑房间", - fontSize = 20.sp, - fontWeight = FontWeight.Bold, - color = Color.White - ) - Text( - text = "管理你的房间列表", - fontSize = 12.sp, - color = Color(0xFF9AA0A6) - ) - } - } - - Box( - modifier = Modifier - .size(32.dp) - .clip(RoundedCornerShape(8.dp)) - .background(Color(0x33FFFFFF)) - .clickable { onDismiss() }, - contentAlignment = Alignment.Center - ) { - Text(text = "✕", color = Color(0xFF9AA0A6), fontSize = 14.sp) - } - } - - // 房间列表 - 使用 weight 占据剩余空间,确保底部按钮始终可见 + // 房间导航 Column( - verticalArrangement = Arrangement.spacedBy(8.dp), - modifier = Modifier - .weight(1f, fill = false) - .verticalScroll(rememberScrollState()) + verticalArrangement = Arrangement.spacedBy(4.dp) ) { - rooms.forEachIndexed { index, name -> + Text( + text = "房间", + color = Color.White.copy(alpha = 0.4f), + fontSize = 12.sp, + letterSpacing = 1.sp, + modifier = Modifier.padding(horizontal = 20.dp, vertical = 8.dp) + ) + roomNavItems.forEachIndexed { index, name -> + val isSelected = selectedRoom == index + Row( modifier = Modifier .fillMaxWidth() - .clip(RoundedCornerShape(14.dp)) - .background(Color.White.copy(alpha = 0.1f)) - .padding(12.dp), - horizontalArrangement = Arrangement.SpaceBetween, + .clip(RoundedCornerShape(12.dp)) + .background( + if (isSelected) { + Color.White.copy(alpha = 0.08f) + } else Color.Transparent + ) + .clickable { onRoomSelect(index) } + .padding(horizontal = 20.dp, vertical = 12.dp), verticalAlignment = Alignment.CenterVertically ) { - if (editingIndex == index) { - // 编辑模式 - 使用 BasicTextField 去掉内层框 - BasicTextField( - value = editingName, - onValueChange = { editingName = it }, - modifier = Modifier - .weight(1f) - .padding(end = 12.dp), - textStyle = androidx.compose.ui.text.TextStyle( - fontSize = 15.sp, - color = Color.White - ), - singleLine = true, - cursorBrush = SolidColor(Color(0xFF00D1FF)) - ) - - Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { - // 确认按钮 - Box( - modifier = Modifier - .size(36.dp) - .clip(RoundedCornerShape(8.dp)) - .background(Color(0xFF4CAF50)) - .clickable { - if (editingName.isNotBlank() && editingName != name) { - onRenameRoom(index, editingName.trim()) - } - editingIndex = -1 - }, - contentAlignment = Alignment.Center - ) { - Text(text = "✓", color = Color.White, fontSize = 16.sp) - } - // 取消按钮 - Box( - modifier = Modifier - .size(36.dp) - .clip(RoundedCornerShape(8.dp)) - .background(Color(0xFF3A3A4E)) - .clickable { editingIndex = -1 }, - contentAlignment = Alignment.Center - ) { - Text(text = "✕", color = Color(0xFFB0B0B0), fontSize = 16.sp) - } - } - } else { - // 显示模式 - Text( - text = name, - color = Color.White, - fontSize = 15.sp, - modifier = Modifier.weight(1f) - ) - - Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { - // 编辑按钮 - Box( - modifier = Modifier - .size(36.dp) - .clip(RoundedCornerShape(8.dp)) - .background(Color.White.copy(alpha = 0.15f)) - .clickable { - editingIndex = index - editingName = name - }, - contentAlignment = Alignment.Center - ) { - Text(text = "✏️", fontSize = 16.sp) - } - // 删除按钮 - if (rooms.size > 1) { - Box( - modifier = Modifier - .size(36.dp) - .clip(RoundedCornerShape(8.dp)) - .background(Color(0xFFFF5252).copy(alpha = 0.2f)) - .clickable { onDeleteRoom(index) }, - contentAlignment = Alignment.Center - ) { - Text(text = "🗑️", fontSize = 16.sp) - } - } - } - } + // 导航点 + Box( + modifier = Modifier + .size(6.dp) + .clip(RoundedCornerShape(3.dp)) + .background( + if (isSelected) Color(0xFF00D1FF) + else Color.White.copy(alpha = 0.3f) + ) + ) + + Spacer(modifier = Modifier.width(16.dp)) + + // 房间名称 + Text( + text = name, + color = if (isSelected) Color.White + else Color.White.copy(alpha = 0.7f), + fontSize = 16.sp, + fontWeight = if (isSelected) FontWeight.SemiBold + else FontWeight.Normal + ) } } } - - // 底部按钮区域 - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(12.dp) + + // 功能导航 + Column( + verticalArrangement = Arrangement.spacedBy(4.dp) ) { - // 添加房间按钮 - Box( - modifier = Modifier - .weight(1f) - .height(52.dp) - .clip(RoundedCornerShape(14.dp)) - .background(Color.White.copy(alpha = 0.15f)) - .clickable { - onAddRoom() - onDismiss() - }, - contentAlignment = Alignment.Center - ) { + Text( + text = "功能", + color = Color.White.copy(alpha = 0.4f), + fontSize = 12.sp, + letterSpacing = 1.sp, + modifier = Modifier.padding(horizontal = 20.dp, vertical = 8.dp) + ) + navItems.forEachIndexed { index, name -> + val isSelected = selectedNavItem == index + Row( - horizontalArrangement = Arrangement.spacedBy(8.dp), + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(12.dp)) + .background( + if (isSelected) { + Color.White.copy(alpha = 0.08f) + } else Color.Transparent + ) + .clickable { onNavItemSelect(index) } + .padding(horizontal = 20.dp, vertical = 12.dp), verticalAlignment = Alignment.CenterVertically ) { - Text( - text = "+", - color = Color.White, - fontWeight = FontWeight.Bold, - fontSize = 18.sp + // 导航点 + Box( + modifier = Modifier + .size(6.dp) + .clip(RoundedCornerShape(3.dp)) + .background( + if (isSelected) Color(0xFF00D1FF) + else Color.White.copy(alpha = 0.3f) + ) ) + + Spacer(modifier = Modifier.width(16.dp)) + + // 导航文本 Text( - text = "添加房间", - color = Color.White, - fontWeight = FontWeight.Medium, - fontSize = 15.sp + text = name, + color = if (isSelected) Color.White + else Color.White.copy(alpha = 0.7f), + fontSize = 16.sp, + fontWeight = if (isSelected) FontWeight.SemiBold + else FontWeight.Normal ) } } - - // 完成按钮 - Box( - modifier = Modifier - .weight(1f) - .height(52.dp) - .clip(RoundedCornerShape(14.dp)) - .background( - Brush.linearGradient(listOf(Color(0xFF00D1FF), Color(0xFFB89CFF))) - ) - .clickable { onDismiss() }, - contentAlignment = Alignment.Center - ) { - Text( - text = "完成", - color = Color.White, - fontWeight = FontWeight.Bold, - fontSize = 15.sp - ) - } } } } } } + +// 扩展函数用于获取 Activity +fun Context.findActivity(): Activity { + var context = this + while (context is ContextWrapper) { + if (context is Activity) return context + context = context.baseContext + } + throw IllegalStateException("Permissions should be called in the context of an Activity") +} +} diff --git a/app/src/main/java/com/example/smarthome/ui/RoomDialog.kt b/app/src/main/java/com/example/smarthome/ui/RoomDialog.kt new file mode 100644 index 0000000..96f50bd --- /dev/null +++ b/app/src/main/java/com/example/smarthome/ui/RoomDialog.kt @@ -0,0 +1,613 @@ +package com.example.smarthome.ui + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Text +import androidx.compose.material3.TextField +import androidx.compose.material3.TextFieldDefaults +import androidx.compose.runtime.* +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.graphics.SolidColor +import androidx.compose.ui.res.painterResource +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 com.example.smarthome.R +import com.example.smarthome.data.tr + +@Composable +fun EditRoomsDialog( + rooms: List, + onDismiss: () -> Unit, + onRenameRoom: (Int, String) -> Unit, + onDeleteRoom: (Int) -> Unit, + onAddRoom: () -> Unit = {} +) { + // 当前编辑的房间索引 + var editingIndex by remember { mutableStateOf(-1) } + var editingName by remember { mutableStateOf("") } + + // 背景遮罩 + Box( + modifier = Modifier + .fillMaxSize() + .clickable( + indication = null, + interactionSource = remember { androidx.compose.foundation.interaction.MutableInteractionSource() } + ) { onDismiss() }, + contentAlignment = Alignment.TopCenter + ) { + // 对话框主体 - 往上挪,使用透明卡片风格 + Box( + modifier = Modifier + .padding(top = 60.dp, bottom = 60.dp) + .widthIn(max = 420.dp) + .fillMaxWidth(0.9f) + .clip(RoundedCornerShape(28.dp)) + .background(Color(0xFF1A1A1A).copy(alpha = 0.65f)) + .border( + width = 1.dp, + color = Color.White.copy(alpha = 0.15f), + shape = RoundedCornerShape(28.dp) + ) + .clickable( + indication = null, + interactionSource = remember { androidx.compose.foundation.interaction.MutableInteractionSource() } + ) { /* 阻止点击穿透 */ } + .padding(28.dp) + ) { + Column( + verticalArrangement = Arrangement.spacedBy(20.dp) + ) { + // 标题区域 + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + Box( + modifier = Modifier + .size(44.dp) + .clip(RoundedCornerShape(12.dp)) + .background( + Brush.linearGradient( + listOf(Color(0xFF00D1FF).copy(alpha = 0.3f), Color(0xFFB89CFF).copy(alpha = 0.3f)) + ) + ), + contentAlignment = Alignment.Center + ) { + Text(text = "🏠", fontSize = 22.sp) + } + Column { + Text( + text = "编辑房间", + fontSize = 20.sp, + fontWeight = FontWeight.Bold, + color = Color.White + ) + Text( + text = "管理你的房间列表", + fontSize = 12.sp, + color = Color(0xFF9AA0A6) + ) + } + } + + Box( + modifier = Modifier + .size(32.dp) + .clip(RoundedCornerShape(8.dp)) + .background(Color(0x33FFFFFF)) + .clickable { onDismiss() }, + contentAlignment = Alignment.Center + ) { + Text(text = "✕", color = Color(0xFF9AA0A6), fontSize = 14.sp) + } + } + + // 房间列表 - 使用 weight 占据剩余空间,确保底部按钮始终可见 + Column( + verticalArrangement = Arrangement.spacedBy(8.dp), + modifier = Modifier + .weight(1f, fill = false) + .verticalScroll(rememberScrollState()) + ) { + rooms.forEachIndexed { index, name -> + Row( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(14.dp)) + .background(Color.White.copy(alpha = 0.1f)) + .padding(12.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + if (editingIndex == index) { + // 编辑模式 - 使用 BasicTextField 去掉内层框 + BasicTextField( + value = editingName, + onValueChange = { editingName = it }, + modifier = Modifier + .weight(1f) + .padding(end = 12.dp), + textStyle = androidx.compose.ui.text.TextStyle( + fontSize = 15.sp, + color = Color.White + ), + singleLine = true, + cursorBrush = SolidColor(Color(0xFF00D1FF)) + ) + + Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { + // 确认按钮 + Box( + modifier = Modifier + .size(32.dp) + .clip(RoundedCornerShape(8.dp)) + .background(Color(0xFF00D1FF).copy(alpha = 0.2f)) + .clickable(enabled = editingName.isNotBlank()) { + if (editingName.isNotBlank()) { + onRenameRoom(index, editingName.trim()) + editingIndex = -1 + editingName = "" + } + }, + contentAlignment = Alignment.Center + ) { + Text( + text = "✓", + color = if (editingName.isNotBlank()) Color(0xFF00D1FF) else Color(0xFF6A6A7A), + fontSize = 16.sp + ) + } + + // 取消按钮 + Box( + modifier = Modifier + .size(32.dp) + .clip(RoundedCornerShape(8.dp)) + .background(Color(0xFF3A3A4E)) + .clickable { + editingIndex = -1 + editingName = "" + }, + contentAlignment = Alignment.Center + ) { + Text( + text = "✕", + color = Color(0xFF9AA0A6), + fontSize = 14.sp + ) + } + } + } else { + // 显示模式 + Text( + text = name, + color = Color.White, + fontSize = 15.sp, + modifier = Modifier.weight(1f) + ) + + Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { + // 编辑按钮 + Box( + modifier = Modifier + .size(32.dp) + .clip(RoundedCornerShape(8.dp)) + .background(Color(0xFF00D1FF).copy(alpha = 0.2f)) + .clickable { + editingIndex = index + editingName = name + }, + contentAlignment = Alignment.Center + ) { + Text( + text = "✏️", + color = Color(0xFF00D1FF), + fontSize = 14.sp + ) + } + + // 删除按钮(总览不能删除) + if (index != 0) { + Box( + modifier = Modifier + .size(32.dp) + .clip(RoundedCornerShape(8.dp)) + .background(Color(0xFFFF5252).copy(alpha = 0.2f)) + .clickable { onDeleteRoom(index) }, + contentAlignment = Alignment.Center + ) { + Text( + text = "🗑️", + color = Color(0xFFFF5252), + fontSize = 14.sp + ) + } + } + } + } + } + } + } + + // 添加新房间按钮 + Box( + modifier = Modifier + .fillMaxWidth() + .height(52.dp) + .clip(RoundedCornerShape(14.dp)) + .background(Color(0xFF1A1A2E)) + .border( + width = 1.dp, + color = Color(0xFF3A3A4E), + shape = RoundedCornerShape(14.dp) + ) + .clickable { onAddRoom() }, + contentAlignment = Alignment.Center + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "+", + color = Color.White, + fontWeight = FontWeight.Bold, + fontSize = 18.sp + ) + Text( + text = "添加房间", + color = Color.White, + fontWeight = FontWeight.Medium, + fontSize = 15.sp + ) + } + } + + // 完成按钮 + Box( + modifier = Modifier + .fillMaxWidth() + .height(52.dp) + .clip(RoundedCornerShape(14.dp)) + .background( + Brush.linearGradient(listOf(Color(0xFF00D1FF), Color(0xFFB89CFF))) + ) + .clickable { onDismiss() }, + contentAlignment = Alignment.Center + ) { + Text( + text = "完成", + color = Color.White, + fontWeight = FontWeight.Bold, + fontSize = 15.sp + ) + } + } + } + } +} + +@Composable +fun AddRoomDialog( + onDismiss: () -> Unit, + onConfirm: (String) -> Unit +) { + var roomName by remember { mutableStateOf("") } + var selectedIcon by remember { mutableStateOf(0) } + + // 房间建议 + val roomSuggestions = listOf("书房", "餐厅", "阳台", "卫生间", "储物间", "健身房", "茶室", "儿童房") + + // 房间图标 + val roomIcons = listOf("🏠", "🛋️", "🍳", "🛏️", "🎬", "🎮", "📚", "🍽️", "🌿", "🏋️", "🍵", "🧸") + + // 背景遮罩(点击关闭) + Box( + modifier = Modifier + .fillMaxSize() + .clickable( + indication = null, + interactionSource = remember { androidx.compose.foundation.interaction.MutableInteractionSource() } + ) { onDismiss() }, + contentAlignment = Alignment.Center + ) { + // 对话框主体 + Box( + modifier = Modifier + .width(400.dp) + .clip(RoundedCornerShape(28.dp)) + .background( + Brush.verticalGradient( + listOf( + Color(0xFF2A2A3E), + Color(0xFF1A1A2E) + ) + ) + ) + .border( + width = 1.dp, + brush = Brush.linearGradient( + listOf(Color(0xFF00D1FF).copy(alpha = 0.3f), Color(0xFFB89CFF).copy(alpha = 0.3f)) + ), + shape = RoundedCornerShape(28.dp) + ) + .clickable( + indication = null, + interactionSource = remember { androidx.compose.foundation.interaction.MutableInteractionSource() } + ) { /* 阻止点击穿透 */ } + .padding(28.dp) + ) { + Column( + verticalArrangement = Arrangement.spacedBy(24.dp) + ) { + // 标题区域 + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + Box( + modifier = Modifier + .size(44.dp) + .clip(RoundedCornerShape(12.dp)) + .background( + Brush.linearGradient( + listOf(Color(0xFF00D1FF).copy(alpha = 0.3f), Color(0xFFB89CFF).copy(alpha = 0.3f)) + ) + ), + contentAlignment = Alignment.Center + ) { + Text(text = "➕", fontSize = 22.sp) + } + Column { + Text( + text = "添加房间", + fontSize = 20.sp, + fontWeight = FontWeight.Bold, + color = Color.White + ) + Text( + text = "创建一个新的房间", + fontSize = 12.sp, + color = Color(0xFF9AA0A6) + ) + } + } + + Box( + modifier = Modifier + .size(32.dp) + .clip(RoundedCornerShape(8.dp)) + .background(Color(0x33FFFFFF)) + .clickable { onDismiss() }, + contentAlignment = Alignment.Center + ) { + Text(text = "✕", color = Color(0xFF9AA0A6), fontSize = 14.sp) + } + } + + // 房间名称输入 + Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { + Text( + text = "房间名称", + fontSize = 14.sp, + fontWeight = FontWeight.Medium, + color = Color(0xFFB0B0B0) + ) + TextField( + value = roomName, + onValueChange = { roomName = it }, + placeholder = { Text("输入房间名称...", color = Color(0xFF6A6A7A)) }, + modifier = Modifier + .fillMaxWidth() + .height(56.dp), + colors = TextFieldDefaults.colors( + focusedContainerColor = Color(0xFF1A1A2E), + unfocusedContainerColor = Color(0xFF1A1A2E), + focusedTextColor = Color.White, + unfocusedTextColor = Color.White, + cursorColor = Color(0xFF00D1FF), + focusedIndicatorColor = Color.Transparent, + unfocusedIndicatorColor = Color.Transparent + ), + shape = RoundedCornerShape(14.dp), + singleLine = true, + textStyle = androidx.compose.ui.text.TextStyle(fontSize = 16.sp) + ) + } + + // 快速选择 + Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { + Text( + text = "快速选择", + fontSize = 14.sp, + fontWeight = FontWeight.Medium, + color = Color(0xFFB0B0B0) + ) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + roomSuggestions.take(3).forEach { suggestion -> + Box( + modifier = Modifier + .clip(RoundedCornerShape(20.dp)) + .background( + if (roomName == suggestion) Color(0xFF00D1FF).copy(alpha = 0.3f) + else Color(0xFF1A1A2E) + ) + .border( + width = 1.dp, + color = if (roomName == suggestion) Color(0xFF00D1FF) else Color(0xFF3A3A4E), + shape = RoundedCornerShape(20.dp) + ) + .clickable { roomName = suggestion } + .padding(horizontal = 16.dp, vertical = 8.dp) + ) { + Text( + text = suggestion, + color = if (roomName == suggestion) Color.White else Color(0xFF9AA0A6), + fontSize = 13.sp + ) + } + } + } + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + roomSuggestions.drop(3).forEach { suggestion -> + Box( + modifier = Modifier + .clip(RoundedCornerShape(20.dp)) + .background( + if (roomName == suggestion) Color(0xFF00D1FF).copy(alpha = 0.3f) + else Color(0xFF1A1A2E) + ) + .border( + width = 1.dp, + color = if (roomName == suggestion) Color(0xFF00D1FF) else Color(0xFF3A3A4E), + shape = RoundedCornerShape(20.dp) + ) + .clickable { roomName = suggestion } + .padding(horizontal = 16.dp, vertical = 8.dp) + ) { + Text( + text = suggestion, + color = if (roomName == suggestion) Color.White else Color(0xFF9AA0A6), + fontSize = 13.sp + ) + } + } + } + } + + // 选择图标 + Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { + Text( + text = "选择图标", + fontSize = 14.sp, + fontWeight = FontWeight.Medium, + color = Color(0xFFB0B0B0) + ) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceEvenly + ) { + roomIcons.forEachIndexed { index, icon -> + Box( + modifier = Modifier + .size(44.dp) + .clip(RoundedCornerShape(12.dp)) + .then( + if (selectedIcon == index) + Modifier.background(Brush.linearGradient(listOf(Color(0xFF00D1FF), Color(0xFFB89CFF)))) + else Modifier.background(Color(0xFF1A1A2E)) + ) + .border( + width = if (selectedIcon == index) 0.dp else 1.dp, + color = Color(0xFF3A3A4E), + shape = RoundedCornerShape(12.dp) + ) + .clickable { selectedIcon = index }, + contentAlignment = Alignment.Center + ) { + Text(text = icon, fontSize = 20.sp) + } + } + } + } + + // 按钮区域 + Row( + modifier = Modifier + .fillMaxWidth() + .padding(top = 8.dp), + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + // 取消按钮 + Box( + modifier = Modifier + .weight(1f) + .height(52.dp) + .clip(RoundedCornerShape(14.dp)) + .background(Color(0xFF1A1A2E)) + .border( + width = 1.dp, + color = Color(0xFF3A3A4E), + shape = RoundedCornerShape(14.dp) + ) + .clickable { onDismiss() }, + contentAlignment = Alignment.Center + ) { + Text( + text = "取消", + color = Color(0xFFB0B0B0), + fontWeight = FontWeight.Medium, + fontSize = 15.sp + ) + } + + // 确定按钮 + Box( + modifier = Modifier + .weight(1f) + .height(52.dp) + .clip(RoundedCornerShape(14.dp)) + .background( + if (roomName.isNotBlank()) + Brush.linearGradient(listOf(Color(0xFF00D1FF), Color(0xFFB89CFF))) + else + Brush.linearGradient(listOf(Color(0xFF3A3A4E), Color(0xFF3A3A4E))) + ) + .clickable(enabled = roomName.isNotBlank()) { + if (roomName.isNotBlank()) { + onConfirm(roomName.trim()) + } + }, + contentAlignment = Alignment.Center + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + Text( + text = "✓", + color = if (roomName.isNotBlank()) Color.White else Color(0xFF6A6A7A), + fontSize = 16.sp + ) + Text( + text = "添加房间", + color = if (roomName.isNotBlank()) Color.White else Color(0xFF6A6A7A), + fontWeight = FontWeight.Bold, + fontSize = 15.sp + ) + } + } + } + } + } + } +} \ No newline at end of file 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 66f0781..520a650 100644 --- a/app/src/main/java/com/example/smarthome/ui/SettingsScreen.kt +++ b/app/src/main/java/com/example/smarthome/ui/SettingsScreen.kt @@ -46,7 +46,13 @@ fun SettingsScreen(onBack: () -> Unit) { } @Composable -fun SettingsContentList() { +fun SettingsContentList( + rooms: List = listOf("总览", "客厅", "厨房", "卧室", "影音室", "游戏房"), + onAddRoom: (String) -> Unit = {}, + onDeleteRoom: (Int) -> Unit = {}, + onRenameRoom: (Int, String) -> Unit = { _, _ -> }, + onShowEditRoomsDialog: () -> Unit = {} +) { val context = LocalContext.current val currentLang by LanguageManager.currentLanguage.collectAsState() var showLanguageDialog by remember { mutableStateOf(false) } @@ -81,6 +87,12 @@ fun SettingsContentList() { }} item { SettingsSection(title = tr("settings_device")) { + SettingsItem( + title = "房间管理", + subtitle = "添加、删除或重命名房间", + onClick = { onShowEditRoomsDialog() } + ) + var autoConnect by remember { mutableStateOf(true) } SettingsSwitchItem( title = tr("settings_auto_connect"), @@ -466,7 +478,14 @@ fun LogoutButton(onClick: () -> Unit) { @Composable -fun SettingsContent() { +fun SettingsContent( + rooms: List = listOf("总览", "客厅", "厨房", "卧室", "影音室", "游戏房"), + onAddRoom: (String) -> Unit = {}, + onDeleteRoom: (Int) -> Unit = {}, + onRenameRoom: (Int, String) -> Unit = { _, _ -> } +) { + var showEditRoomsDialog by remember { mutableStateOf(false) } + Column( modifier = Modifier .fillMaxSize() @@ -482,7 +501,24 @@ fun SettingsContent() { ) // 设置内容 - SettingsContentList() + SettingsContentList( + rooms = rooms, + onAddRoom = onAddRoom, + onDeleteRoom = onDeleteRoom, + onRenameRoom = onRenameRoom, + onShowEditRoomsDialog = { showEditRoomsDialog = true } + ) + } + + // 编辑房间对话框 + if (showEditRoomsDialog) { + EditRoomsDialog( + rooms = rooms, + onDismiss = { showEditRoomsDialog = false }, + onRenameRoom = onRenameRoom, + onDeleteRoom = onDeleteRoom, + onAddRoom = { /* 添加房间通过对话框内的按钮处理 */ } + ) } } diff --git a/app/src/main/java/com/example/smarthome/ui/SmartHomeScreen.kt b/app/src/main/java/com/example/smarthome/ui/SmartHomeScreen.kt new file mode 100644 index 0000000..85ff3ff --- /dev/null +++ b/app/src/main/java/com/example/smarthome/ui/SmartHomeScreen.kt @@ -0,0 +1,345 @@ +package com.example.smarthome.ui + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.items +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +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.unit.dp +import androidx.compose.ui.unit.sp +import dev.chrisbanes.haze.HazeState +import dev.chrisbanes.haze.HazeStyle +import dev.chrisbanes.haze.HazeTint +import dev.chrisbanes.haze.haze +import dev.chrisbanes.haze.hazeChild +import dev.chrisbanes.haze.hazeEffect +import dev.chrisbanes.haze.hazeSource + +@Composable +fun SmartHomeScreen() { + val hazeState = HazeState() + + Box( + modifier = Modifier + .fillMaxSize() + .background( + Brush.verticalGradient( + colors = listOf( + Color(0xFF1A1A2E), + Color(0xFF16213E), + Color(0xFF0F3460) + ) + ) + ) + .hazeSource(state = hazeState) + ) { + // 背景装饰 + BackgroundDecoration() + + Row( + modifier = Modifier.fillMaxSize() + ) { + // 左侧毛玻璃边栏 + GlassSidebarWithHaze( + hazeState = hazeState, + modifier = Modifier + .width(260.dp) + .padding(start = 24.dp, top = 24.dp, bottom = 24.dp) + ) + + Spacer(modifier = Modifier.width(24.dp)) + + // 主内容区域 + MainContentArea( + hazeState = hazeState, + modifier = Modifier + .fillMaxSize() + .padding(end = 24.dp, top = 24.dp, bottom = 24.dp) + ) + } + } +} + +@Composable +private fun BackgroundDecoration() { + Column( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.SpaceEvenly, + horizontalAlignment = Alignment.CenterHorizontally + ) { + repeat(5) { index -> + Box( + modifier = Modifier + .size((100 + index * 20).dp) + .clip(RoundedCornerShape(50)) + .background( + Brush.radialGradient( + colors = listOf( + Color(0xFF6C5CE7), + Color(0xFFA29BFE), + Color.Transparent + ) + ) + ) + ) + } + } +} + +@Composable +private fun GlassSidebarWithHaze( + hazeState: HazeState, + modifier: Modifier = Modifier +) { + Box( + modifier = modifier + .fillMaxHeight() + .clip(RoundedCornerShape(32.dp)) + .hazeEffect( + state = hazeState, + style = HazeStyle( + blurRadius = 20.dp, + tint = HazeTint(Color.White.copy(alpha = 0.15f)), + noiseFactor = 0.0f + ) + ) + .padding(32.dp) + ) { + Column( + verticalArrangement = Arrangement.SpaceBetween + ) { + Column { + Text( + text = "Lumina", + color = Color.White, + fontSize = 32.sp, + fontWeight = FontWeight.Bold + ) + + Text( + text = "Smart Home", + color = Color.White.copy(alpha = 0.6f), + fontSize = 14.sp + ) + + Spacer(modifier = Modifier.height(48.dp)) + + listOf( + "🏠 首页" to true, + "🌡️ 温控" to false, + "💡 照明" to false, + "🔒 安全" to false, + "🎬 场景" to false, + "⚙️ 自动化" to false + ).forEach { (item, isSelected) -> + Text( + text = item, + color = if (isSelected) Color.White else Color.White.copy(alpha = 0.6f), + fontSize = 16.sp, + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 12.dp) + ) + } + } + + // 底部用户信息 + Column { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .size(40.dp) + .clip(RoundedCornerShape(20)) + .background( + Brush.linearGradient( + colors = listOf( + Color(0xFF6C5CE7), + Color(0xFFA29BFE) + ) + ) + ) + ) + + Spacer(modifier = Modifier.width(12.dp)) + + Column { + Text( + text = "管理员", + color = Color.White, + fontSize = 14.sp, + fontWeight = FontWeight.Medium + ) + Text( + text = "在线", + color = Color.White.copy(alpha = 0.6f), + fontSize = 12.sp + ) + } + } + } + } + } +} + +@Composable +private fun MainContentArea( + hazeState: HazeState, + modifier: Modifier = Modifier +) { + Column( + modifier = modifier.fillMaxSize(), + verticalArrangement = Arrangement.spacedBy(24.dp) + ) { + // 顶部状态卡片 + StatusCard(hazeState = hazeState) + + // 设备网格 + LazyVerticalGrid( + columns = GridCells.Fixed(2), + modifier = Modifier.fillMaxSize(), + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + items(6) { index -> + DeviceCard( + index = index, + hazeState = hazeState + ) + } + } + } +} + +@Composable +private fun StatusCard(hazeState: HazeState) { + Box( + modifier = Modifier + .fillMaxWidth() + .height(200.dp) + .clip(RoundedCornerShape(24.dp)) + .hazeEffect( + state = hazeState, + style = HazeStyle( + blurRadius = 25.dp, + tint = HazeTint(Color.White.copy(alpha = 0.2f)), + noiseFactor = 0.0f + ) + ) + .padding(32.dp) + ) { + Column( + verticalArrangement = Arrangement.SpaceBetween + ) { + Column { + Text( + text = "智能家居控制中心", + color = Color.White, + fontSize = 24.sp, + fontWeight = FontWeight.Bold + ) + + Spacer(modifier = Modifier.height(16.dp)) + + Row( + horizontalArrangement = Arrangement.SpaceEvenly, + modifier = Modifier.fillMaxWidth() + ) { + StatusItem("温度", "26°C") + StatusItem("湿度", "65%") + StatusItem("空气质量", "优") + } + } + + Text( + text = "6 个设备在线", + color = Color.White.copy(alpha = 0.8f), + fontSize = 14.sp + ) + } + } +} + +@Composable +private fun StatusItem(label: String, value: String) { + Column( + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = value, + color = Color.White, + fontSize = 20.sp, + fontWeight = FontWeight.Bold + ) + Text( + text = label, + color = Color.White.copy(alpha = 0.6f), + fontSize = 12.sp + ) + } +} + +@Composable +private fun DeviceCard( + index: Int, + hazeState: HazeState +) { + val devices = listOf( + "客厅灯" to "💡", + "空调" to "❄️", + "电视" to "📺", + "音响" to "🔊", + "摄像头" to "📹", + "门锁" to "🔒" + ) + + val (name, icon) = devices[index] + + Box( + modifier = Modifier + .fillMaxWidth() + .height(150.dp) + .clip(RoundedCornerShape(20.dp)) + .hazeEffect( + state = hazeState, + style = HazeStyle( + blurRadius = 20.dp, + tint = HazeTint(Color.White.copy(alpha = 0.15f)), + noiseFactor = 0.0f + ) + ) + .padding(20.dp), + contentAlignment = Alignment.Center + ) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + Text( + text = icon, + fontSize = 40.sp + ) + Text( + text = name, + color = Color.White, + fontSize = 16.sp, + fontWeight = FontWeight.Medium + ) + Text( + text = "开启", + color = Color.White.copy(alpha = 0.8f), + fontSize = 12.sp + ) + } + } +} diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 016cbb6..20e4878 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,27 +1,13 @@ - - - - - diff --git a/build.gradle.kts b/build.gradle.kts index ace0bbe..60c0400 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,6 +1,7 @@ plugins { - id("com.android.application") version "8.6.0" apply false - id("org.jetbrains.kotlin.android") version "1.9.24" apply false + id("com.android.application") version "8.9.1" apply false + id("org.jetbrains.kotlin.android") version "2.1.0" apply false + id("org.jetbrains.kotlin.plugin.compose") version "2.1.0" apply false } tasks.register("clean", Delete::class) { diff --git a/settings.gradle.kts b/settings.gradle.kts index 2893fda..8c3ad0b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -16,5 +16,5 @@ dependencyResolutionManagement { } } -rootProject.name = "SmartHome" +rootProject.name = "智能家居" include(":app")