This commit is contained in:
zzh 2025-11-29 13:24:42 +08:00
parent 238958f3d2
commit fb20e2e64b
5 changed files with 716 additions and 149 deletions

View File

@ -74,6 +74,7 @@ dependencies {
// ZXing 二维码生成 // ZXing 二维码生成
implementation("com.google.zxing:core:3.5.2") implementation("com.google.zxing:core:3.5.2")
debugImplementation("com.squareup.leakcanary:leakcanary-android:2.12") debugImplementation("com.squareup.leakcanary:leakcanary-android:2.12")

View File

@ -134,7 +134,7 @@ fun MainContent() {
} }
var selectedRoom by remember { mutableStateOf(0) } var selectedRoom by remember { mutableStateOf(0) }
var selectedNavItem by remember { mutableStateOf(0) } // 0=控制台, 5=设置 var selectedNavItem by remember { mutableStateOf(0) }
var rooms by remember { mutableStateOf(savedRooms) } var rooms by remember { mutableStateOf(savedRooms) }
// 保存房间列表到SharedPreferences // 保存房间列表到SharedPreferences
@ -170,26 +170,29 @@ fun MainContent() {
.background(Color(overlayAlpha shl 24 or 0x121212)) .background(Color(overlayAlpha shl 24 or 0x121212))
) )
// 主内容 - 添加系统栏内边距 // 主内容 - 全屏显示
Box(modifier = Modifier.fillMaxSize().systemBarsPadding()) { Box(modifier = Modifier.fillMaxSize()) {
MainScaffold( MainScaffold(
selectedRoom = selectedRoom, selectedRoom = selectedRoom,
onRoomSelect = { selectedRoom = it }, onRoomSelect = { selectedRoom = it },
selectedNavItem = selectedNavItem, selectedNavItem = selectedNavItem,
onNavItemSelect = { selectedNavItem = it }, onNavItemSelect = { selectedNavItem = it },
rooms = rooms, rooms = rooms,
onAddRoom = { newRoomName -> onAddRoom = { newRoomName ->
saveRooms(rooms + newRoomName) saveRooms(rooms + newRoomName)
}, },
onDeleteRoom = { index -> onDeleteRoom = { index ->
if (rooms.size > 1) { // 至少保留一个房间 if (rooms.size > 1) { // 至少保留一个房间
saveRooms(rooms.filterIndexed { i, _ -> i != index }) saveRooms(rooms.filterIndexed { i, _ -> i != index })
if (selectedRoom >= rooms.size - 1) { if (selectedRoom >= rooms.size - 1) {
selectedRoom = (rooms.size - 2).coerceAtLeast(0) selectedRoom = (rooms.size - 2).coerceAtLeast(0)
}
} }
},
onRenameRoom = { index, newName ->
saveRooms(rooms.mapIndexed { i, name -> if (i == index) newName else name })
} }
} )
)
} }
} }
} }

View File

