Item loses drag state when dragged into different list/different ui
Issue is similar to https://github.com/Calvin-LL/Reorderable/issues/49, but i have only 1 list
When I drag from item{} to items{} drag is lost
I think the reason is in different composable functions for elements.
I will be glad to any advice!
https://github.com/user-attachments/assets/f1f4d622-1d57-4a2b-a409-299f0811a26a
I tried solution from #49 issue with merging lists into one, but it didn't work. Workaround branch
Reorderable code snippet:
private fun LazyListScope.currencies(
state: AddQuickScreenState,
reorderableLazyColumnState: ReorderableLazyListState,
haptic: ReorderHapticFeedback,
onAmountChanged: (String) -> Unit,
onCurrencyRemove: (Int) -> Unit,
onCodeChange: (Int) -> Unit,
onSwapClick: () -> Unit,
) {
val from = state.currencies.first()
val to = state.currencies.drop(1)
item {
Text(
modifier = Modifier.padding(top = 16.dp, start = 52.dp),
text = stringResource(CoreRString.quick_from),
fontWeight = FontWeight.Medium,
color = ArkColor.TextSecondary,
)
}
item(key = from.code) {
ReorderableItem(state = reorderableLazyColumnState, key = from.code) {
FromInput(
code = from.code,
amount = from.value,
haptic = haptic,
scope = this,
onAmountChanged = onAmountChanged,
onCodeChange = {
val index = state.currencies.indexOfFirst { it.code == from.code }
onCodeChange(index)
},
)
}
}
item {
SwapBtn(modifier = Modifier.padding(top = 16.dp), onClick = onSwapClick)
Text(
modifier = Modifier.padding(top = 16.dp, start = 52.dp),
text = stringResource(CoreRString.quick_to),
fontWeight = FontWeight.Medium,
color = ArkColor.TextSecondary,
)
}
itemsIndexed(to, key = { _, amount -> amount.code }) { index, item ->
ReorderableItem(state = reorderableLazyColumnState, key = item.code) {
ToResult(
code = item.code,
amount = item.value,
scope = this,
haptic = haptic,
onCurrencyRemove = {
val index = state.currencies.indexOfFirst { it.code == item.code }
onCurrencyRemove(index)
},
onCodeChange = {
val index = state.currencies.indexOfFirst { it.code == item.code }
onCodeChange(index)
},
)
}
}
}
I think the problem in the 🔁 part isn't in a ReorderableItem. Try wrapping it in there and setting enabled to false
I didn't quite understand what you meant by
Try wrapping it in there and setting enabled to false
🔁 code
val reorderableLazyColumnState =
rememberReorderableLazyListState(lazyListState) { from, to ->
val fromIndex = state.currencies.indexOfFirst { it.code == from.key }
val toIndex = state.currencies.indexOfFirst { it.code == to.key }
onPairsSwap(fromIndex, toIndex)
haptic.performHapticFeedback(ReorderHapticFeedbackType.MOVE)
}
fun onPairsSwap(
from: Int,
to: Int,
) = intent {
val new =
state.currencies.toMutableList().apply {
add(to, removeAt(from))
}
reduce {
state.copy(currencies = new)
}
}
Wrap the content of the item with 🔁 in a ReorderableItem
Ah, you mean icon button Same behavior..
item {
Text(
modifier = Modifier.padding(top = 16.dp, start = 52.dp),
text = stringResource(CoreRString.quick_from),
fontWeight = FontWeight.Medium,
color = ArkColor.TextSecondary,
)
}
item(key = from.code) {
ReorderableItem(state = reorderableLazyColumnState, key = from.code) {
FromInput(
code = from.code,
amount = from.value,
haptic = haptic,
scope = this,
onAmountChanged = onAmountChanged,
onCodeChange = {
val index = state.currencies.indexOfFirst { it.code == from.code }
onCodeChange(index)
},
)
}
}
item(key = "To") {
ReorderableItem(state = reorderableLazyColumnState, key = "To", enabled = false) {
Column {
SwapBtn(modifier = Modifier.padding(top = 16.dp), onClick = onSwapClick)
Text(
modifier = Modifier.padding(top = 16.dp, start = 52.dp),
text = stringResource(CoreRString.quick_to),
fontWeight = FontWeight.Medium,
color = ArkColor.TextSecondary,
)
}
}
}
itemsIndexed(to, key = { _, amount -> amount.code }) { index, item ->
ReorderableItem(state = reorderableLazyColumnState, key = item.code) {
ToResult(
code = item.code,
amount = item.value,
scope = this,
haptic = haptic,
onCurrencyRemove = {
val index = state.currencies.indexOfFirst { it.code == item.code }
onCurrencyRemove(index)
},
onCodeChange = {
val index = state.currencies.indexOfFirst { it.code == item.code }
onCodeChange(index)
},
)
}
}
Hmm let me give it a try. I wonder if this was a Compose bug that got fixed in a later version of compose.
Any idea which version you're using?
1.7.5
Bug still exists in versions 1.7.7, 1.8.0-beta01
https://github.com/Calvin-LL/Reorderable/blob/main/demoApp/composeApp/src/commonMain/kotlin/sh/calvin/reorderable/demo/ui/TwoReorderableLazyColumnScreen.kt
See here this works.
https://github.com/user-attachments/assets/44173fcb-385f-4a78-9b5c-d52c01ccd519
It seems like a very strange composable bug. The commented out code below is semantically identical, the same functions are called in the same order except the commented out code is unrolled.
Still not working If you have time can you add an example with 2 different ui items?
val from = state.currencies.first()
val to = state.currencies.drop(1)
val combinedList = listOf(listOf(from), to)
item {
Text(
modifier = Modifier.padding(top = 16.dp, start = 52.dp),
text = stringResource(CoreRString.quick_from),
fontWeight = FontWeight.Medium,
color = ArkColor.TextSecondary,
)
}
combinedList.forEachIndexed { listIndex, items ->
if (listIndex == 1) {
item {
Column {
SwapBtn(modifier = Modifier.padding(top = 16.dp), onClick = onSwapClick)
Text(
modifier = Modifier.padding(top = 16.dp, start = 52.dp),
text = stringResource(CoreRString.quick_to),
fontWeight = FontWeight.Medium,
color = ArkColor.TextSecondary,
)
}
}
}
items(items, key = { item -> item.code }) { item ->
ReorderableItem(state = reorderableLazyColumnState, key = item.code) {
FromOrToItem(
listIndex = listIndex,
code = item.code,
amount = item.value,
haptic = haptic,
scope = this,
onAmountChanged = onAmountChanged,
onCurrencyRemove = {
val index = state.currencies.indexOfFirst { it.code == item.code }
onCurrencyRemove(index)
},
onCodeChange = {
val index = state.currencies.indexOfFirst { it.code == from.code }
onCodeChange(index)
},
)
}
}
}