Updated on 2026-08-14

This commit is contained in:
Tangem 2026-05-14 13:12:57 +03:00
parent ad9def0d21
commit a9b5490cc4
46 changed files with 2679 additions and 163 deletions

View file

@ -39,6 +39,7 @@ fun SecondaryTangemButton(buttonUM: TangemButtonUM, modifier: Modifier = Modifie
isLoading = buttonUM.isLoading,
size = buttonUM.size,
shape = buttonUM.shape,
onLongClick = buttonUM.onLongClick,
)
}
@ -68,6 +69,7 @@ fun SecondaryTangemButton(
isLoading: Boolean = false,
size: TangemButtonSize = TangemButtonSize.X15,
shape: TangemButtonShape = TangemButtonShape.Default,
onLongClick: (() -> Unit)? = null,
) {
val backgroundModifier = if (isEnabled) {
Modifier.background(TangemTheme.colors2.button.backgroundSecondary)
@ -93,6 +95,7 @@ fun SecondaryTangemButton(
isLoading = isLoading,
size = size,
iconPosition = iconPosition,
onLongClick = onLongClick,
)
}

View file

@ -67,12 +67,13 @@ internal fun TangemButtonInternal(
hasPadding: Boolean = true,
contentColor: Color = TangemTheme.colors2.text.neutral.primary,
size: TangemButtonSize = TangemButtonSize.X15,
onLongClick: (() -> Unit)? = null,
) {
ProvideButtonRippleConfiguration {
Box(
modifier = modifier
.testTag(BaseButtonTestTags.BUTTON)
.clickableSingle(enabled = isEnabled, onClick = onClick, role = Role.Button)
.buttonClickable(isEnabled = isEnabled, onClick = onClick, onLongClick = onLongClick)
.heightIn(min = size.toHeightDp())
.conditionalCompose(text == null) {
width(size.toHeightDp())
@ -181,6 +182,19 @@ private fun ButtonContent(
}
}
private fun Modifier.buttonClickable(isEnabled: Boolean, onClick: () -> Unit, onLongClick: (() -> Unit)?): Modifier {
return if (onLongClick != null) {
combinedClickableSingle(
enabled = isEnabled,
role = Role.Button,
onClick = onClick,
onLongClick = onLongClick,
)
} else {
clickableSingle(enabled = isEnabled, onClick = onClick, role = Role.Button)
}
}
@Composable
private inline fun ProvideButtonRippleConfiguration(crossinline content: @Composable () -> Unit) {
CompositionLocalProvider(

View file

@ -17,6 +17,7 @@ import com.tangem.core.ui.extensions.TextReference
* @param shape TangemButtonShape defining the shape of the button.
* @param type TangemButtonType defining the style type of the button.
* @param onClick Lambda to be invoked when the button is clicked.
* @param onLongClick Lambda to be invoked when the button is long-clicked.
*
[REDACTED_AUTHOR]
*/
@ -32,6 +33,7 @@ data class TangemButtonUM(
val shape: TangemButtonShape = TangemButtonShape.Default,
val type: TangemButtonType,
val onClick: () -> Unit,
val onLongClick: (() -> Unit)? = null,
)
/** Enum class representing the style types of Tangem buttons */

View file

@ -60,6 +60,7 @@ fun ActionButtons(buttons: ImmutableList<TangemButtonUM>, modifier: Modifier = M
onClick = button.onClick,
isEnabled = button.isEnabled,
shape = TangemButtonShape.Rounded,
onLongClick = button.onLongClick,
)
Text(
text = button.text.orEmpty().resolveReference(),

View file

@ -3,6 +3,7 @@ package com.tangem.core.ui.extensions
import androidx.compose.foundation.LocalIndication
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
@ -37,6 +38,31 @@ fun Modifier.clickableSingle(
)
}
/**
* Combined clickable modifier that debounces multiple [onClick] events in a short period of time.
* Mirrors [clickableSingle] but also exposes [onLongClick]; long-press is not debounced.
*/
fun Modifier.combinedClickableSingle(
enabled: Boolean = true,
onClickLabel: String? = null,
role: Role? = null,
onLongClickLabel: String? = null,
onLongClick: (() -> Unit)? = null,
onClick: () -> Unit,
) = composed {
val multipleEventsCutter = remember { MultipleClickPreventer.get() }
Modifier.combinedClickable(
enabled = enabled,
onClickLabel = onClickLabel,
role = role,
onLongClickLabel = onLongClickLabel,
onLongClick = onLongClick,
onClick = { multipleEventsCutter.processEvent { onClick() } },
indication = LocalIndication.current,
interactionSource = remember { MutableInteractionSource() },
)
}
/**
* Conditionally applies a modifier based on a boolean condition.
*/