Updated on 2026-08-14

This commit is contained in:
Tangem 2026-03-27 08:23:48 +05:00
parent c76d1de3cf
commit 7a7af53464
17 changed files with 713 additions and 281 deletions

View file

@ -3,7 +3,9 @@ package com.tangem.features.tangempay.component
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.ui.Modifier
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.ui.res.LocalRedesignEnabled
import com.tangem.features.tangempay.entity.TangemPayMainUM
import com.tangem.features.tangempay.ui.TangemPayMainBlockContent
import com.tangem.features.tangempay.ui.TangemPayMainBlockItem
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
@ -26,7 +28,11 @@ internal class DefaultTangemPayMainBlockComponent @AssistedInject constructor(
key = TANGEM_PAY_ACCOUNT_CONTENT_TYPE,
contentType = TANGEM_PAY_ACCOUNT_CONTENT_TYPE,
) {
TangemPayMainBlockItem(state, isBalanceHidden, modifier)
if (LocalRedesignEnabled.current) {
TangemPayMainBlockContent(state, isBalanceHidden, modifier)
} else {
TangemPayMainBlockItem(state, isBalanceHidden, modifier)
}
}
}

View file

@ -2,123 +2,199 @@ package com.tangem.features.tangempay.ui
import android.content.res.Configuration
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
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.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.layoutId
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.AnnotatedString
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 androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.CircleShimmer
import com.tangem.core.ui.components.RectangleShimmer
import com.tangem.core.ui.components.SpacerWMax
import com.tangem.core.ui.components.block.BlockCard
import com.tangem.core.ui.components.inputrow.InputRowImageBase
import com.tangem.core.ui.components.TextShimmer
import com.tangem.core.ui.components.text.applyBladeBrush
import com.tangem.core.ui.ds.row.TangemRowContainer
import com.tangem.core.ui.ds.row.TangemRowLayoutId
import com.tangem.core.ui.extensions.*
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.res.TangemThemePreviewRedesign
import com.tangem.features.tangempay.entity.TangemPayMainUM
import com.tangem.features.tangempay.main.impl.R
import com.tangem.utils.StringsSigns.DASH_SIGN
private const val DISABLED_ALPHA = 0.6F
private const val DISABLED_ALPHA = 0.5F
@Composable
internal fun TangemPayMainBlockItem(state: TangemPayMainUM, isBalanceHidden: Boolean, modifier: Modifier = Modifier) {
internal fun TangemPayMainBlockContent(
state: TangemPayMainUM,
isBalanceHidden: Boolean,
modifier: Modifier = Modifier,
) {
when (state) {
is TangemPayMainUM.Empty -> Unit
is TangemPayMainUM.Loading -> TangemPayMainLoadingItem(modifier)
is TangemPayMainUM.UnderReview -> TangemPayMainUnderReviewItem(state, modifier)
is TangemPayMainUM.IssuingCard -> TangemPayMainIssuingCardItem(state, modifier)
is TangemPayMainUM.FailedToIssue -> TangemPayMainFailedIssueItem(state, modifier)
is TangemPayMainUM.Content -> TangemPayMainBlockContent(state, isBalanceHidden, modifier)
is TangemPayMainUM.TemporaryUnavailable -> TangemPayMainTempUnavailableItem(modifier)
is TangemPayMainUM.SyncNeeded -> TangemPayMainSyncNeededItem(modifier)
is TangemPayMainUM.ExposedDevice -> TangemPayMainExposedDeviceItem(modifier)
is TangemPayMainUM.Loading -> TangemPayMainLoading(modifier)
is TangemPayMainUM.UnderReview -> TangemPayStateRow(
subtitle = state.subtitle,
modifier = modifier,
onClick = state.onClick,
)
is TangemPayMainUM.IssuingCard -> TangemPayStateRow(
subtitle = resourceReference(R.string.tangempay_issuing_your_card),
modifier = modifier,
onClick = state.onClick,
)
is TangemPayMainUM.FailedToIssue -> TangemPayStateRow(
subtitle = resourceReference(R.string.tangempay_failed_to_issue_card),
modifier = modifier,
showError = true,
onClick = state.onClick,
)
is TangemPayMainUM.Content -> TangemPayMainContent(state, isBalanceHidden, modifier)
is TangemPayMainUM.TemporaryUnavailable -> TangemPayStateRow(
subtitle = stringReference(DASH_SIGN),
modifier = modifier,
isEnabled = false,
)
is TangemPayMainUM.SyncNeeded -> TangemPayStateRow(
subtitle = resourceReference(R.string.tangempay_payment_account_sync_needed),
modifier = modifier,
isEnabled = false,
)
is TangemPayMainUM.ExposedDevice -> TangemPayStateRow(
subtitle = resourceReference(R.string.tangem_pay_rooted_device_subtitle),
modifier = modifier,
)
}
}
@Composable
private fun TangemPayMainBlockContent(
state: TangemPayMainUM.Content,
private fun TangemPayMainContent(
payMainUM: TangemPayMainUM.Content,
isBalanceHidden: Boolean,
modifier: Modifier = Modifier,
) {
Surface(
modifier = modifier,
shape = TangemTheme.shapes.roundedCornersXMedium,
color = TangemTheme.colors.background.primary,
onClick = state.onClick,
TangemRowContainer(
modifier = modifier
.clip(RoundedCornerShape(size = 18.dp))
.background(TangemTheme.colors2.surface.level3)
.clickableSingle(onClick = payMainUM.onClick),
) {
Row(
Image(
painter = painterResource(R.drawable.img_visa_36),
contentDescription = null,
modifier = Modifier
.fillMaxWidth()
.height(IntrinsicSize.Min)
.padding(horizontal = 12.dp, vertical = 16.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(12.dp),
) {
Image(
painter = painterResource(R.drawable.img_visa_36),
contentDescription = null,
modifier = Modifier.size(36.dp),
)
.layoutId(TangemRowLayoutId.HEAD)
.size(TangemTheme.dimens2.x10)
.padding(end = TangemTheme.dimens2.x2),
)
Text(
text = stringResourceSafe(R.string.tangempay_payment_account),
color = TangemTheme.colors2.text.neutral.primary,
style = TangemTheme.typography2.bodySemibold16,
modifier = Modifier.layoutId(TangemRowLayoutId.START_TOP),
)
Text(
text = payMainUM.subtitle.resolveReference(),
color = TangemTheme.colors2.text.neutral.secondary,
style = TangemTheme.typography2.captionSemibold12,
modifier = Modifier.layoutId(TangemRowLayoutId.START_BOTTOM),
)
TangemPayFiatAmount(
text = payMainUM.balance.orMaskWithStars(isBalanceHidden).resolveAnnotatedReference(),
isBalanceFlickering = payMainUM.isBalanceFlickering,
isBalanceFromCache = payMainUM.shouldShowOnlyCacheWarning,
modifier = Modifier.layoutId(TangemRowLayoutId.END_TOP),
)
Text(
text = payMainUM.balanceSubtitle.resolveReference(),
color = TangemTheme.colors2.text.neutral.secondary,
style = TangemTheme.typography2.captionSemibold12,
modifier = Modifier.layoutId(TangemRowLayoutId.END_BOTTOM),
)
}
}
Column(
modifier = Modifier.weight(1f),
verticalArrangement = Arrangement.spacedBy(2.dp),
) {
Text(
text = stringResourceSafe(R.string.tangempay_payment_account),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.primary1,
)
Text(
text = state.subtitle.resolveReference(),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
)
}
Column(
modifier = Modifier.fillMaxHeight(),
verticalArrangement = Arrangement.spacedBy(2.dp),
horizontalAlignment = Alignment.End,
) {
TangemPayFiatAmount(
text = state.balance.resolveReference(),
isBalanceFlickering = state.isBalanceFlickering,
isBalanceFromCache = state.shouldShowOnlyCacheWarning,
isBalanceHidden = isBalanceHidden,
)
Text(
text = state.balanceSubtitle.resolveReference(),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
textAlign = TextAlign.End,
)
}
@Composable
private fun TangemPayStateRow(
subtitle: TextReference,
modifier: Modifier = Modifier,
onClick: (() -> Unit)? = null,
showError: Boolean = false,
isEnabled: Boolean = true,
) {
TangemRowContainer(
modifier = modifier
.clip(RoundedCornerShape(size = 18.dp))
.background(TangemTheme.colors2.surface.level3)
.conditional(onClick != null && isEnabled) { clickableSingle(onClick = requireNotNull(onClick)) },
) {
Image(
painter = painterResource(R.drawable.img_visa_36),
contentDescription = null,
modifier = Modifier
.layoutId(TangemRowLayoutId.HEAD)
.size(TangemTheme.dimens2.x10)
.padding(end = TangemTheme.dimens2.x2)
.conditionalCompose(!isEnabled) {
alpha(DISABLED_ALPHA)
},
)
Text(
text = stringResourceSafe(R.string.tangempay_payment_account),
color = if (isEnabled) {
TangemTheme.colors2.text.neutral.primary
} else {
TangemTheme.colors2.text.status.disabled
},
style = TangemTheme.typography2.bodySemibold16,
modifier = Modifier.layoutId(TangemRowLayoutId.START_TOP),
)
Text(
text = subtitle.resolveReference(),
color = if (isEnabled) {
TangemTheme.colors2.text.neutral.secondary
} else {
TangemTheme.colors2.text.status.disabled
},
style = TangemTheme.typography2.captionSemibold12,
modifier = Modifier.layoutId(TangemRowLayoutId.START_BOTTOM),
)
AnimatedVisibility(
visible = showError,
enter = fadeIn(),
exit = fadeOut(),
label = "Error Icon Animation",
modifier = Modifier
.layoutId(TangemRowLayoutId.TAIL)
.size(TangemTheme.dimens2.x4),
) {
Icon(
painter = painterResource(R.drawable.ic_alert_24),
tint = TangemTheme.colors2.graphic.status.warning,
contentDescription = null,
)
}
}
}
@Composable
private fun TangemPayFiatAmount(
text: String,
text: AnnotatedString,
isBalanceFlickering: Boolean,
isBalanceFromCache: Boolean,
isBalanceHidden: Boolean,
modifier: Modifier = Modifier,
) {
Row(
@ -134,17 +210,17 @@ private fun TangemPayFiatAmount(
Icon(
modifier = Modifier.size(12.dp),
painter = painterResource(R.drawable.ic_error_sync_24),
tint = TangemTheme.colors.icon.inactive,
tint = TangemTheme.colors2.graphic.neutral.secondary,
contentDescription = null,
)
}
}
Text(
text = text.orMaskWithStars(isBalanceHidden),
style = TangemTheme.typography.body2.applyBladeBrush(
text = text,
style = TangemTheme.typography2.bodySemibold16.applyBladeBrush(
isEnabled = isBalanceFlickering,
textColor = TangemTheme.colors.text.primary1,
textColor = TangemTheme.colors2.text.neutral.primary,
),
textAlign = TextAlign.End,
)
@ -152,189 +228,63 @@ private fun TangemPayFiatAmount(
}
@Composable
private fun TangemPayMainUnderReviewItem(state: TangemPayMainUM.UnderReview, modifier: Modifier = Modifier) {
BlockCard(
private fun TangemPayMainLoading(modifier: Modifier = Modifier) {
TangemRowContainer(
modifier = modifier
.clip(RoundedCornerShape(size = TangemTheme.dimens.radius14))
.background(TangemTheme.colors.background.primary),
onClick = state.onClick,
.clip(RoundedCornerShape(size = 18.dp))
.background(TangemTheme.colors2.surface.level3),
) {
InputRowImageBase(
CircleShimmer(
modifier = Modifier
.padding(
all = TangemTheme.dimens.spacing12,
),
subtitle = resourceReference(R.string.tangempay_payment_account),
caption = state.subtitle,
subtitleColor = TangemTheme.colors.text.primary1,
captionColor = TangemTheme.colors.text.tertiary,
iconResWebp = R.drawable.img_visa_36,
.layoutId(TangemRowLayoutId.HEAD)
.padding(end = TangemTheme.dimens2.x2)
.size(TangemTheme.dimens2.x10),
)
}
}
@Composable
private fun TangemPayMainTempUnavailableItem(modifier: Modifier = Modifier) {
BlockCard(
modifier = modifier
.clip(RoundedCornerShape(size = TangemTheme.dimens.radius14))
.background(TangemTheme.colors.background.primary),
enabled = false,
) {
InputRowImageBase(
modifier = Modifier.padding(all = TangemTheme.dimens.spacing12),
subtitle = resourceReference(R.string.tangempay_payment_account),
caption = TextReference.Str(DASH_SIGN),
subtitleColor = TangemTheme.colors.text.tertiary,
captionColor = TangemTheme.colors.text.tertiary,
iconResWebp = R.drawable.img_visa_36,
)
}
}
@Composable
private fun TangemPayMainIssuingCardItem(state: TangemPayMainUM.IssuingCard, modifier: Modifier = Modifier) {
BlockCard(
modifier = modifier
.clip(RoundedCornerShape(size = TangemTheme.dimens.radius14))
.background(TangemTheme.colors.background.primary),
onClick = state.onClick,
) {
InputRowImageBase(
TextShimmer(
style = TangemTheme.typography2.bodySemibold16,
radius = TangemTheme.dimens2.x25,
modifier = Modifier
.padding(all = TangemTheme.dimens.spacing12),
subtitle = resourceReference(R.string.tangempay_payment_account),
caption = resourceReference(R.string.tangempay_issuing_your_card),
subtitleColor = TangemTheme.colors.text.primary1,
captionColor = TangemTheme.colors.text.tertiary,
iconResWebp = R.drawable.img_visa_36,
.layoutId(TangemRowLayoutId.START_TOP)
.width(TangemTheme.dimens2.x25),
)
}
}
@Composable
private fun TangemPayMainFailedIssueItem(state: TangemPayMainUM.FailedToIssue, modifier: Modifier = Modifier) {
BlockCard(
modifier = modifier
.clip(RoundedCornerShape(size = TangemTheme.dimens.radius14))
.background(TangemTheme.colors.background.primary),
onClick = state.onClick,
) {
InputRowImageBase(
TextShimmer(
style = TangemTheme.typography2.captionSemibold12,
radius = TangemTheme.dimens2.x25,
modifier = Modifier
.padding(
all = TangemTheme.dimens.spacing12,
),
subtitle = TextReference.Res(R.string.tangempay_payment_account),
caption = TextReference.Res(R.string.tangempay_failed_to_issue_card),
subtitleColor = TangemTheme.colors.text.primary1,
captionColor = TangemTheme.colors.text.tertiary,
iconResWebp = com.tangem.core.ui.R.drawable.img_visa_36,
iconEndRes = R.drawable.ic_alert_24,
endIconTint = TangemTheme.colors.icon.warning,
.layoutId(TangemRowLayoutId.START_BOTTOM)
.width(TangemTheme.dimens2.x11),
)
}
}
@Composable
private fun TangemPayMainSyncNeededItem(modifier: Modifier = Modifier) {
BlockCard(
modifier = modifier
.clip(RoundedCornerShape(size = TangemTheme.dimens.radius14))
.background(TangemTheme.colors.background.primary),
enabled = false,
) {
InputRowImageBase(
modifier = Modifier.padding(
all = TangemTheme.dimens.spacing12,
),
subtitle = resourceReference(R.string.tangempay_payment_account),
caption = resourceReference(R.string.tangempay_payment_account_sync_needed),
subtitleColor = TangemTheme.colors.text.tertiary,
captionColor = TangemTheme.colors.text.tertiary,
iconResWebp = R.drawable.img_visa_36,
)
}
}
@Composable
private fun TangemPayMainExposedDeviceItem(modifier: Modifier = Modifier) {
BlockCard(
modifier = modifier
.clip(RoundedCornerShape(size = TangemTheme.dimens.radius14))
.background(TangemTheme.colors.background.primary)
.alpha(DISABLED_ALPHA),
enabled = false,
) {
InputRowImageBase(
TextShimmer(
style = TangemTheme.typography2.bodyRegular16,
radius = TangemTheme.dimens2.x25,
modifier = Modifier
.padding(
all = TangemTheme.dimens.spacing12,
),
subtitle = resourceReference(R.string.tangempay_payment_account),
caption = resourceReference(R.string.tangem_pay_rooted_device_subtitle),
subtitleColor = TangemTheme.colors.text.primary1,
captionColor = TangemTheme.colors.text.tertiary,
iconResWebp = R.drawable.img_visa_36,
endIconTint = TangemTheme.colors.icon.warning,
.layoutId(TangemRowLayoutId.END_TOP)
.width(TangemTheme.dimens2.x20),
)
TextShimmer(
style = TangemTheme.typography2.bodyRegular16,
radius = TangemTheme.dimens2.x25,
modifier = Modifier
.layoutId(TangemRowLayoutId.END_BOTTOM)
.width(TangemTheme.dimens2.x11),
)
}
}
// region Preview
@Preview(showBackground = true, widthDp = 360)
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun TangemPayMainLoadingItem(modifier: Modifier = Modifier) {
Row(
modifier = modifier
.fillMaxWidth()
.background(color = TangemTheme.colors.background.primary, shape = TangemTheme.shapes.roundedCornersXMedium)
.padding(horizontal = 12.dp, vertical = 16.dp),
verticalAlignment = Alignment.CenterVertically,
) {
CircleShimmer(modifier = Modifier.size(36.dp))
Column(
modifier = Modifier.padding(start = 12.dp),
verticalArrangement = Arrangement.spacedBy(2.dp),
) {
RectangleShimmer(
modifier = Modifier
.padding(vertical = 4.dp)
.sizeIn(minWidth = 70.dp, minHeight = 12.dp),
)
RectangleShimmer(
modifier = Modifier
.padding(vertical = 2.dp)
.sizeIn(minWidth = 52.dp, minHeight = 12.dp),
)
}
SpacerWMax()
Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
RectangleShimmer(
modifier = Modifier
.padding(vertical = 4.dp)
.sizeIn(minWidth = 40.dp, minHeight = 12.dp),
)
RectangleShimmer(
modifier = Modifier
.padding(vertical = 2.dp)
.sizeIn(minWidth = 40.dp, minHeight = 12.dp),
)
}
}
}
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Preview
@Composable
private fun TangemPayMainItemsPreview(
@PreviewParameter(TangemPayMainUMPreviewParameterProvider::class)
private fun TangemPayMainBlockContent_Preview(
@PreviewParameter(TangemPayMainBlockContentPreviewParameterProvider::class)
state: TangemPayMainUM,
) {
TangemThemePreview {
TangemPayMainBlockItem(state = state, isBalanceHidden = false)
TangemThemePreviewRedesign {
TangemPayMainBlockContent(state = state, isBalanceHidden = false)
}
}
private class TangemPayMainUMPreviewParameterProvider : CollectionPreviewParameterProvider<TangemPayMainUM>(
private class TangemPayMainBlockContentPreviewParameterProvider : CollectionPreviewParameterProvider<TangemPayMainUM>(
collection = listOf(
TangemPayMainUM.Loading,
TangemPayMainUM.SyncNeeded,
@ -352,4 +302,5 @@ private class TangemPayMainUMPreviewParameterProvider : CollectionPreviewParamet
shouldShowOnlyCacheWarning = true,
),
),
)
)
// endregion

View file

@ -0,0 +1,355 @@
package com.tangem.features.tangempay.ui
import android.content.res.Configuration
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
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.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.painterResource
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 androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.CircleShimmer
import com.tangem.core.ui.components.RectangleShimmer
import com.tangem.core.ui.components.SpacerWMax
import com.tangem.core.ui.components.block.BlockCard
import com.tangem.core.ui.components.inputrow.InputRowImageBase
import com.tangem.core.ui.components.text.applyBladeBrush
import com.tangem.core.ui.extensions.*
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.features.tangempay.entity.TangemPayMainUM
import com.tangem.features.tangempay.main.impl.R
import com.tangem.utils.StringsSigns.DASH_SIGN
private const val DISABLED_ALPHA = 0.6F
@Composable
internal fun TangemPayMainBlockItem(state: TangemPayMainUM, isBalanceHidden: Boolean, modifier: Modifier = Modifier) {
when (state) {
is TangemPayMainUM.Empty -> Unit
is TangemPayMainUM.Loading -> TangemPayMainLoadingItem(modifier)
is TangemPayMainUM.UnderReview -> TangemPayMainUnderReviewItem(state, modifier)
is TangemPayMainUM.IssuingCard -> TangemPayMainIssuingCardItem(state, modifier)
is TangemPayMainUM.FailedToIssue -> TangemPayMainFailedIssueItem(state, modifier)
is TangemPayMainUM.Content -> TangemPayMainBlockContent(state, isBalanceHidden, modifier)
is TangemPayMainUM.TemporaryUnavailable -> TangemPayMainTempUnavailableItem(modifier)
is TangemPayMainUM.SyncNeeded -> TangemPayMainSyncNeededItem(modifier)
is TangemPayMainUM.ExposedDevice -> TangemPayMainExposedDeviceItem(modifier)
}
}
@Composable
private fun TangemPayMainBlockContent(
state: TangemPayMainUM.Content,
isBalanceHidden: Boolean,
modifier: Modifier = Modifier,
) {
Surface(
modifier = modifier,
shape = TangemTheme.shapes.roundedCornersXMedium,
color = TangemTheme.colors.background.primary,
onClick = state.onClick,
) {
Row(
modifier = Modifier
.fillMaxWidth()
.height(IntrinsicSize.Min)
.padding(horizontal = 12.dp, vertical = 16.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(12.dp),
) {
Image(
painter = painterResource(R.drawable.img_visa_36),
contentDescription = null,
modifier = Modifier.size(36.dp),
)
Column(
modifier = Modifier.weight(1f),
verticalArrangement = Arrangement.spacedBy(2.dp),
) {
Text(
text = stringResourceSafe(R.string.tangempay_payment_account),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.primary1,
)
Text(
text = state.subtitle.resolveReference(),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
)
}
Column(
modifier = Modifier.fillMaxHeight(),
verticalArrangement = Arrangement.spacedBy(2.dp),
horizontalAlignment = Alignment.End,
) {
TangemPayFiatAmount(
text = state.balance.resolveReference(),
isBalanceFlickering = state.isBalanceFlickering,
isBalanceFromCache = state.shouldShowOnlyCacheWarning,
isBalanceHidden = isBalanceHidden,
)
Text(
text = state.balanceSubtitle.resolveReference(),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
textAlign = TextAlign.End,
)
}
}
}
}
@Composable
private fun TangemPayFiatAmount(
text: String,
isBalanceFlickering: Boolean,
isBalanceFromCache: Boolean,
isBalanceHidden: Boolean,
modifier: Modifier = Modifier,
) {
Row(
modifier = modifier,
verticalAlignment = Alignment.CenterVertically,
) {
AnimatedVisibility(isBalanceFromCache) {
Row(
modifier = Modifier.padding(horizontal = 4.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(4.dp),
) {
Icon(
modifier = Modifier.size(12.dp),
painter = painterResource(R.drawable.ic_error_sync_24),
tint = TangemTheme.colors.icon.inactive,
contentDescription = null,
)
}
}
Text(
text = text.orMaskWithStars(isBalanceHidden),
style = TangemTheme.typography.body2.applyBladeBrush(
isEnabled = isBalanceFlickering,
textColor = TangemTheme.colors.text.primary1,
),
textAlign = TextAlign.End,
)
}
}
@Composable
private fun TangemPayMainUnderReviewItem(state: TangemPayMainUM.UnderReview, modifier: Modifier = Modifier) {
BlockCard(
modifier = modifier
.clip(RoundedCornerShape(size = TangemTheme.dimens.radius14))
.background(TangemTheme.colors.background.primary),
onClick = state.onClick,
) {
InputRowImageBase(
modifier = Modifier
.padding(
all = TangemTheme.dimens.spacing12,
),
subtitle = resourceReference(R.string.tangempay_payment_account),
caption = state.subtitle,
subtitleColor = TangemTheme.colors.text.primary1,
captionColor = TangemTheme.colors.text.tertiary,
iconResWebp = R.drawable.img_visa_36,
)
}
}
@Composable
private fun TangemPayMainTempUnavailableItem(modifier: Modifier = Modifier) {
BlockCard(
modifier = modifier
.clip(RoundedCornerShape(size = TangemTheme.dimens.radius14))
.background(TangemTheme.colors.background.primary),
enabled = false,
) {
InputRowImageBase(
modifier = Modifier.padding(all = TangemTheme.dimens.spacing12),
subtitle = resourceReference(R.string.tangempay_payment_account),
caption = TextReference.Str(DASH_SIGN),
subtitleColor = TangemTheme.colors.text.tertiary,
captionColor = TangemTheme.colors.text.tertiary,
iconResWebp = R.drawable.img_visa_36,
)
}
}
@Composable
private fun TangemPayMainIssuingCardItem(state: TangemPayMainUM.IssuingCard, modifier: Modifier = Modifier) {
BlockCard(
modifier = modifier
.clip(RoundedCornerShape(size = TangemTheme.dimens.radius14))
.background(TangemTheme.colors.background.primary),
onClick = state.onClick,
) {
InputRowImageBase(
modifier = Modifier
.padding(all = TangemTheme.dimens.spacing12),
subtitle = resourceReference(R.string.tangempay_payment_account),
caption = resourceReference(R.string.tangempay_issuing_your_card),
subtitleColor = TangemTheme.colors.text.primary1,
captionColor = TangemTheme.colors.text.tertiary,
iconResWebp = R.drawable.img_visa_36,
)
}
}
@Composable
private fun TangemPayMainFailedIssueItem(state: TangemPayMainUM.FailedToIssue, modifier: Modifier = Modifier) {
BlockCard(
modifier = modifier
.clip(RoundedCornerShape(size = TangemTheme.dimens.radius14))
.background(TangemTheme.colors.background.primary),
onClick = state.onClick,
) {
InputRowImageBase(
modifier = Modifier
.padding(
all = TangemTheme.dimens.spacing12,
),
subtitle = TextReference.Res(R.string.tangempay_payment_account),
caption = TextReference.Res(R.string.tangempay_failed_to_issue_card),
subtitleColor = TangemTheme.colors.text.primary1,
captionColor = TangemTheme.colors.text.tertiary,
iconResWebp = com.tangem.core.ui.R.drawable.img_visa_36,
iconEndRes = R.drawable.ic_alert_24,
endIconTint = TangemTheme.colors.icon.warning,
)
}
}
@Composable
private fun TangemPayMainSyncNeededItem(modifier: Modifier = Modifier) {
BlockCard(
modifier = modifier
.clip(RoundedCornerShape(size = TangemTheme.dimens.radius14))
.background(TangemTheme.colors.background.primary),
enabled = false,
) {
InputRowImageBase(
modifier = Modifier.padding(
all = TangemTheme.dimens.spacing12,
),
subtitle = resourceReference(R.string.tangempay_payment_account),
caption = resourceReference(R.string.tangempay_payment_account_sync_needed),
subtitleColor = TangemTheme.colors.text.tertiary,
captionColor = TangemTheme.colors.text.tertiary,
iconResWebp = R.drawable.img_visa_36,
)
}
}
@Composable
private fun TangemPayMainExposedDeviceItem(modifier: Modifier = Modifier) {
BlockCard(
modifier = modifier
.clip(RoundedCornerShape(size = TangemTheme.dimens.radius14))
.background(TangemTheme.colors.background.primary)
.alpha(DISABLED_ALPHA),
enabled = false,
) {
InputRowImageBase(
modifier = Modifier
.padding(
all = TangemTheme.dimens.spacing12,
),
subtitle = resourceReference(R.string.tangempay_payment_account),
caption = resourceReference(R.string.tangem_pay_rooted_device_subtitle),
subtitleColor = TangemTheme.colors.text.primary1,
captionColor = TangemTheme.colors.text.tertiary,
iconResWebp = R.drawable.img_visa_36,
endIconTint = TangemTheme.colors.icon.warning,
)
}
}
@Composable
private fun TangemPayMainLoadingItem(modifier: Modifier = Modifier) {
Row(
modifier = modifier
.fillMaxWidth()
.background(color = TangemTheme.colors.background.primary, shape = TangemTheme.shapes.roundedCornersXMedium)
.padding(horizontal = 12.dp, vertical = 16.dp),
verticalAlignment = Alignment.CenterVertically,
) {
CircleShimmer(modifier = Modifier.size(36.dp))
Column(
modifier = Modifier.padding(start = 12.dp),
verticalArrangement = Arrangement.spacedBy(2.dp),
) {
RectangleShimmer(
modifier = Modifier
.padding(vertical = 4.dp)
.sizeIn(minWidth = 70.dp, minHeight = 12.dp),
)
RectangleShimmer(
modifier = Modifier
.padding(vertical = 2.dp)
.sizeIn(minWidth = 52.dp, minHeight = 12.dp),
)
}
SpacerWMax()
Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
RectangleShimmer(
modifier = Modifier
.padding(vertical = 4.dp)
.sizeIn(minWidth = 40.dp, minHeight = 12.dp),
)
RectangleShimmer(
modifier = Modifier
.padding(vertical = 2.dp)
.sizeIn(minWidth = 40.dp, minHeight = 12.dp),
)
}
}
}
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Preview
@Composable
private fun TangemPayMainItemsPreview(
@PreviewParameter(TangemPayMainUMPreviewParameterProvider::class)
state: TangemPayMainUM,
) {
TangemThemePreview {
TangemPayMainBlockItem(state = state, isBalanceHidden = false)
}
}
private class TangemPayMainUMPreviewParameterProvider : CollectionPreviewParameterProvider<TangemPayMainUM>(
collection = listOf(
TangemPayMainUM.Loading,
TangemPayMainUM.SyncNeeded,
TangemPayMainUM.TemporaryUnavailable,
TangemPayMainUM.ExposedDevice,
TangemPayMainUM.FailedToIssue(onClick = {}),
TangemPayMainUM.UnderReview(subtitle = resourceReference(R.string.tangempay_kyc_in_progress), onClick = {}),
TangemPayMainUM.IssuingCard(onClick = {}),
TangemPayMainUM.Content(
subtitle = TextReference.Str("*1234"),
isBalanceFlickering = true,
balance = TextReference.Str("$ 101.56"),
balanceSubtitle = TextReference.Str("USDC"),
onClick = {},
shouldShowOnlyCacheWarning = true,
),
),
)