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

No support for changing lists in canDragOver? #269

Open
CalamityDeadshot opened this issue May 31, 2023 · 1 comment
Open

No support for changing lists in canDragOver? #269

CalamityDeadshot opened this issue May 31, 2023 · 1 comment

Comments

@CalamityDeadshot
Copy link

CalamityDeadshot commented May 31, 2023

I have a list of selectable items and I want to be able to reorder only selected items. So I have a composable like this:

@Composable
private fun EmployeeSelectionDialog(
    employees: List<EmployeeEntity>,
    selectedEmployees: List<EmployeeEntity>,
    onDismissRequest: () -> Unit,
    onClick: (EmployeeEntity, Boolean) -> Unit,
    onReordered: (List<EmployeeEntity>) -> Unit
) {

    var selectedEmployeesMutable = remember(selectedEmployees) {
        println("Selected employees: ${selectedEmployees.joinToString { it.id.toString() }}")
        selectedEmployees
    }

    val reorderState = rememberReorderableLazyListState(
        onMove = { from, to ->
            selectedEmployeesMutable = selectedEmployeesMutable.toMutableList().apply {
                add(to.index, removeAt(from.index))
            }
        },
        canDragOver = { draggedOver: ItemPosition, _: ItemPosition ->
            (draggedOver.key in selectedEmployeesMutable.map { it.id }).also {
                println("Can drag over ${draggedOver.key}: $it (against [${selectedEmployeesMutable.joinToString { it.id.toString() }}])")
            }
        },
        onDragEnd = { _, _ ->
            onReordered(selectedEmployeesMutable)
        }
    )

    val unselectedEmployees by remember(employees, selectedEmployees) {
        mutableStateOf(employees.filter { it !in selectedEmployees })
    }

    @Composable
    fun LazyItemScope.EmployeeItem(
        employee: EmployeeEntity,
        isDragging: Boolean,
    ) {
        // Composing what I need and applying the detectReorder modifier if selected
    }

    LazyColumn(
        modifier = Modifier
            .width(400.dp)
            .reorderable(reorderState),
        state = reorderState.listState
    ) {
        items(
            items = selectedEmployeesMutable,
            key = { it.id }
        ) { employee ->
            ReorderableItem(reorderState, key = employee.id) { isDragging ->
                EmployeeItem(
                    employee = employee,
                    isDragging = isDragging
                )
            }
        }
        if (selectedEmployees.isNotEmpty()) {
            item {
                Divider()
            }
        }
        items(
            items = unselectedEmployees,
            key = { it.id }
        ) { employee ->
            EmployeeItem(
                employee = employee,
                isDragging = false
            )
        }
    }
  }
}

onClick and onReordered functions end up making a DB write to mark items selected or change their order respectively, and this data then gets passed back into composition through Flows.

The problem is that the canDragOver factory seems to capture what it needs in a closure and be remembered along with its ReorderableLazyListState, not caring that selectedEmployeesMutable was changed. So if I check some checkboxes and then try to reorder selected items, my console will look like this:

Selected employees: 
Selected employees: 42
Selected employees: 42, 26
Can drag over 26: false (against [])
Can drag over 26: false (against [])

This issue is even worse for un-checking some items since selectedEmployeesMutable captured in a closure retains wrong items, and this can cause IndexOutOfBoundsExceptions.

So are my assumptions correct and can I fix this on my end, or is the fix needed in the library? Thanks.

@OliverRhyme
Copy link

did you try using rememberUpdatedState?

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