Updated on 2026-08-14
This commit is contained in:
commit
9abedff8b5
80 changed files with 1567 additions and 3658 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
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
package com.tangem.core.ui.components
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
/**
|
||||
* Closable notification with custom icon
|
||||
* Child of parent component
|
||||
* @see <a href = "https://www.figma.com/file/14ISV23YB1yVW1uNVwqrKv/Android?node-id=1045-807&t=6CVvYDJe0sB7wBKE-0">Figma component</a>
|
||||
*
|
||||
* Use to show banner with custom icon and possibility to close
|
||||
* i.e. Feedback notification
|
||||
*
|
||||
* @param title notification title
|
||||
* @param icon drawable res on icon
|
||||
* @param iconColor icon color
|
||||
* @param onClick callback on click
|
||||
* @param onCloseClick callback on close icon click
|
||||
*/
|
||||
@Composable
|
||||
fun ClosableNotification(
|
||||
title: String,
|
||||
@DrawableRes icon: Int,
|
||||
iconColor: Color,
|
||||
onClick: (() -> Unit),
|
||||
onCloseClick: (() -> Unit),
|
||||
) {
|
||||
NotificationCardTemplate(onClick) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens.size20)
|
||||
.align(Alignment.CenterStart),
|
||||
painter = painterResource(id = icon),
|
||||
tint = iconColor,
|
||||
contentDescription = null,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing28)
|
||||
.align(Alignment.CenterStart),
|
||||
text = title,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
)
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens.size20)
|
||||
.align(Alignment.CenterEnd)
|
||||
.clickable(onClick = onCloseClick),
|
||||
painter = painterResource(id = R.drawable.ic_close_24),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors.icon.informative,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification component from Design system
|
||||
* There are few states for this component, but only one parent, see link below
|
||||
*
|
||||
* Use this for Notification with title, subtitle, clickable or not
|
||||
*
|
||||
* @param title notification title
|
||||
* @param subtitle notification subtitle
|
||||
* @param onClick click on notification, if its null then no chevron icon
|
||||
*
|
||||
* @see <a href = "https://www.figma.com/file/14ISV23YB1yVW1uNVwqrKv/Android?node-id=1045-807&t=6CVvYDJe0sB7wBKE-0">Figma component</a>
|
||||
*/
|
||||
@Composable
|
||||
fun WarningNotification(title: String, subtitle: String?, onClick: (() -> Unit)?) {
|
||||
NotificationCardTemplate(onClick) {
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens.size20)
|
||||
.align(Alignment.CenterStart),
|
||||
painter = painterResource(id = R.drawable.img_attention_20),
|
||||
contentDescription = null,
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing28)
|
||||
.align(Alignment.CenterStart),
|
||||
) {
|
||||
Text(
|
||||
text = title,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
)
|
||||
if (!subtitle.isNullOrEmpty()) {
|
||||
SpacerH2()
|
||||
Text(
|
||||
text = subtitle,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
style = TangemTheme.typography.caption,
|
||||
)
|
||||
}
|
||||
}
|
||||
if (onClick != null) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens.size20)
|
||||
.align(Alignment.CenterEnd),
|
||||
painter = painterResource(id = R.drawable.ic_chevron_right_24),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors.icon.informative,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
private fun NotificationCardTemplate(onClick: (() -> Unit)? = null, content: @Composable BoxScope.() -> Unit) {
|
||||
Surface(
|
||||
color = TangemTheme.colors.button.secondary,
|
||||
shape = RoundedCornerShape(TangemTheme.dimens.radius18),
|
||||
onClick = onClick ?: {},
|
||||
enabled = onClick != null,
|
||||
) {
|
||||
Box(
|
||||
Modifier
|
||||
.padding(
|
||||
horizontal = TangemTheme.dimens.spacing12,
|
||||
vertical = TangemTheme.dimens.spacing8,
|
||||
)
|
||||
.wrapContentSize(),
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// region Preview
|
||||
|
||||
@Composable
|
||||
private fun WarningNotificationPreview() {
|
||||
Column(modifier = Modifier.fillMaxWidth()) {
|
||||
WarningNotification(
|
||||
title = "Your wallet hasn’t been backed up",
|
||||
subtitle = "Lorem ipsum dolor sit amet, consectetur " +
|
||||
"adipiscing elit, sed do eiusmod tempor incididunt ut labore et...",
|
||||
onClick = {},
|
||||
)
|
||||
SpacerH32()
|
||||
WarningNotification(
|
||||
title = "Your wallet hasn’t been backed up",
|
||||
subtitle = null,
|
||||
onClick = {},
|
||||
)
|
||||
SpacerH32()
|
||||
WarningNotification(
|
||||
title = "Your wallet hasn’t been backed up",
|
||||
subtitle = "Lorem ipsum dolor sit amet, consectetur " +
|
||||
"adipiscing elit, sed do eiusmod tempor incididunt ut labore et...",
|
||||
onClick = null,
|
||||
)
|
||||
SpacerH32()
|
||||
WarningNotification(
|
||||
title = "Your wallet hasn’t been backed up",
|
||||
subtitle = null,
|
||||
onClick = null,
|
||||
)
|
||||
SpacerH32()
|
||||
ClosableNotification(
|
||||
title = "Like tangem app?",
|
||||
icon = R.drawable.ic_star_24,
|
||||
iconColor = TangemTheme.colors.icon.attention,
|
||||
onClick = {},
|
||||
onCloseClick = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun Preview_WarningNotification_InLightTheme() {
|
||||
TangemTheme(isDark = false) {
|
||||
WarningNotificationPreview()
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun Preview_WarningNotification_InDarkTheme() {
|
||||
TangemTheme(isDark = true) {
|
||||
WarningNotificationPreview()
|
||||
}
|
||||
}
|
||||
|
||||
// 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,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
package com.tangem.core.ui.components.notifications
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
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.SpacerH2
|
||||
import com.tangem.core.ui.res.TangemColorPalette
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
/**
|
||||
* Notification component from Design system.
|
||||
* Use this for Notification with title, subtitle, clickable or not.
|
||||
*
|
||||
* @param state component state
|
||||
* @param modifier modifier
|
||||
*
|
||||
* @see <a href = "https://www.figma.com/file/14ISV23YB1yVW1uNVwqrKv/Android?node-id=1045-807&t=6CVvYDJe0sB7wBKE-0"
|
||||
* >Figma component</a>
|
||||
*/
|
||||
@Composable
|
||||
fun Notification(state: NotificationState, modifier: Modifier = Modifier) {
|
||||
Surface(
|
||||
onClick = if (state is NotificationState.Action) {
|
||||
state.onClick
|
||||
} else {
|
||||
{}
|
||||
},
|
||||
modifier = modifier,
|
||||
enabled = when (state) {
|
||||
is NotificationState.Simple -> false
|
||||
is NotificationState.Action -> true
|
||||
},
|
||||
shape = RoundedCornerShape(TangemTheme.dimens.radius18),
|
||||
color = TangemTheme.colors.button.secondary,
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = TangemTheme.dimens.spacing12, vertical = TangemTheme.dimens.spacing8),
|
||||
) {
|
||||
NotificationIcon(
|
||||
iconResId = state.iconResId,
|
||||
iconTint = state.tint,
|
||||
modifier = Modifier
|
||||
.size(size = TangemTheme.dimens.size20)
|
||||
.align(alignment = Alignment.CenterStart),
|
||||
)
|
||||
|
||||
NotificationInfoBlock(
|
||||
title = state.title,
|
||||
subtitle = state.subtitle,
|
||||
modifier = Modifier.align(alignment = Alignment.CenterStart),
|
||||
)
|
||||
|
||||
if (state is NotificationState.Action) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.size(size = TangemTheme.dimens.size20)
|
||||
.align(alignment = Alignment.CenterEnd),
|
||||
painter = painterResource(id = R.drawable.ic_chevron_right_24),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors.icon.informative,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NotificationIcon(@DrawableRes iconResId: Int, iconTint: Color?, modifier: Modifier = Modifier) {
|
||||
if (iconTint != null) {
|
||||
Icon(
|
||||
painter = painterResource(id = iconResId),
|
||||
contentDescription = null,
|
||||
modifier = modifier,
|
||||
tint = iconTint,
|
||||
)
|
||||
} else {
|
||||
Image(
|
||||
painter = painterResource(id = iconResId),
|
||||
contentDescription = null,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NotificationInfoBlock(title: String, subtitle: String?, modifier: Modifier = Modifier) {
|
||||
Column(modifier = modifier.padding(horizontal = TangemTheme.dimens.spacing30)) {
|
||||
Text(
|
||||
text = title,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.body2,
|
||||
)
|
||||
|
||||
if (!subtitle.isNullOrEmpty()) {
|
||||
SpacerH2()
|
||||
Text(
|
||||
text = subtitle,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
style = TangemTheme.typography.caption,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun Preview_WarningNotification_Light(
|
||||
@PreviewParameter(NotificationStateProvider::class)
|
||||
state: NotificationState,
|
||||
) {
|
||||
TangemTheme(isDark = false) {
|
||||
Notification(state)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun Preview_WarningNotification_Dark(
|
||||
@PreviewParameter(NotificationStateProvider::class)
|
||||
state: NotificationState,
|
||||
) {
|
||||
TangemTheme(isDark = true) {
|
||||
Notification(state)
|
||||
}
|
||||
}
|
||||
|
||||
private class NotificationStateProvider : CollectionPreviewParameterProvider<NotificationState>(
|
||||
collection = listOf(
|
||||
NotificationState.Simple(
|
||||
title = "Your wallet hasn’t been backed up",
|
||||
subtitle = "Lorem ipsum dolor sit amet, consectetur " +
|
||||
"adipiscing elit, sed do eiusmod tempor incididunt ut labore et...",
|
||||
iconResId = R.drawable.img_attention_20,
|
||||
),
|
||||
NotificationState.Simple(
|
||||
title = "Your wallet hasn’t been backed up",
|
||||
subtitle = null,
|
||||
iconResId = R.drawable.ic_alert_circle_24,
|
||||
tint = TangemColorPalette.Amaranth,
|
||||
),
|
||||
NotificationState.Action(
|
||||
title = "Your wallet hasn’t been backed up",
|
||||
subtitle = "Lorem ipsum dolor sit amet, consectetur " +
|
||||
"adipiscing elit, sed do eiusmod tempor incididunt ut labore et...",
|
||||
iconResId = R.drawable.img_attention_20,
|
||||
onClick = {},
|
||||
),
|
||||
NotificationState.Action(
|
||||
title = "Your wallet hasn’t been backed up",
|
||||
subtitle = null,
|
||||
iconResId = R.drawable.ic_alert_circle_24,
|
||||
tint = TangemColorPalette.Amaranth,
|
||||
onClick = {},
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
package com.tangem.core.ui.components.notifications
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
/**
|
||||
* Notification component state
|
||||
*
|
||||
* @property title title
|
||||
* @property subtitle subtitle
|
||||
* @property iconResId icon resource id
|
||||
* @property tint icon tint
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
sealed class NotificationState(
|
||||
open val title: String,
|
||||
open val subtitle: String? = null,
|
||||
@DrawableRes open val iconResId: Int,
|
||||
open val tint: Color? = null,
|
||||
) {
|
||||
|
||||
/**
|
||||
* Simple notification state. Non clickable.
|
||||
*
|
||||
* @property title title
|
||||
* @property subtitle subtitle
|
||||
* @property iconResId icon resource id
|
||||
* @property tint icon tint
|
||||
*/
|
||||
data class Simple(
|
||||
override val title: String,
|
||||
override val subtitle: String? = null,
|
||||
@DrawableRes override val iconResId: Int,
|
||||
override val tint: Color? = null,
|
||||
) : NotificationState(title, subtitle, iconResId, tint)
|
||||
|
||||
/**
|
||||
* Clickable notification state
|
||||
*
|
||||
* @property title title
|
||||
* @property subtitle subtitle
|
||||
* @property iconResId icon resource id
|
||||
* @property tint icon tint
|
||||
* @param onClick lambda be invoked when notification component is clicked
|
||||
*/
|
||||
data class Action(
|
||||
override val title: String,
|
||||
override val subtitle: String? = null,
|
||||
@DrawableRes override val iconResId: Int,
|
||||
override val tint: Color? = null,
|
||||
val onClick: () -> Unit,
|
||||
) : NotificationState(title, subtitle, iconResId, tint)
|
||||
}
|
||||
|
|
@ -76,6 +76,7 @@ data class TangemDimens internal constructor(
|
|||
val size200: Dp = 200.dp,
|
||||
// endregion Size
|
||||
// region Spacing
|
||||
val spacing0: Dp = 0.dp,
|
||||
val spacing0_5: Dp = 0.5.dp,
|
||||
val spacing2: Dp = 2.dp,
|
||||
val spacing4: Dp = 4.dp,
|
||||
|
|
@ -91,6 +92,7 @@ data class TangemDimens internal constructor(
|
|||
val spacing24: Dp = 24.dp,
|
||||
val spacing26: Dp = 26.dp,
|
||||
val spacing28: Dp = 28.dp,
|
||||
val spacing30: Dp = 30.dp,
|
||||
val spacing32: Dp = 32.dp,
|
||||
val spacing34: Dp = 34.dp,
|
||||
val spacing36: Dp = 34.dp,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue