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

commonMain.io.github.lyxnx.compose.compodals.dialogs.CompodalDialog.kt Maven / Gradle / Ivy

package io.github.lyxnx.compose.compodals.dialogs

import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.background
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import io.github.lyxnx.compose.compodals.Compodal
import io.github.lyxnx.compose.compodals.CompodalDefaults
import io.github.lyxnx.compose.compodals.CompodalProperties

/**
 * Container for the defaults used by a [CompodalDialog]
 */
public object CompodalDialogDefaults {

    /**
     * The default background color of a modal dialog
     */
    public val BackgroundColor: Color = Color.White

    /**
     * The default shape of a modal dialog
     */
    public val DialogShape: Shape = RoundedCornerShape(10.dp)

}

/**
 * Creates a new modal dialog with the given [content]
 *
 * By default, the content is not scrollable in any direction, but [verticalScrollState] and [horizontalScrollState] can
 * be specified to allow scrolling in the vertical and/or horizontal directions respectively
 *
 * @param onDismiss callback used when the dialog is dismissed. This will be called when the user touches outside the
 * content area and [dismissOnTouchOutside][CompodalProperties.dismissOnTouchOutside] is true
 * @param dimColor color to apply to the background area - this is commonly called a scrim in design systems
 * @param backgroundColor background color for the dialog content area
 * @param shape shape of the dialog content area - the content area will be clipped to this, so any elements that go outside
 * this will not be visible
 * @param properties properties to apply to the dialog window
 * @param size the size of the dialog content area. Each axis can have its own policy for sizing
 * @param contentPadding inner padding to apply to the dialog content
 * @param verticalScrollState scroll state for the vertical direction. Use null to prevent scrolling in this direction
 * @param horizontalScrollState scroll state for the horizontal direction. Use null to prevent scrolling in this direction
 * @param content content to display within this dialog
 *
 * @see Compodal
 * @see DialogSize
 * @see DialogAxisSize
 */
@Composable
public fun CompodalDialog(
    onDismiss: () -> Unit,
    dimColor: Color = CompodalDefaults.DimColor,
    backgroundColor: Color = CompodalDialogDefaults.BackgroundColor,
    shape: Shape = CompodalDialogDefaults.DialogShape,
    properties: CompodalProperties = CompodalProperties(),
    size: DialogSize = DialogSize(),
    contentPadding: PaddingValues = PaddingValues(),
    verticalScrollState: ScrollState? = null,
    horizontalScrollState: ScrollState? = null,
    content: @Composable ColumnScope.() -> Unit,
) {
    val currentBackgroundColor by rememberUpdatedState(backgroundColor)
    val currentShape by rememberUpdatedState(shape)
    val currentSize by rememberUpdatedState(size)
    val currentContentPadding by rememberUpdatedState(contentPadding)
    val currentVScrollState by rememberUpdatedState(verticalScrollState)
    val currentHScrollState by rememberUpdatedState(horizontalScrollState)
    val currentContent by rememberUpdatedState(content)

    Compodal(
        onDismiss = onDismiss,
        dimColor = dimColor,
        properties = properties,
        contentAlignment = Alignment.Center
    ) {
        DialogContentLayout(
            width = currentSize.width,
            height = currentSize.height,
            modifier = Modifier.systemBarsPadding()
        ) {
            Column(
                modifier = Modifier
                    .clip(currentShape)
                    .background(currentBackgroundColor)
                    .then(
                        if (currentVScrollState != null) Modifier.verticalScroll(currentVScrollState!!)
                        else Modifier
                    )
                    .then(
                        if (currentHScrollState != null) Modifier.horizontalScroll(currentHScrollState!!)
                        else Modifier
                    )
                    .padding(currentContentPadding),
                content = currentContent
            )
        }
    }
}

@Composable
private fun DialogContentLayout(
    width: DialogAxisSize,
    height: DialogAxisSize,
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit,
) {
    val density = LocalDensity.current

    Layout(
        modifier = modifier,
        content = content
    ) { measurables, constraints ->
        val (minWidth, maxWidth) = with(width) {
            density.calculateMinWidth(constraints) to density.calculateMaxWidth(constraints)
        }

        val (minHeight, maxHeight) = with(height) {
            density.calculateMinHeight(constraints) to density.calculateMaxHeight(constraints)
        }

        val placeable = measurables.first().measure(
            constraints.copy(
                minWidth = minWidth,
                maxWidth = maxWidth,
                minHeight = minHeight,
                maxHeight = maxHeight
            )
        )

        layout(placeable.width, placeable.height) {
            placeable.placeRelative(0, 0)
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy