Updated on 2026-08-14

This commit is contained in:
Tangem 2026-06-26 11:04:11 +02:00
parent 2a06529480
commit 3b8d57864c
11 changed files with 162 additions and 57 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8 KiB

View file

@ -3,6 +3,7 @@ package com.tangem.features.tangempay.entity
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.models.account.CardDisplayName
import com.tangem.domain.models.pay.TangemPayCardFrozenState
import com.tangem.domain.models.pay.TangemPayCardState
import com.tangem.features.tangempay.details.impl.R
import com.tangem.utils.StringsSigns
@ -11,6 +12,7 @@ internal class TangemPayCardDetailsBlockStateFactory(
private val cardNumberEnd: String,
private val displayName: CardDisplayName?,
private val isEditingNameEnabled: Boolean,
private val cardState: TangemPayCardState,
private val onEditNameClick: () -> Unit,
private val onReveal: () -> Unit,
private val onCopy: (String, CardDataType) -> Unit,
@ -38,6 +40,7 @@ internal class TangemPayCardDetailsBlockStateFactory(
null
},
shouldShowCardDetailsButtonOnCard = shouldShowCardDetailsButtonOnCard,
cardState = cardState,
)
}
}

View file

@ -38,6 +38,7 @@ internal data class TangemPayCardDetailsUM(
val displayNameState: DisplayNameState?,
val isActionsAvailable: Boolean = false,
val shouldShowCardDetailsButtonOnCard: Boolean = false,
val cardState: TangemPayCardState = TangemPayCardState.Active,
)
@Immutable

View file

@ -77,6 +77,7 @@ internal class TangemPayCardDetailsController @AssistedInject constructor(
onReveal = ::requestReveal,
onCopy = ::copyData,
shouldShowCardDetailsButtonOnCard = config.shouldShowCardDetailsButtonOnCard,
cardState = card.state,
)
val uiState: StateFlow<TangemPayCardDetailsUM>
@ -117,6 +118,7 @@ internal class TangemPayCardDetailsController @AssistedInject constructor(
numberShort = "${StringsSigns.ASTERISK}${card.lastDigits}",
cardFrozenState = card.frozenState,
isActionsAvailable = card.state == TangemPayCardState.Active,
cardState = card.state,
)
}
subscribeToCardFrozenState(card.id)

View file

