Updated on 2026-08-14

This commit is contained in:
Tangem 2024-12-02 18:56:22 +04:00
parent 4812e53ba2
commit 17d3649cb3
4 changed files with 112 additions and 25 deletions

View file

@ -0,0 +1,67 @@
package com.tangem.core.ui.utils
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.graphics.*
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
/**
* Add a dashed border around a Composable component.
*
* @param color color
* @param shape shape
* @param strokeWidth stroke width
* @param dashLength length of each dash
* @param gapLength length of the gap between each dash
* @param cap stroke cap
*/
fun Modifier.dashedBorder(
color: Color,
shape: Shape,
dashLength: Dp,
gapLength: Dp,
strokeWidth: Dp = 1.dp,
cap: StrokeCap = StrokeCap.Round,
) = dashedBorder(
brush = SolidColor(color),
shape = shape,
strokeWidth = strokeWidth,
dashLength = dashLength,
gapLength = gapLength,
cap = cap,
)
/**
* Add a dashed border around a Composable component.
*
* @param brush brush
* @param shape shape
* @param strokeWidth stroke width
* @param dashLength length of each dash
* @param gapLength length of the gap between each dash
* @param cap stroke cap
*/
fun Modifier.dashedBorder(
brush: Brush,
shape: Shape,
strokeWidth: Dp = 2.dp,
dashLength: Dp = 4.dp,
gapLength: Dp = 4.dp,
cap: StrokeCap = StrokeCap.Round,
) = this.drawWithContent {
val outline = shape.createOutline(size = size, layoutDirection = layoutDirection, density = this)
val dashedStroke = Stroke(
cap = cap,
width = strokeWidth.toPx(),
pathEffect = PathEffect.dashPathEffect(
intervals = floatArrayOf(dashLength.toPx(), gapLength.toPx()),
),
)
drawContent()
drawOutline(outline = outline, style = dashedStroke, brush = brush)
}

View file

@ -1,10 +1,7 @@
package com.tangem.features.onramp.swap.entity
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.components.token.state.TokenItemState
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.features.onramp.impl.R
/**
* Exchange card UI model
@ -19,9 +16,6 @@ internal sealed interface ExchangeCardUM {
/** Remove button UI model */
val removeButtonUM: RemoveButtonUM?
/** Token item state */
val tokenItemState: TokenItemState
/**
* Empty state
*
@ -34,19 +28,6 @@ internal sealed interface ExchangeCardUM {
) : ExchangeCardUM {
override val removeButtonUM: RemoveButtonUM? = null
override val tokenItemState: TokenItemState = TokenItemState.Content(
id = "empty",
iconState = CurrencyIconState.Empty(R.drawable.ic_empty_64),
titleState = TokenItemState.TitleState.Content(
text = resourceReference(id = R.string.action_buttons_swap_choose_token),
),
subtitleState = TokenItemState.SubtitleState.TextContent(value = subtitleReference),
fiatAmountState = TokenItemState.FiatAmountState.Content(text = ""),
subtitle2State = TokenItemState.Subtitle2State.TextContent(text = ""),
onItemClick = null,
onItemLongClick = null,
)
}
/**
@ -59,7 +40,7 @@ internal sealed interface ExchangeCardUM {
data class Filled(
override val titleReference: TextReference,
override val removeButtonUM: RemoveButtonUM?,
override val tokenItemState: TokenItemState,
val tokenItemState: TokenItemState,
) : ExchangeCardUM
data class RemoveButtonUM(val onClick: () -> Unit)

View file

@ -1,16 +1,18 @@
package com.tangem.features.onramp.swap.ui
import android.content.res.Configuration
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.*
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.material3.ripple
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
@ -29,6 +31,7 @@ import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.utils.dashedBorder
import com.tangem.features.onramp.impl.R
import com.tangem.features.onramp.swap.entity.ExchangeCardUM
@ -54,8 +57,18 @@ internal fun ExchangeCard(state: ExchangeCardUM, modifier: Modifier = Modifier)
) {
Title(titleReference = state.titleReference, removeButtonUM = state.removeButtonUM)
AnimatedContent(targetState = state.tokenItemState, label = "TokenItem's changing ") {
TokenItem(state = it, isBalanceHidden = false)
AnimatedContent(
targetState = state,
transitionSpec = {
fadeIn(animationSpec = tween(durationMillis = 220, delayMillis = 90))
.togetherWith(fadeOut(animationSpec = tween(durationMillis = 90)))
},
label = "TokenItem's changing",
) { animatedState ->
when (animatedState) {
is ExchangeCardUM.Empty -> EmptyTokenBlock(text = animatedState.subtitleReference)
is ExchangeCardUM.Filled -> TokenItem(state = animatedState.tokenItemState, isBalanceHidden = false)
}
}
}
}
@ -96,6 +109,32 @@ private fun RemoveButton(state: ExchangeCardUM.RemoveButtonUM?) {
}
}
@Composable
private fun EmptyTokenBlock(text: TextReference, modifier: Modifier = Modifier) {
Box(
modifier = modifier
.padding(horizontal = 12.dp, vertical = 13.dp)
.heightIn(min = 50.dp)
.fillMaxWidth()
.dashedBorder(
color = TangemTheme.colors.icon.informative,
shape = RoundedCornerShape(16.dp),
dashLength = 2.dp,
gapLength = 6.dp,
)
.padding(vertical = 15.dp),
contentAlignment = Alignment.Center,
) {
Text(
text = text.resolveReference(),
color = TangemTheme.colors.text.tertiary,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
style = TangemTheme.typography.body2,
)
}
}
@Preview(showBackground = true, widthDp = 360)
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable

View file

@ -57,7 +57,7 @@ internal fun SwapScreenContent(state: SwapStateHolder, modifier: Modifier = Modi
.padding(
start = TangemTheme.dimens.spacing16,
end = TangemTheme.dimens.spacing16,
top = TangemTheme.dimens.spacing16,
top = TangemTheme.dimens.spacing8,
bottom = TangemTheme.dimens.spacing32,
),
horizontalAlignment = Alignment.CenterHorizontally,