Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Item loses drag state when dragged into different list/different ui #69

Open
mdrlzy opened this issue Feb 2, 2025 · 9 comments
Open

Comments

@mdrlzy
Copy link

mdrlzy commented Feb 2, 2025

Issue is similar to #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!

20250202_222.mp4

Pull request with source code

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)
                },
            )
        }
    }
}
@Calvin-LL
Copy link
Owner

I think the problem in the 🔁 part isn't in a ReorderableItem. Try wrapping it in there and setting enabled to false

@mdrlzy
Copy link
Author

mdrlzy commented Feb 2, 2025

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)
        }
    }

@Calvin-LL
Copy link
Owner

Wrap the content of the item with 🔁 in a ReorderableItem

@mdrlzy
Copy link
Author

mdrlzy commented Feb 2, 2025

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)
                },
            )
        }
    }

@Calvin-LL
Copy link
Owner

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?

@mdrlzy
Copy link
Author

mdrlzy commented Feb 2, 2025

1.7.5

@mdrlzy
Copy link
Author

mdrlzy commented Feb 2, 2025

Bug still exists in versions 1.7.7, 1.8.0-beta01

@Calvin-LL
Copy link
Owner

https://github.com/Calvin-LL/Reorderable/blob/main/demoApp/composeApp/src/commonMain/kotlin/sh/calvin/reorderable/demo/ui/TwoReorderableLazyColumnScreen.kt

See here this works.

Screen_recording_20250202_224234.mp4

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.

@mdrlzy
Copy link
Author

mdrlzy commented Feb 3, 2025

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)
                    },
                )
            }
        }
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants