Skip to content

Instantly share code, notes, and snippets.

@adrientetar
Created May 10, 2024 19:13
Show Gist options
  • Save adrientetar/59e094580678ed6afadea8e768ff21be to your computer and use it in GitHub Desktop.
Save adrientetar/59e094580678ed6afadea8e768ff21be to your computer and use it in GitHub Desktop.
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.FocusInteraction
import androidx.compose.foundation.interaction.HoverInteraction
import androidx.compose.foundation.interaction.Interaction
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.PressInteraction
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CornerSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.platform.LocalWindowInfo
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.dp
@Composable
fun Button(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
active: Boolean = false,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
shape: Shape = DefaultShape,
// TODO: introduce a Appearance class
backgroundColor: Color = Color.White,
border: BorderStroke? = DefaultBorder,
contentPadding: PaddingValues = DefaultContentPadding,
content: @Composable RowScope.() -> Unit
) {
val interactions = remember { mutableStateListOf<Interaction>() }
LaunchedEffect(interactionSource) {
interactionSource.interactions.collect { interaction ->
when (interaction) {
is HoverInteraction.Enter -> {
interactions.add(interaction)
}
is HoverInteraction.Exit -> {
interactions.remove(interaction.enter)
}
is FocusInteraction.Focus -> {
interactions.add(interaction)
}
is FocusInteraction.Unfocus -> {
interactions.remove(interaction.focus)
}
is PressInteraction.Press -> {
interactions.add(interaction)
}
is PressInteraction.Release -> {
interactions.remove(interaction.press)
}
is PressInteraction.Cancel -> {
interactions.remove(interaction.press)
}
}
}
}
val interaction = interactions.lastOrNull()
val isFocused = interaction.isFocus && LocalWindowInfo.current.isWindowFocused
val backgroundModifier = when {
enabled && (active || interaction.isPress) -> {
Modifier.background(Color(0xFFD6D6D6), shape)
}
interaction.isHover -> Modifier.background(Color(0xFFE4E4E4), shape)
else -> Modifier.background(backgroundColor, shape)
}
Box(
modifier
.clickable(
onClick = onClick,
enabled = enabled,
role = Role.Button,
interactionSource = interactionSource,
indication = null
)
.then(backgroundModifier),
propagateMinConstraints = true
) {
Row(
Modifier
.defaultMinSize(8.dp, 8.dp)
.padding(contentPadding),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
content = content
)
}
}
val Interaction?.isFocus: Boolean
get() = this is FocusInteraction.Focus
val Interaction?.isHover: Boolean
get() = this is HoverInteraction.Enter
val Interaction?.isPress: Boolean
get() = this is PressInteraction.Press
private val DefaultBorder = BorderStroke(1.dp, Color(0xFFD1D1D1))
private val DefaultShape = RoundedCornerShape(CornerSize(4.dp))
private val DefaultContentPadding = PaddingValues(8.dp, 6.dp)
private val DefaultIconContentPadding = PaddingValues(2.dp)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment