From 26e7178300feaee6799404e015d099d45ff96adb Mon Sep 17 00:00:00 2001 From: aj-rosado <109146700+aj-rosado@users.noreply.github.com> Date: Wed, 3 Dec 2025 17:46:03 +0000 Subject: [PATCH] [PM-28835] Added validations to prevent duplicate press on buttons (#6209) --- .../button/BitwardenFilledButton.kt | 3 +- .../button/BitwardenOutlinedButton.kt | 3 +- .../components/button/BitwardenTextButton.kt | 3 +- .../components/util/ThrottledClick.kt | 38 +++++++++++++++++++ 4 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 ui/src/main/kotlin/com/bitwarden/ui/platform/components/util/ThrottledClick.kt diff --git a/ui/src/main/kotlin/com/bitwarden/ui/platform/components/button/BitwardenFilledButton.kt b/ui/src/main/kotlin/com/bitwarden/ui/platform/components/button/BitwardenFilledButton.kt index ce860e83c0..84d5ac82ec 100644 --- a/ui/src/main/kotlin/com/bitwarden/ui/platform/components/button/BitwardenFilledButton.kt +++ b/ui/src/main/kotlin/com/bitwarden/ui/platform/components/button/BitwardenFilledButton.kt @@ -18,6 +18,7 @@ import com.bitwarden.ui.platform.base.util.cardStyle import com.bitwarden.ui.platform.components.button.color.bitwardenFilledButtonColors import com.bitwarden.ui.platform.components.model.CardStyle import com.bitwarden.ui.platform.components.util.rememberVectorPainter +import com.bitwarden.ui.platform.components.util.throttledClick import com.bitwarden.ui.platform.resource.BitwardenDrawable import com.bitwarden.ui.platform.theme.BitwardenTheme @@ -48,7 +49,7 @@ fun BitwardenFilledButton( modifier = modifier .semantics(mergeDescendants = true) {} .cardStyle(cardStyle = cardStyle, padding = cardInsets), - onClick = onClick, + onClick = throttledClick(onClick = onClick), enabled = isEnabled, contentPadding = PaddingValues( top = 10.dp, diff --git a/ui/src/main/kotlin/com/bitwarden/ui/platform/components/button/BitwardenOutlinedButton.kt b/ui/src/main/kotlin/com/bitwarden/ui/platform/components/button/BitwardenOutlinedButton.kt index 1145261586..0d3b211f1f 100644 --- a/ui/src/main/kotlin/com/bitwarden/ui/platform/components/button/BitwardenOutlinedButton.kt +++ b/ui/src/main/kotlin/com/bitwarden/ui/platform/components/button/BitwardenOutlinedButton.kt @@ -19,6 +19,7 @@ import com.bitwarden.ui.platform.components.button.color.bitwardenOutlinedButton import com.bitwarden.ui.platform.components.button.model.BitwardenOutlinedButtonColors import com.bitwarden.ui.platform.components.model.CardStyle import com.bitwarden.ui.platform.components.util.rememberVectorPainter +import com.bitwarden.ui.platform.components.util.throttledClick import com.bitwarden.ui.platform.resource.BitwardenDrawable import com.bitwarden.ui.platform.theme.BitwardenTheme @@ -50,7 +51,7 @@ fun BitwardenOutlinedButton( modifier = modifier .semantics(mergeDescendants = true) { } .cardStyle(cardStyle = cardStyle, padding = cardInsets), - onClick = onClick, + onClick = throttledClick(onClick = onClick), enabled = isEnabled, contentPadding = PaddingValues( top = 10.dp, diff --git a/ui/src/main/kotlin/com/bitwarden/ui/platform/components/button/BitwardenTextButton.kt b/ui/src/main/kotlin/com/bitwarden/ui/platform/components/button/BitwardenTextButton.kt index 6312eabbc7..7178f8f249 100644 --- a/ui/src/main/kotlin/com/bitwarden/ui/platform/components/button/BitwardenTextButton.kt +++ b/ui/src/main/kotlin/com/bitwarden/ui/platform/components/button/BitwardenTextButton.kt @@ -15,6 +15,7 @@ import androidx.compose.ui.semantics.semantics import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.bitwarden.ui.platform.components.button.color.bitwardenTextButtonColors +import com.bitwarden.ui.platform.components.util.throttledClick import com.bitwarden.ui.platform.theme.BitwardenTheme /** @@ -37,7 +38,7 @@ fun BitwardenTextButton( ) { TextButton( modifier = modifier.semantics(mergeDescendants = true) {}, - onClick = onClick, + onClick = throttledClick(onClick = onClick), enabled = isEnabled, contentPadding = PaddingValues( top = 10.dp, diff --git a/ui/src/main/kotlin/com/bitwarden/ui/platform/components/util/ThrottledClick.kt b/ui/src/main/kotlin/com/bitwarden/ui/platform/components/util/ThrottledClick.kt new file mode 100644 index 0000000000..fd0f412028 --- /dev/null +++ b/ui/src/main/kotlin/com/bitwarden/ui/platform/components/util/ThrottledClick.kt @@ -0,0 +1,38 @@ +package com.bitwarden.ui.platform.components.util + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +/** + * Creates a throttled click handler that prevents rapid successive clicks. + * + * @param coroutineScope The coroutine scope for launching click handlers. + * @param delayMs The minimum time in milliseconds between clicks. + * @param onClick The action to perform when clicked. + * @return A throttled click handler function. + */ +@Composable +fun throttledClick( + coroutineScope: CoroutineScope = rememberCoroutineScope(), + delayMs: Long = 300, + onClick: () -> Unit, +): () -> Unit { + var isEnabled by remember { mutableStateOf(value = true) } + return { + coroutineScope.launch { + if (isEnabled) { + isEnabled = false + onClick() + delay(timeMillis = delayMs) + isEnabled = true + } + } + } +}