fix: resolve tab long-press context menu blocked by drag gesture

The detectDragGesturesAfterLongPress modifier was consuming the
long-press event before combinedClickable.onLongClick could fire.
Replace combinedClickable with movement-tracking inside the drag
handler — small movement on release shows the context menu, large
movement commits the reorder. Move tap handling into Tab.onClick.

Made-with: Cursor
This commit is contained in:
cottongin
2026-03-11 17:12:14 -04:00
parent 5f7cb050e5
commit 8872b9de96

View File

@@ -390,14 +390,10 @@ private fun DragReorderTabRow(
key(tab.playlist?.id ?: -1L) { key(tab.playlist?.id ?: -1L) {
val isDraggable = tab.playlist != null val isDraggable = tab.playlist != null
var showTabMenu by remember(tab) { mutableStateOf(false) } var showTabMenu by remember(tab) { mutableStateOf(false) }
var totalDragDistance by remember { mutableFloatStateOf(0f) }
val dragThreshold = swapThresholdPx / 3
val tabModifier = Modifier val tabModifier = Modifier
.combinedClickable(
onClick = { onSelectTab(index) },
onLongClick = {
if (isDraggable) showTabMenu = true
}
)
.then( .then(
if (dragState.isDragging && dragState.draggedIndex == index) { if (dragState.isDragging && dragState.draggedIndex == index) {
Modifier.graphicsLayer { translationX = dragState.dragOffset } Modifier.graphicsLayer { translationX = dragState.dragOffset }
@@ -410,6 +406,7 @@ private fun DragReorderTabRow(
Modifier.pointerInput(tabs) { Modifier.pointerInput(tabs) {
detectDragGesturesAfterLongPress( detectDragGesturesAfterLongPress(
onDragStart = { onDragStart = {
totalDragDistance = 0f
dragState.isDragging = true dragState.isDragging = true
dragState.draggedIndex = index dragState.draggedIndex = index
dragState.dragOffset = 0f dragState.dragOffset = 0f
@@ -417,6 +414,7 @@ private fun DragReorderTabRow(
}, },
onDrag = { change, dragAmount -> onDrag = { change, dragAmount ->
change.consume() change.consume()
totalDragDistance += kotlin.math.abs(dragAmount.x) + kotlin.math.abs(dragAmount.y)
val currentIndex = dragState.draggedIndex val currentIndex = dragState.draggedIndex
val newOffset = dragState.dragOffset + dragAmount.x val newOffset = dragState.dragOffset + dragAmount.x
val groupStart = if (currentIndex < pinnedEnd) 0 else unpinnedStart val groupStart = if (currentIndex < pinnedEnd) 0 else unpinnedStart
@@ -443,20 +441,27 @@ private fun DragReorderTabRow(
} }
}, },
onDragEnd = { onDragEnd = {
val reordered = dragState.currentTabs if (totalDragDistance < dragThreshold) {
val playlists = if (dragState.draggedIndex < pinnedEnd) { showTabMenu = true
reordered.subList(0, pinnedEnd).mapNotNull { it.playlist }
} else { } else {
reordered.subList(unpinnedStart, reordered.size).mapNotNull { it.playlist } val reordered = dragState.currentTabs
} val playlists = if (dragState.draggedIndex < pinnedEnd) {
if (playlists.isNotEmpty()) { reordered.subList(0, pinnedEnd).mapNotNull { it.playlist }
onReorderTabs(playlists) } else {
reordered.subList(unpinnedStart, reordered.size).mapNotNull { it.playlist }
}
if (playlists.isNotEmpty()) {
onReorderTabs(playlists)
}
} }
dragState.isDragging = false dragState.isDragging = false
dragState.draggedIndex = -1 dragState.draggedIndex = -1
dragState.dragOffset = 0f dragState.dragOffset = 0f
}, },
onDragCancel = { onDragCancel = {
if (totalDragDistance < dragThreshold) {
showTabMenu = true
}
dragState.isDragging = false dragState.isDragging = false
dragState.draggedIndex = -1 dragState.draggedIndex = -1
dragState.dragOffset = 0f dragState.dragOffset = 0f
@@ -471,7 +476,7 @@ private fun DragReorderTabRow(
Box { Box {
Tab( Tab(
selected = selectedTabIndex == index, selected = selectedTabIndex == index,
onClick = {}, onClick = { onSelectTab(index) },
text = { text = {
Text( Text(
text = tab.label, text = tab.label,