@ -36,6 +36,7 @@ import com.example.smarthome.data.LanguageManager
import com.example.smarthome.data.tr import com.example.smarthome.data.tr
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalView import androidx.compose.ui.platform.LocalView
import android.view.SoundEffectConstants import android.view.SoundEffectConstants
@ -47,6 +48,7 @@ import androidx.compose.foundation.gestures.detectHorizontalDragGestures
import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.offset
import androidx.compose.ui.draw.rotate import androidx.compose.ui.draw.rotate
import androidx.compose.ui.layout.ContentScale
@Composable @Composable
fun MainScaffold( fun MainScaffold(
@ -56,27 +58,34 @@ fun MainScaffold(
onNavItemSelect: (Int) -> Unit = {}, onNavItemSelect: (Int) -> Unit = {},
rooms: List<String> = listOf("总览", "客厅", "厨房", "卧室", "影音室", "游戏房"), rooms: List<String> = listOf("总览", "客厅", "厨房", "卧室", "影音室", "游戏房"),
onAddRoom: (String) -> Unit = {}, onAddRoom: (String) -> Unit = {},
onDeleteRoom: (Int) -> Unit = {} onDeleteRoom: (Int) -> Unit = {},
onRenameRoom: (Int, String) -> Unit = { _, _ -> }
) { ) {
Row(modifier = Modifier.fillMaxSize()) { Box(modifier = Modifier.fillMaxSize()) {
SideNavRail( // 内容区域 - 全屏显示
selectedNavItem = selectedNavItem, Box(
onNavItemSelect = onNavItemSelect modifier = Modifier.fillMaxSize()
) ) {
// 内容区域 - 减少左侧间距
Box(modifier = Modifier.fillMaxSize()) {
// 根据选中的导航项显示不同的内容 // 根据选中的导航项显示不同的内容
// 底部导航: 0-Dashboard, 1-Scene, 2-Automation, 3-Security, 4-Settings
when (selectedNavItem) { when (selectedNavItem) {
0 -> DashboardContent(selectedRoom, onRoomSelect, rooms, onAddRoom, onDeleteRoom) 0 -> DashboardContent(selectedRoom, onRoomSelect, rooms, onAddRoom, onDeleteRoom, onRenameRoom)
1 -> SceneScreen() 1 -> SceneScreen()
2 -> AutomationScreen() 2 -> AutomationScreen()
3 -> StatisticsScreen() 3 -> SecurityScreen()
4 -> SecurityScreen() 4 -> SettingsContent()
5 -> SettingsContent() else -> DashboardContent(selectedRoom, onRoomSelect, rooms, onAddRoom, onDeleteRoom, onRenameRoom)
else -> DashboardContent(selectedRoom, onRoomSelect, rooms, onAddRoom, onDeleteRoom)
} }
} }
// 底部悬浮导航栏 - 置于内容之上
FloatingBottomNav(
selectedNavItem = selectedNavItem,
onNavItemSelect = onNavItemSelect,
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(bottom = 24.dp)
)
} }
} }
@ -86,23 +95,33 @@ fun DashboardContent(
onRoomSelect: (Int) -> Unit, onRoomSelect: (Int) -> Unit,
rooms: List<String> = listOf("总览", "客厅", "厨房", "卧室", "影音室", "游戏房"), rooms: List<String> = listOf("总览", "客厅", "厨房", "卧室", "影音室", "游戏房"),
onAddRoom: (String) -> Unit = {}, onAddRoom: (String) -> Unit = {},
onDeleteRoom: (Int) -> Unit = {} onDeleteRoom: (Int) -> Unit = {},
onRenameRoom: (Int, String) -> Unit = { _, _ -> }
) { ) {
var showAddRoomDialog by remember { mutableStateOf(false) } var showAddRoomDialog by remember { mutableStateOf(false) }
var editMode by remember { mutableStateOf(false) }
// 总览和客厅使用默认壁纸
val roomName = rooms.getOrNull(selectedRoom) ?: "总览"
val hasWallpaper = selectedRoom == 0 || roomName == "客厅"
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.pointerInput(editMode) {
if (editMode) {
detectTapGestures(
onTap = { editMode = false }
)
}
}
) { ) {
Column(modifier = Modifier.fillMaxSize().padding(start = 0.dp, end = 16.dp, top = 16.dp, bottom = 16.dp)) { // 房间壁纸背景(总览和客厅)- 放在最底层
if (hasWallpaper) {
Image(
painter = painterResource(id = R.drawable.room_wallpaper_default),
contentDescription = null,
modifier = Modifier
.fillMaxSize()
.clip(RoundedCornerShape(24.dp)),
contentScale = ContentScale.Crop,
alpha = 0.25f
)
}
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 16.dp, vertical = 16.dp)) {
TopBar() TopBar()
RoomTabs( RoomTabs(
selectedRoom = selectedRoom, selectedRoom = selectedRoom,
@ -110,11 +129,10 @@ fun DashboardContent(
rooms = rooms, rooms = rooms,
onAddRoomClick = { showAddRoomDialog = true }, onAddRoomClick = { showAddRoomDialog = true },
onDeleteRoom = onDeleteRoom, onDeleteRoom = onDeleteRoom,
editMode = editMode, onRenameRoom = onRenameRoom
onEditModeChange = { editMode = it }
) )
// 根据选中的房间显示不同的内容 // 根据选中的房间显示不同的内容
RoomContent(selectedRoom = selectedRoom, roomName = rooms.getOrNull(selectedRoom) ?: "总览") RoomContent(selectedRoom = selectedRoom, roomName = roomName)
} }
if (showAddRoomDialog) { if (showAddRoomDialog) {
@ -288,9 +306,11 @@ fun RoomTabs(
rooms: List<String> = listOf("总览", "客厅", "厨房", "卧室", "影音室", "游戏房"), rooms: List<String> = listOf("总览", "客厅", "厨房", "卧室", "影音室", "游戏房"),
onAddRoomClick: () -> Unit = {}, onAddRoomClick: () -> Unit = {},
onDeleteRoom: (Int) -> Unit = {}, onDeleteRoom: (Int) -> Unit = {},
editMode: Boolean = false, onRenameRoom: (Int, String) -> Unit = { _, _ -> }
onEditModeChange: (Boolean) -> Unit = {}
) { ) {
// 编辑房间对话框状态
var showEditRoomsDialog by remember { mutableStateOf(false) }
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@ -308,24 +328,40 @@ fun RoomTabs(
RoomTab( RoomTab(
name = name, name = name,
selected = index == selectedRoom, selected = index == selectedRoom,
editMode = editMode, onClick = { onRoomSelect(index) }
canDelete = rooms.size > 1,
onClick = {
if (!editMode) {
onRoomSelect(index)
}
},
onLongClick = { onEditModeChange(true) },
onDelete = {
onDeleteRoom(index)
onEditModeChange(false)
}
) )
} }
} }
// 固定的添加按钮 // 编辑按钮
GradientButton("+ 添加房间", onClick = onAddRoomClick) Box(
modifier = Modifier
.size(44.dp)
.clip(RoundedCornerShape(12.dp))
.background(Color(0xFF2A2A3E))
.border(
width = 1.dp,
color = Color(0xFF3A3A4E),
shape = RoundedCornerShape(12.dp)
)
.clickable { showEditRoomsDialog = true },
contentAlignment = Alignment.Center
) {
Text(text = "✏️", fontSize = 18.sp)
}
// 添加按钮
GradientButton("+ 添加", onClick = onAddRoomClick)
}
// 编辑房间对话框
if (showEditRoomsDialog) {
EditRoomsDialog(
rooms = rooms,
onDismiss = { showEditRoomsDialog = false },
onRenameRoom = onRenameRoom,
onDeleteRoom = onDeleteRoom
)
} }
} }
@ -333,98 +369,25 @@ fun RoomTabs(
fun RoomTab( fun RoomTab(
name: String, name: String,
selected: Boolean, selected: Boolean,
editMode: Boolean, onClick: () -> Unit
canDelete: Boolean,
onClick: () -> Unit,
onLongClick: () -> Unit,
onDelete: () -> Unit
) { ) {
val scope = rememberCoroutineScope() val base = Modifier.clip(RoundedCornerShape(20.dp))
val mod = if (selected) {
// 改进的晃动动画 - 使用无限循环的旋转动画 base.background(brush = Brush.linearGradient(listOf(Color(0xFFA9F0FF), Color(0xFFB89CFF))))
val infiniteTransition = rememberInfiniteTransition(label = "shake") } else {
val rotation by infiniteTransition.animateFloat( base.background(color = Color(0x50121212))
initialValue = -3f, }
targetValue = 3f,
animationSpec = infiniteRepeatable(
animation = tween(150, easing = LinearEasing),
repeatMode = RepeatMode.Reverse
),
label = "rotation"
)
// 缩放动画
val scale by androidx.compose.animation.core.animateFloatAsState(
targetValue = if (editMode && canDelete) 0.95f else 1f,
animationSpec = androidx.compose.animation.core.spring(
dampingRatio = androidx.compose.animation.core.Spring.DampingRatioMediumBouncy,
stiffness = androidx.compose.animation.core.Spring.StiffnessLow
),
label = "scale"
)
Box( Box(
modifier = Modifier modifier = mod
.scale(scale) .clickable { onClick() }
.then( .padding(horizontal = 14.dp, vertical = 10.dp)
if (editMode && canDelete) {
Modifier.rotate(rotation)
} else {
Modifier
}
)
.pointerInput(Unit) {
detectTapGestures(
onTap = { onClick() },
onLongPress = {
if (canDelete) {
onLongClick()
}
}
)
}
) { ) {
val base = Modifier.clip(RoundedCornerShape(20.dp)) Text(
val mod = if (selected) { text = name,
base.background(brush = Brush.linearGradient(listOf(Color(0xFFA9F0FF), Color(0xFFB89CFF)))) color = if (selected) Color.Black else Color(0xFFB0B0B0),
} else { maxLines = 1
base.background(color = Color(0x50121212)) )
}
Box(
modifier = mod.padding(horizontal = 14.dp, vertical = 10.dp)
) {
Text(
text = name,
color = if (selected) Color.Black else Color(0xFFB0B0B0),
maxLines = 1
)
}
// 删除按钮
if (editMode && canDelete) {
Box(
modifier = Modifier
.size(22.dp)
.offset(x = (-4).dp, y = (-4).dp)
.align(Alignment.TopEnd)
.shadow(4.dp, RoundedCornerShape(11.dp))
.clip(RoundedCornerShape(11.dp))
.background(Color(0xFFFF5252))
.clickable(
indication = null,
interactionSource = remember { MutableInteractionSource() }
) { onDelete() },
contentAlignment = Alignment.Center
) {
Text(
text = "×",
color = Color.White,
fontSize = 18.sp,
fontWeight = FontWeight.Bold
)
}
}
} }
} }
@ -573,6 +536,177 @@ fun NavItem(title: String, selected: Boolean) {
} }
} }
// 底部悬浮导航栏 - 带液态玻璃滑动效果
@Composable
fun FloatingBottomNav(
selectedNavItem: Int = 0,
onNavItemSelect: (Int) -> Unit = {},
modifier: Modifier = Modifier
) {
// 监听语言变化以触发重组
val currentLang by LanguageManager.currentLanguage.collectAsState()
val navItems = listOf(
R.drawable.ic_dashboard,
R.drawable.ic_scene,
R.drawable.ic_automation,
R.drawable.ic_security,
R.drawable.ic_settings
)
val itemWidth = 52.dp
val itemSpacing = 4.dp
val totalItemWidth = itemWidth + itemSpacing
// 是否正在拖动
var isDragging by remember { mutableStateOf(false) }
// 拖动时的临时选中项
var dragIndex by remember { mutableStateOf(selectedNavItem) }
// 当外部 selectedNavItem 变化时,同步更新 dragIndex
LaunchedEffect(selectedNavItem) {
if (!isDragging) {
dragIndex = selectedNavItem
}
}
// 选中框的动画偏移量 - 跟随 dragIndex拖动时或 selectedNavItem点击时
val currentIndex = if (isDragging) dragIndex else selectedNavItem
val animatedOffset by animateFloatAsState(
targetValue = currentIndex * (itemWidth.value + itemSpacing.value),
animationSpec = spring(
dampingRatio = Spring.DampingRatioMediumBouncy,
stiffness = Spring.StiffnessHigh
),
label = "liquid_glass_offset"
)
val density = LocalDensity.current
// 菜单栏高度(胶囊形)
val navBarHeight = 68.dp
val navBarPadding = 10.dp
val innerHeight = navBarHeight - navBarPadding * 2 // 48dp
// 选中指示器尺寸 - 按住时放大到贴合菜单栏边缘
val indicatorSize by animateFloatAsState(
targetValue = if (isDragging) (navBarHeight.value - 4f) else innerHeight.value,
animationSpec = spring(
dampingRatio = Spring.DampingRatioMediumBouncy,
stiffness = Spring.StiffnessMedium
),
label = "indicator_size"
)
Box(
modifier = modifier
.height(navBarHeight)
.shadow(24.dp, RoundedCornerShape(50))
.clip(RoundedCornerShape(50))
.background(
Brush.linearGradient(
colors = listOf(
Color(0xFF1A1A2E).copy(alpha = 0.95f),
Color(0xFF16213E).copy(alpha = 0.95f)
)
)
)
.border(
width = 1.dp,
brush = Brush.linearGradient(
colors = listOf(
Color.White.copy(alpha = 0.1f),
Color.White.copy(alpha = 0.05f)
)
),
shape = RoundedCornerShape(50)
)
.padding(horizontal = 10.dp, vertical = 10.dp)
.pointerInput(Unit) {
detectHorizontalDragGestures(
onDragStart = { offset ->
isDragging = true
val index = (offset.x / (itemWidth.toPx() + itemSpacing.toPx())).toInt()
.coerceIn(0, navItems.size - 1)
dragIndex = index
},
onDragEnd = {
isDragging = false
onNavItemSelect(dragIndex)
},
onDragCancel = {
isDragging = false
dragIndex = selectedNavItem
},
onHorizontalDrag = { change, _ ->
change.consume()
val index = (change.position.x / (itemWidth.toPx() + itemSpacing.toPx())).toInt()
.coerceIn(0, navItems.size - 1)
if (index != dragIndex) {
dragIndex = index
}
}
)
}
) {
Box(
contentAlignment = Alignment.CenterStart
) {
// 选中指示器 - 按住时放大贴合菜单栏边缘
val horizontalOffset = (itemWidth.value - indicatorSize) / 2f
Box(
modifier = Modifier
.align(Alignment.CenterStart)
.offset(x = animatedOffset.dp + horizontalOffset.dp)
.size(indicatorSize.dp)
.clip(RoundedCornerShape(50))
.background(Color.White.copy(alpha = if (isDragging) 0.2f else 0.12f))
.border(
width = if (isDragging) 2.dp else 1.5.dp,
color = Color.White.copy(alpha = if (isDragging) 0.6f else 0.25f),
shape = RoundedCornerShape(50)
)
)
// 图标层
Row(
horizontalArrangement = Arrangement.spacedBy(itemSpacing),
verticalAlignment = Alignment.CenterVertically
) {
navItems.forEachIndexed { index, iconRes ->
val isCurrentSelected = if (isDragging) index == dragIndex else index == selectedNavItem
Box(
modifier = Modifier
.size(itemWidth)
.clip(RoundedCornerShape(16.dp))
.clickable(
indication = null,
interactionSource = remember { MutableInteractionSource() }
) {
if (!isDragging) {
onNavItemSelect(index)
}
},
contentAlignment = Alignment.Center
) {
Image(
painter = painterResource(id = iconRes),
contentDescription = null,
modifier = Modifier.size(24.dp),
colorFilter = androidx.compose.ui.graphics.ColorFilter.tint(
if (isCurrentSelected) Color.White else Color(0xFFB0B0B0)
)
)
}
}
}
}
}
}
@Composable @Composable
fun SideNavRail(selectedNavItem: Int = 0, onNavItemSelect: (Int) -> Unit = {}) { fun SideNavRail(selectedNavItem: Int = 0, onNavItemSelect: (Int) -> Unit = {}) {
val context = androidx.compose.ui.platform.LocalContext.current val context = androidx.compose.ui.platform.LocalContext.current
@ -2501,3 +2635,432 @@ fun AddRoomDialog(
} }
} }
} }
@Composable
fun RenameRoomDialog(
currentName: String,
onDismiss: () -> Unit,
onConfirm: (String) -> Unit
) {
var roomName by remember { mutableStateOf(currentName) }
// 背景遮罩(点击关闭)
Box(
modifier = Modifier
.fillMaxSize()
.clickable(
indication = null,
interactionSource = remember { MutableInteractionSource() }
) { onDismiss() },
contentAlignment = Alignment.Center
) {
// 对话框主体
Box(
modifier = Modifier
.width(380.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)
) {
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)
)
}
// 按钮区域
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<String>,
onDismiss: () -> Unit,
onRenameRoom: (Int, String) -> Unit,
onDeleteRoom: (Int) -> 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.Center
) {
// 对话框主体
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)
) {
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)
}
}
// 房间列表
Column(
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier.heightIn(max = 300.dp).verticalScroll(rememberScrollState())
) {
rooms.forEachIndexed { index, name ->
Row(
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(14.dp))
.background(Color(0xFF1A1A2E))
.padding(12.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
if (editingIndex == index) {
// 编辑模式
TextField(
value = editingName,
onValueChange = { editingName = it },
modifier = Modifier
.weight(1f)
.height(48.dp),
colors = TextFieldDefaults.colors(
focusedContainerColor = Color(0xFF2A2A3E),
unfocusedContainerColor = Color(0xFF2A2A3E),
focusedTextColor = Color.White,
unfocusedTextColor = Color.White,
cursorColor = Color(0xFF00D1FF),
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent
),
shape = RoundedCornerShape(10.dp),
singleLine = true,
textStyle = androidx.compose.ui.text.TextStyle(fontSize = 15.sp)
)
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(0xFF3A3A4E))
.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
.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
)
}
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB