Updated on 2026-08-14
This commit is contained in:
parent
6f095384c1
commit
4b07ed004f
8 changed files with 999 additions and 16 deletions
|
|
@ -0,0 +1,125 @@
|
|||
package com.tangem.core.ui.ds.button
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
|
||||
/**
|
||||
* [Accent Tangem button](https://www.figma.com/design/RU7AIgwHtGdMfy83T5UOoR/Core-Library?node-id=8004-26798)
|
||||
*
|
||||
* @param onClick Lambda to be invoked when the button is clicked.
|
||||
* @param modifier Modifier to be applied to the button.
|
||||
* @param text TextReference for the button label.
|
||||
* @param iconRes Drawable resource ID for the icon to be displayed in the button.
|
||||
* @param iconPosition Position of the icon (Start or End).
|
||||
* @param enabled Boolean indicating whether the button is enabled.
|
||||
* @param size TangemButtonSize defining the size of the button.
|
||||
* @param state TangemButtonState defining the current state of the button.
|
||||
* @param shape TangemButtonShape defining the shape of the button.
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Composable
|
||||
fun AccentTangemButton(
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
text: TextReference? = null,
|
||||
@DrawableRes iconRes: Int? = null,
|
||||
iconPosition: TangemButtonIconPosition = TangemButtonIconPosition.Start,
|
||||
enabled: Boolean = true,
|
||||
size: TangemButtonSize = TangemButtonSize.X15,
|
||||
state: TangemButtonState = TangemButtonState.Default,
|
||||
shape: TangemButtonShape = TangemButtonShape.Default,
|
||||
) {
|
||||
TangemButtonInternal(
|
||||
onClick = onClick,
|
||||
modifier = modifier
|
||||
.clip(shape.toShape(size))
|
||||
.then(
|
||||
when (state) {
|
||||
TangemButtonState.Disabled,
|
||||
TangemButtonState.Default,
|
||||
-> Modifier.background(TangemTheme.colors2.button.backgroundPositive)
|
||||
TangemButtonState.Loading,
|
||||
TangemButtonState.Pressed,
|
||||
-> Modifier
|
||||
.background(TangemTheme.colors2.button.backgroundPositive)
|
||||
.background(TangemTheme.colors2.overlay.overlaySecondary)
|
||||
},
|
||||
),
|
||||
text = text,
|
||||
contentColor = TangemTheme.colors2.text.neutral.primaryInvertedConstant,
|
||||
iconRes = iconRes,
|
||||
enabled = enabled,
|
||||
size = size,
|
||||
state = state,
|
||||
iconPosition = iconPosition,
|
||||
)
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 480)
|
||||
@Preview(showBackground = true, widthDp = 480, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun AccentTangemButton_Preview(
|
||||
@PreviewParameter(AccentTangemButtonPreviewProvider::class) params: TangemButtonState,
|
||||
) {
|
||||
TangemThemePreviewRedesign {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(21.dp),
|
||||
modifier = Modifier
|
||||
.background(TangemTheme.colors2.surface.level1)
|
||||
.padding(8.dp),
|
||||
) {
|
||||
repeat(4) { yIndex ->
|
||||
val shape = if (yIndex < 2) TangemButtonShape.Default else TangemButtonShape.Rounded
|
||||
val text = if (yIndex % 2 == 1) null else stringReference("Button")
|
||||
Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
repeat(2) { xIndex ->
|
||||
val iconPosition = if (xIndex == 1) {
|
||||
TangemButtonIconPosition.Start
|
||||
} else {
|
||||
TangemButtonIconPosition.End
|
||||
}
|
||||
AccentTangemButton(
|
||||
onClick = {},
|
||||
text = text,
|
||||
size = TangemButtonSize.X15,
|
||||
shape = shape,
|
||||
iconPosition = iconPosition,
|
||||
iconRes = R.drawable.ic_tangem_24,
|
||||
state = params,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class AccentTangemButtonPreviewProvider : PreviewParameterProvider<TangemButtonState> {
|
||||
override val values: Sequence<TangemButtonState>
|
||||
get() = sequenceOf(
|
||||
TangemButtonState.Default,
|
||||
TangemButtonState.Pressed,
|
||||
TangemButtonState.Loading,
|
||||
TangemButtonState.Disabled,
|
||||
)
|
||||
}
|
||||
// endregion
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
package com.tangem.core.ui.ds.button
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
|
||||
/**
|
||||
* [Ghost Tangem button](https://www.figma.com/design/RU7AIgwHtGdMfy83T5UOoR/Core-Library?node-id=5854-4804)
|
||||
*
|
||||
* @param onClick Lambda to be invoked when the button is clicked.
|
||||
* @param modifier Modifier to be applied to the button.
|
||||
* @param text TextReference for the button label.
|
||||
* @param iconRes Drawable resource ID for the icon to be displayed in the button.
|
||||
* @param iconPosition Position of the icon (Start or End).
|
||||
* @param enabled Boolean indicating whether the button is enabled.
|
||||
* @param size TangemButtonSize defining the size of the button.
|
||||
* @param state TangemButtonState defining the current state of the button.
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Composable
|
||||
fun GhostTangemButton(
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
text: TextReference? = null,
|
||||
@DrawableRes iconRes: Int? = null,
|
||||
enabled: Boolean = true,
|
||||
size: TangemButtonSize = TangemButtonSize.X15,
|
||||
state: TangemButtonState = TangemButtonState.Default,
|
||||
iconPosition: TangemButtonIconPosition = TangemButtonIconPosition.Start,
|
||||
) {
|
||||
val contentColor = when (state) {
|
||||
TangemButtonState.Disabled -> TangemTheme.colors2.text.status.disabled
|
||||
else -> TangemTheme.colors2.text.neutral.primary
|
||||
}
|
||||
TangemButtonInternal(
|
||||
onClick = onClick,
|
||||
modifier = modifier,
|
||||
text = text,
|
||||
contentColor = contentColor,
|
||||
enabled = enabled,
|
||||
size = size,
|
||||
state = state,
|
||||
iconPosition = iconPosition,
|
||||
iconRes = iconRes,
|
||||
)
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 480)
|
||||
@Preview(showBackground = true, widthDp = 480, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun GhostTangemButton_Preview(
|
||||
@PreviewParameter(GhostTangemButtonPreviewProvider::class) params: TangemButtonState,
|
||||
) {
|
||||
TangemThemePreviewRedesign {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(21.dp),
|
||||
modifier = Modifier
|
||||
.background(TangemTheme.colors2.surface.level1)
|
||||
.padding(8.dp),
|
||||
) {
|
||||
repeat(4) { yIndex ->
|
||||
val text = if (yIndex % 2 == 1) null else stringReference("Button")
|
||||
Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
repeat(2) { xIndex ->
|
||||
val iconPosition = if (xIndex == 1) {
|
||||
TangemButtonIconPosition.Start
|
||||
} else {
|
||||
TangemButtonIconPosition.End
|
||||
}
|
||||
GhostTangemButton(
|
||||
onClick = {},
|
||||
text = text,
|
||||
size = TangemButtonSize.X15,
|
||||
iconPosition = iconPosition,
|
||||
iconRes = R.drawable.ic_tangem_24,
|
||||
state = params,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class GhostTangemButtonPreviewProvider : PreviewParameterProvider<TangemButtonState> {
|
||||
override val values: Sequence<TangemButtonState>
|
||||
get() = sequenceOf(
|
||||
TangemButtonState.Default,
|
||||
TangemButtonState.Pressed,
|
||||
TangemButtonState.Loading,
|
||||
TangemButtonState.Disabled,
|
||||
)
|
||||
}
|
||||
// endregion
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
package com.tangem.core.ui.ds.button
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
|
||||
/**
|
||||
* [Outline Tangem button](https://www.figma.com/design/RU7AIgwHtGdMfy83T5UOoR/Core-Library?node-id=5854-4800)
|
||||
*
|
||||
* @param onClick Lambda to be invoked when the button is clicked.
|
||||
* @param modifier Modifier to be applied to the button.
|
||||
* @param text TextReference for the button label.
|
||||
* @param iconRes Drawable resource ID for the icon to be displayed in the button.
|
||||
* @param iconPosition Position of the icon (Start or End).
|
||||
* @param enabled Boolean indicating whether the button is enabled.
|
||||
* @param size TangemButtonSize defining the size of the button.
|
||||
* @param state TangemButtonState defining the current state of the button.
|
||||
* @param shape TangemButtonShape defining the shape of the button.
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Composable
|
||||
fun OutlineTangemButton(
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
text: TextReference? = null,
|
||||
@DrawableRes iconRes: Int? = null,
|
||||
iconPosition: TangemButtonIconPosition = TangemButtonIconPosition.Start,
|
||||
enabled: Boolean = true,
|
||||
size: TangemButtonSize = TangemButtonSize.X15,
|
||||
state: TangemButtonState = TangemButtonState.Default,
|
||||
shape: TangemButtonShape = TangemButtonShape.Default,
|
||||
) {
|
||||
val backgroundModifier = when (state) {
|
||||
TangemButtonState.Loading,
|
||||
TangemButtonState.Pressed,
|
||||
TangemButtonState.Disabled,
|
||||
TangemButtonState.Default,
|
||||
-> Modifier
|
||||
.background(TangemTheme.colors2.surface.level1)
|
||||
.border(
|
||||
width = 1.dp,
|
||||
color = TangemTheme.colors2.border.neutral.primary,
|
||||
shape = shape.toShape(size),
|
||||
)
|
||||
}
|
||||
val contentColor = when (state) {
|
||||
TangemButtonState.Disabled -> TangemTheme.colors2.text.status.disabled
|
||||
else -> TangemTheme.colors2.text.neutral.primary
|
||||
}
|
||||
TangemButtonInternal(
|
||||
onClick = onClick,
|
||||
modifier = modifier
|
||||
.clip(shape.toShape(size))
|
||||
.then(backgroundModifier),
|
||||
text = text,
|
||||
contentColor = contentColor,
|
||||
iconRes = iconRes,
|
||||
enabled = enabled,
|
||||
size = size,
|
||||
state = state,
|
||||
iconPosition = iconPosition,
|
||||
)
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 480)
|
||||
@Preview(showBackground = true, widthDp = 480, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun OutlineTangemButton_Preview(
|
||||
@PreviewParameter(OutlineTangemButtonPreviewProvider::class) params: TangemButtonState,
|
||||
) {
|
||||
TangemThemePreviewRedesign {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(21.dp),
|
||||
modifier = Modifier
|
||||
.background(TangemTheme.colors2.surface.level1)
|
||||
.padding(8.dp),
|
||||
) {
|
||||
repeat(4) { yIndex ->
|
||||
val shape = if (yIndex < 2) TangemButtonShape.Default else TangemButtonShape.Rounded
|
||||
val text = if (yIndex % 2 == 1) null else stringReference("Button")
|
||||
Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
repeat(2) { xIndex ->
|
||||
val iconPosition = if (xIndex == 0) {
|
||||
TangemButtonIconPosition.Start
|
||||
} else {
|
||||
TangemButtonIconPosition.End
|
||||
}
|
||||
OutlineTangemButton(
|
||||
onClick = {},
|
||||
text = text,
|
||||
size = TangemButtonSize.X15,
|
||||
shape = shape,
|
||||
iconPosition = iconPosition,
|
||||
iconRes = R.drawable.ic_tangem_24,
|
||||
state = params,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class OutlineTangemButtonPreviewProvider : PreviewParameterProvider<TangemButtonState> {
|
||||
override val values: Sequence<TangemButtonState>
|
||||
get() = sequenceOf(
|
||||
TangemButtonState.Default,
|
||||
TangemButtonState.Pressed,
|
||||
TangemButtonState.Loading,
|
||||
TangemButtonState.Disabled,
|
||||
)
|
||||
}
|
||||
// endregion
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
package com.tangem.core.ui.ds.button
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
|
||||
/**
|
||||
* [Primary Inverse Tangem button](https://www.figma.com/design/RU7AIgwHtGdMfy83T5UOoR/Core-Library?node-id=7545-78314)
|
||||
*
|
||||
* @param onClick Lambda to be invoked when the button is clicked.
|
||||
* @param modifier Modifier to be applied to the button.
|
||||
* @param text TextReference for the button label.
|
||||
* @param iconRes Drawable resource ID for the icon to be displayed in the button.
|
||||
* @param iconPosition Position of the icon (Start or End).
|
||||
* @param enabled Boolean indicating whether the button is enabled.
|
||||
* @param size TangemButtonSize defining the size of the button.
|
||||
* @param state TangemButtonState defining the current state of the button.
|
||||
* @param shape TangemButtonShape defining the shape of the button.
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Composable
|
||||
fun PrimaryInverseTangemButton(
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
text: TextReference? = null,
|
||||
@DrawableRes iconRes: Int? = null,
|
||||
iconPosition: TangemButtonIconPosition = TangemButtonIconPosition.Start,
|
||||
enabled: Boolean = true,
|
||||
size: TangemButtonSize = TangemButtonSize.X15,
|
||||
state: TangemButtonState = TangemButtonState.Default,
|
||||
shape: TangemButtonShape = TangemButtonShape.Default,
|
||||
) {
|
||||
val backgroundModifier = when (state) {
|
||||
TangemButtonState.Default -> Modifier.background(TangemTheme.colors2.button.backgroundPrimaryInverse)
|
||||
TangemButtonState.Disabled -> Modifier.background(TangemTheme.colors2.button.backgroundDisabled)
|
||||
TangemButtonState.Loading,
|
||||
TangemButtonState.Pressed,
|
||||
-> Modifier
|
||||
.background(TangemTheme.colors2.button.backgroundPrimaryInverse)
|
||||
.background(TangemTheme.colors2.overlay.overlayPrimary)
|
||||
}
|
||||
val contentColor = when (state) {
|
||||
TangemButtonState.Disabled -> TangemTheme.colors2.text.status.disabled
|
||||
else -> TangemTheme.colors2.text.neutral.primary
|
||||
}
|
||||
TangemButtonInternal(
|
||||
onClick = onClick,
|
||||
modifier = modifier
|
||||
.clip(shape.toShape(size))
|
||||
.then(backgroundModifier),
|
||||
text = text,
|
||||
contentColor = contentColor,
|
||||
enabled = enabled,
|
||||
size = size,
|
||||
state = state,
|
||||
iconPosition = iconPosition,
|
||||
iconRes = iconRes,
|
||||
)
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 480)
|
||||
@Preview(showBackground = true, widthDp = 480, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun PrimaryInverseTangemButton_Preview(
|
||||
@PreviewParameter(PrimaryInverseTangemButtonPreviewProvider::class) params: TangemButtonState,
|
||||
) {
|
||||
TangemThemePreviewRedesign {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(21.dp),
|
||||
modifier = Modifier
|
||||
.background(TangemTheme.colors2.surface.level2)
|
||||
.padding(8.dp),
|
||||
) {
|
||||
repeat(4) { yIndex ->
|
||||
val shape = if (yIndex < 2) TangemButtonShape.Default else TangemButtonShape.Rounded
|
||||
val text = if (yIndex % 2 == 1) null else stringReference("Button")
|
||||
Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
repeat(2) { xIndex ->
|
||||
val iconPosition = if (xIndex == 0) {
|
||||
TangemButtonIconPosition.Start
|
||||
} else {
|
||||
TangemButtonIconPosition.End
|
||||
}
|
||||
PrimaryInverseTangemButton(
|
||||
onClick = {},
|
||||
text = text,
|
||||
size = TangemButtonSize.X15,
|
||||
shape = shape,
|
||||
iconPosition = iconPosition,
|
||||
iconRes = R.drawable.ic_tangem_24,
|
||||
state = params,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class PrimaryInverseTangemButtonPreviewProvider : PreviewParameterProvider<TangemButtonState> {
|
||||
override val values: Sequence<TangemButtonState>
|
||||
get() = sequenceOf(
|
||||
TangemButtonState.Default,
|
||||
TangemButtonState.Pressed,
|
||||
TangemButtonState.Loading,
|
||||
TangemButtonState.Disabled,
|
||||
)
|
||||
}
|
||||
// endregion
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
package com.tangem.core.ui.ds.button
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
|
||||
/**
|
||||
* [Primary Tangem button](https://www.figma.com/design/RU7AIgwHtGdMfy83T5UOoR/Core-Library?node-id=5854-4732&t=euYo1qCxPlQl3Fa6-4)
|
||||
*
|
||||
* @param onClick Lambda to be invoked when the button is clicked.
|
||||
* @param modifier Modifier to be applied to the button.
|
||||
* @param text TextReference for the button label.
|
||||
* @param iconRes Drawable resource ID for the icon to be displayed in the button.
|
||||
* @param iconPosition Position of the icon (Start or End).
|
||||
* @param enabled Boolean indicating whether the button is enabled.
|
||||
* @param size TangemButtonSize defining the size of the button.
|
||||
* @param state TangemButtonState defining the current state of the button.
|
||||
* @param shape TangemButtonShape defining the shape of the button.
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Composable
|
||||
fun PrimaryTangemButton(
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
text: TextReference? = null,
|
||||
@DrawableRes iconRes: Int? = null,
|
||||
iconPosition: TangemButtonIconPosition = TangemButtonIconPosition.Start,
|
||||
enabled: Boolean = true,
|
||||
size: TangemButtonSize = TangemButtonSize.X15,
|
||||
state: TangemButtonState = TangemButtonState.Default,
|
||||
shape: TangemButtonShape = TangemButtonShape.Default,
|
||||
) {
|
||||
val backgroundModifier = when (state) {
|
||||
TangemButtonState.Loading,
|
||||
TangemButtonState.Default,
|
||||
-> Modifier.background(TangemTheme.colors2.button.backgroundPrimary)
|
||||
TangemButtonState.Disabled -> Modifier.background(TangemTheme.colors2.button.backgroundDisabled)
|
||||
TangemButtonState.Pressed -> Modifier
|
||||
.background(TangemTheme.colors2.button.backgroundPrimary)
|
||||
.background(TangemTheme.colors2.overlay.overlaySecondary)
|
||||
}
|
||||
val contentColor = when (state) {
|
||||
TangemButtonState.Disabled -> TangemTheme.colors2.text.status.disabled
|
||||
else -> TangemTheme.colors2.text.neutral.primaryInverted
|
||||
}
|
||||
TangemButtonInternal(
|
||||
onClick = onClick,
|
||||
modifier = modifier
|
||||
.clip(shape.toShape(size))
|
||||
.then(backgroundModifier),
|
||||
text = text,
|
||||
contentColor = contentColor,
|
||||
enabled = enabled,
|
||||
size = size,
|
||||
state = state,
|
||||
iconPosition = iconPosition,
|
||||
iconRes = iconRes,
|
||||
)
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 480)
|
||||
@Preview(showBackground = true, widthDp = 480, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun PrimaryTangemButton_Preview(
|
||||
@PreviewParameter(PrimaryTangemButtonPreviewProvider::class) params: TangemButtonState,
|
||||
) {
|
||||
TangemThemePreviewRedesign {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(21.dp),
|
||||
modifier = Modifier
|
||||
.background(TangemTheme.colors2.surface.level1)
|
||||
.padding(8.dp),
|
||||
) {
|
||||
repeat(4) { yIndex ->
|
||||
val shape = if (yIndex < 2) TangemButtonShape.Default else TangemButtonShape.Rounded
|
||||
val text = if (yIndex % 2 == 1) null else stringReference("Button")
|
||||
Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
repeat(TangemButtonIconPosition.entries.size) { xIndex ->
|
||||
PrimaryTangemButton(
|
||||
onClick = {},
|
||||
text = text,
|
||||
size = TangemButtonSize.X15,
|
||||
shape = shape,
|
||||
iconPosition = TangemButtonIconPosition.entries[xIndex],
|
||||
iconRes = R.drawable.ic_tangem_24,
|
||||
state = params,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class PrimaryTangemButtonPreviewProvider : PreviewParameterProvider<TangemButtonState> {
|
||||
override val values: Sequence<TangemButtonState>
|
||||
get() = sequenceOf(
|
||||
TangemButtonState.Default,
|
||||
TangemButtonState.Pressed,
|
||||
TangemButtonState.Loading,
|
||||
TangemButtonState.Disabled,
|
||||
)
|
||||
}
|
||||
// endregion
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
package com.tangem.core.ui.ds.button
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
|
||||
/**
|
||||
* [Secondary Tangem button](https://www.figma.com/design/RU7AIgwHtGdMfy83T5UOoR/Core-Library?node-id=5854-4796)
|
||||
*
|
||||
* @param onClick Lambda to be invoked when the button is clicked.
|
||||
* @param modifier Modifier to be applied to the button.
|
||||
* @param text TextReference for the button label.
|
||||
* @param iconRes Drawable resource ID for the icon to be displayed in the button.
|
||||
* @param iconPosition Position of the icon (Start or End).
|
||||
* @param enabled Boolean indicating whether the button is enabled.
|
||||
* @param size TangemButtonSize defining the size of the button.
|
||||
* @param state TangemButtonState defining the current state of the button.
|
||||
* @param shape TangemButtonShape defining the shape of the button.
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Composable
|
||||
fun SecondaryTangemButton(
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
text: TextReference? = null,
|
||||
@DrawableRes iconRes: Int? = null,
|
||||
iconPosition: TangemButtonIconPosition = TangemButtonIconPosition.Start,
|
||||
enabled: Boolean = true,
|
||||
size: TangemButtonSize = TangemButtonSize.X15,
|
||||
state: TangemButtonState = TangemButtonState.Default,
|
||||
shape: TangemButtonShape = TangemButtonShape.Default,
|
||||
) {
|
||||
val backgroundModifier = when (state) {
|
||||
TangemButtonState.Loading,
|
||||
TangemButtonState.Default,
|
||||
-> Modifier.background(TangemTheme.colors2.button.backgroundSecondary)
|
||||
TangemButtonState.Disabled -> Modifier.background(TangemTheme.colors2.button.backgroundDisabled)
|
||||
TangemButtonState.Pressed -> Modifier.background(TangemTheme.colors2.overlay.overlayPrimary)
|
||||
}
|
||||
val contentColor = when (state) {
|
||||
TangemButtonState.Disabled -> TangemTheme.colors2.text.status.disabled
|
||||
else -> TangemTheme.colors2.text.neutral.primary
|
||||
}
|
||||
TangemButtonInternal(
|
||||
onClick = onClick,
|
||||
modifier = modifier
|
||||
.clip(shape.toShape(size))
|
||||
.then(backgroundModifier),
|
||||
text = text,
|
||||
contentColor = contentColor,
|
||||
iconRes = iconRes,
|
||||
enabled = enabled,
|
||||
size = size,
|
||||
state = state,
|
||||
iconPosition = iconPosition,
|
||||
)
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 480)
|
||||
@Preview(showBackground = true, widthDp = 480, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun SecondaryTangemButton_Preview(
|
||||
@PreviewParameter(SecondaryTangemButtonPreviewProvider::class) params: TangemButtonState,
|
||||
) {
|
||||
TangemThemePreviewRedesign {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(21.dp),
|
||||
modifier = Modifier
|
||||
.background(TangemTheme.colors2.surface.level1)
|
||||
.padding(8.dp),
|
||||
) {
|
||||
repeat(4) { yIndex ->
|
||||
val shape = if (yIndex < 2) TangemButtonShape.Default else TangemButtonShape.Rounded
|
||||
val text = if (yIndex % 2 == 1) null else stringReference("Button")
|
||||
Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
repeat(2) { xIndex ->
|
||||
val iconPosition = if (xIndex == 0) {
|
||||
TangemButtonIconPosition.Start
|
||||
} else {
|
||||
TangemButtonIconPosition.End
|
||||
}
|
||||
SecondaryTangemButton(
|
||||
onClick = {},
|
||||
text = text,
|
||||
size = TangemButtonSize.X15,
|
||||
shape = shape,
|
||||
iconPosition = iconPosition,
|
||||
iconRes = R.drawable.ic_tangem_24,
|
||||
state = params,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SecondaryTangemButtonPreviewProvider : PreviewParameterProvider<TangemButtonState> {
|
||||
override val values: Sequence<TangemButtonState>
|
||||
get() = sequenceOf(
|
||||
TangemButtonState.Default,
|
||||
TangemButtonState.Pressed,
|
||||
TangemButtonState.Loading,
|
||||
TangemButtonState.Disabled,
|
||||
)
|
||||
}
|
||||
// endregion
|
||||
|
|
@ -0,0 +1,256 @@
|
|||
package com.tangem.core.ui.ds.button
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.TextAutoSize
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
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.StrokeCap
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.clickableSingle
|
||||
import com.tangem.core.ui.extensions.conditionalCompose
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.test.BaseButtonTestTags
|
||||
|
||||
/**
|
||||
* A customizable button component that supports text, icons, and different states.
|
||||
*
|
||||
* @param onClick Lambda to be invoked when the button is clicked.
|
||||
* @param modifier Modifier to be applied to the button.
|
||||
* @param text TextReference for the button label.
|
||||
* @param iconRes Drawable resource ID for the icon to be displayed in the button.
|
||||
* @param iconPosition Position of the icon (Start or End).
|
||||
* @param enabled Boolean indicating whether the button is enabled.
|
||||
* @param contentColor Color of the button content (text and icon).
|
||||
* @param size TangemButtonSize defining the size of the button.
|
||||
* @param state TangemButtonState defining the current state of the button.
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Composable
|
||||
internal fun TangemButtonInternal(
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
text: TextReference? = null,
|
||||
@DrawableRes iconRes: Int? = null,
|
||||
iconPosition: TangemButtonIconPosition = TangemButtonIconPosition.Start,
|
||||
enabled: Boolean = true,
|
||||
contentColor: Color = TangemTheme.colors2.text.neutral.primary,
|
||||
size: TangemButtonSize = TangemButtonSize.X15,
|
||||
state: TangemButtonState = TangemButtonState.Default,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.testTag(BaseButtonTestTags.BUTTON)
|
||||
.height(size.toHeightDp())
|
||||
.conditionalCompose(text == null) {
|
||||
width(size.toHeightDp())
|
||||
}
|
||||
.clickableSingle(enabled = enabled, onClick = onClick, role = Role.Button)
|
||||
.conditionalCompose(text != null) {
|
||||
padding(horizontal = size.toPaddingDp())
|
||||
}
|
||||
.animateContentSize(),
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp, Alignment.CenterHorizontally),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
AnimatedVisibility(
|
||||
visible = iconRes != null && iconPosition == TangemButtonIconPosition.Start,
|
||||
modifier = Modifier.size(size = size.toContentSize()),
|
||||
) {
|
||||
val wrappedIconRes = remember(this) { requireNotNull(iconRes) }
|
||||
TangemButtonIcon(iconRes = wrappedIconRes, state = state, iconColor = contentColor, size = size)
|
||||
}
|
||||
|
||||
AnimatedVisibility(text != null && state != TangemButtonState.Loading) {
|
||||
val wrappedText = remember(this) { requireNotNull(text) }
|
||||
val textStyle = size.toTextStyle()
|
||||
Text(
|
||||
text = wrappedText.resolveReference(),
|
||||
style = textStyle,
|
||||
color = contentColor,
|
||||
textAlign = TextAlign.Center,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
autoSize = TextAutoSize.StepBased(
|
||||
minFontSize = 12.sp,
|
||||
maxFontSize = textStyle.fontSize,
|
||||
),
|
||||
modifier = Modifier.testTag(BaseButtonTestTags.TEXT),
|
||||
)
|
||||
}
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = iconRes != null && iconPosition == TangemButtonIconPosition.End,
|
||||
modifier = Modifier.size(size = size.toContentSize()),
|
||||
) {
|
||||
val wrappedIconRes = remember(this) { requireNotNull(iconRes) }
|
||||
TangemButtonIcon(iconRes = wrappedIconRes, state = state, iconColor = contentColor, size = size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TangemButtonIcon(
|
||||
@DrawableRes iconRes: Int,
|
||||
iconColor: Color,
|
||||
state: TangemButtonState,
|
||||
size: TangemButtonSize,
|
||||
) {
|
||||
AnimatedContent(state) { targetState ->
|
||||
when (targetState) {
|
||||
TangemButtonState.Loading -> CircularProgressIndicator(
|
||||
color = iconColor,
|
||||
strokeWidth = 2.dp,
|
||||
strokeCap = StrokeCap.Round,
|
||||
modifier = Modifier.padding(
|
||||
when (size) {
|
||||
TangemButtonSize.X7,
|
||||
TangemButtonSize.X8,
|
||||
TangemButtonSize.X9,
|
||||
TangemButtonSize.X10,
|
||||
-> 0.5.dp
|
||||
TangemButtonSize.X12,
|
||||
TangemButtonSize.X15,
|
||||
-> 4.5.dp
|
||||
},
|
||||
),
|
||||
)
|
||||
else -> Icon(
|
||||
painter = painterResource(id = iconRes),
|
||||
contentDescription = null,
|
||||
tint = iconColor,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the shape of the Tangem button.
|
||||
*/
|
||||
enum class TangemButtonShape {
|
||||
Default,
|
||||
Rounded,
|
||||
;
|
||||
|
||||
@ReadOnlyComposable
|
||||
@Composable
|
||||
internal fun toShape(size: TangemButtonSize) = RoundedCornerShape(
|
||||
when (this) {
|
||||
Default -> size.toShapeRadius()
|
||||
Rounded -> 100.dp
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the size of the Tangem button.
|
||||
*/
|
||||
enum class TangemButtonSize {
|
||||
X7,
|
||||
X8,
|
||||
X9,
|
||||
X10,
|
||||
X12,
|
||||
X15,
|
||||
;
|
||||
|
||||
@ReadOnlyComposable
|
||||
@Composable
|
||||
internal fun toHeightDp() = when (this) {
|
||||
X7 -> TangemTheme.dimens2.x7
|
||||
X8 -> TangemTheme.dimens2.x8
|
||||
X9 -> TangemTheme.dimens2.x9
|
||||
X10 -> TangemTheme.dimens2.x10
|
||||
X12 -> TangemTheme.dimens2.x12
|
||||
X15 -> TangemTheme.dimens2.x15
|
||||
}
|
||||
|
||||
@ReadOnlyComposable
|
||||
@Composable
|
||||
internal fun toPaddingDp() = when (this) {
|
||||
X7 -> TangemTheme.dimens2.x2
|
||||
X8,
|
||||
X9,
|
||||
X10,
|
||||
-> TangemTheme.dimens2.x3
|
||||
X12,
|
||||
X15,
|
||||
-> TangemTheme.dimens2.x6
|
||||
}
|
||||
|
||||
@ReadOnlyComposable
|
||||
@Composable
|
||||
internal fun toContentSize() = when (this) {
|
||||
X7,
|
||||
X8,
|
||||
X9,
|
||||
X10,
|
||||
-> TangemTheme.dimens2.x5
|
||||
X12,
|
||||
X15,
|
||||
-> TangemTheme.dimens2.x7
|
||||
}
|
||||
|
||||
@ReadOnlyComposable
|
||||
@Composable
|
||||
internal fun toShapeRadius() = when (this) {
|
||||
X7,
|
||||
X8,
|
||||
X9,
|
||||
X10,
|
||||
-> TangemTheme.dimens2.x2
|
||||
X12 -> TangemTheme.dimens2.x3
|
||||
X15 -> TangemTheme.dimens2.x4
|
||||
}
|
||||
|
||||
@ReadOnlyComposable
|
||||
@Composable
|
||||
internal fun toTextStyle(): TextStyle = when (this) {
|
||||
X7 -> TangemTheme.typography2.bodyRegular14
|
||||
X8,
|
||||
X9,
|
||||
X10,
|
||||
X12,
|
||||
X15,
|
||||
-> TangemTheme.typography2.bodySemibold16
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the state of the Tangem button.
|
||||
*/
|
||||
enum class TangemButtonState {
|
||||
Default,
|
||||
Disabled,
|
||||
Pressed,
|
||||
Loading,
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the position of the icon in the Tangem button.
|
||||
*/
|
||||
enum class TangemButtonIconPosition {
|
||||
Start,
|
||||
End,
|
||||
}
|
||||
|
|
@ -54,23 +54,8 @@ fun Modifier.conditional(condition: Boolean, modifier: Modifier.() -> Modifier):
|
|||
@Composable
|
||||
fun Modifier.conditionalCompose(
|
||||
condition: Boolean,
|
||||
modifier: @Composable Modifier.() -> Modifier = { Modifier },
|
||||
): Modifier {
|
||||
return if (condition) {
|
||||
then(modifier(Modifier))
|
||||
} else {
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Conditionally applies a modifier based on a boolean condition.
|
||||
*/
|
||||
@Composable
|
||||
fun Modifier.conditionalCompose(
|
||||
condition: Boolean,
|
||||
modifier: @Composable Modifier.() -> Modifier = { Modifier },
|
||||
otherModifier: @Composable Modifier.() -> Modifier = { this },
|
||||
modifier: @Composable Modifier.() -> Modifier = { Modifier },
|
||||
): Modifier {
|
||||
return if (condition) {
|
||||
then(modifier(Modifier))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue