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

@ -75,6 +75,7 @@ dependencies {
// ZXing 二维码生成
implementation("com.google.zxing:core:3.5.2")
debugImplementation("com.squareup.leakcanary:leakcanary-android:2.12")
androidTestImplementation(platform("androidx.compose:compose-bom:2024.10.00"))

View File

@ -134,7 +134,7 @@ fun MainContent() {
}
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) }
// 保存房间列表到SharedPreferences
@ -170,26 +170,29 @@ fun MainContent() {
.background(Color(overlayAlpha shl 24 or 0x121212))
)
// 主内容 - 添加系统栏内边距
Box(modifier = Modifier.fillMaxSize().systemBarsPadding()) {
// 主内容 - 全屏显示
Box(modifier = Modifier.fillMaxSize()) {
MainScaffold(
selectedRoom = selectedRoom,
onRoomSelect = { selectedRoom = it },
selectedNavItem = selectedNavItem,
onNavItemSelect = { selectedNavItem = it },
rooms = rooms,
onAddRoom = { newRoomName ->
saveRooms(rooms + newRoomName)
},
onDeleteRoom = { index ->
if (rooms.size > 1) { // 至少保留一个房间
saveRooms(rooms.filterIndexed { i, _ -> i != index })
if (selectedRoom >= rooms.size - 1) {
selectedRoom = (rooms.size - 2).coerceAtLeast(0)
selectedRoom = selectedRoom,
onRoomSelect = { selectedRoom = it },
selectedNavItem = selectedNavItem,
onNavItemSelect = { selectedNavItem = it },
rooms = rooms,
onAddRoom = { newRoomName ->
saveRooms(rooms + newRoomName)
},
onDeleteRoom = { index ->
if (rooms.size > 1) { // 至少保留一个房间
saveRooms(rooms.filterIndexed { i, _ -> i != index })
if (selectedRoom >= rooms.size - 1) {
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 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 android.view.SoundEffectConstants
@ -47,6 +48,7 @@ import androidx.compose.foundation.gestures.detectHorizontalDragGestures
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.foundation.layout.offset
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.layout.ContentScale
@Composable
fun MainScaffold(
@ -56,27 +58,34 @@ fun MainScaffold(
onNavItemSelect: (Int) -> Unit = {},
rooms: List<String> = listOf("总览", "客厅", "厨房", "卧室", "影音室", "游戏房"),
onAddRoom: (String) -> Unit = {},
onDeleteRoom: (Int) -> Unit = {}
onDeleteRoom: (Int) -> Unit = {},
onRenameRoom: (Int, String) -> Unit = { _, _ -> }
) {
Row(modifier = Modifier.fillMaxSize()) {
SideNavRail(
selectedNavItem = selectedNavItem,
onNavItemSelect = onNavItemSelect
)
// 内容区域 - 减少左侧间距
Box(modifier = Modifier.fillMaxSize()) {
Box(modifier = Modifier.fillMaxSize()) {
// 内容区域 - 全屏显示
Box(
modifier = Modifier.fillMaxSize()
) {
// 根据选中的导航项显示不同的内容
// 底部导航: 0-Dashboard, 1-Scene, 2-Automation, 3-Security, 4-Settings
when (selectedNavItem) {
0 -> DashboardContent(selectedRoom, onRoomSelect, rooms, onAddRoom, onDeleteRoom)
0 -> DashboardContent(selectedRoom, onRoomSelect, rooms, onAddRoom, onDeleteRoom, onRenameRoom)
1 -> SceneScreen()
2 -> AutomationScreen()
3 -> StatisticsScreen()
4 -> SecurityScreen()
5 -> SettingsContent()
else -> DashboardContent(selectedRoom, onRoomSelect, rooms, onAddRoom, onDeleteRoom)
3 -> SecurityScreen()
4 -> SettingsContent()
else -> DashboardContent(selectedRoom, onRoomSelect, rooms, onAddRoom, onDeleteRoom, onRenameRoom)
}
}
// 底部悬浮导航栏 - 置于内容之上
FloatingBottomNav(
selectedNavItem = selectedNavItem,
onNavItemSelect = onNavItemSelect,
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(bottom = 24.dp)
)
}
}
@ -86,23 +95,33 @@ fun DashboardContent(
onRoomSelect: (Int) -> Unit,
rooms: List<String> = listOf("总览", "客厅", "厨房", "卧室", "影音室", "游戏房"),
onAddRoom: (String) -> Unit = {},
onDeleteRoom: (Int) -> Unit = {}
onDeleteRoom: (Int) -> Unit = {},
onRenameRoom: (Int, String) -> Unit = { _, _ -> }
) {
var showAddRoomDialog by remember { mutableStateOf(false) }
var editMode by remember { mutableStateOf(false) }
// 总览和客厅使用默认壁纸
val roomName = rooms.getOrNull(selectedRoom) ?: "总览"
val hasWallpaper = selectedRoom == 0 || roomName == "客厅"
Box(
modifier = Modifier
.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()
RoomTabs(
selectedRoom = selectedRoom,
@ -110,11 +129,10 @@ fun DashboardContent(
rooms = rooms,
onAddRoomClick = { showAddRoomDialog = true },
onDeleteRoom = onDeleteRoom,
editMode = editMode,
onEditModeChange = { editMode = it }
onRenameRoom = onRenameRoom
)
// 根据选中的房间显示不同的内容
RoomContent(selectedRoom = selectedRoom, roomName = rooms.getOrNull(selectedRoom) ?: "总览")
RoomContent(selectedRoom = selectedRoom, roomName = roomName)
}
if (showAddRoomDialog) {
@ -288,9 +306,11 @@ fun RoomTabs(
rooms: List<String> = listOf("总览", "客厅", "厨房", "卧室", "影音室", "游戏房"),
onAddRoomClick: () -> Unit = {},
onDeleteRoom: (Int) -> Unit = {},
editMode: Boolean = false,
onEditModeChange: (Boolean) -> Unit = {}
onRenameRoom: (Int, String) -> Unit = { _, _ -> }
) {
// 编辑房间对话框状态
var showEditRoomsDialog by remember { mutableStateOf(false) }
Row(
modifier = Modifier
.fillMaxWidth()
@ -308,24 +328,40 @@ fun RoomTabs(
RoomTab(
name = name,
selected = index == selectedRoom,
editMode = editMode,
canDelete = rooms.size > 1,
onClick = {
if (!editMode) {
onRoomSelect(index)
}
},
onLongClick = { onEditModeChange(true) },
onDelete = {
onDeleteRoom(index)
onEditModeChange(false)
}
onClick = { onRoomSelect(index) }
)
}
}
// 固定的添加按钮
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(
name: String,
selected: Boolean,
editMode: Boolean,
canDelete: Boolean,
onClick: () -> Unit,
onLongClick: () -> Unit,
onDelete: () -> Unit
onClick: () -> Unit
) {
val scope = rememberCoroutineScope()
// 改进的晃动动画 - 使用无限循环的旋转动画
val infiniteTransition = rememberInfiniteTransition(label = "shake")
val rotation by infiniteTransition.animateFloat(
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"
)
val base = Modifier.clip(RoundedCornerShape(20.dp))
val mod = if (selected) {
base.background(brush = Brush.linearGradient(listOf(Color(0xFFA9F0FF), Color(0xFFB89CFF))))
} else {
base.background(color = Color(0x50121212))
}
Box(
modifier = Modifier
.scale(scale)
.then(
if (editMode && canDelete) {
Modifier.rotate(rotation)
} else {
Modifier
}
)
.pointerInput(Unit) {
detectTapGestures(
onTap = { onClick() },
onLongPress = {
if (canDelete) {
onLongClick()
}
}
)
}
modifier = mod
.clickable { onClick() }
.padding(horizontal = 14.dp, vertical = 10.dp)
) {
val base = Modifier.clip(RoundedCornerShape(20.dp))
val mod = if (selected) {
base.background(brush = Brush.linearGradient(listOf(Color(0xFFA9F0FF), Color(0xFFB89CFF))))
} else {
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
)
}
}
Text(
text = name,
color = if (selected) Color.Black else Color(0xFFB0B0B0),
maxLines = 1
)
}
}
@ -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
fun SideNavRail(selectedNavItem: Int = 0, onNavItemSelect: (Int) -> Unit = {}) {
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