balls
This commit is contained in:
@@ -150,6 +150,7 @@ fun MainScreen(
|
||||
isReorderMode = isReorderMode,
|
||||
onToggleReorderMode = { viewModel.toggleReorderMode() },
|
||||
onMoveChannel = { from, to -> viewModel.moveChannel(from, to) },
|
||||
onMoveChannelById = { id, delta -> viewModel.moveChannelById(id, delta) },
|
||||
onMoveChildSpace = { from, to -> viewModel.moveChildSpace(from, to) },
|
||||
)
|
||||
}
|
||||
|
||||
@@ -348,8 +348,13 @@ class MainViewModel(
|
||||
|
||||
// Child space sections
|
||||
for ((csId, csName, csRoomIds) in childSpaces) {
|
||||
val sectionChannels = csRoomIds.mapNotNull { channelMap[it] }
|
||||
val csChannels = csRoomIds.mapNotNull { channelMap[it] }
|
||||
.filter { it.id !in usedIds }
|
||||
// Respect saved channel order within child space sections
|
||||
val sectionChannels = if (savedOrder != null) {
|
||||
val idxMap = savedOrder.withIndex().associate { (i, id) -> id to i }
|
||||
csChannels.sortedBy { idxMap[it.id] ?: Int.MAX_VALUE }
|
||||
} else csChannels
|
||||
if (sectionChannels.isNotEmpty()) {
|
||||
sectionList.add(ChannelSection(spaceId = csId, spaceName = csName, channels = sectionChannels))
|
||||
usedIds.addAll(sectionChannels.map { it.id })
|
||||
@@ -1128,6 +1133,23 @@ class MainViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
fun moveChannelById(channelId: String, delta: Int) {
|
||||
val current = _channels.value.toMutableList()
|
||||
val fromIdx = current.indexOfFirst { it.id == channelId }
|
||||
if (fromIdx < 0) return
|
||||
val toIdx = (fromIdx + delta).coerceIn(0, current.lastIndex)
|
||||
if (fromIdx == toIdx) return
|
||||
val item = current.removeAt(fromIdx)
|
||||
current.add(toIdx, item)
|
||||
_channels.value = current
|
||||
val spaceId = _selectedSpace.value ?: return
|
||||
val roomIds = current.map { it.id }
|
||||
_channelOrderMap.value = _channelOrderMap.value + (spaceId to roomIds)
|
||||
viewModelScope.launch {
|
||||
preferencesManager.saveChannelOrder(spaceId, roomIds)
|
||||
}
|
||||
}
|
||||
|
||||
fun moveChildSpace(from: Int, to: Int) {
|
||||
val spaceId = _selectedSpace.value ?: return
|
||||
val current = _directChildSpaces.value[spaceId]?.toMutableList() ?: return
|
||||
|
||||
@@ -74,14 +74,15 @@ fun ChannelList(
|
||||
isReorderMode: Boolean = false,
|
||||
onToggleReorderMode: () -> Unit = {},
|
||||
onMoveChannel: (from: Int, to: Int) -> Unit = { _, _ -> },
|
||||
onMoveChannelById: (channelId: String, delta: Int) -> Unit = { _, _ -> },
|
||||
onMoveChildSpace: (from: Int, to: Int) -> Unit = { _, _ -> },
|
||||
) {
|
||||
var showLogoutDialog by remember { mutableStateOf(false) }
|
||||
val collapsedSections = remember { mutableStateMapOf<String, Boolean>() }
|
||||
|
||||
// Channel drag state
|
||||
var draggingIndex by remember { mutableIntStateOf(-1) }
|
||||
var dragOffsetY by remember { mutableFloatStateOf(0f) }
|
||||
// Channel drag state — track by ID, no visual offset (let LazyColumn handle positioning)
|
||||
var draggingChannelId by remember { mutableStateOf<String?>(null) }
|
||||
var dragAccumulator by remember { mutableFloatStateOf(0f) }
|
||||
|
||||
// Section drag state
|
||||
var draggingSectionIndex by remember { mutableIntStateOf(-1) }
|
||||
@@ -260,9 +261,7 @@ fun ChannelList(
|
||||
itemsIndexed(section.channels, key = { _, ch -> ch.id }) { index, channel ->
|
||||
val isSelected = channel.id == selectedChannel
|
||||
val hasUnread = channel.unreadStatus != UnreadStatus.NONE
|
||||
val globalIndex = channels.indexOfFirst { it.id == channel.id }
|
||||
val isDragging = draggingIndex == globalIndex
|
||||
val elevation by animateDpAsState(if (isDragging) 8.dp else 0.dp, label = "elevation")
|
||||
val isDragging = draggingChannelId == channel.id
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
@@ -270,8 +269,7 @@ fun ChannelList(
|
||||
.then(
|
||||
if (isDragging) Modifier
|
||||
.zIndex(1f)
|
||||
.offset { IntOffset(0, dragOffsetY.roundToInt()) }
|
||||
.shadow(elevation, RoundedCornerShape(8.dp))
|
||||
.background(MaterialTheme.colorScheme.surfaceContainerHigh)
|
||||
else Modifier
|
||||
)
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
@@ -287,7 +285,9 @@ fun ChannelList(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
if (isReorderMode) {
|
||||
val currentGlobalIndex by rememberUpdatedState(globalIndex)
|
||||
val currentChannelId by rememberUpdatedState(channel.id)
|
||||
val currentSectionSize by rememberUpdatedState(section.channels.size)
|
||||
val currentLocalIndex by rememberUpdatedState(index)
|
||||
Icon(
|
||||
imageVector = Icons.Default.DragHandle,
|
||||
contentDescription = "Drag to reorder",
|
||||
@@ -296,28 +296,29 @@ fun ChannelList(
|
||||
.pointerInput(Unit) {
|
||||
detectDragGesturesAfterLongPress(
|
||||
onDragStart = {
|
||||
draggingIndex = currentGlobalIndex
|
||||
dragOffsetY = 0f
|
||||
draggingChannelId = currentChannelId
|
||||
dragAccumulator = 0f
|
||||
},
|
||||
onDrag = { change, dragAmount ->
|
||||
change.consume()
|
||||
dragOffsetY += dragAmount.y
|
||||
val itemHeight = 40.dp.toPx()
|
||||
val draggedPositions = (dragOffsetY / itemHeight).roundToInt()
|
||||
val targetIndex = (draggingIndex + draggedPositions).coerceIn(0, channels.lastIndex)
|
||||
if (targetIndex != draggingIndex) {
|
||||
onMoveChannel(draggingIndex, targetIndex)
|
||||
dragOffsetY -= (targetIndex - draggingIndex) * itemHeight
|
||||
draggingIndex = targetIndex
|
||||
dragAccumulator += dragAmount.y
|
||||
val itemHeight = 56.dp.toPx()
|
||||
val id = draggingChannelId ?: return@detectDragGesturesAfterLongPress
|
||||
if (dragAccumulator > itemHeight * 0.6f && currentLocalIndex < currentSectionSize - 1) {
|
||||
onMoveChannelById(id, 1)
|
||||
dragAccumulator = 0f
|
||||
} else if (dragAccumulator < -itemHeight * 0.6f && currentLocalIndex > 0) {
|
||||
onMoveChannelById(id, -1)
|
||||
dragAccumulator = 0f
|
||||
}
|
||||
},
|
||||
onDragEnd = {
|
||||
draggingIndex = -1
|
||||
dragOffsetY = 0f
|
||||
draggingChannelId = null
|
||||
dragAccumulator = 0f
|
||||
},
|
||||
onDragCancel = {
|
||||
draggingIndex = -1
|
||||
dragOffsetY = 0f
|
||||
draggingChannelId = null
|
||||
dragAccumulator = 0f
|
||||
},
|
||||
)
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user