Code
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.hoverable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsDraggedAsState
import androidx.compose.foundation.interaction.collectIsHoveredAsState
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Slider
import androidx.compose.material3.SliderDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.TileMode
import androidx.compose.ui.input.pointer.PointerIcon
import androidx.compose.ui.input.pointer.pointerHoverIcon
import androidx.compose.ui.unit.dp
import demos.effects.CRTBox
import playground.gradient.ui.Offset
import theme.Black
import theme.Pink300
import theme.Pink400
import theme.Pink500
import theme.Rose800
import theme.Transparent
import theme.Zinc900
import theme.Zinc950
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CRTSlider() {
CRTBox(
xSize = 0f,
ySize = 8f,
) {
var value by remember { mutableStateOf(.5f) }
val interaction = remember { MutableInteractionSource() }
val isDragged by interaction.collectIsDraggedAsState()
val isHovered by interaction.collectIsHoveredAsState()
val borderWidth by animateDpAsState(
targetValue = when {
isDragged -> 6.dp
isHovered -> 2.dp
else -> 4.dp
}
)
Slider(
value = value,
onValueChange = { value = it },
modifier = Modifier
.width(300.dp),
interactionSource = interaction,
thumb = {
Box(
modifier = Modifier
.pointerHoverIcon(PointerIcon.Hand)
.hoverable(interaction)
.height(56.dp)
.width(18.dp)
.background(
color = Zinc950.copy(alpha = .9f),
shape = CircleShape,
)
.border(
width = borderWidth,
color = Pink500,
shape = CircleShape,
)
)
},
colors = SliderDefaults.colors(
activeTrackColor = Pink400,
inactiveTrackColor = Rose800.copy(alpha = .5f)
),
track = { sliderPositions ->
val fraction by remember {
derivedStateOf {
(value - sliderPositions.valueRange.start) / (sliderPositions.valueRange.endInclusive - sliderPositions.valueRange.start)
}
}
Box(
modifier = Modifier
.fillMaxWidth()
.border(
width = 2.dp,
color = Pink300,
shape = CircleShape,
)
.background(
color = Pink400.copy(alpha = .06f),
shape = CircleShape,
)
.clip(CircleShape)
) {
Box(
modifier = Modifier
.fillMaxWidth(fraction)
.padding(end = 9.dp)
.height(24.dp)
.drawBehind {
drawRect(
brush = Brush.linearGradient(
0f to Pink400,
.5f to Pink400,
.5f to Transparent,
1f to Transparent,
start = Offset(0f, 0f),
end = Offset(20f, 20f),
tileMode = TileMode.Repeated,
)
)
}
)
}
}
)
}
}