diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayEditDisplayNameComponent.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayEditDisplayNameComponent.kt index b70a927a75..0eaac3c857 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayEditDisplayNameComponent.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayEditDisplayNameComponent.kt @@ -52,6 +52,7 @@ internal class TangemPayEditDisplayNameComponent( cardDetailsBlockComponent = cardDetailsBlockComponent, cardDetailsState = editingCardDetailsState, modifier = modifier, + isRedesignEnabled = model.isRedesignEnabled(), ) } } \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayEditDisplayNameModel.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayEditDisplayNameModel.kt index 6bca0bdf1b..b5330e2d0a 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayEditDisplayNameModel.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayEditDisplayNameModel.kt @@ -18,6 +18,7 @@ import com.tangem.domain.models.account.requireCardWithId import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.pay.flow.PaymentAccountStatusSupplier import com.tangem.domain.pay.usecase.UpdateTangemPayCardNameUseCase +import com.tangem.features.tangempay.TangemPayFeatureToggles import com.tangem.features.tangempay.components.TangemPayDetailsContainerComponent import com.tangem.features.tangempay.details.impl.R import com.tangem.features.tangempay.entity.TangemPayEditDisplayNameUM @@ -28,6 +29,7 @@ import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import javax.inject.Inject +@Suppress("LongParameterList") @Stable @ModelScoped internal class TangemPayEditDisplayNameModel @Inject constructor( @@ -37,6 +39,7 @@ internal class TangemPayEditDisplayNameModel @Inject constructor( private val updateCardNameUseCase: UpdateTangemPayCardNameUseCase, private val uiMessageSender: UiMessageSender, private val paymentAccountStatusSupplier: PaymentAccountStatusSupplier, + private val featureToggles: TangemPayFeatureToggles, ) : Model() { private val params: TangemPayDetailsContainerComponent.Params = paramsContainer.require() @@ -63,6 +66,8 @@ internal class TangemPayEditDisplayNameModel @Inject constructor( subscribeToCardNameChanges(card.id, params.initialStatus.userWalletId) } + fun isRedesignEnabled() = featureToggles.isRedesignEnabled + private fun subscribeToCardNameChanges(cardId: String, userWalletId: UserWalletId) { paymentAccountStatusSupplier.invoke(userWalletId) .onEach { state -> diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayCardDetailsBlock.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayCardDetailsBlock.kt index 1e21a98814..24f15fce6d 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayCardDetailsBlock.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayCardDetailsBlock.kt @@ -38,6 +38,7 @@ 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 androidx.compose.ui.zIndex import androidx.constraintlayout.compose.ConstrainedLayoutReference import androidx.constraintlayout.compose.ConstraintLayout import androidx.constraintlayout.compose.ConstraintLayoutScope @@ -49,6 +50,7 @@ import com.tangem.core.ui.components.buttons.common.TangemButtonSize import com.tangem.core.ui.ds.image.TangemIconUM import com.tangem.core.ui.ds2.button.TangemButton import com.tangem.core.ui.extensions.conditional +import com.tangem.core.ui.extensions.conditionalCompose import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.stringResourceSafe import com.tangem.core.ui.res.* @@ -62,6 +64,7 @@ import com.tangem.features.tangempay.model.CardDataType private const val TEXT_WIDTH_PADDING = 2 private const val FREEZE_ANIMATION_DURATION_MS = 600 private val CustomCardBlockColor = Color(0x1F828282) +private val CardBackgroundColor = Color(0xFF171A27) @Suppress("MagicNumber") @Composable @@ -80,26 +83,10 @@ internal fun TangemPayCard(state: TangemPayCardDetailsUM, modifier: Modifier = M // Determine which side to show based on the rotation angle val shouldShowDetails = rotateCardY > 90f - Box( - modifier = modifier - .fillMaxWidth() - .aspectRatio(328f / 212f) // size of img_tangem_pay_visa - .graphicsLayer { - rotationY = rotateCardY - cameraDistance = zAxisDistance - } - .clip(RoundedCornerShape(16.dp)) - .background(Color(red = 18, green = 21, blue = 31)) - .border( - width = 1.dp, - brush = Brush.linearGradient( - colors = listOf( - TangemTheme.colors.text.constantWhite.copy(alpha = 0.1F), - TangemTheme.colors.text.constantWhite.copy(alpha = 0f), - ), - ), - shape = RoundedCornerShape(16.dp), - ), + CardBgWrapper( + rotateCardY = rotateCardY, + zAxisDistance = zAxisDistance, + modifier = modifier, ) { if (shouldShowDetails) { TangemPayCardDetailsShownBlock( @@ -113,9 +100,7 @@ internal fun TangemPayCard(state: TangemPayCardDetailsUM, modifier: Modifier = M modifier = Modifier.graphicsLayer { rotationY = 180f }, ) } else { - TangemPayCardDetailsHiddenBlock( - state = state, - ) + TangemPayCardDetailsHiddenBlock(state = state) } } } @@ -123,79 +108,94 @@ internal fun TangemPayCard(state: TangemPayCardDetailsUM, modifier: Modifier = M @Suppress("LongMethod", "DestructuringDeclarationWithTooManyEntries") @Composable private fun TangemPayCardDetailsHiddenBlock(state: TangemPayCardDetailsUM, modifier: Modifier = Modifier) { + val isRenaming = state.displayNameState is DisplayNameState.Editing + Box(modifier = modifier.fillMaxSize()) { - TangemPayCardBackground(cardFrozenState = state.cardFrozenState) - CardTopBlock() + TangemPayCardBackground( + modifier = Modifier + .fillMaxSize() + .zIndex(0f), + isRenaming = isRenaming, + cardFrozenState = state.cardFrozenState, + ) - if (state.isActionsAvailable) { - ConstraintLayout( - modifier = Modifier - .align(Alignment.BottomCenter) - .padding(horizontal = 16.dp) - .padding(bottom = 8.dp) - .fillMaxWidth(), - ) { - val (displayNameRef, cardNumberRef, frozenIconRef, buttonRef) = createRefs() + Box( + modifier = Modifier + .fillMaxSize() + .zIndex(1f), + ) { + CardTopBlock() - if (state.displayNameState != null) { - CardDisplayName( - state = state.displayNameState, - modifier = Modifier.constrainAs(displayNameRef) { - start.linkTo(parent.start) - bottom.linkTo(cardNumberRef.top) - width = Dimension.wrapContent - }, - ) - } - CardNumberBlock( - numberShort = state.numberShort, - cardNumberRef = cardNumberRef, - ) - - when (state.cardFrozenState) { - TangemPayCardFrozenState.Frozen -> Icon( - modifier = Modifier - .constrainAs(frozenIconRef) { - start.linkTo(cardNumberRef.end, margin = 4.dp) - top.linkTo(cardNumberRef.top) - bottom.linkTo(cardNumberRef.bottom) - } - .padding(bottom = 8.dp) - .size(16.dp) - .testTag(TangemPayTestTags.CARD_FROZEN_BADGE), - painter = painterResource(id = R.drawable.ic_snow_24), - contentDescription = null, - tint = TangemTheme.colors.icon.constant, - ) - TangemPayCardFrozenState.Pending -> CircularProgressIndicator( - modifier = Modifier - .constrainAs(frozenIconRef) { - start.linkTo(cardNumberRef.end, margin = 4.dp) - top.linkTo(cardNumberRef.top) - bottom.linkTo(cardNumberRef.bottom) - } - .padding(bottom = 8.dp) - .size(16.dp) - .testTag(TangemPayTestTags.CARD_FROZEN_BADGE), - color = TangemTheme.colors.text.constantWhite, - strokeWidth = 1.dp, - ) - TangemPayCardFrozenState.Unfrozen -> Unit - } - AnimatedVisibility( + if (state.isActionsAvailable) { + ConstraintLayout( modifier = Modifier - .constrainAs(buttonRef) { - end.linkTo(parent.end) - bottom.linkTo(parent.bottom) - } - .testTag(TangemPayTestTags.CARD_DETAILS_SHOW_BUTTON), - visible = !LocalVisaRedesignEnabled.current || state.isLoading, + .align(Alignment.BottomCenter) + .padding(horizontal = 16.dp) + .padding(bottom = 8.dp) + .fillMaxWidth(), ) { - TangemPayCardDetailsCustomButton( - text = stringResourceSafe(id = R.string.tangempay_card_details_show_details), - onClick = state.onClick, - showProgress = state.isLoading, + val (displayNameRef, cardNumberRef, frozenIconRef, buttonRef) = createRefs() + + if (state.displayNameState != null) { + CardDisplayName( + state = state.displayNameState, + modifier = Modifier.constrainAs(displayNameRef) { + start.linkTo(parent.start) + bottom.linkTo(cardNumberRef.top) + width = Dimension.wrapContent + }, + ) + } + CardNumberBlock( + numberShort = state.numberShort, + cardNumberRef = cardNumberRef, ) + + when (state.cardFrozenState) { + TangemPayCardFrozenState.Frozen -> Icon( + modifier = Modifier + .constrainAs(frozenIconRef) { + start.linkTo(cardNumberRef.end, margin = 4.dp) + top.linkTo(cardNumberRef.top) + bottom.linkTo(cardNumberRef.bottom) + } + .padding(bottom = 8.dp) + .size(16.dp) + .testTag(TangemPayTestTags.CARD_FROZEN_BADGE), + painter = painterResource(id = R.drawable.ic_snow_24), + contentDescription = null, + tint = TangemTheme.colors.icon.constant, + ) + TangemPayCardFrozenState.Pending -> CircularProgressIndicator( + modifier = Modifier + .constrainAs(frozenIconRef) { + start.linkTo(cardNumberRef.end, margin = 4.dp) + top.linkTo(cardNumberRef.top) + bottom.linkTo(cardNumberRef.bottom) + } + .padding(bottom = 8.dp) + .size(16.dp) + .testTag(TangemPayTestTags.CARD_FROZEN_BADGE), + color = TangemTheme.colors.text.constantWhite, + strokeWidth = 1.dp, + ) + TangemPayCardFrozenState.Unfrozen -> Unit + } + AnimatedVisibility( + modifier = Modifier + .constrainAs(buttonRef) { + end.linkTo(parent.end) + bottom.linkTo(parent.bottom) + } + .testTag(TangemPayTestTags.CARD_DETAILS_SHOW_BUTTON), + visible = !LocalVisaRedesignEnabled.current || state.isLoading, + ) { + TangemPayCardDetailsCustomButton( + text = stringResourceSafe(id = R.string.tangempay_card_details_show_details), + onClick = state.onClick, + showProgress = state.isLoading, + ) + } } } } @@ -203,7 +203,11 @@ private fun TangemPayCardDetailsHiddenBlock(state: TangemPayCardDetailsUM, modif } @Composable -private fun TangemPayCardBackground(cardFrozenState: TangemPayCardFrozenState, modifier: Modifier = Modifier) { +private fun TangemPayCardBackground( + isRenaming: Boolean, + cardFrozenState: TangemPayCardFrozenState, + modifier: Modifier = Modifier, +) { val isFrozen = cardFrozenState == TangemPayCardFrozenState.Frozen val freezeProgress by animateFloatAsState( targetValue = if (isFrozen) 1f else 0f, @@ -221,6 +225,14 @@ private fun TangemPayCardBackground(cardFrozenState: TangemPayCardFrozenState, m contentDescription = null, ) + if (isRenaming && LocalVisaRedesignEnabled.current) { + Box( + modifier = Modifier + .fillMaxSize() + .background(CardBackgroundColor.copy(alpha = 0.8f)), + ) + } + if (isFrozen || freezeProgress > 0f) { Image( modifier = Modifier @@ -233,6 +245,69 @@ private fun TangemPayCardBackground(cardFrozenState: TangemPayCardFrozenState, m } } +@Suppress("MagicNumber") +@Composable +private fun CardBgWrapper( + rotateCardY: Float, + zAxisDistance: Float, + modifier: Modifier = Modifier, + content: @Composable BoxScope.() -> Unit, +) { + val isRedesignEnabled = LocalVisaRedesignEnabled.current + val shouldShowDetailsBg = rotateCardY > 90f && isRedesignEnabled + Box( + modifier = modifier + .fillMaxWidth() + .aspectRatio(328f / 212f) // size of img_tangem_pay_visa + .graphicsLayer { + rotationY = rotateCardY + cameraDistance = zAxisDistance + } + .conditionalCompose( + condition = isRedesignEnabled, + modifier = { + clip(RoundedCornerShape(TangemTheme.dimens2.x5)) + .border( + width = 1.dp, + shape = RoundedCornerShape(TangemTheme.dimens2.x5), + color = TangemTheme.colors3.border.secondary, + ) + .background(CardBackgroundColor) + }, + otherModifier = { + clip(RoundedCornerShape(16.dp)) + .background(CardBackgroundColor) + .border( + width = 1.dp, + brush = Brush.linearGradient( + colors = listOf( + TangemTheme.colors.text.constantWhite.copy(alpha = 0.1F), + TangemTheme.colors.text.constantWhite.copy(alpha = 0f), + ), + ), + shape = RoundedCornerShape(16.dp), + ) + }, + ), + ) { + Box(modifier = Modifier.fillMaxWidth()) { + if (shouldShowDetailsBg) { + Image( + modifier = Modifier + .fillMaxSize() + .graphicsLayer { + rotationY = rotateCardY + cameraDistance = zAxisDistance + }, + painter = painterResource(R.drawable.img_bg_card_details), + contentDescription = null, + ) + } + content() + } + } +} + @Composable private fun CardTopBlock(modifier: Modifier = Modifier) { Row( diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayEditDisplayNameScreen.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayEditDisplayNameScreen.kt index 18008536a7..f543b7507d 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayEditDisplayNameScreen.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayEditDisplayNameScreen.kt @@ -2,6 +2,8 @@ package com.tangem.features.tangempay.ui import androidx.compose.foundation.background import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.runtime.Composable @@ -9,8 +11,14 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import com.tangem.core.ui.components.PrimaryButton +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.resourceReference import com.tangem.core.ui.extensions.stringResourceSafe 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_cross_20 import com.tangem.features.tangempay.components.cardDetails.TangemPayCardDetailsBlockComponent import com.tangem.features.tangempay.details.impl.R import com.tangem.features.tangempay.entity.TangemPayCardDetailsUM @@ -18,6 +26,31 @@ import com.tangem.features.tangempay.entity.TangemPayEditDisplayNameUM @Composable internal fun TangemPayEditDisplayNameScreen( + isRedesignEnabled: Boolean, + state: TangemPayEditDisplayNameUM, + cardDetailsBlockComponent: TangemPayCardDetailsBlockComponent, + cardDetailsState: TangemPayCardDetailsUM, + modifier: Modifier = Modifier, +) { + if (isRedesignEnabled) { + TangemPayEditDisplayNameScreenV2( + state = state, + cardDetailsBlockComponent = cardDetailsBlockComponent, + cardDetailsState = cardDetailsState, + modifier = modifier, + ) + } else { + TangemPayEditDisplayNameScreenV1( + state = state, + cardDetailsBlockComponent = cardDetailsBlockComponent, + cardDetailsState = cardDetailsState, + modifier = modifier, + ) + } +} + +@Composable +internal fun TangemPayEditDisplayNameScreenV1( state: TangemPayEditDisplayNameUM, cardDetailsBlockComponent: TangemPayCardDetailsBlockComponent, cardDetailsState: TangemPayCardDetailsUM, @@ -67,4 +100,55 @@ internal fun TangemPayEditDisplayNameScreen( enabled = !state.isLoading && state.isDoneEnabled, ) } +} + +@Composable +internal fun TangemPayEditDisplayNameScreenV2( + state: TangemPayEditDisplayNameUM, + cardDetailsBlockComponent: TangemPayCardDetailsBlockComponent, + cardDetailsState: TangemPayCardDetailsUM, + modifier: Modifier = Modifier, +) { + Column( + modifier = modifier + .fillMaxSize() + .background(TangemTheme.colors3.bg.primary) + .systemBarsPadding(), + ) { + TangemTopBar( + endContent = { + TangemButton( + iconStart = TangemIconUM.Icon(imageVector = Icons.ic_cross_20), + onClick = state.onDismiss, + size = TangemButton.Size.X11, + variant = TangemButton.Variant.Material, + ) + }, + title = resourceReference(R.string.tangem_pay_rename_card_title), + ) + + Column( + modifier = Modifier + .weight(1f) + .fillMaxWidth() + .verticalScroll(rememberScrollState()), + ) { + cardDetailsBlockComponent.CardDetailsBlockContent( + modifier = Modifier.padding(horizontal = TangemTheme.dimens2.x4, vertical = TangemTheme.dimens2.x2), + state = cardDetailsState, + ) + } + + TangemButton( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = TangemTheme.dimens2.x3, horizontal = TangemTheme.dimens2.x4) + .imePadding(), + text = resourceReference(R.string.common_save), + onClick = state.onDoneClick, + isLoading = state.isLoading, + isEnabled = !state.isLoading && state.isDoneEnabled, + size = TangemButton.Size.X12, + ) + } } \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/res/drawable-hdpi/img_bg_card_details.webp b/features/tangempay/details/impl/src/main/res/drawable-hdpi/img_bg_card_details.webp new file mode 100644 index 0000000000..056318597d Binary files /dev/null and b/features/tangempay/details/impl/src/main/res/drawable-hdpi/img_bg_card_details.webp differ diff --git a/features/tangempay/details/impl/src/main/res/drawable-xhdpi/img_bg_card_details.webp b/features/tangempay/details/impl/src/main/res/drawable-xhdpi/img_bg_card_details.webp new file mode 100644 index 0000000000..ed60b82e06 Binary files /dev/null and b/features/tangempay/details/impl/src/main/res/drawable-xhdpi/img_bg_card_details.webp differ diff --git a/features/tangempay/details/impl/src/main/res/drawable-xxhdpi/img_bg_card_details.webp b/features/tangempay/details/impl/src/main/res/drawable-xxhdpi/img_bg_card_details.webp new file mode 100644 index 0000000000..73506af453 Binary files /dev/null and b/features/tangempay/details/impl/src/main/res/drawable-xxhdpi/img_bg_card_details.webp differ diff --git a/features/tangempay/details/impl/src/main/res/drawable-xxxhdpi/img_bg_card_details.webp b/features/tangempay/details/impl/src/main/res/drawable-xxxhdpi/img_bg_card_details.webp new file mode 100644 index 0000000000..1d7e423675 Binary files /dev/null and b/features/tangempay/details/impl/src/main/res/drawable-xxxhdpi/img_bg_card_details.webp differ