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,
|
||||
)
|
||||
}
|
||||
|
|
@ -170,6 +170,14 @@ internal object WalletPreviewData {
|
|||
),
|
||||
)
|
||||
|
||||
val manageButtons = persistentListOf(
|
||||
WalletManageButton.Buy(onClick = {}),
|
||||
WalletManageButton.Send(onClick = {}),
|
||||
WalletManageButton.Receive(onClick = {}),
|
||||
WalletManageButton.Exchange(onClick = {}),
|
||||
WalletManageButton.CopyAddress(onClick = {}),
|
||||
)
|
||||
|
||||
val multicurrencyWalletScreenState = WalletStateHolder.MultiCurrencyContent(
|
||||
onBackClick = {},
|
||||
topBarConfig = walletTopBarConfig,
|
||||
|
|
@ -273,5 +281,6 @@ internal object WalletPreviewData {
|
|||
WalletNotification.NeedToBackup(onClick = {}),
|
||||
WalletNotification.ScanCard(onClick = {}),
|
||||
),
|
||||
buttons = manageButtons,
|
||||
)
|
||||
}
|
||||
|
|
@ -21,9 +21,10 @@ import androidx.compose.ui.res.stringResource
|
|||
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.components.BackgroundActionButton
|
||||
import com.tangem.core.ui.components.PrimaryButton
|
||||
import com.tangem.core.ui.components.SecondaryButton
|
||||
import com.tangem.core.ui.components.buttons.actions.ActionConfig
|
||||
import com.tangem.core.ui.components.buttons.actions.BackgroundActionButton
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
|
||||
|
|
@ -214,16 +215,20 @@ private fun TopBar(
|
|||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
|
||||
) {
|
||||
BackgroundActionButton(
|
||||
config = ActionConfig(
|
||||
text = stringResource(id = R.string.organize_tokens_sort_by_balance),
|
||||
iconResId = R.drawable.ic_sort_24,
|
||||
onClick = config.onSortByBalanceClick,
|
||||
),
|
||||
modifier = Modifier.weight(1f),
|
||||
text = stringResource(id = R.string.organize_tokens_sort_by_balance),
|
||||
iconResId = R.drawable.ic_sort_24,
|
||||
onClick = config.onSortByBalanceClick,
|
||||
)
|
||||
BackgroundActionButton(
|
||||
config = ActionConfig(
|
||||
text = stringResource(id = R.string.organize_tokens_group),
|
||||
iconResId = R.drawable.ic_group_24,
|
||||
onClick = config.onGroupByNetworkClick,
|
||||
),
|
||||
modifier = Modifier.weight(1f),
|
||||
text = stringResource(id = R.string.organize_tokens_group),
|
||||
iconResId = R.drawable.ic_group_24,
|
||||
onClick = config.onGroupByNetworkClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state
|
||||
|
||||
import com.tangem.core.ui.components.buttons.actions.ActionConfig
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
|
||||
/**
|
||||
* Wallet manage button state
|
||||
*
|
||||
* @param config action config
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
sealed class WalletManageButton(val config: ActionConfig) {
|
||||
|
||||
/**
|
||||
* Buy
|
||||
*
|
||||
* @param onClick lambda be invoked when manage button is clicked
|
||||
*/
|
||||
data class Buy(val onClick: () -> Unit) : WalletManageButton(
|
||||
config = ActionConfig(
|
||||
text = "Buy",
|
||||
iconResId = R.drawable.ic_plus_24,
|
||||
onClick = onClick,
|
||||
),
|
||||
)
|
||||
|
||||
/**
|
||||
* Send
|
||||
*
|
||||
* @param onClick lambda be invoked when manage button is clicked
|
||||
*/
|
||||
data class Send(val onClick: () -> Unit) : WalletManageButton(
|
||||
config = ActionConfig(
|
||||
text = "Send",
|
||||
iconResId = R.drawable.ic_arrow_up_24,
|
||||
onClick = onClick,
|
||||
),
|
||||
)
|
||||
|
||||
/**
|
||||
* Receive
|
||||
*
|
||||
* @param onClick lambda be invoked when manage button is clicked
|
||||
*/
|
||||
data class Receive(val onClick: () -> Unit) : WalletManageButton(
|
||||
config = ActionConfig(
|
||||
text = "Receive",
|
||||
iconResId = R.drawable.ic_arrow_down_24,
|
||||
onClick = onClick,
|
||||
),
|
||||
)
|
||||
|
||||
/**
|
||||
* Exchange
|
||||
*
|
||||
* @param onClick lambda be invoked when manage button is clicked
|
||||
*/
|
||||
data class Exchange(val onClick: () -> Unit) : WalletManageButton(
|
||||
config = ActionConfig(
|
||||
text = "Exchange",
|
||||
iconResId = R.drawable.ic_exchange_vertical_24,
|
||||
onClick = onClick,
|
||||
),
|
||||
)
|
||||
|
||||
/**
|
||||
* Copy address
|
||||
*
|
||||
* @param onClick lambda be invoked when manage button is clicked
|
||||
*/
|
||||
data class CopyAddress(val onClick: () -> Unit) : WalletManageButton(
|
||||
config = ActionConfig(
|
||||
text = "Copy address",
|
||||
iconResId = R.drawable.ic_copy_24,
|
||||
onClick = onClick,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state
|
||||
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.key
|
||||
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.components.buttons.actions.ActionButton
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
/**
|
||||
* Wallet manage buttons
|
||||
*
|
||||
* @param buttons manage buttons
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Composable
|
||||
internal fun WalletManageButtons(buttons: ImmutableList<WalletManageButton>) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.horizontalScroll(state = rememberScrollState())
|
||||
.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing8),
|
||||
) {
|
||||
buttons.forEach { button ->
|
||||
key(button.config.text) {
|
||||
ActionButton(config = button.config)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun Preview_WalletManageButtons_Light(
|
||||
@PreviewParameter(WalletManageButtonProvider::class) buttons: ImmutableList<WalletManageButton>,
|
||||
) {
|
||||
TangemTheme(isDark = false) {
|
||||
WalletManageButtons(buttons = buttons)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun Preview_WalletManageButtons_Dark(
|
||||
@PreviewParameter(WalletManageButtonProvider::class) buttons: ImmutableList<WalletManageButton>,
|
||||
) {
|
||||
TangemTheme(isDark = true) {
|
||||
WalletManageButtons(buttons = buttons)
|
||||
}
|
||||
}
|
||||
|
||||
private class WalletManageButtonProvider : CollectionPreviewParameterProvider<ImmutableList<WalletManageButton>>(
|
||||
collection = listOf(WalletPreviewData.manageButtons),
|
||||
)
|
||||
|
|
@ -53,6 +53,7 @@ internal sealed class WalletStateHolder(
|
|||
* @property wallets list of wallets states
|
||||
* @property contentItems content items
|
||||
* @property notifications notifications
|
||||
* @property buttons manage buttons
|
||||
*/
|
||||
data class SingleCurrencyContent(
|
||||
override val onBackClick: () -> Unit,
|
||||
|
|
@ -61,5 +62,6 @@ internal sealed class WalletStateHolder(
|
|||
override val wallets: ImmutableList<WalletCardState>,
|
||||
override val contentItems: ImmutableList<WalletContentItemState.SingleCurrencyItem>,
|
||||
override val notifications: ImmutableList<WalletNotification>,
|
||||
val buttons: ImmutableList<WalletManageButton>,
|
||||
) : WalletStateHolder(onBackClick, topBarConfig, selectedWallet, wallets, contentItems, notifications)
|
||||
}
|
||||
|
|
@ -1,28 +1,26 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.ui
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.composed
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
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.components.RoundedActionButton
|
||||
import com.tangem.core.ui.components.buttons.actions.ActionConfig
|
||||
import com.tangem.core.ui.components.buttons.actions.RoundedActionButton
|
||||
import com.tangem.core.ui.components.notifications.Notification
|
||||
import com.tangem.core.ui.components.transactions.Transaction
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
|
|
@ -30,9 +28,11 @@ import com.tangem.feature.wallet.presentation.common.WalletPreviewData
|
|||
import com.tangem.feature.wallet.presentation.common.component.NetworkGroupItem
|
||||
import com.tangem.feature.wallet.presentation.common.component.TokenItem
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletContentItemState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletManageButtons
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.components.WalletCardsList
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.components.WalletTopBar
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.decorations.walletContentItemDecoration
|
||||
|
||||
/**
|
||||
* Wallet screen
|
||||
|
|
@ -49,15 +49,29 @@ internal fun WalletScreen(state: WalletStateHolder, modifier: Modifier = Modifie
|
|||
topBar = { WalletTopBar(config = state.topBarConfig) },
|
||||
containerColor = TangemTheme.colors.background.secondary,
|
||||
) { scaffoldPaddings ->
|
||||
val lastContentItemIndex = remember(state.contentItems) { state.contentItems.lastIndex }
|
||||
|
||||
LazyColumn(
|
||||
modifier = modifier
|
||||
.padding(scaffoldPaddings)
|
||||
.padding(paddingValues = scaffoldPaddings)
|
||||
.fillMaxSize(),
|
||||
contentPadding = PaddingValues(
|
||||
horizontal = TangemTheme.dimens.spacing16,
|
||||
vertical = TangemTheme.dimens.spacing8,
|
||||
),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
item { WalletCardsList(wallets = state.wallets) }
|
||||
item {
|
||||
WalletCardsList(
|
||||
wallets = state.wallets,
|
||||
modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing12),
|
||||
)
|
||||
}
|
||||
|
||||
if (state is WalletStateHolder.SingleCurrencyContent) {
|
||||
item { WalletManageButtons(buttons = state.buttons) }
|
||||
}
|
||||
|
||||
items(items = state.notifications, itemContent = { Notification(state = it.state) })
|
||||
|
||||
itemsIndexed(
|
||||
items = state.contentItems,
|
||||
|
|
@ -70,36 +84,19 @@ internal fun WalletScreen(state: WalletStateHolder, modifier: Modifier = Modifie
|
|||
is WalletContentItemState.SingleCurrencyItem.Transaction -> index
|
||||
}
|
||||
},
|
||||
) { index, item ->
|
||||
val itemModifier = Modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
.clipFirstAndLastItems(index, lastContentItemIndex)
|
||||
|
||||
when (item) {
|
||||
is WalletContentItemState.MultiCurrencyItem.NetworkGroupTitle -> {
|
||||
NetworkGroupItem(networkName = item.networkName, modifier = itemModifier)
|
||||
}
|
||||
is WalletContentItemState.MultiCurrencyItem.Token -> {
|
||||
TokenItem(state = item.state, modifier = itemModifier)
|
||||
}
|
||||
is WalletContentItemState.SingleCurrencyItem.Title -> {
|
||||
SingleCurrencyTitle(config = item, modifier = itemModifier)
|
||||
}
|
||||
is WalletContentItemState.SingleCurrencyItem.TransactionGroupTitle -> {
|
||||
TransactionGroupTitle(config = item, modifier = itemModifier)
|
||||
}
|
||||
is WalletContentItemState.SingleCurrencyItem.Transaction -> {
|
||||
Transaction(state = item.state, modifier = itemModifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
itemContent = { index, item ->
|
||||
ContentItem(currentIndex = index, lastIndex = state.contentItems.lastIndex, item = item)
|
||||
},
|
||||
)
|
||||
|
||||
if (state is WalletStateHolder.MultiCurrencyContent) {
|
||||
item {
|
||||
RoundedActionButton(
|
||||
text = stringResource(id = R.string.organize_tokens_title),
|
||||
iconResId = R.drawable.ic_filter_24,
|
||||
onClick = state.onOrganizeTokensClick,
|
||||
config = ActionConfig(
|
||||
text = stringResource(id = R.string.organize_tokens_title),
|
||||
iconResId = R.drawable.ic_filter_24,
|
||||
onClick = state.onOrganizeTokensClick,
|
||||
),
|
||||
modifier = Modifier.padding(top = TangemTheme.dimens.spacing14),
|
||||
)
|
||||
}
|
||||
|
|
@ -108,6 +105,29 @@ internal fun WalletScreen(state: WalletStateHolder, modifier: Modifier = Modifie
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ContentItem(currentIndex: Int, lastIndex: Int, item: WalletContentItemState) {
|
||||
val itemModifier = Modifier.walletContentItemDecoration(currentIndex, lastIndex)
|
||||
|
||||
when (item) {
|
||||
is WalletContentItemState.MultiCurrencyItem.NetworkGroupTitle -> {
|
||||
NetworkGroupItem(networkName = item.networkName, modifier = itemModifier)
|
||||
}
|
||||
is WalletContentItemState.MultiCurrencyItem.Token -> {
|
||||
TokenItem(state = item.state, modifier = itemModifier)
|
||||
}
|
||||
is WalletContentItemState.SingleCurrencyItem.Title -> {
|
||||
SingleCurrencyTitle(config = item, modifier = itemModifier)
|
||||
}
|
||||
is WalletContentItemState.SingleCurrencyItem.TransactionGroupTitle -> {
|
||||
TransactionGroupTitle(config = item, modifier = itemModifier)
|
||||
}
|
||||
is WalletContentItemState.SingleCurrencyItem.Transaction -> {
|
||||
Transaction(state = item.state, modifier = itemModifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SingleCurrencyTitle(
|
||||
config: WalletContentItemState.SingleCurrencyItem.Title,
|
||||
|
|
@ -166,31 +186,6 @@ private fun TransactionGroupTitle(
|
|||
)
|
||||
}
|
||||
|
||||
private fun Modifier.clipFirstAndLastItems(index: Int, lastItemIndex: Int): Modifier = composed {
|
||||
when (index) {
|
||||
0 -> {
|
||||
this
|
||||
.padding(top = TangemTheme.dimens.spacing14)
|
||||
.clip(
|
||||
RoundedCornerShape(
|
||||
topStart = TangemTheme.dimens.radius16,
|
||||
topEnd = TangemTheme.dimens.radius16,
|
||||
),
|
||||
)
|
||||
}
|
||||
lastItemIndex -> {
|
||||
this
|
||||
.clip(
|
||||
RoundedCornerShape(
|
||||
bottomStart = TangemTheme.dimens.radius16,
|
||||
bottomEnd = TangemTheme.dimens.radius16,
|
||||
),
|
||||
)
|
||||
}
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -23,21 +23,21 @@ import kotlinx.collections.immutable.persistentListOf
|
|||
/**
|
||||
* Wallets list
|
||||
*
|
||||
* @param wallets list of wallet state
|
||||
* @param wallets list of wallet state
|
||||
* @param modifier modifier
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
internal fun WalletCardsList(wallets: ImmutableList<WalletCardState>) {
|
||||
internal fun WalletCardsList(wallets: ImmutableList<WalletCardState>, modifier: Modifier = Modifier) {
|
||||
val horizontalCardPadding = TangemTheme.dimens.spacing16
|
||||
val itemWidth = LocalConfiguration.current.screenWidthDp.dp - horizontalCardPadding * 2
|
||||
|
||||
val lazyListState = rememberLazyListState()
|
||||
LazyRow(
|
||||
modifier = Modifier.background(color = TangemTheme.colors.background.secondary),
|
||||
modifier = modifier.background(color = TangemTheme.colors.background.secondary),
|
||||
state = lazyListState,
|
||||
contentPadding = PaddingValues(horizontal = TangemTheme.dimens.spacing16),
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
|
||||
flingBehavior = rememberSnapFlingBehavior(lazyListState = lazyListState),
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.ui.decorations
|
||||
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.composed
|
||||
import androidx.compose.ui.draw.clip
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal fun Modifier.walletContentItemDecoration(currentIndex: Int, lastItemIndex: Int): Modifier = composed {
|
||||
when (currentIndex) {
|
||||
0 -> {
|
||||
this
|
||||
.padding(top = TangemTheme.dimens.spacing14)
|
||||
.clip(
|
||||
RoundedCornerShape(
|
||||
topStart = TangemTheme.dimens.radius16,
|
||||
topEnd = TangemTheme.dimens.radius16,
|
||||
),
|
||||
)
|
||||
}
|
||||
lastItemIndex -> {
|
||||
this
|
||||
.clip(
|
||||
RoundedCornerShape(
|
||||
bottomStart = TangemTheme.dimens.radius16,
|
||||
bottomEnd = TangemTheme.dimens.radius16,
|
||||
),
|
||||
)
|
||||
}
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue