From 442d1728e63292972fb1dd2d2817caf01de55278 Mon Sep 17 00:00:00 2001 From: GuhDoy Date: Wed, 28 Feb 2024 20:24:42 +0800 Subject: [PATCH] Support combine KeyItemMaps --- .../java/me/gm/selection/KeyIndexItemMap.kt | 66 +++++++++++++++---- .../java/me/gm/selection/SelectionState.kt | 1 - sample/src/main/AndroidManifest.xml | 1 + .../me/gm/selection/sample/SampleScreen.kt | 31 ++++++++- 4 files changed, 83 insertions(+), 16 deletions(-) diff --git a/library/src/main/java/me/gm/selection/KeyIndexItemMap.kt b/library/src/main/java/me/gm/selection/KeyIndexItemMap.kt index dada062..bd7d956 100644 --- a/library/src/main/java/me/gm/selection/KeyIndexItemMap.kt +++ b/library/src/main/java/me/gm/selection/KeyIndexItemMap.kt @@ -25,12 +25,19 @@ import androidx.compose.runtime.remember * @see [androidx.compose.foundation.lazy.layout.LazyLayoutKeyIndexMap] */ sealed interface KeyIndexItemMap { + val items: List fun getItem(e: K): V? fun getFullItemMappings(): Iterable> } +interface KeyItemMap : KeyIndexItemMap { + val key: (index: Int) -> Any +} + +interface IndexItemMap : KeyIndexItemMap + /** * Automatically deselect removed keys when items change. */ @@ -60,7 +67,7 @@ fun rememberKeyItemMap( } return remember(items, key) { - KeyItemMap(items) { index -> key(items[index]) } + KeyItemMapImpl(items) { index -> key(items[index]) } } } @@ -76,17 +83,17 @@ fun rememberKeyItemMap( } return remember(items, key) { - KeyItemMap(items) { index -> key(index, items[index]) } + KeyItemMapImpl(items) { index -> key(index, items[index]) } } } /** * @see [androidx.compose.foundation.lazy.layout.NearestRangeKeyIndexMap] */ -open class KeyItemMap( - val items: List, - val key: ((index: Int) -> Any), -) : KeyIndexItemMap { +open class KeyItemMapImpl( + override val items: List, + override val key: (index: Int) -> Any, +) : KeyItemMap { private val map: MutableScatterMap = MutableScatterMap() override fun getItem(e: Any): V? = map.getOrElse(e) { @@ -117,13 +124,13 @@ fun rememberIndexItemMap( } return remember(items) { - IndexItemMap(items) + IndexItemMapImpl(items) } } -open class IndexItemMap( - val items: List -) : KeyIndexItemMap { +open class IndexItemMapImpl( + override val items: List +) : IndexItemMap { override fun getItem(e: Int): V? = items[e] @@ -131,6 +138,41 @@ open class IndexItemMap( items.mapIndexed { index, item -> index to item } } -operator fun KeyIndexItemMap<*, *>.plus(other: KeyIndexItemMap<*, *>): KeyIndexItemMap<*, *> { - TODO() +/** + * This can only be used as a parameter for modifiers. + */ +private class CombinedKeyItemMap( + val maps: MutableList>, + override val items: List = emptyList(), + override val key: (Int) -> Any = { throw UnsupportedOperationException() } +) : KeyItemMap { + + override fun getItem(e: Any): V? { + for (map in maps) { + val item = map.getItem(e) + if (item != null) { + return item + } + } + return null + } + + override fun getFullItemMappings(): Iterable> = + throw UnsupportedOperationException() +} + +operator fun KeyItemMap.plus(other: KeyItemMap): KeyItemMap { + return if (this is CombinedKeyItemMap) { + this.maps.add(other) + this + } else { + CombinedKeyItemMap(mutableListOf(this, other)) + } } + +/* + * Combining [IndexItemMap] requires knowing the position of each interval, which is similar to + * [androidx.compose.foundation.lazy.layout.MutableIntervalList]. + * This introduces some implicit restrictions on usage, which we do not favor, and therefore, + * we do not provide a built-in implementation. + */ diff --git a/library/src/main/java/me/gm/selection/SelectionState.kt b/library/src/main/java/me/gm/selection/SelectionState.kt index de31911..f79068e 100644 --- a/library/src/main/java/me/gm/selection/SelectionState.kt +++ b/library/src/main/java/me/gm/selection/SelectionState.kt @@ -56,7 +56,6 @@ fun rememberKeySelectionState( * [noOpSaver] or [viewModelSaver] to keep the implementation simple. Alternatively, you can use * [autoSaver] or a custom [Saver] to ensure data is not lost * @param initialSelection the initial value for [SelectionSupport.selection] - * @see [androidx.compose.foundation.lazy.layout.MutableIntervalList] */ @Composable fun rememberIndexSelectionState( diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index a6025b0..286d51e 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ diff --git a/sample/src/main/java/me/gm/selection/sample/SampleScreen.kt b/sample/src/main/java/me/gm/selection/sample/SampleScreen.kt index acbb972..f61c683 100644 --- a/sample/src/main/java/me/gm/selection/sample/SampleScreen.kt +++ b/sample/src/main/java/me/gm/selection/sample/SampleScreen.kt @@ -68,6 +68,7 @@ import me.gm.selection.grid.selectableItems import me.gm.selection.grid.tapInActionModeToToggleGesture import me.gm.selection.list.dragAfterLongPressToSelectGesture import me.gm.selection.list.selectableItems +import me.gm.selection.plus import me.gm.selection.rememberKeyItemMap import me.gm.selection.rememberKeySelectionState @@ -78,12 +79,12 @@ import me.gm.selection.rememberKeySelectionState @Composable fun SampleScreen() { val itemsA = remember { - List(10) { index -> + List(8) { index -> index } } val itemsB = remember { - List(10) { index -> + List(8) { index -> index } } @@ -123,6 +124,11 @@ fun SampleScreen() { key = { item -> "A" to item }, state = selectionState ) + val mapB = rememberKeyItemMap( + items = itemsB, + key = { item -> "B" to item }, + state = selectionState + ) Column( modifier = Modifier .fillMaxSize() @@ -135,7 +141,9 @@ fun SampleScreen() { modifier = Modifier .fillMaxSize() .weight(1f) - .dragAfterLongPressToSelectGesture(listState, selectionState, mapA), + .dragAfterLongPressToSelectGesture( + listState, selectionState, mapA + mapB + ), state = listState ) { selectableItems( @@ -155,6 +163,23 @@ fun SampleScreen() { text = "ItemA $item", ) } + selectableItems( + state = selectionState, + map = mapB + ) { helper, item -> + val context = LocalContext.current + SampleListItem( + modifier = Modifier + .animateItemPlacement() + .clickable { + Toast + .makeText(context, "ItemB $item", Toast.LENGTH_SHORT) + .show() + }, + helper = helper, + text = "ItemB $item", + ) + } } }