All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.com.dragselectcompose.grid.LazyDragSelectGridScope.kt Maven / Gradle / Ivy

Go to download

A Compose multiplatform library for adding Google Photos style drag-to-select multi-selection to a LazyGrid.

The newest version!
package com.dragselectcompose.grid

import androidx.compose.foundation.lazy.grid.GridItemSpan
import androidx.compose.foundation.lazy.grid.LazyGridItemSpanScope
import androidx.compose.foundation.lazy.grid.LazyGridScope
import androidx.compose.foundation.lazy.grid.LazyGridScopeMarker
import androidx.compose.foundation.lazy.grid.itemsIndexed
import androidx.compose.runtime.Composable
import com.dragselectcompose.core.DragSelectState

/**
 * Receiver scope for [LazyDragSelectHorizontalGrid] and [LazyDragSelectVerticalGrid].
 *
 * This is essentially a copy of [LazyGridScope].
 */
@LazyGridScopeMarker
public interface LazyDragSelectGridScope {

    /**
     * Adds a single item to the scope.
     *
     * Wrapper around [LazyGridScope.item].
     *
     * @see LazyGridScope.item
     * @param[key] a stable and unique key representing the item. Using the same key for multiple
     * items in the grid is not allowed. Type of the key should be saveable via Bundle on Android.
     * If null is passed the position in the grid will represent the key. When you specify the key
     * the scroll position will be maintained based on the key, which means if you add/remove items
     * before the current visible item the item with the given key will be kept as the first visible one.
     * @param[span] the span of the item. Default is 1x1. It is good practice to leave it `null`
     * when this matches the intended behavior, as providing a custom implementation impacts performance.
     * @param[contentType] the type of the content of this item. The item compositions of the same
     * type could be reused more efficiently. Note that null is a valid type and items of such
     * type will be considered compatible.
     * @param[content] the content of the item.
     */
    public fun item(
        key: Any? = null,
        span: (LazyGridItemSpanScope.() -> GridItemSpan)? = null,
        contentType: Any? = null,
        content: @Composable LazyDragSelectGridItemScope.() -> Unit,
    )

    /**
     * Adds a list of items from the [Item]s in the scope.
     *
     * Wrapper around [LazyGridScope.items].
     *
     * @see LazyGridScope.items
     * @param[key] a factory of stable and unique keys representing the item. Using the
     * same key for multiple items in the grid is not allowed. Type of the key should be saveable
     * via Bundle on Android. If null is passed the position in the grid will represent the key.
     * When you specify the key the scroll position will be maintained based on the key, which
     * means if you add/remove items before the current visible item the item with the given key
     * will be kept as the first visible one.
     * @param[span] define custom spans for the items. Default is 1x1. It is good practice to leave
     * it null when this matches the intended behavior, as providing a custom implementation
     * impacts performance.
     * @param[contentType] a factory of the content types for the item. The item compositions of
     * the same type could be reused more efficiently. Note that null is a valid type and items of
     * such type will be considered compatible.
     * @param[itemContent] the content displayed by a single item.
     */
    public fun items(
        key: ((item: Item) -> Any)? = null,
        span: (LazyGridItemSpanScope.(item: Item) -> GridItemSpan)? = null,
        contentType: (item: Item) -> Any? = { null },
        itemContent: @Composable LazyDragSelectGridItemScope.(item: Item) -> Unit,
    )

    public fun itemsIndexed(
        key: ((index: Int, item: Item) -> Any)? = null,
        span: (LazyGridItemSpanScope.(index: Int, item: Item) -> GridItemSpan)? = null,
        contentType: (index: Int, item: Item) -> Any? = { _, _ -> null },
        itemContent: @Composable LazyDragSelectGridItemScope.(index: Int, item: Item) -> Unit,
    )
}

/**
 * Implementation of [LazyDragSelectGridScope] that wraps a [LazyGridScope].
 *
 * @param[gridScope] The [LazyGridScope] to wrap.
 * @param[items] The list of items to display.
 * @param[stateProvider] A function that returns the [DragSelectState] for this grid.
 */
internal class DefaultLazyDragSelectGridScope(
    private val gridScope: LazyGridScope,
    private val items: List,
    private val stateProvider: () -> DragSelectState,
) : LazyDragSelectGridScope {

    /**
     * Adds a single item to the scope.
     *
     * @see[LazyGridScope.item]
     * @see[LazyDragSelectGridScope.item]
     */
    override fun item(
        key: Any?,
        span: (LazyGridItemSpanScope.() -> GridItemSpan)?,
        contentType: Any?,
        content: @Composable (LazyDragSelectGridItemScope.() -> Unit),
    ) {
        gridScope.item(key, span, contentType) {
            val scope = LazyDragSelectGridItemScope(
                state = [email protected](),
                lazyGridItemScope = this,
            )
            content(scope)
        }
    }

    /**
     * Adds [items] to the scope.
     *
     * @see[LazyGridScope.items]
     * @see[LazyDragSelectGridScope.items]
     */
    override fun items(
        key: ((item: Item) -> Any)?,
        span: (LazyGridItemSpanScope.(item: Item) -> GridItemSpan)?,
        contentType: (item: Item) -> Any?,
        itemContent: @Composable (LazyDragSelectGridItemScope.(item: Item) -> Unit),
    ) {
        val items = this.items
        gridScope.items(
            count = items.size,
            key = if (key != null) { index -> key(items[index]) } else null,
            span = if (span == null) null
            else {
                { span(items[it]) }
            },
            contentType = { index -> contentType(items[index]) }
        ) { index ->
            val scope = LazyDragSelectGridItemScope(
                state = [email protected](),
                lazyGridItemScope = this,
            )
            itemContent(scope, items[index])
        }
    }

    override fun itemsIndexed(
        key: ((index: Int, item: Item) -> Any)?,
        span: (LazyGridItemSpanScope.(index: Int, item: Item) -> GridItemSpan)?,
        contentType: (index: Int, item: Item) -> Any?,
        itemContent: @Composable LazyDragSelectGridItemScope.(index: Int, item: Item) -> Unit,
    ) {
        val items = this.items
        gridScope.itemsIndexed(
            items = items,
            key = key,
            span = span,
            contentType = contentType,
        ) { index, item ->
            val scope = LazyDragSelectGridItemScope(
                state = [email protected](),
                lazyGridItemScope = this,
            )
            itemContent(scope, index, item)
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy