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")