Updated on 2026-08-14
This commit is contained in:
parent
b0f23e3660
commit
938d7baee1
14 changed files with 569 additions and 24 deletions
|
|
@ -139,6 +139,7 @@ private fun Icon(name: String, iconUrl: String, modifier: Modifier = Modifier) {
|
|||
)
|
||||
}
|
||||
|
||||
// TODO(use CurrencyPlaceholderIcon here?)
|
||||
@Composable
|
||||
private fun PlaceholderIcon(name: String, modifier: Modifier = Modifier) {
|
||||
Box(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
package com.tangem.core.ui.components
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.valentinilk.shimmer.shimmer
|
||||
|
||||
/**
|
||||
* Rectangle shimmer item with rounded shape from DS
|
||||
*/
|
||||
@Composable
|
||||
fun ShimmerRectangle(modifier: Modifier = Modifier) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.shimmer()
|
||||
.background(
|
||||
color = TangemTheme.colors.button.secondary,
|
||||
shape = RoundedCornerShape(TangemTheme.dimens.radius6),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Circle shimmer item
|
||||
* Size should be set in modifier
|
||||
*/
|
||||
@Composable
|
||||
fun CircleShimmer(modifier: Modifier = Modifier) {
|
||||
Box(modifier = modifier.shimmer()) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.matchParentSize()
|
||||
.background(
|
||||
color = TangemTheme.colors.button.secondary,
|
||||
shape = CircleShape,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// region preview
|
||||
|
||||
@Composable
|
||||
private fun ShimmersPreview() {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing18),
|
||||
) {
|
||||
ShimmerRectangle(
|
||||
modifier = Modifier.size(
|
||||
width = TangemTheme.dimens.size72,
|
||||
height = TangemTheme.dimens.size12,
|
||||
),
|
||||
)
|
||||
CircleShimmer(modifier = Modifier.size(size = TangemTheme.dimens.size42))
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun Shimmers_InLightTheme() {
|
||||
TangemTheme(isDark = false) {
|
||||
ShimmersPreview()
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun Shimmers_InDarkTheme() {
|
||||
TangemTheme(isDark = true) {
|
||||
ShimmersPreview()
|
||||
}
|
||||
}
|
||||
|
||||
// endregion preview
|
||||
|
|
@ -58,6 +58,7 @@ data class TangemDimens internal constructor(
|
|||
val size50: Dp = 50.dp,
|
||||
val size56: Dp = 56.dp,
|
||||
val size62: Dp = 62.dp,
|
||||
val size68: Dp = 68.dp,
|
||||
val size72: Dp = 72.dp,
|
||||
val size80: Dp = 80.dp,
|
||||
val size84: Dp = 84.dp,
|
||||
|
|
|
|||
10
core/ui/src/main/res/drawable/ic_drag_24.xml
Normal file
10
core/ui/src/main/res/drawable/ic_drag_24.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M19,8H5V10H19V8ZM19,14H5V16H19V14Z"
|
||||
android:fillColor="#B0B0B0"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
9
core/ui/src/main/res/drawable/img_arrow_down_8.xml
Normal file
9
core/ui/src/main/res/drawable/img_arrow_down_8.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="9dp"
|
||||
android:height="8dp"
|
||||
android:viewportWidth="9"
|
||||
android:viewportHeight="8">
|
||||
<path
|
||||
android:pathData="M4.6114,6.8903C4.8128,7.1793 5.2419,7.175 5.4375,6.8821L8.9151,1.6731C9.1369,1.3409 8.8988,0.8955 8.4993,0.8955L1.3921,0.8955C0.9881,0.8955 0.7509,1.3499 0.9819,1.6814L4.6114,6.8903Z"
|
||||
android:fillColor="#FF3333"/>
|
||||
</vector>
|
||||
9
core/ui/src/main/res/drawable/img_arrow_up_8.xml
Normal file
9
core/ui/src/main/res/drawable/img_arrow_up_8.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="9dp"
|
||||
android:height="8dp"
|
||||
android:viewportWidth="9"
|
||||
android:viewportHeight="8">
|
||||
<path
|
||||
android:pathData="M4.6114,1.1097C4.8128,0.8207 5.2419,0.825 5.4375,1.1179L8.9151,6.3269C9.1369,6.6591 8.8988,7.1045 8.4993,7.1045L1.3921,7.1045C0.9881,7.1045 0.7509,6.6501 0.9819,6.3186L4.6114,1.1097Z"
|
||||
android:fillColor="#1ACE80"/>
|
||||
</vector>
|
||||
19
core/ui/src/main/res/drawable/img_loader_15.xml
Normal file
19
core/ui/src/main/res/drawable/img_loader_15.xml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="15dp"
|
||||
android:height="4dp"
|
||||
android:viewportWidth="15"
|
||||
android:viewportHeight="4">
|
||||
<path
|
||||
android:pathData="M13.5,3.5C12.672,3.5 12,2.828 12,2C12,1.172 12.672,0.5 13.5,0.5C14.328,0.5 15,1.172 15,2C15,2.828 14.328,3.5 13.5,3.5Z"
|
||||
android:fillColor="#FFB71B"/>
|
||||
<path
|
||||
android:pathData="M7.5,3.5C6.672,3.5 6,2.828 6,2C6,1.172 6.672,0.5 7.5,0.5C8.328,0.5 9,1.172 9,2C9,2.828 8.328,3.5 7.5,3.5Z"
|
||||
android:strokeAlpha="0.55"
|
||||
android:fillColor="#FFB71B"
|
||||
android:fillAlpha="0.55"/>
|
||||
<path
|
||||
android:pathData="M1.5,3.5C0.672,3.5 0,2.828 0,2C0,1.172 0.672,0.5 1.5,0.5C2.328,0.5 3,1.172 3,2C3,2.828 2.328,3.5 1.5,3.5Z"
|
||||
android:strokeAlpha="0.25"
|
||||
android:fillColor="#FFB71B"
|
||||
android:fillAlpha="0.25"/>
|
||||
</vector>
|
||||
|
|
@ -11,6 +11,8 @@ dependencies {
|
|||
implementation(deps.androidx.activity.compose)
|
||||
|
||||
/** Compose */
|
||||
implementation(deps.compose.coil)
|
||||
implementation(deps.compose.constraintLayout)
|
||||
implementation(deps.compose.material)
|
||||
implementation(deps.compose.foundation)
|
||||
implementation(deps.compose.navigation)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,355 @@
|
|||
package com.tangem.feature.wallet.presentation.ui
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.Surface
|
||||
import androidx.compose.material.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.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.constraintlayout.compose.ConstraintLayout
|
||||
import androidx.constraintlayout.compose.Dimension
|
||||
import coil.compose.SubcomposeAsyncImage
|
||||
import coil.request.ImageRequest
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.*
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemTypography
|
||||
import com.tangem.feature.wallet.presentation.ui.config.PriceChange
|
||||
import com.tangem.feature.wallet.presentation.ui.config.PriceChangeType
|
||||
import com.tangem.feature.wallet.presentation.ui.config.TokenV2Config
|
||||
import com.tangem.feature.wallet.presentation.ui.state.TokenOptionsUIState
|
||||
import com.tangem.feature.wallet.presentation.ui.state.TokenUIState
|
||||
|
||||
private const val DOTS = "•••"
|
||||
|
||||
@Composable
|
||||
fun TokenItemV2(config: TokenV2Config) {
|
||||
when (config.tokenUIState) {
|
||||
TokenUIState.LOADED -> LoadedTokenState(config)
|
||||
TokenUIState.LOADING -> LoadingTokenState()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LoadedTokenState(config: TokenV2Config) {
|
||||
BaseSurface {
|
||||
ConstraintLayout(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
horizontal = TangemTheme.dimens.spacing12,
|
||||
vertical = TangemTheme.dimens.spacing4,
|
||||
),
|
||||
) {
|
||||
val (iconItem, tokenNameItem, fiatItem) = createRefs()
|
||||
TokenIcon(
|
||||
modifier = Modifier.constrainAs(iconItem) {
|
||||
centerVerticallyTo(parent)
|
||||
start.linkTo(parent.start)
|
||||
},
|
||||
tokenIconUrl = config.iconUrl,
|
||||
icon = config.icon,
|
||||
networkIconRes = config.networkIcon,
|
||||
)
|
||||
TokenTitleAmountBlock(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing12)
|
||||
.constrainAs(tokenNameItem) {
|
||||
centerVerticallyTo(parent)
|
||||
start.linkTo(iconItem.end)
|
||||
end.linkTo(fiatItem.start)
|
||||
width = Dimension.fillToConstraints
|
||||
},
|
||||
title = config.name,
|
||||
amount = config.amount,
|
||||
hasPending = config.hasPending,
|
||||
)
|
||||
TokenOptionsBlock(
|
||||
config = config,
|
||||
modifier = Modifier.constrainAs(fiatItem) {
|
||||
centerVerticallyTo(parent)
|
||||
end.linkTo(parent.end)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Block for end part of token item
|
||||
* shows status is reachable, is drag, hidden or show balance
|
||||
*/
|
||||
@Composable
|
||||
private fun TokenOptionsBlock(config: TokenV2Config, modifier: Modifier = Modifier) {
|
||||
when (config.tokenOptionsUIState) {
|
||||
TokenOptionsUIState.VISIBLE -> TokenFiatPercentageBlock(
|
||||
modifier = modifier,
|
||||
fiatAmount = config.fiatAmount,
|
||||
priceChange = config.priceChange,
|
||||
)
|
||||
TokenOptionsUIState.UNREACHABLE -> Text(
|
||||
modifier = modifier,
|
||||
text = "Unreachable", // TODO (conform this text)
|
||||
style = TangemTypography.body2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
TokenOptionsUIState.HIDDEN -> TokenFiatPercentageBlock(
|
||||
modifier = modifier,
|
||||
fiatAmount = DOTS,
|
||||
priceChange = config.priceChange,
|
||||
)
|
||||
TokenOptionsUIState.DRAG -> Icon(
|
||||
modifier = modifier,
|
||||
painter = painterResource(id = R.drawable.ic_drag_24),
|
||||
tint = TangemTheme.colors.icon.informative,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LoadingTokenState() {
|
||||
BaseSurface {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
horizontal = TangemTheme.dimens.spacing12,
|
||||
vertical = TangemTheme.dimens.spacing4,
|
||||
),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
CircleShimmer(modifier = Modifier.size(size = TangemTheme.dimens.size42))
|
||||
SpacerW12()
|
||||
Column(verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8)) {
|
||||
ShimmerRectangle(
|
||||
modifier = Modifier.size(
|
||||
width = TangemTheme.dimens.size72,
|
||||
height = TangemTheme.dimens.size12,
|
||||
),
|
||||
)
|
||||
ShimmerRectangle(
|
||||
modifier = Modifier.size(
|
||||
width = TangemTheme.dimens.size50,
|
||||
height = TangemTheme.dimens.size12,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
|
||||
) {
|
||||
ShimmerRectangle(
|
||||
modifier = Modifier.size(
|
||||
width = TangemTheme.dimens.size40,
|
||||
height = TangemTheme.dimens.size12,
|
||||
),
|
||||
)
|
||||
ShimmerRectangle(
|
||||
modifier = Modifier.size(
|
||||
width = TangemTheme.dimens.size40,
|
||||
height = TangemTheme.dimens.size12,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
private fun BaseSurface(onClick: (() -> Unit)? = null, content: @Composable () -> Unit) {
|
||||
Surface(
|
||||
modifier = Modifier.defaultMinSize(minHeight = TangemTheme.dimens.size68),
|
||||
color = TangemTheme.colors.background.primary,
|
||||
onClick = onClick ?: {},
|
||||
enabled = onClick != null,
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TokenTitleAmountBlock(title: String, amount: String, hasPending: Boolean, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing2),
|
||||
) {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8)) {
|
||||
Text(
|
||||
text = title,
|
||||
style = TangemTypography.subtitle2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
if (hasPending) {
|
||||
Image(
|
||||
modifier = Modifier.align(Alignment.CenterVertically),
|
||||
painter = painterResource(id = R.drawable.img_loader_15),
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
Text(
|
||||
text = amount,
|
||||
style = TangemTypography.body2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TokenFiatPercentageBlock(fiatAmount: String, priceChange: PriceChange, modifier: Modifier = Modifier) {
|
||||
Column(modifier = modifier.requiredWidth(IntrinsicSize.Max)) {
|
||||
Text(
|
||||
modifier = Modifier.align(Alignment.End),
|
||||
text = fiatAmount,
|
||||
style = TangemTypography.body2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
SpacerH2()
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.End,
|
||||
) {
|
||||
val iconChangeArrow: Int
|
||||
val changeTextColor: Color
|
||||
if (priceChange.type == PriceChangeType.UP) {
|
||||
iconChangeArrow = R.drawable.img_arrow_up_8
|
||||
changeTextColor = TangemTheme.colors.text.accent
|
||||
} else {
|
||||
iconChangeArrow = R.drawable.img_arrow_down_8
|
||||
changeTextColor = TangemTheme.colors.text.warning
|
||||
}
|
||||
Image(
|
||||
modifier = Modifier.align(Alignment.CenterVertically),
|
||||
painter = painterResource(id = iconChangeArrow),
|
||||
contentDescription = null,
|
||||
)
|
||||
SpacerW4()
|
||||
Text(
|
||||
modifier = Modifier.align(Alignment.CenterVertically),
|
||||
text = priceChange.valuePercent,
|
||||
style = TangemTypography.body2,
|
||||
color = changeTextColor,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TokenIcon(
|
||||
tokenIconUrl: String?,
|
||||
modifier: Modifier = Modifier,
|
||||
@DrawableRes icon: Int? = null,
|
||||
@DrawableRes networkIconRes: Int? = null,
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.padding(end = TangemTheme.dimens.spacing16)
|
||||
.size(TangemTheme.dimens.size42),
|
||||
) {
|
||||
val tokenImageModifier = Modifier
|
||||
.align(Alignment.BottomStart)
|
||||
.size(TangemTheme.dimens.size36)
|
||||
|
||||
val data = if (tokenIconUrl.isNullOrEmpty()) {
|
||||
icon
|
||||
} else {
|
||||
tokenIconUrl
|
||||
}
|
||||
SubcomposeAsyncImage(
|
||||
modifier = tokenImageModifier,
|
||||
model = ImageRequest.Builder(LocalContext.current)
|
||||
.data(data)
|
||||
.crossfade(true)
|
||||
.build(),
|
||||
loading = { CircleShimmer(modifier = tokenImageModifier) },
|
||||
contentDescription = null,
|
||||
)
|
||||
|
||||
if (networkIconRes != null) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopEnd)
|
||||
.size(TangemTheme.dimens.size18)
|
||||
.background(color = Color.White, shape = CircleShape),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Image(
|
||||
modifier = Modifier.padding(all = 0.5.dp),
|
||||
painter = painterResource(id = networkIconRes),
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// region preview
|
||||
|
||||
@Composable
|
||||
private fun TokensPreview() {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing18),
|
||||
) {
|
||||
val config = TokenV2Config(
|
||||
name = "Polygon",
|
||||
amount = "5,412 MATIC",
|
||||
fiatAmount = "321 $",
|
||||
priceChange = PriceChange(
|
||||
valuePercent = "2%",
|
||||
type = PriceChangeType.UP,
|
||||
),
|
||||
iconUrl = null,
|
||||
icon = R.drawable.img_polygon_22,
|
||||
networkIcon = R.drawable.img_polygon_22,
|
||||
tokenUIState = TokenUIState.LOADED,
|
||||
tokenOptionsUIState = TokenOptionsUIState.VISIBLE,
|
||||
hasPending = true,
|
||||
)
|
||||
// Loaded item
|
||||
TokenItemV2(config)
|
||||
// Unreachable item
|
||||
TokenItemV2(config.copy(tokenOptionsUIState = TokenOptionsUIState.UNREACHABLE))
|
||||
// Drag item
|
||||
TokenItemV2(config.copy(tokenOptionsUIState = TokenOptionsUIState.DRAG))
|
||||
// Hidden item
|
||||
TokenItemV2(config.copy(tokenOptionsUIState = TokenOptionsUIState.UNREACHABLE))
|
||||
// Loading item
|
||||
TokenItemV2(
|
||||
config.copy(
|
||||
tokenUIState = TokenUIState.LOADING,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun Preview_Tokens_InLightTheme() {
|
||||
TangemTheme(isDark = false) {
|
||||
TokensPreview()
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun Preview_Tokens_InDarkTheme() {
|
||||
TangemTheme(isDark = true) {
|
||||
TokensPreview()
|
||||
}
|
||||
}
|
||||
|
||||
// endregion preview
|
||||
|
|
@ -1,9 +1,7 @@
|
|||
package com.tangem.feature.main.presentation.ui
|
||||
package com.tangem.feature.wallet.presentation.ui
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.Surface
|
||||
|
|
@ -14,10 +12,15 @@ import androidx.compose.ui.layout.ContentScale
|
|||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.constraintlayout.compose.ConstraintLayout
|
||||
import androidx.constraintlayout.compose.Dimension
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.*
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.valentinilk.shimmer.shimmer
|
||||
import com.tangem.feature.wallet.presentation.ui.config.WalletHeaderConfig
|
||||
import com.tangem.feature.wallet.presentation.ui.state.BalanceUIState
|
||||
|
||||
private const val DOTS = "•••"
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
|
|
@ -29,14 +32,19 @@ fun WalletHeaderCard(config: WalletHeaderConfig, modifier: Modifier = Modifier)
|
|||
onClick = config.onClick ?: {},
|
||||
enabled = config.onClick != null,
|
||||
) {
|
||||
Row(
|
||||
ConstraintLayout(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(intrinsicSize = IntrinsicSize.Max),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
.padding(horizontal = TangemTheme.dimens.spacing12),
|
||||
) {
|
||||
val (balanceBlock, imageItem) = createRefs()
|
||||
Column(
|
||||
modifier = Modifier.padding(all = TangemTheme.dimens.spacing12),
|
||||
modifier = Modifier.constrainAs(balanceBlock) {
|
||||
centerVerticallyTo(parent)
|
||||
start.linkTo(parent.start)
|
||||
end.linkTo(imageItem.start)
|
||||
width = Dimension.fillToConstraints
|
||||
},
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
|
||||
) {
|
||||
HeaderWalletName(
|
||||
|
|
@ -53,11 +61,15 @@ fun WalletHeaderCard(config: WalletHeaderConfig, modifier: Modifier = Modifier)
|
|||
style = TangemTheme.typography.caption,
|
||||
)
|
||||
}
|
||||
val imageWidth = TangemTheme.dimens.size120
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.width(TangemTheme.dimens.size120)
|
||||
.padding(end = TangemTheme.dimens.spacing18)
|
||||
.fillMaxHeight(),
|
||||
modifier = Modifier.constrainAs(imageItem) {
|
||||
centerVerticallyTo(parent)
|
||||
top.linkTo(parent.top)
|
||||
end.linkTo(parent.end)
|
||||
height = Dimension.fillToConstraints
|
||||
width = Dimension.value(imageWidth)
|
||||
},
|
||||
painter = config.cardImage,
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.FillWidth,
|
||||
|
|
@ -106,20 +118,16 @@ private fun HeaderBalanceTitle(balance: String, balanceState: BalanceUIState) {
|
|||
)
|
||||
}
|
||||
BalanceUIState.LOADING -> {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(vertical = TangemTheme.dimens.spacing4)
|
||||
.size(width = TangemTheme.dimens.size102, height = TangemTheme.dimens.size24)
|
||||
.shimmer()
|
||||
.background(
|
||||
color = TangemTheme.colors.button.secondary,
|
||||
shape = RoundedCornerShape(TangemTheme.dimens.radius6),
|
||||
),
|
||||
ShimmerRectangle(
|
||||
modifier = Modifier.size(
|
||||
width = TangemTheme.dimens.size102,
|
||||
height = TangemTheme.dimens.size24,
|
||||
),
|
||||
)
|
||||
}
|
||||
BalanceUIState.HIDDEN -> {
|
||||
Text(
|
||||
text = "•••",
|
||||
text = DOTS,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.h2,
|
||||
)
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package com.tangem.feature.wallet.presentation.ui.config
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import com.tangem.feature.wallet.presentation.ui.state.TokenOptionsUIState
|
||||
import com.tangem.feature.wallet.presentation.ui.state.TokenUIState
|
||||
|
||||
/**
|
||||
* Token config
|
||||
*
|
||||
* @property name of token/coin
|
||||
* @property amount of token
|
||||
* @property fiatAmount amount in fiat
|
||||
* @property priceChange value of price changing
|
||||
* @property iconUrl
|
||||
* @property icon token/coin icon
|
||||
* @property networkIcon
|
||||
* @property tokenUIState token state [TokenUIState] loading etc.
|
||||
* @property tokenOptionsUIState state for token options like 'unreachable', 'hidden' etc
|
||||
* @property hasPending pending tx in blockchain
|
||||
*/
|
||||
data class TokenV2Config(
|
||||
val name: String,
|
||||
val amount: String,
|
||||
val fiatAmount: String,
|
||||
val priceChange: PriceChange,
|
||||
val iconUrl: String?,
|
||||
@DrawableRes val icon: Int?,
|
||||
@DrawableRes val networkIcon: Int,
|
||||
val tokenUIState: TokenUIState,
|
||||
val tokenOptionsUIState: TokenOptionsUIState,
|
||||
val hasPending: Boolean,
|
||||
)
|
||||
|
||||
data class PriceChange(
|
||||
val valuePercent: String,
|
||||
val type: PriceChangeType,
|
||||
)
|
||||
|
||||
enum class PriceChangeType {
|
||||
UP, DOWN
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.feature.main.presentation.ui
|
||||
package com.tangem.feature.wallet.presentation.ui.config
|
||||
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import com.tangem.feature.wallet.presentation.ui.state.BalanceUIState
|
||||
|
||||
data class WalletHeaderConfig(
|
||||
val walletName: String,
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.feature.main.presentation.ui
|
||||
package com.tangem.feature.wallet.presentation.ui.state
|
||||
|
||||
enum class BalanceUIState {
|
||||
VISIBLE, LOADING, HIDDEN, NONE
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.tangem.feature.wallet.presentation.ui.state
|
||||
|
||||
enum class TokenUIState {
|
||||
LOADED, LOADING
|
||||
}
|
||||
|
||||
enum class TokenOptionsUIState {
|
||||
VISIBLE, HIDDEN, DRAG, UNREACHABLE
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue