Updated on 2026-08-14
This commit is contained in:
parent
b97ea5faf8
commit
6145f3c5db
16 changed files with 716 additions and 478 deletions
|
|
@ -2,19 +2,17 @@ package com.tangem.core.ui.components
|
|||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButton
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButtonSize
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButtonsDefaults
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
// region TextButton
|
||||
|
|
@ -26,7 +24,7 @@ fun TextButton(text: String, onClick: () -> Unit, modifier: Modifier = Modifier,
|
|||
TangemButton(
|
||||
modifier = modifier,
|
||||
text = text,
|
||||
icon = TangemButtonIcon.None,
|
||||
icon = TangemButtonIconPosition.None,
|
||||
onClick = onClick,
|
||||
enabled = enabled,
|
||||
showProgress = false,
|
||||
|
|
@ -49,7 +47,7 @@ fun TextButtonIconStart(
|
|||
TangemButton(
|
||||
modifier = modifier,
|
||||
text = text,
|
||||
icon = TangemButtonIcon.Start(iconResId),
|
||||
icon = TangemButtonIconPosition.Start(iconResId),
|
||||
onClick = onClick,
|
||||
enabled = enabled,
|
||||
showProgress = false,
|
||||
|
|
@ -63,7 +61,7 @@ fun WarningTextButton(text: String, onClick: () -> Unit, modifier: Modifier = Mo
|
|||
TangemButton(
|
||||
modifier = modifier,
|
||||
text = text,
|
||||
icon = TangemButtonIcon.None,
|
||||
icon = TangemButtonIconPosition.None,
|
||||
onClick = onClick,
|
||||
enabled = enabled,
|
||||
showProgress = false,
|
||||
|
|
@ -85,7 +83,7 @@ fun PrimaryButton(
|
|||
TangemButton(
|
||||
modifier = modifier,
|
||||
text = text,
|
||||
icon = TangemButtonIcon.None,
|
||||
icon = TangemButtonIconPosition.None,
|
||||
onClick = onClick,
|
||||
colors = TangemButtonsDefaults.primaryButtonColors,
|
||||
enabled = enabled,
|
||||
|
|
@ -108,7 +106,7 @@ fun PrimaryButtonIconEnd(
|
|||
TangemButton(
|
||||
modifier = modifier,
|
||||
text = text,
|
||||
icon = TangemButtonIcon.End(iconResId),
|
||||
icon = TangemButtonIconPosition.End(iconResId),
|
||||
onClick = onClick,
|
||||
colors = TangemButtonsDefaults.primaryButtonColors,
|
||||
enabled = enabled,
|
||||
|
|
@ -131,7 +129,7 @@ fun PrimaryButtonIconStart(
|
|||
TangemButton(
|
||||
modifier = modifier,
|
||||
text = text,
|
||||
icon = TangemButtonIcon.Start(iconResId),
|
||||
icon = TangemButtonIconPosition.Start(iconResId),
|
||||
onClick = onClick,
|
||||
colors = TangemButtonsDefaults.primaryButtonColors,
|
||||
enabled = enabled,
|
||||
|
|
@ -152,7 +150,7 @@ fun SecondaryButton(
|
|||
TangemButton(
|
||||
modifier = modifier,
|
||||
text = text,
|
||||
icon = TangemButtonIcon.None,
|
||||
icon = TangemButtonIconPosition.None,
|
||||
onClick = onClick,
|
||||
colors = TangemButtonsDefaults.secondaryButtonColors,
|
||||
enabled = enabled,
|
||||
|
|
@ -175,7 +173,7 @@ fun SecondaryButtonIconEnd(
|
|||
TangemButton(
|
||||
modifier = modifier,
|
||||
text = text,
|
||||
icon = TangemButtonIcon.End(iconResId),
|
||||
icon = TangemButtonIconPosition.End(iconResId),
|
||||
onClick = onClick,
|
||||
colors = TangemButtonsDefaults.secondaryButtonColors,
|
||||
enabled = enabled,
|
||||
|
|
@ -198,7 +196,7 @@ fun SecondaryButtonIconStart(
|
|||
TangemButton(
|
||||
modifier = modifier,
|
||||
text = text,
|
||||
icon = TangemButtonIcon.Start(iconResId),
|
||||
icon = TangemButtonIconPosition.Start(iconResId),
|
||||
onClick = onClick,
|
||||
colors = TangemButtonsDefaults.secondaryButtonColors,
|
||||
enabled = enabled,
|
||||
|
|
@ -214,7 +212,7 @@ fun SelectorButton(text: String, onClick: () -> Unit, modifier: Modifier = Modif
|
|||
modifier = modifier,
|
||||
text = text,
|
||||
textStyle = TangemTheme.typography.subtitle2,
|
||||
icon = TangemButtonIcon.End(iconResId = R.drawable.ic_chevron_24),
|
||||
icon = TangemButtonIconPosition.End(iconResId = R.drawable.ic_chevron_24),
|
||||
onClick = onClick,
|
||||
colors = TangemButtonsDefaults.selectorButtonColors,
|
||||
showProgress = false,
|
||||
|
|
@ -224,362 +222,6 @@ fun SelectorButton(text: String, onClick: () -> Unit, modifier: Modifier = Modif
|
|||
}
|
||||
// endregion Other
|
||||
|
||||
// region Action
|
||||
|
||||
/**
|
||||
* [Show in Figma](https://www.figma.com/file/14ISV23YB1yVW1uNVwqrKv/Android?type=design&node-id=290-305&t=3z98eFnTeyIx5TH5-4)
|
||||
* */
|
||||
@Composable
|
||||
fun RoundedActionButton(
|
||||
text: String,
|
||||
@DrawableRes iconResId: Int,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true,
|
||||
) {
|
||||
TangemButton(
|
||||
modifier = modifier,
|
||||
text = text,
|
||||
icon = TangemButtonIcon.Start(iconResId),
|
||||
onClick = onClick,
|
||||
enabled = enabled,
|
||||
showProgress = false,
|
||||
colors = TangemButtonsDefaults.secondaryButtonColors,
|
||||
size = TangemButtonSize.RoundedAction,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* [Show in Figma](https://www.figma.com/file/14ISV23YB1yVW1uNVwqrKv/Android?type=design&node-id=1208-1395&t=3z98eFnTeyIx5TH5-4)
|
||||
* */
|
||||
@Composable
|
||||
fun ActionButton(
|
||||
text: String,
|
||||
@DrawableRes iconResId: Int,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true,
|
||||
) {
|
||||
TangemButton(
|
||||
modifier = modifier,
|
||||
text = text,
|
||||
icon = TangemButtonIcon.Start(iconResId),
|
||||
onClick = onClick,
|
||||
enabled = enabled,
|
||||
showProgress = false,
|
||||
colors = TangemButtonsDefaults.secondaryButtonColors,
|
||||
size = TangemButtonSize.Action,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as [RoundedActionButton] but colored in primary background color
|
||||
* */
|
||||
@Composable
|
||||
fun BackgroundActionButton(
|
||||
text: String,
|
||||
@DrawableRes iconResId: Int,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true,
|
||||
) {
|
||||
TangemButton(
|
||||
modifier = modifier,
|
||||
text = text,
|
||||
icon = TangemButtonIcon.Start(iconResId),
|
||||
onClick = onClick,
|
||||
enabled = enabled,
|
||||
showProgress = false,
|
||||
colors = TangemButtonsDefaults.backgroundButtonColors,
|
||||
size = TangemButtonSize.RoundedAction,
|
||||
)
|
||||
}
|
||||
// endregion Action
|
||||
|
||||
// region Defaults
|
||||
@Suppress("LongParameterList")
|
||||
@Composable
|
||||
private fun TangemButton(
|
||||
text: String,
|
||||
icon: TangemButtonIcon,
|
||||
onClick: () -> Unit,
|
||||
colors: ButtonColors,
|
||||
showProgress: Boolean,
|
||||
enabled: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
size: TangemButtonSize = TangemButtonSize.Default,
|
||||
elevation: ButtonElevation = TangemButtonsDefaults.elevation,
|
||||
textStyle: TextStyle = TangemTheme.typography.button,
|
||||
) {
|
||||
Button(
|
||||
modifier = modifier.heightIn(min = size.toHeightDp()),
|
||||
onClick = { if (!showProgress) onClick() },
|
||||
enabled = enabled,
|
||||
elevation = elevation,
|
||||
shape = size.toShape(),
|
||||
colors = colors,
|
||||
contentPadding = size.toContentPadding(icon = icon),
|
||||
) {
|
||||
ButtonContent(
|
||||
text = text,
|
||||
textStyle = textStyle,
|
||||
buttonIcon = icon,
|
||||
colors = colors,
|
||||
showProgress = showProgress,
|
||||
enabled = enabled,
|
||||
size = size,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@Composable
|
||||
private fun ButtonContent(
|
||||
text: String,
|
||||
textStyle: TextStyle,
|
||||
buttonIcon: TangemButtonIcon,
|
||||
colors: ButtonColors,
|
||||
size: TangemButtonSize,
|
||||
enabled: Boolean,
|
||||
showProgress: Boolean,
|
||||
) {
|
||||
val icon = @Composable { iconResId: Int ->
|
||||
Icon(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size20),
|
||||
painter = painterResource(id = iconResId),
|
||||
tint = colors.contentColor(enabled = enabled).value,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
||||
if (showProgress) {
|
||||
Box(modifier = Modifier.wrapContentSize()) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.size(TangemTheme.dimens.size24),
|
||||
color = colors.contentColor(enabled = enabled).value,
|
||||
strokeWidth = TangemTheme.dimens.size4,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(size.toIconPadding()),
|
||||
) {
|
||||
if (buttonIcon is TangemButtonIcon.Start) {
|
||||
icon(buttonIcon.iconResId)
|
||||
}
|
||||
Text(
|
||||
text = text,
|
||||
style = textStyle,
|
||||
color = colors.contentColor(enabled = enabled).value,
|
||||
maxLines = 1,
|
||||
)
|
||||
if (buttonIcon is TangemButtonIcon.End) {
|
||||
icon(buttonIcon.iconResId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
private sealed interface TangemButtonIcon {
|
||||
val iconResId: Int?
|
||||
|
||||
data class Start(override val iconResId: Int) : TangemButtonIcon
|
||||
|
||||
data class End(override val iconResId: Int) : TangemButtonIcon
|
||||
|
||||
object None : TangemButtonIcon {
|
||||
override val iconResId: Int? = null
|
||||
}
|
||||
}
|
||||
|
||||
private enum class TangemButtonSize {
|
||||
Default,
|
||||
Text,
|
||||
Selector,
|
||||
Action,
|
||||
RoundedAction,
|
||||
}
|
||||
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
private fun TangemButtonSize.toHeightDp(): Dp = when (this) {
|
||||
TangemButtonSize.Default -> TangemTheme.dimens.size48
|
||||
TangemButtonSize.Text -> TangemTheme.dimens.size40
|
||||
TangemButtonSize.Selector -> TangemTheme.dimens.size24
|
||||
TangemButtonSize.Action,
|
||||
TangemButtonSize.RoundedAction,
|
||||
-> TangemTheme.dimens.size36
|
||||
}
|
||||
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
private fun TangemButtonSize.toShape(): Shape = when (this) {
|
||||
TangemButtonSize.Default -> TangemTheme.shapes.roundedCornersMedium
|
||||
TangemButtonSize.Text -> TangemTheme.shapes.roundedCornersSmall
|
||||
TangemButtonSize.Selector -> TangemTheme.shapes.roundedCornersSmall
|
||||
TangemButtonSize.Action -> TangemTheme.shapes.roundedCornersMedium
|
||||
TangemButtonSize.RoundedAction -> TangemTheme.shapes.roundedCornersLarge
|
||||
}
|
||||
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
private fun TangemButtonSize.toIconPadding(): Dp = when (this) {
|
||||
TangemButtonSize.Default -> TangemTheme.dimens.spacing8
|
||||
TangemButtonSize.Text -> TangemTheme.dimens.spacing8
|
||||
TangemButtonSize.Selector -> 0.dp
|
||||
TangemButtonSize.Action,
|
||||
TangemButtonSize.RoundedAction,
|
||||
-> TangemTheme.dimens.spacing8
|
||||
}
|
||||
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
private fun TangemButtonSize.toContentPadding(icon: TangemButtonIcon): PaddingValues {
|
||||
val horizontalPadding = this.toHorizontalContentPadding(icon = icon)
|
||||
|
||||
return when (this) {
|
||||
TangemButtonSize.Default -> PaddingValues(
|
||||
top = TangemTheme.dimens.spacing14,
|
||||
bottom = TangemTheme.dimens.spacing14,
|
||||
start = horizontalPadding.first,
|
||||
end = horizontalPadding.second,
|
||||
)
|
||||
TangemButtonSize.Text -> PaddingValues(
|
||||
top = TangemTheme.dimens.spacing10,
|
||||
bottom = TangemTheme.dimens.spacing10,
|
||||
start = horizontalPadding.first,
|
||||
end = horizontalPadding.second,
|
||||
)
|
||||
TangemButtonSize.Selector -> PaddingValues(
|
||||
top = TangemTheme.dimens.spacing0_5,
|
||||
bottom = TangemTheme.dimens.spacing0_5,
|
||||
start = horizontalPadding.first,
|
||||
end = horizontalPadding.second,
|
||||
)
|
||||
TangemButtonSize.Action,
|
||||
TangemButtonSize.RoundedAction,
|
||||
-> PaddingValues(
|
||||
top = TangemTheme.dimens.spacing8,
|
||||
bottom = TangemTheme.dimens.spacing8,
|
||||
start = horizontalPadding.first,
|
||||
end = horizontalPadding.second,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
private fun TangemButtonSize.toHorizontalContentPadding(icon: TangemButtonIcon): Pair<Dp, Dp> {
|
||||
return when (this) {
|
||||
TangemButtonSize.Default -> TangemTheme.dimens.spacing32 to TangemTheme.dimens.spacing32
|
||||
TangemButtonSize.Text -> when (icon) {
|
||||
is TangemButtonIcon.None -> TangemTheme.dimens.spacing16 to TangemTheme.dimens.spacing16
|
||||
is TangemButtonIcon.Start -> TangemTheme.dimens.spacing14 to TangemTheme.dimens.spacing16
|
||||
is TangemButtonIcon.End -> TangemTheme.dimens.spacing16 to TangemTheme.dimens.spacing14
|
||||
}
|
||||
TangemButtonSize.Selector -> TangemTheme.dimens.spacing0_5 to TangemTheme.dimens.spacing0_5
|
||||
TangemButtonSize.Action,
|
||||
TangemButtonSize.RoundedAction,
|
||||
-> when (icon) {
|
||||
is TangemButtonIcon.None -> TangemTheme.dimens.spacing24 to TangemTheme.dimens.spacing24
|
||||
is TangemButtonIcon.Start -> TangemTheme.dimens.spacing16 to TangemTheme.dimens.spacing24
|
||||
is TangemButtonIcon.End -> TangemTheme.dimens.spacing24 to TangemTheme.dimens.spacing16
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private object TangemButtonsDefaults {
|
||||
val elevation: ButtonElevation
|
||||
@Composable get() = ButtonDefaults
|
||||
.elevation(
|
||||
defaultElevation = TangemTheme.dimens.elevation0,
|
||||
pressedElevation = TangemTheme.dimens.elevation0,
|
||||
)
|
||||
|
||||
val primaryButtonColors: ButtonColors
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
get() = TangemButtonColors(
|
||||
backgroundColor = TangemTheme.colors.button.primary,
|
||||
contentColor = TangemTheme.colors.text.primary2,
|
||||
disabledBackgroundColor = TangemTheme.colors.button.disabled,
|
||||
disabledContentColor = TangemTheme.colors.text.disabled,
|
||||
)
|
||||
|
||||
val secondaryButtonColors: ButtonColors
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
get() = TangemButtonColors(
|
||||
backgroundColor = TangemTheme.colors.button.secondary,
|
||||
contentColor = TangemTheme.colors.text.primary1,
|
||||
disabledBackgroundColor = TangemTheme.colors.button.disabled,
|
||||
disabledContentColor = TangemTheme.colors.text.disabled,
|
||||
)
|
||||
|
||||
val defaultTextButtonColors: ButtonColors
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
get() = TangemButtonColors(
|
||||
backgroundColor = Color.Transparent,
|
||||
contentColor = TangemTheme.colors.text.secondary,
|
||||
disabledBackgroundColor = Color.Transparent,
|
||||
disabledContentColor = TangemTheme.colors.text.disabled,
|
||||
)
|
||||
|
||||
val warningTextButtonColors: ButtonColors
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
get() = TangemButtonColors(
|
||||
backgroundColor = Color.Transparent,
|
||||
contentColor = TangemTheme.colors.text.warning,
|
||||
disabledBackgroundColor = Color.Transparent,
|
||||
disabledContentColor = TangemTheme.colors.text.disabled,
|
||||
)
|
||||
|
||||
val selectorButtonColors: ButtonColors
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
get() = TangemButtonColors(
|
||||
backgroundColor = Color.Transparent,
|
||||
contentColor = TangemTheme.colors.text.tertiary,
|
||||
disabledBackgroundColor = Color.Transparent,
|
||||
disabledContentColor = TangemTheme.colors.text.disabled,
|
||||
)
|
||||
|
||||
val backgroundButtonColors: ButtonColors
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
get() = TangemButtonColors(
|
||||
backgroundColor = TangemTheme.colors.background.primary,
|
||||
contentColor = TangemTheme.colors.text.primary1,
|
||||
disabledBackgroundColor = TangemTheme.colors.button.disabled,
|
||||
disabledContentColor = TangemTheme.colors.text.disabled,
|
||||
)
|
||||
}
|
||||
|
||||
@Immutable
|
||||
private open class TangemButtonColors(
|
||||
private val backgroundColor: Color,
|
||||
private val contentColor: Color,
|
||||
private val disabledBackgroundColor: Color,
|
||||
private val disabledContentColor: Color,
|
||||
) : ButtonColors {
|
||||
@Composable
|
||||
override fun backgroundColor(enabled: Boolean): State<Color> {
|
||||
return rememberUpdatedState(newValue = if (enabled) backgroundColor else disabledBackgroundColor)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun contentColor(enabled: Boolean): State<Color> {
|
||||
return rememberUpdatedState(newValue = if (enabled) contentColor else disabledContentColor)
|
||||
}
|
||||
}
|
||||
// endregion Defaults
|
||||
|
||||
// region Preview
|
||||
@Composable
|
||||
private fun PrimaryButtonSample() {
|
||||
|
|
@ -730,34 +372,4 @@ private fun TextButtonPreview_DarkTheme() {
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ActionButtonSample() {
|
||||
Column(
|
||||
modifier = Modifier.background(TangemTheme.colors.background.primary),
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
|
||||
) {
|
||||
RoundedActionButton(text = "Send", iconResId = R.drawable.ic_arrow_up_24, onClick = { })
|
||||
ActionButton(text = "Send", iconResId = R.drawable.ic_arrow_up_24, onClick = { })
|
||||
BackgroundActionButton(text = "Send", iconResId = R.drawable.ic_arrow_up_24, onClick = { })
|
||||
RoundedActionButton(text = "Send", iconResId = R.drawable.ic_arrow_up_24, enabled = false, onClick = { })
|
||||
ActionButton(text = "Send", iconResId = R.drawable.ic_arrow_up_24, enabled = false, onClick = { })
|
||||
BackgroundActionButton(text = "Send", iconResId = R.drawable.ic_arrow_up_24, enabled = false, onClick = { })
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Composable
|
||||
private fun ActionButtonPreview_LightTheme() {
|
||||
TangemTheme {
|
||||
ActionButtonSample()
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Composable
|
||||
private fun ActionButtonPreview_DarkTheme() {
|
||||
TangemTheme(isDark = true) {
|
||||
ActionButtonSample()
|
||||
}
|
||||
}
|
||||
// endregion Preview
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.core.ui.components.buttons.actions
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
|
||||
/**
|
||||
* Action button config
|
||||
*
|
||||
* @property text text
|
||||
* @property iconResId icon resource id
|
||||
* @property onClick lambda be invoked when action component is clicked
|
||||
* @property enabled enabled
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
data class ActionConfig(
|
||||
val text: String,
|
||||
@DrawableRes val iconResId: Int,
|
||||
val onClick: () -> Unit,
|
||||
val enabled: Boolean = true,
|
||||
)
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
package com.tangem.core.ui.components.buttons.actions
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
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.datasource.CollectionPreviewParameterProvider
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButton
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButtonSize
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButtonsDefaults
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
/**
|
||||
* [Show in Figma](https://www.figma.com/file/14ISV23YB1yVW1uNVwqrKv/Android?type=design&node-id=290-305&t=3z98eFnTeyIx5TH5-4)
|
||||
*/
|
||||
@Composable
|
||||
fun RoundedActionButton(config: ActionConfig, modifier: Modifier = Modifier) {
|
||||
TangemButton(
|
||||
modifier = modifier,
|
||||
text = config.text,
|
||||
icon = TangemButtonIconPosition.Start(config.iconResId),
|
||||
onClick = config.onClick,
|
||||
enabled = config.enabled,
|
||||
showProgress = false,
|
||||
colors = TangemButtonsDefaults.secondaryButtonColors,
|
||||
size = TangemButtonSize.RoundedAction,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* [Show in Figma](https://www.figma.com/file/14ISV23YB1yVW1uNVwqrKv/Android?type=design&node-id=1208-1395&t=3z98eFnTeyIx5TH5-4)
|
||||
*/
|
||||
@Composable
|
||||
fun ActionButton(config: ActionConfig, modifier: Modifier = Modifier) {
|
||||
TangemButton(
|
||||
modifier = modifier,
|
||||
text = config.text,
|
||||
icon = TangemButtonIconPosition.Start(config.iconResId),
|
||||
onClick = config.onClick,
|
||||
enabled = config.enabled,
|
||||
showProgress = false,
|
||||
colors = TangemButtonsDefaults.secondaryButtonColors,
|
||||
size = TangemButtonSize.Action,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as [RoundedActionButton] but colored in primary background color
|
||||
*/
|
||||
@Composable
|
||||
fun BackgroundActionButton(config: ActionConfig, modifier: Modifier = Modifier) {
|
||||
TangemButton(
|
||||
modifier = modifier,
|
||||
text = config.text,
|
||||
icon = TangemButtonIconPosition.Start(config.iconResId),
|
||||
onClick = config.onClick,
|
||||
enabled = config.enabled,
|
||||
showProgress = false,
|
||||
colors = TangemButtonsDefaults.backgroundButtonColors,
|
||||
size = TangemButtonSize.RoundedAction,
|
||||
)
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun Preview_ActionButton_Light(@PreviewParameter(ActionStateProvider::class) state: ActionConfig) {
|
||||
TangemTheme(isDark = false) {
|
||||
Column {
|
||||
RoundedActionButton(state)
|
||||
ActionButton(state)
|
||||
BackgroundActionButton(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun Preview_ActionButton_Dark(@PreviewParameter(ActionStateProvider::class) state: ActionConfig) {
|
||||
TangemTheme {
|
||||
Column {
|
||||
RoundedActionButton(state)
|
||||
ActionButton(state)
|
||||
BackgroundActionButton(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ActionStateProvider : CollectionPreviewParameterProvider<ActionConfig>(
|
||||
collection = listOf(
|
||||
ActionConfig(text = "Send", iconResId = R.drawable.ic_arrow_up_24, onClick = {}),
|
||||
ActionConfig(text = "Receive", iconResId = R.drawable.ic_arrow_down_24, enabled = false, onClick = {}),
|
||||
),
|
||||
)
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
package com.tangem.core.ui.components.buttons.common
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@Composable
|
||||
internal fun TangemButton(
|
||||
text: String,
|
||||
icon: TangemButtonIconPosition,
|
||||
onClick: () -> Unit,
|
||||
colors: ButtonColors,
|
||||
showProgress: Boolean,
|
||||
enabled: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
size: TangemButtonSize = TangemButtonSize.Default,
|
||||
elevation: ButtonElevation = TangemButtonsDefaults.elevation,
|
||||
textStyle: TextStyle = TangemTheme.typography.button,
|
||||
) {
|
||||
Button(
|
||||
modifier = modifier.heightIn(min = size.toHeightDp()),
|
||||
onClick = { if (!showProgress) onClick() },
|
||||
enabled = enabled,
|
||||
elevation = elevation,
|
||||
shape = size.toShape(),
|
||||
colors = colors,
|
||||
contentPadding = size.toContentPadding(icon = icon),
|
||||
) {
|
||||
ButtonContent(
|
||||
text = text,
|
||||
textStyle = textStyle,
|
||||
buttonIcon = icon,
|
||||
colors = colors,
|
||||
showProgress = showProgress,
|
||||
enabled = enabled,
|
||||
size = size,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@Composable
|
||||
private fun ButtonContent(
|
||||
text: String,
|
||||
textStyle: TextStyle,
|
||||
buttonIcon: TangemButtonIconPosition,
|
||||
colors: ButtonColors,
|
||||
size: TangemButtonSize,
|
||||
enabled: Boolean,
|
||||
showProgress: Boolean,
|
||||
) {
|
||||
val icon = @Composable { iconResId: Int ->
|
||||
Icon(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size20),
|
||||
painter = painterResource(id = iconResId),
|
||||
tint = colors.contentColor(enabled = enabled).value,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
||||
if (showProgress) {
|
||||
Box(modifier = Modifier.wrapContentSize()) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.size(TangemTheme.dimens.size24),
|
||||
color = colors.contentColor(enabled = enabled).value,
|
||||
strokeWidth = TangemTheme.dimens.size4,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(size.toIconPadding()),
|
||||
) {
|
||||
if (buttonIcon is TangemButtonIconPosition.Start) {
|
||||
icon(buttonIcon.iconResId)
|
||||
}
|
||||
Text(
|
||||
text = text,
|
||||
style = textStyle,
|
||||
color = colors.contentColor(enabled = enabled).value,
|
||||
maxLines = 1,
|
||||
)
|
||||
if (buttonIcon is TangemButtonIconPosition.End) {
|
||||
icon(buttonIcon.iconResId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.tangem.core.ui.components.buttons.common
|
||||
|
||||
import androidx.compose.material.ButtonColors
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
internal class TangemButtonColors(
|
||||
private val backgroundColor: Color,
|
||||
private val contentColor: Color,
|
||||
private val disabledBackgroundColor: Color,
|
||||
private val disabledContentColor: Color,
|
||||
) : ButtonColors {
|
||||
|
||||
@Composable
|
||||
override fun backgroundColor(enabled: Boolean): State<Color> {
|
||||
return rememberUpdatedState(newValue = if (enabled) backgroundColor else disabledBackgroundColor)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun contentColor(enabled: Boolean): State<Color> {
|
||||
return rememberUpdatedState(newValue = if (enabled) contentColor else disabledContentColor)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.tangem.core.ui.components.buttons.common
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
|
||||
internal sealed interface TangemButtonIconPosition {
|
||||
val iconResId: Int?
|
||||
|
||||
data class Start(@DrawableRes override val iconResId: Int) : TangemButtonIconPosition
|
||||
|
||||
data class End(@DrawableRes override val iconResId: Int) : TangemButtonIconPosition
|
||||
|
||||
object None : TangemButtonIconPosition {
|
||||
@DrawableRes
|
||||
override val iconResId: Int? = null
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
package com.tangem.core.ui.components.buttons.common
|
||||
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
internal enum class TangemButtonSize {
|
||||
Default,
|
||||
Text,
|
||||
Selector,
|
||||
Action,
|
||||
RoundedAction,
|
||||
}
|
||||
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
internal fun TangemButtonSize.toHeightDp(): Dp = when (this) {
|
||||
TangemButtonSize.Default -> TangemTheme.dimens.size48
|
||||
TangemButtonSize.Text -> TangemTheme.dimens.size40
|
||||
TangemButtonSize.Selector -> TangemTheme.dimens.size24
|
||||
TangemButtonSize.Action,
|
||||
TangemButtonSize.RoundedAction,
|
||||
-> TangemTheme.dimens.size36
|
||||
}
|
||||
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
internal fun TangemButtonSize.toShape(): Shape = when (this) {
|
||||
TangemButtonSize.Default -> TangemTheme.shapes.roundedCornersMedium
|
||||
TangemButtonSize.Text -> TangemTheme.shapes.roundedCornersSmall
|
||||
TangemButtonSize.Selector -> TangemTheme.shapes.roundedCornersSmall
|
||||
TangemButtonSize.Action -> TangemTheme.shapes.roundedCornersMedium
|
||||
TangemButtonSize.RoundedAction -> TangemTheme.shapes.roundedCornersLarge
|
||||
}
|
||||
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
internal fun TangemButtonSize.toIconPadding(): Dp = when (this) {
|
||||
TangemButtonSize.Default -> TangemTheme.dimens.spacing8
|
||||
TangemButtonSize.Text -> TangemTheme.dimens.spacing8
|
||||
TangemButtonSize.Selector -> 0.dp
|
||||
TangemButtonSize.Action,
|
||||
TangemButtonSize.RoundedAction,
|
||||
-> TangemTheme.dimens.spacing8
|
||||
}
|
||||
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
internal fun TangemButtonSize.toContentPadding(icon: TangemButtonIconPosition): PaddingValues {
|
||||
val horizontalPadding = this.toHorizontalContentPadding(icon = icon)
|
||||
|
||||
return when (this) {
|
||||
TangemButtonSize.Default -> PaddingValues(
|
||||
top = TangemTheme.dimens.spacing14,
|
||||
bottom = TangemTheme.dimens.spacing14,
|
||||
start = horizontalPadding.first,
|
||||
end = horizontalPadding.second,
|
||||
)
|
||||
TangemButtonSize.Text -> PaddingValues(
|
||||
top = TangemTheme.dimens.spacing10,
|
||||
bottom = TangemTheme.dimens.spacing10,
|
||||
start = horizontalPadding.first,
|
||||
end = horizontalPadding.second,
|
||||
)
|
||||
TangemButtonSize.Selector -> PaddingValues(
|
||||
top = TangemTheme.dimens.spacing0_5,
|
||||
bottom = TangemTheme.dimens.spacing0_5,
|
||||
start = horizontalPadding.first,
|
||||
end = horizontalPadding.second,
|
||||
)
|
||||
TangemButtonSize.Action,
|
||||
TangemButtonSize.RoundedAction,
|
||||
-> PaddingValues(
|
||||
top = TangemTheme.dimens.spacing8,
|
||||
bottom = TangemTheme.dimens.spacing8,
|
||||
start = horizontalPadding.first,
|
||||
end = horizontalPadding.second,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
internal fun TangemButtonSize.toHorizontalContentPadding(icon: TangemButtonIconPosition): Pair<Dp, Dp> {
|
||||
return when (this) {
|
||||
TangemButtonSize.Default -> TangemTheme.dimens.spacing32 to TangemTheme.dimens.spacing32
|
||||
TangemButtonSize.Text -> when (icon) {
|
||||
is TangemButtonIconPosition.None -> TangemTheme.dimens.spacing16 to TangemTheme.dimens.spacing16
|
||||
is TangemButtonIconPosition.Start -> TangemTheme.dimens.spacing14 to TangemTheme.dimens.spacing16
|
||||
is TangemButtonIconPosition.End -> TangemTheme.dimens.spacing16 to TangemTheme.dimens.spacing14
|
||||
}
|
||||
TangemButtonSize.Selector -> TangemTheme.dimens.spacing0_5 to TangemTheme.dimens.spacing0_5
|
||||
TangemButtonSize.Action,
|
||||
TangemButtonSize.RoundedAction,
|
||||
-> when (icon) {
|
||||
is TangemButtonIconPosition.None -> TangemTheme.dimens.spacing24 to TangemTheme.dimens.spacing24
|
||||
is TangemButtonIconPosition.Start -> TangemTheme.dimens.spacing16 to TangemTheme.dimens.spacing24
|
||||
is TangemButtonIconPosition.End -> TangemTheme.dimens.spacing24 to TangemTheme.dimens.spacing16
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
package com.tangem.core.ui.components.buttons.common
|
||||
|
||||
import androidx.compose.material.ButtonColors
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.ButtonElevation
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
internal object TangemButtonsDefaults {
|
||||
|
||||
val elevation: ButtonElevation
|
||||
@Composable get() = ButtonDefaults.elevation(
|
||||
defaultElevation = TangemTheme.dimens.elevation0,
|
||||
pressedElevation = TangemTheme.dimens.elevation0,
|
||||
)
|
||||
|
||||
val primaryButtonColors: ButtonColors
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
get() = TangemButtonColors(
|
||||
backgroundColor = TangemTheme.colors.button.primary,
|
||||
contentColor = TangemTheme.colors.text.primary2,
|
||||
disabledBackgroundColor = TangemTheme.colors.button.disabled,
|
||||
disabledContentColor = TangemTheme.colors.text.disabled,
|
||||
)
|
||||
|
||||
val secondaryButtonColors: ButtonColors
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
get() = TangemButtonColors(
|
||||
backgroundColor = TangemTheme.colors.button.secondary,
|
||||
contentColor = TangemTheme.colors.text.primary1,
|
||||
disabledBackgroundColor = TangemTheme.colors.button.disabled,
|
||||
disabledContentColor = TangemTheme.colors.text.disabled,
|
||||
)
|
||||
|
||||
val defaultTextButtonColors: ButtonColors
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
get() = TangemButtonColors(
|
||||
backgroundColor = Color.Transparent,
|
||||
contentColor = TangemTheme.colors.text.secondary,
|
||||
disabledBackgroundColor = Color.Transparent,
|
||||
disabledContentColor = TangemTheme.colors.text.disabled,
|
||||
)
|
||||
|
||||
val warningTextButtonColors: ButtonColors
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
get() = TangemButtonColors(
|
||||
backgroundColor = Color.Transparent,
|
||||
contentColor = TangemTheme.colors.text.warning,
|
||||
disabledBackgroundColor = Color.Transparent,
|
||||
disabledContentColor = TangemTheme.colors.text.disabled,
|
||||
)
|
||||
|
||||
val selectorButtonColors: ButtonColors
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
get() = TangemButtonColors(
|
||||
backgroundColor = Color.Transparent,
|
||||
contentColor = TangemTheme.colors.text.tertiary,
|
||||
disabledBackgroundColor = Color.Transparent,
|
||||
disabledContentColor = TangemTheme.colors.text.disabled,
|
||||
)
|
||||
|
||||
val backgroundButtonColors: ButtonColors
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
get() = TangemButtonColors(
|
||||
backgroundColor = TangemTheme.colors.background.primary,
|
||||
contentColor = TangemTheme.colors.text.primary1,
|
||||
disabledBackgroundColor = TangemTheme.colors.button.disabled,
|
||||
disabledContentColor = TangemTheme.colors.text.disabled,
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue