Updated on 2026-08-14
This commit is contained in:
parent
579b3cba32
commit
f74c37a080
25 changed files with 154 additions and 40 deletions
|
|
@ -13,6 +13,7 @@ internal class TangemPayCardDetailsBlockStateFactory(
|
|||
private val displayName: CardDisplayName?,
|
||||
private val isEditingNameEnabled: Boolean,
|
||||
private val cardState: TangemPayCardState,
|
||||
private val cardImageUrl: String?,
|
||||
private val onEditNameClick: () -> Unit,
|
||||
private val onReveal: () -> Unit,
|
||||
private val onCopy: (String, CardDataType) -> Unit,
|
||||
|
|
@ -41,6 +42,7 @@ internal class TangemPayCardDetailsBlockStateFactory(
|
|||
},
|
||||
shouldShowCardDetailsButtonOnCard = shouldShowCardDetailsButtonOnCard,
|
||||
cardState = cardState,
|
||||
cardImageUrl = cardImageUrl,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -18,6 +18,7 @@ import com.tangem.domain.models.pay.TangemPayCard
|
|||
import com.tangem.domain.models.pay.TangemPayCardFrozenState
|
||||
import com.tangem.domain.models.pay.TangemPayCardState
|
||||
import com.tangem.domain.models.pay.isFrozen
|
||||
import com.tangem.domain.models.pay.thumbnailUrl
|
||||
import com.tangem.features.tangempay.details.impl.R
|
||||
import com.tangem.features.tangempay.utils.TangemPayDetailIntents
|
||||
import com.tangem.features.tangempay.utils.hasWithdrawableAmount
|
||||
|
|
@ -102,6 +103,7 @@ internal class TangemPayDetailsStateFactory(
|
|||
.map { cardItem ->
|
||||
TangemPayDetailsBalanceBlockState.Card(
|
||||
lastDigits = cardItem.lastDigits,
|
||||
imageUrl = cardItem.thumbnailUrl,
|
||||
onClick = { intents.onCardClick(cardItem.id) },
|
||||
isEnabled = status.error == null,
|
||||
isFrozen = cardItem.isFrozen,
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ internal data class TangemPayCardDetailsUM(
|
|||
val isLoading: Boolean = false,
|
||||
val cardFrozenState: TangemPayCardFrozenState,
|
||||
val displayNameState: DisplayNameState?,
|
||||
val cardImageUrl: String?,
|
||||
val isActionsAvailable: Boolean = false,
|
||||
val shouldShowCardDetailsButtonOnCard: Boolean = false,
|
||||
val cardState: TangemPayCardState = TangemPayCardState.Active,
|
||||
|
|
@ -111,6 +112,7 @@ internal sealed class TangemPayDetailsBalanceBlockState {
|
|||
|
||||
data class Card(
|
||||
val lastDigits: String,
|
||||
val imageUrl: String?,
|
||||
val onClick: () -> Unit,
|
||||
val state: TangemPayCardUiState,
|
||||
val isFrozen: Boolean,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import com.tangem.domain.models.account.findCardWithId
|
|||
import com.tangem.domain.models.pay.TangemPayCard
|
||||
import com.tangem.domain.models.pay.TangemPayCardFrozenState
|
||||
import com.tangem.domain.models.pay.TangemPayCardState
|
||||
import com.tangem.domain.models.pay.mainImageUrl
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.flow.PaymentAccountStatusSupplier
|
||||
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
|
||||
|
|
@ -78,6 +79,7 @@ internal class TangemPayCardDetailsController @AssistedInject constructor(
|
|||
onCopy = ::copyData,
|
||||
shouldShowCardDetailsButtonOnCard = config.shouldShowCardDetailsButtonOnCard,
|
||||
cardState = card.state,
|
||||
cardImageUrl = card.mainImageUrl,
|
||||
)
|
||||
|
||||
val uiState: StateFlow<TangemPayCardDetailsUM>
|
||||
|
|
@ -119,6 +121,7 @@ internal class TangemPayCardDetailsController @AssistedInject constructor(
|
|||
cardFrozenState = card.frozenState,
|
||||
isActionsAvailable = card.state == TangemPayCardState.Active,
|
||||
cardState = card.state,
|
||||
cardImageUrl = card.mainImageUrl,
|
||||
)
|
||||
}
|
||||
subscribeToCardFrozenState(card.id)
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ package com.tangem.features.tangempay.tiers.select
|
|||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.pager.HorizontalPager
|
||||
import androidx.compose.foundation.pager.rememberPagerState
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
|
|
@ -16,7 +16,6 @@ import androidx.compose.runtime.LaunchedEffect
|
|||
import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
|
|
@ -26,7 +25,6 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.compose.ui.util.fastForEach
|
||||
import coil.compose.SubcomposeAsyncImage
|
||||
import coil.request.ImageRequest
|
||||
import com.tangem.core.ui.components.RectangleShimmer
|
||||
import com.tangem.core.ui.ds.TangemPagerIndicator
|
||||
import com.tangem.core.ui.ds.topbar.TangemTopBar
|
||||
import com.tangem.core.ui.ds2.button.Back
|
||||
|
|
@ -268,31 +266,29 @@ private fun ConfirmFooter(content: TangemPaySelectPlanUM.Content.Confirm, modifi
|
|||
@Suppress("MagicNumber")
|
||||
@Composable
|
||||
private fun PlanCard(imageUrl: String?, modifier: Modifier = Modifier) {
|
||||
SubcomposeAsyncImage(
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(ratio = 266f / 172f)
|
||||
.clip(RoundedCornerShape(12.dp)),
|
||||
model = ImageRequest.Builder(LocalContext.current)
|
||||
.data(imageUrl)
|
||||
.crossfade(true)
|
||||
.build(),
|
||||
loading = {
|
||||
RectangleShimmer(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
radius = 12.dp,
|
||||
)
|
||||
},
|
||||
error = {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(TangemTheme.colors3.bg.secondary),
|
||||
)
|
||||
},
|
||||
contentScale = ContentScale.Crop,
|
||||
contentDescription = null,
|
||||
)
|
||||
.aspectRatio(ratio = 266f / 172f),
|
||||
) {
|
||||
Image(
|
||||
modifier = Modifier.matchParentSize(),
|
||||
painter = painterResource(R.drawable.img_tangem_pay_visa_reissuing),
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.FillBounds,
|
||||
)
|
||||
SubcomposeAsyncImage(
|
||||
modifier = Modifier.matchParentSize(),
|
||||
model = ImageRequest.Builder(LocalContext.current)
|
||||
.data(imageUrl)
|
||||
.crossfade(true)
|
||||
.build(),
|
||||
loading = {},
|
||||
error = {},
|
||||
contentScale = ContentScale.FillBounds,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, device = Devices.PIXEL_7_PRO)
|
||||
|
|
|
|||
|
|
@ -186,6 +186,7 @@ private fun PreviewTangemPayAddToWalletScreen() {
|
|||
buttonText = TextReference.Res(R.string.tangempay_card_details_hide_text),
|
||||
cardFrozenState = TangemPayCardFrozenState.Unfrozen,
|
||||
displayNameState = null,
|
||||
cardImageUrl = null,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -220,6 +220,7 @@ private fun PreviewTangemPayAddToWalletScreen() {
|
|||
buttonText = TextReference.Res(R.string.tangempay_card_details_hide_text),
|
||||
cardFrozenState = TangemPayCardFrozenState.Unfrozen,
|
||||
displayNameState = null,
|
||||
cardImageUrl = null,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import androidx.compose.ui.graphics.graphicsLayer
|
|||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.layout.SubcomposeLayout
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.painterResource
|
||||
|
|
@ -46,6 +47,8 @@ import androidx.constraintlayout.compose.ConstrainedLayoutReference
|
|||
import androidx.constraintlayout.compose.ConstraintLayout
|
||||
import androidx.constraintlayout.compose.ConstraintLayoutScope
|
||||
import androidx.constraintlayout.compose.Dimension
|
||||
import coil.compose.SubcomposeAsyncImage
|
||||
import coil.request.ImageRequest
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.components.SpacerWMax
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButton
|
||||
|
|
@ -123,6 +126,7 @@ private fun TangemPayCardDetailsHiddenBlock(state: TangemPayCardDetailsUM, modif
|
|||
.zIndex(0f),
|
||||
cardFrozenState = state.cardFrozenState,
|
||||
cardState = state.cardState,
|
||||
cardImageUrl = state.cardImageUrl,
|
||||
)
|
||||
|
||||
Box(
|
||||
|
|
@ -219,6 +223,7 @@ private fun TangemPayCardDetailsHiddenBlock(state: TangemPayCardDetailsUM, modif
|
|||
private fun TangemPayCardBackground(
|
||||
cardState: TangemPayCardState,
|
||||
cardFrozenState: TangemPayCardFrozenState,
|
||||
cardImageUrl: String?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val isFrozen = cardFrozenState == TangemPayCardFrozenState.Frozen
|
||||
|
|
@ -233,7 +238,7 @@ private fun TangemPayCardBackground(
|
|||
|
||||
Box(modifier = modifier.fillMaxSize()) {
|
||||
Image(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
modifier = Modifier.matchParentSize(),
|
||||
painter = when (cardState) {
|
||||
TangemPayCardState.Active,
|
||||
-> painterResource(R.drawable.img_tangem_pay_visa)
|
||||
|
|
@ -245,7 +250,19 @@ private fun TangemPayCardBackground(
|
|||
contentDescription = null,
|
||||
contentScale = ContentScale.FillBounds,
|
||||
)
|
||||
|
||||
if (cardImageUrl != null && cardState == TangemPayCardState.Active) {
|
||||
SubcomposeAsyncImage(
|
||||
modifier = Modifier.matchParentSize(),
|
||||
model = ImageRequest.Builder(LocalContext.current)
|
||||
.data(cardImageUrl)
|
||||
.crossfade(true)
|
||||
.build(),
|
||||
loading = {},
|
||||
error = {},
|
||||
contentScale = ContentScale.FillBounds,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
if (isFrozen || freezeProgress > 0f) {
|
||||
Image(
|
||||
modifier = Modifier
|
||||
|
|
@ -756,6 +773,7 @@ private class TangemPayCardDetailsUMProvider : CollectionPreviewParameterProvide
|
|||
cvv = "",
|
||||
buttonText = resourceReference(R.string.tangempay_card_details_show_details),
|
||||
onCopy = { _, _ -> },
|
||||
cardImageUrl = null,
|
||||
isHidden = true,
|
||||
cardFrozenState = TangemPayCardFrozenState.Frozen,
|
||||
displayNameState = DisplayNameState.Editing(
|
||||
|
|
@ -776,6 +794,7 @@ private class TangemPayCardDetailsUMProvider : CollectionPreviewParameterProvide
|
|||
cvv = "",
|
||||
buttonText = resourceReference(R.string.tangempay_card_details_show_details),
|
||||
onCopy = { _, _ -> },
|
||||
cardImageUrl = null,
|
||||
isHidden = true,
|
||||
cardFrozenState = TangemPayCardFrozenState.Unfrozen,
|
||||
displayNameState = DisplayNameState.Editing(
|
||||
|
|
@ -796,6 +815,7 @@ private class TangemPayCardDetailsUMProvider : CollectionPreviewParameterProvide
|
|||
cvv = "",
|
||||
buttonText = resourceReference(R.string.tangempay_card_details_show_details),
|
||||
onCopy = { _, _ -> },
|
||||
cardImageUrl = null,
|
||||
isHidden = true,
|
||||
cardFrozenState = TangemPayCardFrozenState.Pending,
|
||||
displayNameState = DisplayNameState.Display(
|
||||
|
|
@ -809,6 +829,7 @@ private class TangemPayCardDetailsUMProvider : CollectionPreviewParameterProvide
|
|||
onClick = {},
|
||||
buttonText = resourceReference(R.string.tangempay_card_details_hide_details),
|
||||
onCopy = { _, _ -> },
|
||||
cardImageUrl = null,
|
||||
isHidden = false,
|
||||
number = "1234 5678 9012 3456",
|
||||
numberShort = "*3456",
|
||||
|
|
|
|||
|
|
@ -428,6 +428,7 @@ private fun previewCardDetailsState(): TangemPayCardDetailsUM = TangemPayCardDet
|
|||
onClick = {},
|
||||
isEditingEnabled = false,
|
||||
),
|
||||
cardImageUrl = null,
|
||||
)
|
||||
|
||||
@Preview
|
||||
|
|
|
|||
|
|
@ -491,6 +491,7 @@ internal class TangemPayDetailsUMProvider : CollectionPreviewParameterProvider<T
|
|||
cards = persistentListOf(
|
||||
TangemPayDetailsBalanceBlockState.Card(
|
||||
lastDigits = "1234",
|
||||
imageUrl = null,
|
||||
onClick = {},
|
||||
isEnabled = false,
|
||||
isFrozen = false,
|
||||
|
|
@ -498,6 +499,7 @@ internal class TangemPayDetailsUMProvider : CollectionPreviewParameterProvider<T
|
|||
),
|
||||
TangemPayDetailsBalanceBlockState.Card(
|
||||
lastDigits = "3456",
|
||||
imageUrl = null,
|
||||
onClick = {},
|
||||
isEnabled = true,
|
||||
isFrozen = false,
|
||||
|
|
@ -531,6 +533,7 @@ internal class TangemPayDetailsUMProvider : CollectionPreviewParameterProvider<T
|
|||
cards = persistentListOf(
|
||||
TangemPayDetailsBalanceBlockState.Card(
|
||||
lastDigits = "1234",
|
||||
imageUrl = null,
|
||||
onClick = {},
|
||||
isFrozen = false,
|
||||
isEnabled = true,
|
||||
|
|
|
|||
|
|
@ -412,6 +412,7 @@ private fun CardsBlock(
|
|||
TangemPayCardView(
|
||||
isIssueInProgress = item.state != TangemPayCardUiState.Active,
|
||||
lastDigits = item.lastDigits,
|
||||
imageUrl = item.imageUrl,
|
||||
onClick = item.onClick,
|
||||
isEnabled = item.isEnabled,
|
||||
isFrozen = item.isFrozen,
|
||||
|
|
|
|||
|
|
@ -19,12 +19,16 @@ import androidx.compose.ui.graphics.Brush
|
|||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.TileMode
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.tooling.preview.Devices
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import coil.compose.SubcomposeAsyncImage
|
||||
import coil.request.ImageRequest
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.extensions.clickableSingle
|
||||
|
|
@ -40,11 +44,13 @@ private const val DEFAULT_CARD_BG = 0xFF1C1F29
|
|||
private const val REISSUING_CARD_BG = 0xFF1E1E1E
|
||||
private const val DISABLED_ALPHA = 0.5f
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@Composable
|
||||
internal fun TangemPayCardView(
|
||||
isIssueInProgress: Boolean,
|
||||
isEnabled: Boolean,
|
||||
lastDigits: String,
|
||||
imageUrl: String?,
|
||||
onClick: () -> Unit,
|
||||
isFrozen: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
|
|
@ -58,6 +64,7 @@ internal fun TangemPayCardView(
|
|||
.testTag(TangemPayTestTags.PAYMENT_ACCOUNT_CARD_BUTTON),
|
||||
isIssueInProgress = isIssueInProgress,
|
||||
isEnabled = isEnabled,
|
||||
imageUrl = imageUrl,
|
||||
onClick = onClick,
|
||||
) {
|
||||
Row(
|
||||
|
|
@ -78,7 +85,6 @@ internal fun TangemPayCardView(
|
|||
tint = TangemTheme.colors3.icon.staticDark,
|
||||
contentDescription = null,
|
||||
)
|
||||
|
||||
Icon(
|
||||
modifier = Modifier.size(height = TangemTheme.dimens2.x2, width = 22.dp),
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_visa_logo),
|
||||
|
|
@ -126,6 +132,7 @@ internal fun TangemPayAddCardView(onClick: () -> Unit, isEnabled: Boolean, modif
|
|||
private fun CardBackground(
|
||||
isIssueInProgress: Boolean,
|
||||
isEnabled: Boolean,
|
||||
imageUrl: String?,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
content: @Composable BoxScope.() -> Unit,
|
||||
|
|
@ -137,7 +144,6 @@ private fun CardBackground(
|
|||
Color(DEFAULT_CARD_BG)
|
||||
}
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = modifier
|
||||
.alpha(if (isEnabled) 1f else DISABLED_ALPHA)
|
||||
|
|
@ -171,8 +177,22 @@ private fun CardBackground(
|
|||
shape = RoundedCornerShape(6.dp),
|
||||
)
|
||||
.clickableSingle(onClick = onClick, enabled = isEnabled),
|
||||
content = content,
|
||||
)
|
||||
) {
|
||||
if (imageUrl != null) {
|
||||
SubcomposeAsyncImage(
|
||||
modifier = Modifier.matchParentSize(),
|
||||
model = ImageRequest.Builder(LocalContext.current)
|
||||
.data(imageUrl)
|
||||
.crossfade(true)
|
||||
.build(),
|
||||
loading = {},
|
||||
error = {},
|
||||
contentScale = ContentScale.Crop,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES, device = Devices.PIXEL_7_PRO)
|
||||
|
|
@ -189,6 +209,7 @@ private fun CardBackgroundPreview() {
|
|||
onClick = {},
|
||||
content = {},
|
||||
isEnabled = true,
|
||||
imageUrl = null,
|
||||
)
|
||||
SpacerH(TangemTheme.dimens2.x4)
|
||||
CardBackground(
|
||||
|
|
@ -197,6 +218,7 @@ private fun CardBackgroundPreview() {
|
|||
width = TangemTheme.dimens2.x14,
|
||||
),
|
||||
isIssueInProgress = true,
|
||||
imageUrl = null,
|
||||
onClick = {},
|
||||
content = {},
|
||||
isEnabled = true,
|
||||
|
|
@ -206,6 +228,7 @@ private fun CardBackgroundPreview() {
|
|||
isIssueInProgress = false,
|
||||
onClick = {},
|
||||
lastDigits = "1234",
|
||||
imageUrl = null,
|
||||
isEnabled = true,
|
||||
isFrozen = false,
|
||||
)
|
||||
|
|
@ -214,6 +237,7 @@ private fun CardBackgroundPreview() {
|
|||
isIssueInProgress = true,
|
||||
onClick = {},
|
||||
lastDigits = "",
|
||||
imageUrl = null,
|
||||
isEnabled = true,
|
||||
isFrozen = false,
|
||||
)
|
||||
|
|
@ -224,6 +248,7 @@ private fun CardBackgroundPreview() {
|
|||
isIssueInProgress = false,
|
||||
onClick = {},
|
||||
lastDigits = "1234",
|
||||
imageUrl = null,
|
||||
isEnabled = true,
|
||||
isFrozen = true,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -58,5 +58,6 @@ internal fun tangemPayCard(
|
|||
limit = null,
|
||||
frozenState = frozenState,
|
||||
lastDigits = lastDigits,
|
||||
images = emptyList(),
|
||||
state = state,
|
||||
)
|
||||
|
|
@ -47,6 +47,7 @@ internal class TangemPayCardLimitSetupModelTest {
|
|||
frozenState = TangemPayCardFrozenState.Unfrozen,
|
||||
lastDigits = "1234",
|
||||
limit = null,
|
||||
images = emptyList(),
|
||||
state = TangemPayCardState.Active,
|
||||
)
|
||||
|
||||
|
|
@ -72,6 +73,7 @@ internal class TangemPayCardLimitSetupModelTest {
|
|||
)
|
||||
}
|
||||
),
|
||||
images = emptyList(),
|
||||
state = TangemPayCardState.Active,
|
||||
)
|
||||
val statusWithLimit: PaymentAccountStatusValue.Loaded = mockk(relaxed = true) {
|
||||
|
|
|
|||
|
|
@ -162,6 +162,7 @@ internal class TangemPayEditDisplayNameModelTest {
|
|||
limit = null,
|
||||
frozenState = TangemPayCardFrozenState.Unfrozen,
|
||||
lastDigits = "1234",
|
||||
images = emptyList(),
|
||||
state = TangemPayCardState.Active,
|
||||
)
|
||||
}
|
||||
|
|
@ -238,6 +238,7 @@ internal class TangemPayCardDetailsControllerTest {
|
|||
limit = null,
|
||||
frozenState = frozenState,
|
||||
lastDigits = lastDigits,
|
||||
images = emptyList(),
|
||||
state = state,
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue