|
@Composable |
|
fun RepeatingButton( |
|
modifier: Modifier = Modifier, |
|
onClick: () -> Unit, |
|
enabled: Boolean = true, |
|
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, |
|
elevation: ButtonElevation? = ButtonDefaults.elevation(), |
|
shape: Shape = MaterialTheme.shapes.small, |
|
border: BorderStroke? = null, |
|
colors: ButtonColors = ButtonDefaults.buttonColors(), |
|
contentPadding: PaddingValues = ButtonDefaults.ContentPadding, |
|
maxDelayMillis: Long = 1000, |
|
minDelayMillis: Long = 5, |
|
delayDecayFactor: Float = .15f, |
|
content: @Composable RowScope.() -> Unit |
|
) { |
|
|
|
val currentClickListener by rememberUpdatedState(onClick) |
|
var pressed by remember { mutableStateOf(false) } |
|
|
|
Button( |
|
modifier = modifier.pointerInteropFilter { |
|
pressed = when (it.action) { |
|
MotionEvent.ACTION_DOWN -> true |
|
|
|
else -> false |
|
} |
|
|
|
true |
|
}, |
|
onClick = {}, |
|
enabled = enabled, |
|
interactionSource = interactionSource, |
|
elevation = elevation, |
|
shape = shape, |
|
border = border, |
|
colors = colors, |
|
contentPadding = contentPadding, |
|
content = content |
|
) |
|
|
|
LaunchedEffect(pressed, enabled) { |
|
var currentDelayMillis = maxDelayMillis |
|
|
|
while (enabled && pressed) { |
|
currentClickListener() |
|
delay(currentDelayMillis) |
|
currentDelayMillis = |
|
(currentDelayMillis - (currentDelayMillis * delayDecayFactor)) |
|
.toLong().coerceAtLeast(minDelayMillis) |
|
} |
|
} |
|
} |