@ -60,6 +60,7 @@ import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.*
import com.tangem.core.ui.test.TangemPayTestTags
import com.tangem.domain.models.pay.TangemPayCardFrozenState
import com.tangem.domain.models.pay.TangemPayCardState
import com.tangem.features.tangempay.details.impl.R
import com.tangem.features.tangempay.entity.CardDataType
import com.tangem.features.tangempay.entity.DisplayNameState
@ -120,6 +121,7 @@ private fun TangemPayCardDetailsHiddenBlock(state: TangemPayCardDetailsUM, modif
.matchParentSize()
.zIndex(0f),
cardFrozenState = state.cardFrozenState,
cardState = state.cardState,
)
Box(
@ -209,7 +211,11 @@ private fun TangemPayCardDetailsHiddenBlock(state: TangemPayCardDetailsUM, modif
}
@Composable
private fun TangemPayCardBackground(cardFrozenState: TangemPayCardFrozenState, modifier: Modifier = Modifier) {
private fun TangemPayCardBackground(
cardState: TangemPayCardState,
cardFrozenState: TangemPayCardFrozenState,
modifier: Modifier = Modifier,
) {
val isFrozen = cardFrozenState == TangemPayCardFrozenState.Frozen
val freezeProgress by animateFloatAsState(
targetValue = if (isFrozen) 1f else 0f,
@ -223,7 +229,14 @@ private fun TangemPayCardBackground(cardFrozenState: TangemPayCardFrozenState, m
Box(modifier = modifier.fillMaxSize()) {
Image(
modifier = Modifier.fillMaxSize(),
painter = painterResource(R.drawable.img_tangem_pay_visa),
painter = when (cardState) {
TangemPayCardState.Active,
-> painterResource(R.drawable.img_tangem_pay_visa)
TangemPayCardState.Reissuing,
TangemPayCardState.Closing,
TangemPayCardState.Issuing,
-> painterResource(R.drawable.img_tangem_pay_visa_reissuing)
},
contentDescription = null,
contentScale = ContentScale.FillBounds,
)

View file

@ -32,9 +32,7 @@ import com.tangem.core.ui.ds.TangemPagerIndicator
import com.tangem.core.ui.ds.image.TangemIconUM
import com.tangem.core.ui.ds.topbar.TangemTopBar
import com.tangem.core.ui.ds2.button.TangemButton
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.extensions.*
import com.tangem.core.ui.res.*
import com.tangem.domain.models.pay.TangemPayCardFrozenState
import com.tangem.domain.models.pay.TangemPayCardState
@ -92,29 +90,93 @@ private fun TangemPayCardPageScreen(
},
) { scaffoldPaddings ->
val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() }
LazyColumn(
val contentBottomPadding = TangemTheme.dimens.spacing16 + bottomBarHeight
val reissueTitle = reissueTitleOrNull(isRedesignEnabled = isRedesignEnabled, cardState = state.cardState)
if (reissueTitle != null) {
ReissueCardLayout(
title = reissueTitle,
cardSection = cardSection,
modifier = Modifier
.fillMaxSize()
.padding(scaffoldPaddings)
.padding(bottom = contentBottomPadding),
)
} else {
LazyColumn(
modifier = Modifier
.fillMaxSize()
.padding(scaffoldPaddings),
contentPadding = PaddingValues(bottom = contentBottomPadding),
verticalArrangement = Arrangement.spacedBy(
if (isRedesignEnabled) 0.dp else TangemTheme.dimens.spacing16,
),
) {
item(key = "Card") {
Box(modifier = Modifier.padding(top = TangemTheme.dimens.spacing8)) {
cardSection()
}
}
if (
isRedesignEnabled &&
state.settingsV2.isNotEmpty() &&
state.cardState == TangemPayCardState.Active
) {
cardPageItem("Settings buttons") {
TangemPayCardPageSettingsButtonsBlock(
modifier = Modifier.fillMaxWidth(),
settings = state.settingsV2,
)
}
}
cardState(state = state)
}
}
}
}
private fun reissueTitleOrNull(isRedesignEnabled: Boolean, cardState: TangemPayCardState): TextReference? {
if (!isRedesignEnabled) return null
return when (cardState) {
TangemPayCardState.Reissuing -> combinedReference(
resourceReference(R.string.tangempay_reissue_card_in_progress),
stringReference(". "),
resourceReference(R.string.tangempay_reissue_card_in_progress_description),
)
TangemPayCardState.Issuing -> combinedReference(
resourceReference(R.string.tangempay_issuing_new_digital_card_title),
stringReference(". "),
resourceReference(R.string.tangempay_reissue_card_in_progress_description),
)
TangemPayCardState.Closing -> combinedReference(
resourceReference(R.string.tangempay_card_page_closing_banner_title),
stringReference(". "),
resourceReference(R.string.tangempay_card_page_closing_banner_description),
)
TangemPayCardState.Active -> null
}
}
@Composable
private fun ReissueCardLayout(
title: TextReference,
modifier: Modifier = Modifier,
cardSection: @Composable () -> Unit,
) {
Column(
modifier = modifier,
horizontalAlignment = Alignment.CenterHorizontally,
) {
Box(modifier = Modifier.padding(top = TangemTheme.dimens.spacing8)) {
cardSection()
}
Box(
modifier = Modifier
.fillMaxSize()
.padding(scaffoldPaddings),
contentPadding = PaddingValues(
bottom = TangemTheme.dimens.spacing16 + bottomBarHeight,
),
verticalArrangement = Arrangement.spacedBy(if (isRedesignEnabled) 0.dp else TangemTheme.dimens.spacing16),
.fillMaxWidth()
.weight(1f),
contentAlignment = Alignment.Center,
) {
item(key = "Card") {
Box(modifier = Modifier.padding(top = TangemTheme.dimens.spacing8)) {
cardSection()
}
}
if (isRedesignEnabled && state.settingsV2.isNotEmpty() && state.cardState == TangemPayCardState.Active) {
cardPageItem("Settings buttons") {
TangemPayCardPageSettingsButtonsBlock(
modifier = Modifier.fillMaxWidth(),
settings = state.settingsV2,
)
}
}
cardState(state)
TangemPayReissueBlock(title = title)
}
}
}

View file

@ -0,0 +1,52 @@
package com.tangem.features.tangempay.ui
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.generated.icons.Icons
import com.tangem.core.ui.res.generated.icons.ic_clock_20
@Composable
internal fun TangemPayReissueBlock(title: TextReference, modifier: Modifier = Modifier) {
Column(
modifier = modifier
.fillMaxWidth()
.padding(horizontal = 48.dp),
verticalArrangement = Arrangement.spacedBy(12.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Box(
modifier = Modifier
.size(40.dp)
.background(
color = TangemTheme.colors3.bg.opaque.primary,
shape = CircleShape,
),
contentAlignment = Alignment.Center,
) {
Icon(
modifier = Modifier.size(20.dp),
imageVector = Icons.ic_clock_20,
tint = TangemTheme.colors3.icon.secondary,
contentDescription = null,
)
}
Text(
modifier = Modifier.fillMaxWidth(),
text = title.resolveReference(),
color = TangemTheme.colors3.text.secondary,
style = TangemTheme.typography3.caption.medium,
textAlign = TextAlign.Center,
)
}
}

View file

@ -2,20 +2,13 @@ package com.tangem.features.tangempay.ui
import android.content.res.Configuration
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.SpacerH24
import com.tangem.core.ui.components.notifications.Notification
import com.tangem.core.ui.components.notifications.NotificationConfig
import com.tangem.core.ui.ds.message.TangemMessage
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.res.LocalVisaRedesignEnabled
@ -31,14 +24,14 @@ internal fun TangemPayReplacingCardBlock(
subtitle: TextReference = resourceReference(R.string.tangempay_reissue_card_in_progress_description),
) {
if (LocalVisaRedesignEnabled.current) {
BlockV2(title = title, subtitle = subtitle, modifier = modifier)
return
} else {
BlockV1(title = title, subtitle = subtitle, modifier = modifier)
Block(title = title, subtitle = subtitle, modifier = modifier)
}
}
@Composable
private fun BlockV1(
private fun Block(
modifier: Modifier = Modifier,
title: TextReference? = resourceReference(R.string.tangempay_reissue_card_in_progress),
subtitle: TextReference = resourceReference(R.string.tangempay_reissue_card_in_progress_description),
@ -55,27 +48,6 @@ private fun BlockV1(
)
}
@Composable
private fun BlockV2(
modifier: Modifier = Modifier,
title: TextReference? = resourceReference(R.string.tangempay_reissue_card_in_progress),
subtitle: TextReference = resourceReference(R.string.tangempay_reissue_card_in_progress_description),
) {
TangemMessage(
modifier = modifier.padding(top = TangemTheme.dimens2.x2),
title = title,
subtitle = subtitle,
leadingContent = {
Icon(
modifier = Modifier.size(20.dp),
imageVector = ImageVector.vectorResource(R.drawable.ic_clock_24),
contentDescription = null,
tint = TangemTheme.colors3.icon.primary,
)
},
)
}
@Preview(showBackground = true)
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable