mirror of
http://180.163.74.83:13000/zhangzhenghao/MPVN_Android.git
synced 2025-12-12 15:24:30 +00:00
优化
This commit is contained in:
parent
238958f3d2
commit
fb20e2e64b
@ -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"))
|
||||
|
||||
@ -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 })
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BIN
app/src/main/res/drawable/room_wallpaper_default.png
Normal file
BIN
app/src/main/res/drawable/room_wallpaper_default.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 MiB |
BIN
zenhome-wallpaper-1764392320729.png
Normal file
BIN
zenhome-wallpaper-1764392320729.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 MiB |
Loading…
Reference in New Issue
Block a user