109 lines
3.8 KiB
Kotlin
109 lines
3.8 KiB
Kotlin
package eu.kanade.presentation.components
|
|
|
|
import androidx.compose.foundation.BorderStroke
|
|
import androidx.compose.foundation.background
|
|
import androidx.compose.foundation.border
|
|
import androidx.compose.foundation.combinedClickable
|
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
|
import androidx.compose.foundation.layout.Box
|
|
import androidx.compose.material.ripple.rememberRipple
|
|
import androidx.compose.material3.ColorScheme
|
|
import androidx.compose.material3.LocalAbsoluteTonalElevation
|
|
import androidx.compose.material3.LocalContentColor
|
|
import androidx.compose.material3.MaterialTheme
|
|
import androidx.compose.material3.contentColorFor
|
|
import androidx.compose.runtime.Composable
|
|
import androidx.compose.runtime.CompositionLocalProvider
|
|
import androidx.compose.runtime.NonRestartableComposable
|
|
import androidx.compose.runtime.ReadOnlyComposable
|
|
import androidx.compose.runtime.remember
|
|
import androidx.compose.ui.Modifier
|
|
import androidx.compose.ui.draw.clip
|
|
import androidx.compose.ui.draw.shadow
|
|
import androidx.compose.ui.graphics.Color
|
|
import androidx.compose.ui.graphics.RectangleShape
|
|
import androidx.compose.ui.graphics.Shape
|
|
import androidx.compose.ui.graphics.compositeOver
|
|
import androidx.compose.ui.semantics.Role
|
|
import androidx.compose.ui.unit.Dp
|
|
import androidx.compose.ui.unit.dp
|
|
import eu.kanade.presentation.util.minimumTouchTargetSize
|
|
import kotlin.math.ln
|
|
|
|
@Composable
|
|
@NonRestartableComposable
|
|
fun Surface(
|
|
onClick: () -> Unit,
|
|
modifier: Modifier = Modifier,
|
|
onLongClick: (() -> Unit)? = null,
|
|
enabled: Boolean = true,
|
|
shape: Shape = RectangleShape,
|
|
color: Color = MaterialTheme.colorScheme.surface,
|
|
contentColor: Color = contentColorFor(color),
|
|
tonalElevation: Dp = 0.dp,
|
|
shadowElevation: Dp = 0.dp,
|
|
border: BorderStroke? = null,
|
|
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
|
content: @Composable () -> Unit,
|
|
) {
|
|
val absoluteElevation = LocalAbsoluteTonalElevation.current + tonalElevation
|
|
CompositionLocalProvider(
|
|
LocalContentColor provides contentColor,
|
|
LocalAbsoluteTonalElevation provides absoluteElevation,
|
|
) {
|
|
Box(
|
|
modifier = modifier
|
|
.minimumTouchTargetSize()
|
|
.surface(
|
|
shape = shape,
|
|
backgroundColor = surfaceColorAtElevation(
|
|
color = color,
|
|
elevation = absoluteElevation,
|
|
),
|
|
border = border,
|
|
shadowElevation = shadowElevation,
|
|
)
|
|
.combinedClickable(
|
|
interactionSource = interactionSource,
|
|
indication = rememberRipple(),
|
|
enabled = enabled,
|
|
role = Role.Button,
|
|
onLongClick = onLongClick,
|
|
onClick = onClick,
|
|
),
|
|
propagateMinConstraints = true,
|
|
) {
|
|
content()
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun Modifier.surface(
|
|
shape: Shape,
|
|
backgroundColor: Color,
|
|
border: BorderStroke?,
|
|
shadowElevation: Dp,
|
|
) = this
|
|
.shadow(shadowElevation, shape, clip = false)
|
|
.then(if (border != null) Modifier.border(border, shape) else Modifier)
|
|
.background(color = backgroundColor, shape = shape)
|
|
.clip(shape)
|
|
|
|
@Composable
|
|
@ReadOnlyComposable
|
|
private fun surfaceColorAtElevation(color: Color, elevation: Dp): Color {
|
|
return if (color == MaterialTheme.colorScheme.surface) {
|
|
MaterialTheme.colorScheme.surfaceColorAtElevation(elevation)
|
|
} else {
|
|
color
|
|
}
|
|
}
|
|
|
|
private fun ColorScheme.surfaceColorAtElevation(
|
|
elevation: Dp,
|
|
): Color {
|
|
if (elevation == 0.dp) return surface
|
|
val alpha = ((4.5f * ln(elevation.value + 1)) + 2f) / 100f
|
|
return surfaceTint.copy(alpha = alpha).compositeOver(surface)
|
|
}
|