Skip to content

Commit

Permalink
Fix error appearing when selectedKeys contain invalid key
Browse files Browse the repository at this point in the history
In this case, we should just skip invalid keys when receiving their indices
  • Loading branch information
Walingar committed Nov 3, 2023
1 parent d73420a commit b240688
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public fun SelectableLazyColumn(
val latestOnSelectedIndexesChanged = rememberUpdatedState(onSelectedIndexesChanged)
LaunchedEffect(state, container) {
snapshotFlow { state.selectedKeys }.collect { selectedKeys ->
val indices = selectedKeys.map { key -> container.getKeyIndex(key) }
val indices = selectedKeys.mapNotNull { key -> container.getKeyIndex(key) }
latestOnSelectedIndexesChanged.value.invoke(indices)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ internal class SelectableLazyListScopeContainer : SelectableLazyListScope {
) : Entry
}

internal fun getKeyIndex(key: Any): Int = keyToIndex[key] ?: error("Cannot find index of '$key'")
internal fun getKeyIndex(key: Any): Int? = keyToIndex[key]

internal fun isKeySelectable(key: Any): Boolean = key !in nonSelectableKeys

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.text.BasicText
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.platform.testTag
Expand Down Expand Up @@ -255,4 +256,49 @@ internal class SelectableLazyColumnTest {
assertEquals(expectedElementsAfterPageDown.size, state.selectedKeys.size)
assertEquals(expectedElementsAfterPageDown.toSet(), state.selectedKeys.toSet())
}

@Test
fun `changing items model with seleciton shouldn't fail`() = runBlocking<Unit> {
val items1 = (0..50).toList()
val items2 = (70..80).toList()
val currentItems = mutableStateOf(items1)
val state = SelectableLazyListState(LazyListState())
composeRule.setContent {
Box(modifier = Modifier.requiredHeight(300.dp)) {
val items = currentItems.value
SelectableLazyColumn(state = state, modifier = Modifier.testTag("list")) {
items(
items.size,
key = {
items[it]
},
) {
val itemText = "Item ${items[it]}"
BasicText(itemText, modifier = Modifier.testTag(itemText))
}
}
}
}
composeRule.awaitIdle()
// select item 5 by click
composeRule.onNodeWithTag("Item 5").assertExists()
composeRule.onNodeWithTag("Item 5").performClick()

// check that 5th element is selected
assertEquals(1, state.selectedKeys.size)
assertEquals(currentItems.value[5], state.selectedKeys.single())

// change items from 0..50 to 70..80, so "Item 5" doesn't exist
currentItems.value = items2
composeRule.awaitIdle()
// TODO: should the selectedKeys be cleared when items are changed
// https://github.com/JetBrains/jewel/issues/242
// assertEquals(0, state.selectedKeys.size)

composeRule.onNodeWithTag("Item 75").assertExists()
composeRule.onNodeWithTag("Item 75").performClick()

assertEquals(1, state.selectedKeys.size)
assertEquals(currentItems.value[5], state.selectedKeys.single())
}
}

0 comments on commit b240688

Please sign in to comment.