diff --git a/core/ui/src/main/res/drawable/ic_replace_20.xml b/core/ui/src/main/res/drawable/ic_replace_20.xml
new file mode 100644
index 0000000000..3fdf7b9e3d
--- /dev/null
+++ b/core/ui/src/main/res/drawable/ic_replace_20.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
diff --git a/core/ui/src/main/res/drawable/ic_visa_logo.xml b/core/ui/src/main/res/drawable/ic_visa_logo.xml
new file mode 100644
index 0000000000..a03fb04772
--- /dev/null
+++ b/core/ui/src/main/res/drawable/ic_visa_logo.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayDetailsComponent.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayDetailsComponent.kt
index a669eab012..abff694265 100644
--- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayDetailsComponent.kt
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayDetailsComponent.kt
@@ -16,11 +16,13 @@ import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.components.NavigationBar3ButtonsScrim
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.core.ui.decompose.ComposableContentComponent
+import com.tangem.core.ui.res.LocalRedesignEnabled
import com.tangem.features.tangempay.components.txHistory.DefaultTangemPayTxHistoryComponent
import com.tangem.features.tangempay.components.txHistory.TangemPayTxHistoryDetailsComponent
import com.tangem.features.tangempay.entity.TangemPayDetailsNavigation
import com.tangem.features.tangempay.model.TangemPayDetailsModel
import com.tangem.features.tangempay.ui.TangemPayDetailsScreen
+import com.tangem.features.tangempay.ui.TangemPayDetailsScreenV2
import com.tangem.features.tangempay.utils.requireLoaded
import com.tangem.features.tangempay.utils.userWalletId
import com.tangem.features.tokendetails.ExpressTransactionsComponent
@@ -72,12 +74,21 @@ internal class TangemPayDetailsComponent(
val bottomSheet by bottomSheetSlot.subscribeAsState()
NavigationBar3ButtonsScrim()
- TangemPayDetailsScreen(
- state = state,
- txHistoryComponent = txHistoryComponent,
- expressTransactionsComponent = expressTransactionsComponent,
- modifier = modifier,
- )
+ if (LocalRedesignEnabled.current) {
+ TangemPayDetailsScreenV2(
+ state = state,
+ txHistoryComponent = txHistoryComponent,
+ expressTransactionsComponent = expressTransactionsComponent,
+ modifier = modifier,
+ )
+ } else {
+ TangemPayDetailsScreen(
+ state = state,
+ txHistoryComponent = txHistoryComponent,
+ expressTransactionsComponent = expressTransactionsComponent,
+ modifier = modifier,
+ )
+ }
bottomSheet.child?.instance?.BottomSheet()
}
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayCardPageUM.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayCardPageUM.kt
index b4d70fd998..cb24f4b42d 100644
--- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayCardPageUM.kt
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayCardPageUM.kt
@@ -17,6 +17,7 @@ internal data class TangemPayCardPageUM(
val dailyLimitState: TangemPayDailyLimitBlockState,
val addToWalletBlockState: AddToWalletBlockState? = null,
val isReissueInProgress: Boolean = false,
+ val menuItems: ImmutableList,
) {
companion object {
fun stub(
@@ -40,6 +41,7 @@ internal data class TangemPayCardPageUM(
onBackClick = {},
isReissueInProgress = isReissueInProgress,
dailyLimitState = dailyLimitState,
+ menuItems = persistentListOf(),
)
}
}
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsStateFactory.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsStateFactory.kt
index efabb31b08..8de4b0c86d 100644
--- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsStateFactory.kt
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsStateFactory.kt
@@ -4,9 +4,12 @@ import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
import com.tangem.core.ui.components.dropdownmenu.TangemDropdownMenuItem
import com.tangem.core.ui.components.notifications.NotificationConfig
+import com.tangem.core.ui.ds.image.TangemIconUM
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.themedColor
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_document_20
import com.tangem.domain.models.pay.TangemPayCardFrozenState
import com.tangem.features.tangempay.details.impl.R
import com.tangem.features.tangempay.utils.TangemPayDetailIntents
@@ -31,6 +34,7 @@ internal class TangemPayDetailsStateFactory(
onBackClick = onBack,
onOpenMenu = onOpenMenu,
items = getTopBarMenuItems(isTangemPayDeactivated),
+ itemsV2 = getTopBarMenuItemsV2(isTangemPayDeactivated),
),
pullToRefreshConfig = PullToRefreshConfig(
isRefreshing = false,
@@ -89,4 +93,31 @@ internal class TangemPayDetailsStateFactory(
),
)
}
+
+ private fun getTopBarMenuItemsV2(isTangemPayDeactivated: Boolean): ImmutableList {
+ if (isTangemPayDeactivated) return persistentListOf()
+
+ return persistentListOf(
+ TangemPayDropDownItemUM(
+ title = resourceReference(R.string.tangem_pay_terms_limits),
+ onClick = intents::onClickTermsAndLimits,
+ icon = TangemIconUM.Icon(
+ imageVector = Icons.ic_document_20,
+ tintReference = {
+ TangemTheme.colors3.icon.primary
+ },
+ ),
+ ),
+ TangemPayDropDownItemUM(
+ title = resourceReference(R.string.tangempay_pay_support),
+ onClick = intents::onContactSupportClicked,
+ icon = TangemIconUM.Icon(
+ imageVector = Icons.ic_document_20,
+ tintReference = {
+ TangemTheme.colors3.icon.primary
+ },
+ ), // TODO change when the icon will be ready in design
+ ),
+ )
+ }
}
\ No newline at end of file
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsTopBarConfig.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsTopBarConfig.kt
index 9675f1b31d..f25f792ca5 100644
--- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsTopBarConfig.kt
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsTopBarConfig.kt
@@ -7,4 +7,5 @@ internal data class TangemPayDetailsTopBarConfig(
val onBackClick: () -> Unit,
val onOpenMenu: () -> Unit,
val items: ImmutableList,
+ val itemsV2: ImmutableList,
)
\ No newline at end of file
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsUM.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsUM.kt
index e51533434b..706d875d26 100644
--- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsUM.kt
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsUM.kt
@@ -77,7 +77,7 @@ internal sealed class TangemPayDetailsBalanceBlockState {
data class Content(
override val actionButtons: ImmutableList,
override val cardsBlockState: CardsBlockState?,
- val fiatBalance: String,
+ val fiatBalance: TextReference,
val isBalanceFlickering: Boolean,
) : TangemPayDetailsBalanceBlockState()
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDropDownItemUM.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDropDownItemUM.kt
new file mode 100644
index 0000000000..71d30e3f2e
--- /dev/null
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDropDownItemUM.kt
@@ -0,0 +1,10 @@
+package com.tangem.features.tangempay.entity
+
+import com.tangem.core.ui.ds.image.TangemIconUM
+import com.tangem.core.ui.extensions.TextReference
+
+internal data class TangemPayDropDownItemUM(
+ val onClick: () -> Unit,
+ val title: TextReference,
+ val icon: TangemIconUM,
+)
\ No newline at end of file
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardPageModel.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardPageModel.kt
index 0694b3694b..9db19e4817 100644
--- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardPageModel.kt
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardPageModel.kt
@@ -13,6 +13,7 @@ import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.decompose.navigation.Router
import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.ui.DesignFeatureToggles
+import com.tangem.core.ui.ds.image.TangemIconUM
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.format.bigdecimal.fiat
@@ -20,6 +21,7 @@ import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.core.ui.format.bigdecimal.getJavaCurrencyByCode
import com.tangem.core.ui.format.bigdecimal.optionalDecimals
import com.tangem.core.ui.message.SnackbarMessage
+import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.test.TangemPayTestTags
import com.tangem.domain.models.StatusSource
import com.tangem.domain.models.TokenReceiveConfig
@@ -53,7 +55,7 @@ import kotlinx.coroutines.launch
import javax.inject.Inject
import com.tangem.core.ui.R as CoreUiR
-@Suppress("LongParameterList")
+@Suppress("LongParameterList", "LargeClass")
@Stable
@ModelScoped
internal class TangemPayCardPageModel @Inject constructor(
@@ -89,6 +91,7 @@ internal class TangemPayCardPageModel @Inject constructor(
dailyLimitState = TangemPayDailyLimitBlockState.Loading,
settings = persistentListOf(),
settingsV2 = persistentListOf(),
+ menuItems = buildMenuItems(),
),
)
@@ -210,6 +213,21 @@ internal class TangemPayCardPageModel @Inject constructor(
)
}
+ private fun buildMenuItems(): ImmutableList {
+ return persistentListOf(
+ TangemPayDropDownItemUM(
+ title = TextReference.Res(R.string.tangempay_card_details_reissue_card),
+ onClick = ::onClickReissueCard,
+ icon = TangemIconUM.Icon(
+ iconRes = CoreUiR.drawable.ic_replace_20,
+ tintReference = {
+ TangemTheme.colors3.icon.primary
+ },
+ ),
+ ),
+ )
+ }
+
private fun onClickViewDetails() {
modelScope.launch(dispatchers.default) {
cardDetailsEventListener.send(CardDetailsEvent.Show)
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/DetailsBalanceTransformer.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/DetailsBalanceTransformer.kt
index d2a9482577..eca90fdbb4 100644
--- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/DetailsBalanceTransformer.kt
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/DetailsBalanceTransformer.kt
@@ -2,8 +2,10 @@ package com.tangem.features.tangempay.model.transformers
import arrow.core.Either
import com.tangem.core.error.UniversalError
+import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.format.bigdecimal.fiat
-import com.tangem.core.ui.format.bigdecimal.format
+import com.tangem.core.ui.format.bigdecimal.formatStyled
+import com.tangem.core.ui.res.TangemTheme
import com.tangem.domain.pay.model.TangemPayCardBalance
import com.tangem.features.tangempay.entity.TangemPayDetailsBalanceBlockState
import com.tangem.features.tangempay.entity.TangemPayDetailsUM
@@ -35,10 +37,14 @@ internal class DetailsBalanceTransformer(
return prevState.copy(balanceBlockState = balance)
}
- private fun getFiatBalanceText(balance: TangemPayCardBalance): String {
+ private fun getFiatBalanceText(balance: TangemPayCardBalance): TextReference {
val currency = Currency.getInstance(balance.currencyCode)
- return balance.fiatBalance.format {
- fiat(fiatCurrencyCode = currency.currencyCode, fiatCurrencySymbol = currency.symbol)
+ return balance.fiatBalance.formatStyled {
+ fiat(
+ fiatCurrencyCode = currency.currencyCode,
+ fiatCurrencySymbol = currency.symbol,
+ spanStyleReference = { TangemTheme.typography3.heading.medium.toSpanStyle() },
+ )
}
}
}
\ No newline at end of file
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayCardPageScreen.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayCardPageScreen.kt
index 6b2374624b..6793c51dd5 100644
--- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayCardPageScreen.kt
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayCardPageScreen.kt
@@ -15,9 +15,8 @@ import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.material3.Scaffold
import androidx.compose.material3.ScaffoldDefaults
import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.runtime.remember
+import androidx.compose.runtime.*
+import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
@@ -25,6 +24,9 @@ import androidx.compose.ui.platform.testTag
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.util.fastForEach
import com.tangem.core.ui.components.appbar.AppBarWithBackButton
+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.stringResourceSafe
import com.tangem.core.ui.res.LocalRedesignEnabled
@@ -36,7 +38,9 @@ import com.tangem.features.tangempay.components.cardDetails.PreviewTangemPayCard
import com.tangem.features.tangempay.components.cardDetails.TangemPayCardDetailsBlockComponent
import com.tangem.features.tangempay.details.impl.R
import com.tangem.features.tangempay.entity.*
+import com.tangem.features.tangempay.ui.components.PayContextMenuBlock
import kotlinx.collections.immutable.ImmutableList
+import com.tangem.core.ui.R as CoreUiR
private const val CONTENT_FADE_DURATION_MS = 300
@@ -51,8 +55,8 @@ internal fun TangemPayCardPageScreen(
Scaffold(
modifier = modifier,
topBar = {
- AppBarWithBackButton(
- modifier = Modifier.statusBarsPadding(),
+ CardPageTopBar(
+ items = state.menuItems,
onBackClick = state.onBackClick,
)
},
@@ -170,6 +174,48 @@ private fun TangemPayCardPageSettingRow(
}
}
+@Composable
+private fun CardPageTopBar(
+ onBackClick: () -> Unit,
+ items: ImmutableList,
+ modifier: Modifier = Modifier,
+) {
+ if (LocalRedesignEnabled.current) {
+ var isDropdownMenuShown by rememberSaveable { mutableStateOf(false) }
+ TangemTopBar(
+ modifier = modifier.statusBarsPadding(),
+ startContent = {
+ TangemButton(
+ iconStart = TangemIconUM.Icon(iconRes = R.drawable.ic_arrow_back_28),
+ onClick = onBackClick,
+ size = TangemButton.Size.X11,
+ variant = TangemButton.Variant.Material,
+ )
+ },
+ endContent = {
+ Box {
+ TangemButton(
+ iconStart = TangemIconUM.Icon(iconRes = CoreUiR.drawable.ic_more_default_24),
+ onClick = { isDropdownMenuShown = true },
+ size = TangemButton.Size.X11,
+ variant = TangemButton.Variant.Material,
+ )
+ PayContextMenuBlock(
+ items = items,
+ onMenuDismiss = { isDropdownMenuShown = false },
+ isDropdownMenuShown = isDropdownMenuShown,
+ )
+ }
+ },
+ )
+ } else {
+ AppBarWithBackButton(
+ modifier = modifier,
+ onBackClick = onBackClick,
+ )
+ }
+}
+
private fun LazyListScope.cardPageItem(
key: Any? = null,
contentType: Any? = null,
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayCardPageSettingsButtonsBlock.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayCardPageSettingsButtonsBlock.kt
index ce36ac6ad5..ca0e75ed12 100644
--- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayCardPageSettingsButtonsBlock.kt
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayCardPageSettingsButtonsBlock.kt
@@ -2,20 +2,20 @@ package com.tangem.features.tangempay.ui
import android.content.res.Configuration
import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.*
-import androidx.compose.material3.Text
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.util.fastForEach
-import com.tangem.core.ui.ds.image.TangemIconUM
-import com.tangem.core.ui.ds2.button.TangemButton
-import com.tangem.core.ui.extensions.resolveAnnotatedReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreviewRedesign
import com.tangem.features.tangempay.entity.TangemPayCardPageSettingV2
+import com.tangem.features.tangempay.ui.components.TangemPayActionButton
import kotlinx.collections.immutable.ImmutableList
@Composable
@@ -30,41 +30,18 @@ internal fun TangemPayCardPageSettingsButtonsBlock(
horizontalArrangement = Arrangement.Center,
) {
settings.fastForEach { setting ->
- TangemPaySettingButton(
- setting = setting,
+ TangemPayActionButton(
modifier = Modifier.then(if (setting.testTag != null) Modifier.testTag(setting.testTag) else Modifier),
+ title = setting.title,
+ iconRes = setting.iconRes,
+ onClick = setting.onClick,
+ isEnabled = setting.isEnabled,
+ isLoading = setting.isLoading,
)
}
}
}
-@Composable
-private fun TangemPaySettingButton(setting: TangemPayCardPageSettingV2, modifier: Modifier = Modifier) {
- Column(
- modifier = modifier.padding(horizontal = TangemTheme.dimens2.x6),
- verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x2),
- horizontalAlignment = Alignment.CenterHorizontally,
- ) {
- TangemButton(
- variant = TangemButton.Variant.Material,
- size = TangemButton.Size.X14,
- onClick = setting.onClick,
- iconStart = TangemIconUM.Icon(
- iconRes = setting.iconRes,
- tintReference = { TangemTheme.colors3.icon.primary },
- ),
- isLoading = setting.isLoading,
- isEnabled = setting.isEnabled,
- )
-
- Text(
- text = setting.title.resolveAnnotatedReference(),
- style = TangemTheme.typography3.subheading.medium,
- color = TangemTheme.colors3.text.primary,
- )
- }
-}
-
@Preview(showBackground = true)
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayDetailsScreen.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayDetailsScreen.kt
index 55d6159978..3371d0dcdb 100644
--- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayDetailsScreen.kt
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayDetailsScreen.kt
@@ -25,6 +25,7 @@ import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.tooling.preview.Devices
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
@@ -45,9 +46,7 @@ import com.tangem.core.ui.components.dropdownmenu.TangemDropdownItem
import com.tangem.core.ui.components.dropdownmenu.TangemDropdownMenu
import com.tangem.core.ui.components.notifications.Notification
import com.tangem.core.ui.components.text.applyBladeBrush
-import com.tangem.core.ui.extensions.orMaskWithStars
-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.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.test.TangemPayTestTags
@@ -343,7 +342,7 @@ private fun FiatBalance(
)
is TangemPayDetailsBalanceBlockState.Content -> Text(
modifier = modifier.testTag(TangemPayTestTags.PAYMENT_ACCOUNT_BALANCE),
- text = state.fiatBalance.orMaskWithStars(isBalanceHidden),
+ text = state.fiatBalance.orMaskWithStars(isBalanceHidden).resolveReference(),
style = TangemTheme.typography.h2.applyBladeBrush(
isEnabled = state.isBalanceFlickering,
textColor = TangemTheme.colors.text.primary1,
@@ -432,10 +431,15 @@ private fun TangemPayDetailsScreenPreview(
}
}
-private class TangemPayDetailsUMProvider : CollectionPreviewParameterProvider(
+internal class TangemPayDetailsUMProvider : CollectionPreviewParameterProvider(
collection = listOf(
TangemPayDetailsUM(
- topBarConfig = TangemPayDetailsTopBarConfig(onBackClick = {}, onOpenMenu = {}, items = persistentListOf()),
+ topBarConfig = TangemPayDetailsTopBarConfig(
+ onBackClick = {},
+ onOpenMenu = {},
+ items = persistentListOf(),
+ itemsV2 = persistentListOf(),
+ ),
pullToRefreshConfig = PullToRefreshConfig(isRefreshing = false, onRefresh = {}),
balanceBlockState = TangemPayDetailsBalanceBlockState.Content(
actionButtons = persistentListOf(
@@ -445,7 +449,14 @@ private class TangemPayDetailsUMProvider : CollectionPreviewParameterProvider(
+internal class TangemPayDetailsTxHistoryProvider : CollectionPreviewParameterProvider(
collection = listOf(
PreviewTangemPayTxHistoryComponent.loadingUM,
PreviewTangemPayTxHistoryComponent.contentUM,
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayDetailsScreenV2.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayDetailsScreenV2.kt
new file mode 100644
index 0000000000..8be30b01d3
--- /dev/null
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayDetailsScreenV2.kt
@@ -0,0 +1,404 @@
+package com.tangem.features.tangempay.ui
+
+import android.content.res.Configuration
+import androidx.compose.animation.AnimatedContent
+import androidx.compose.animation.core.tween
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
+import androidx.compose.animation.togetherWith
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.lazy.*
+import androidx.compose.foundation.text.TextAutoSize
+import androidx.compose.material3.Text
+import androidx.compose.runtime.*
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.layout.onSizeChanged
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.tooling.preview.Devices
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.tooling.preview.PreviewParameter
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.util.fastAny
+import androidx.compose.ui.util.fastForEach
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.tangem.core.ui.components.SpacerW
+import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
+import com.tangem.core.ui.components.containers.pullToRefresh.TangemPullToRefreshSlidingContainer
+import com.tangem.core.ui.components.text.applyBladeBrush
+import com.tangem.core.ui.components.topFade
+import com.tangem.core.ui.ds.image.TangemIconUM
+import com.tangem.core.ui.ds.message.TangemMessage
+import com.tangem.core.ui.ds.message.TangemMessageEffect
+import com.tangem.core.ui.ds.topbar.TangemTopBar
+import com.tangem.core.ui.ds2.button.TangemButton
+import com.tangem.core.ui.ds2.shimmers.TextShimmer
+import com.tangem.core.ui.ds2.shimmers.TextShimmerStyle
+import com.tangem.core.ui.extensions.clickableSingle
+import com.tangem.core.ui.extensions.orMaskWithStars
+import com.tangem.core.ui.extensions.resolveAnnotatedReference
+import com.tangem.core.ui.extensions.resourceReference
+import com.tangem.core.ui.res.TangemTheme
+import com.tangem.core.ui.res.TangemThemePreviewRedesign
+import com.tangem.core.ui.test.TangemPayTestTags
+import com.tangem.features.tangempay.components.express.PreviewEmptyExpressTransactionsComponent
+import com.tangem.features.tangempay.components.txHistory.PreviewTangemPayTxHistoryComponent
+import com.tangem.features.tangempay.components.txHistory.TangemPayTxHistoryComponent
+import com.tangem.features.tangempay.details.impl.R
+import com.tangem.features.tangempay.entity.TangemPayDetailsBalanceBlockState
+import com.tangem.features.tangempay.entity.TangemPayDetailsTopBarConfig
+import com.tangem.features.tangempay.entity.TangemPayDetailsUM
+import com.tangem.features.tangempay.entity.TangemPayTxHistoryUM
+import com.tangem.features.tangempay.ui.components.PayContextMenuBlock
+import com.tangem.features.tangempay.ui.components.TangemPayActionButton
+import com.tangem.features.tangempay.ui.components.TangemPayAddCardView
+import com.tangem.features.tangempay.ui.components.TangemPayCardView
+import com.tangem.features.tokendetails.ExpressTransactionsComponent
+import com.tangem.utils.StringsSigns.DASH_SIGN
+import kotlinx.collections.immutable.ImmutableList
+import com.tangem.core.ui.R as CoreUiR
+
+private val InitialTopBarHeight: Dp = 64.dp
+private val BgImageFadeDistance: Dp = 96.dp
+private const val TOP_FADE_MID_STOP = 0.8f
+private const val TOP_FADE_MID_ALPHA = 0.8f
+
+@Suppress("LongMethod")
+@Composable
+internal fun TangemPayDetailsScreenV2(
+ state: TangemPayDetailsUM,
+ txHistoryComponent: TangemPayTxHistoryComponent,
+ expressTransactionsComponent: ExpressTransactionsComponent,
+ modifier: Modifier = Modifier,
+) {
+ val listState = rememberLazyListState()
+ val density = LocalDensity.current
+ val statusBarHeight = with(density) { WindowInsets.systemBars.getTop(this).toDp() }
+ val bottomBarHeight = with(density) { WindowInsets.systemBars.getBottom(this).toDp() }
+ var topBarTotalHeight by remember { mutableStateOf(InitialTopBarHeight + statusBarHeight) }
+ val rootBackground = TangemTheme.colors3.bg.primary
+ val fadeDistancePx = with(LocalDensity.current) { BgImageFadeDistance.toPx() }
+ val bgImageAlpha by remember(fadeDistancePx) {
+ derivedStateOf {
+ val scrollOffsetPx = when (listState.firstVisibleItemIndex) {
+ 0 -> listState.firstVisibleItemScrollOffset.toFloat()
+ else -> fadeDistancePx
+ }.coerceAtLeast(0f)
+ (1f - scrollOffsetPx / fadeDistancePx).coerceIn(0f, 1f)
+ }
+ }
+
+ val txHistoryState by txHistoryComponent.state.collectAsStateWithLifecycle()
+ val expressState by expressTransactionsComponent.state.collectAsStateWithLifecycle()
+ val expressTransactionsBottomSheetState = expressState.bottomSheetSlot
+
+ Box(
+ modifier = modifier
+ .fillMaxSize()
+ .background(rootBackground),
+ ) {
+ Image(
+ modifier = Modifier
+ .fillMaxWidth(),
+ painter = painterResource(R.drawable.img_bg_pay_details),
+ contentDescription = null,
+ contentScale = ContentScale.FillWidth,
+ alpha = bgImageAlpha,
+ )
+
+ TangemPullToRefreshSlidingContainer(
+ config = state.pullToRefreshConfig,
+ indicatorOffset = topBarTotalHeight,
+ ) {
+ LazyColumn(
+ modifier = Modifier
+ .fillMaxSize()
+ .topFade(
+ height = topBarTotalHeight,
+ 0f to rootBackground.copy(alpha = 1f - bgImageAlpha),
+ TOP_FADE_MID_STOP to rootBackground.copy(alpha = TOP_FADE_MID_ALPHA * (1f - bgImageAlpha)),
+ 1f to Color.Transparent,
+ ),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ state = listState,
+ contentPadding = PaddingValues(
+ top = topBarTotalHeight,
+ bottom = TangemTheme.dimens2.x4 + bottomBarHeight,
+ ),
+ ) {
+ payDetailsBody(state)
+ with(expressTransactionsComponent) {
+ expressTransactionsContent(
+ state = expressState.transactionsToDisplay,
+ modifier = Modifier
+ .padding(horizontal = 16.dp)
+ .padding(top = 12.dp)
+ .fillMaxWidth(),
+ )
+ }
+ with(txHistoryComponent) { txHistoryContent(listState = listState, state = txHistoryState) }
+ }
+ }
+
+ PayDetailsTopBar(
+ config = state.topBarConfig,
+ onHeightChange = { measuredHeight ->
+ if (topBarTotalHeight != measuredHeight) topBarTotalHeight = measuredHeight
+ },
+ )
+ }
+ expressTransactionsBottomSheetState?.content(null)
+}
+
+private fun LazyListScope.payDetailsBody(state: TangemPayDetailsUM) {
+ item("balanceBlock") {
+ BalanceBlock(
+ state = state.balanceBlockState,
+ isBalanceHidden = state.isBalanceHidden,
+ )
+ }
+ state.balanceBlockState.cardsBlockState?.let { cardsState ->
+ item("cardsBlock") {
+ CardsBlock(cardsBlockState = cardsState)
+ }
+ }
+ if (state.balanceBlockState.actionButtons.isNotEmpty()) {
+ item("actionButtonsBlock") {
+ ActionBlock(actionButtons = state.balanceBlockState.actionButtons)
+ }
+ }
+ when {
+ state.balanceBlockState.cardsBlockState?.cards?.fastAny { it.isReissuing } == true -> {
+ item("reissuingBannerBlock") {
+ TangemMessage(
+ modifier = Modifier.padding(horizontal = TangemTheme.dimens2.x4),
+ title = resourceReference(R.string.tangempay_reissue_card_in_progress),
+ subtitle = resourceReference(R.string.tangempay_reissue_card_in_progress_description),
+ )
+ }
+ }
+ else -> {
+ if (state.addToWalletBlockState != null) {
+ item("addToWalletBannerBlock") {
+ TangemPayAddToWalletBlock(
+ state = state.addToWalletBlockState,
+ modifier = Modifier.padding(horizontal = TangemTheme.dimens2.x4),
+ )
+ }
+ }
+ if (state.accountDeactivatedNotificationConfig != null) {
+ item("deactivationBannerBlock") {
+ TangemMessage(
+ modifier = Modifier
+ .padding(horizontal = TangemTheme.dimens2.x4)
+ .clickableSingle(
+ onClick = { state.accountDeactivatedNotificationConfig.onClick?.invoke() },
+ ),
+ title = state.accountDeactivatedNotificationConfig.title,
+ subtitle = state.accountDeactivatedNotificationConfig.subtitle,
+ messageEffect = TangemMessageEffect.Warning,
+ )
+ }
+ }
+ }
+ }
+}
+
+@Composable
+private fun PayDetailsTopBar(
+ config: TangemPayDetailsTopBarConfig,
+ onHeightChange: (Dp) -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ val density = LocalDensity.current
+ TangemTopBar(
+ modifier = modifier
+ .onSizeChanged { size ->
+ onHeightChange(with(density) { size.height.toDp() })
+ }
+ .statusBarsPadding(),
+ title = resourceReference(R.string.tangempay_payment_account),
+ subtitle = resourceReference(R.string.tangempay_usdc_on_polygon_network),
+ startContent = {
+ TangemButton(
+ iconStart = TangemIconUM.Icon(iconRes = CoreUiR.drawable.ic_arrow_back_28),
+ onClick = config.onBackClick,
+ size = TangemButton.Size.X11,
+ variant = TangemButton.Variant.Material,
+ )
+ },
+ endContent = if (config.itemsV2.isNotEmpty()) {
+ {
+ var isDropdownMenuShown by rememberSaveable { mutableStateOf(false) }
+ Box {
+ TangemButton(
+ iconStart = TangemIconUM.Icon(iconRes = CoreUiR.drawable.ic_more_default_24),
+ onClick = {
+ config.onOpenMenu()
+ isDropdownMenuShown = true
+ },
+ size = TangemButton.Size.X11,
+ variant = TangemButton.Variant.Material,
+ )
+ PayContextMenuBlock(
+ items = config.itemsV2,
+ onMenuDismiss = { isDropdownMenuShown = false },
+ isDropdownMenuShown = isDropdownMenuShown,
+ )
+ }
+ }
+ } else {
+ null
+ },
+ )
+}
+
+@Composable
+private fun BalanceBlock(
+ state: TangemPayDetailsBalanceBlockState,
+ isBalanceHidden: Boolean,
+ modifier: Modifier = Modifier,
+) {
+ Column(
+ modifier
+ .fillMaxWidth()
+ .padding(horizontal = TangemTheme.dimens2.x4)
+ .padding(top = TangemTheme.dimens2.x12),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ AnimatedContent(
+ targetState = state,
+ label = "Updating the balance",
+ transitionSpec = {
+ fadeIn(animationSpec = tween(durationMillis = 220, delayMillis = 90)) togetherWith
+ fadeOut(animationSpec = tween(durationMillis = 90))
+ },
+ ) { animatedState ->
+ when (animatedState) {
+ is TangemPayDetailsBalanceBlockState.Loading -> TextShimmer(
+ modifier = Modifier.size(width = 160.dp, height = 56.dp),
+ text = "1234.00",
+ style = TextShimmerStyle.HEADING_MEDIUM,
+ radius = TangemTheme.dimens2.x25,
+ )
+ is TangemPayDetailsBalanceBlockState.Content -> Text(
+ modifier = Modifier.testTag(TangemPayTestTags.PAYMENT_ACCOUNT_BALANCE),
+ text = animatedState.fiatBalance.orMaskWithStars(isBalanceHidden).resolveAnnotatedReference(),
+ style = TangemTheme.typography3.display.medium.applyBladeBrush(
+ isEnabled = animatedState.isBalanceFlickering,
+ textColor = TangemTheme.colors3.text.primary,
+ ),
+ color = TangemTheme.colors3.text.primary,
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis,
+ autoSize = TextAutoSize.StepBased(
+ minFontSize = TangemTheme.typography3.heading.medium.fontSize,
+ maxFontSize = TangemTheme.typography3.display.medium.fontSize,
+ ),
+ )
+ is TangemPayDetailsBalanceBlockState.Error -> Text(
+ modifier = Modifier.testTag(TangemPayTestTags.PAYMENT_ACCOUNT_BALANCE),
+ text = DASH_SIGN.orMaskWithStars(isBalanceHidden),
+ style = TangemTheme.typography3.display.medium,
+ color = TangemTheme.colors3.text.primary,
+ )
+ }
+ }
+ }
+}
+
+@Composable
+private fun CardsBlock(
+ cardsBlockState: TangemPayDetailsBalanceBlockState.CardsBlockState,
+ modifier: Modifier = Modifier,
+) {
+ LazyRow(
+ modifier = modifier.fillMaxWidth(),
+ state = rememberLazyListState(),
+ contentPadding = PaddingValues(
+ horizontal = TangemTheme.dimens2.x4,
+ vertical = TangemTheme.dimens2.x6,
+ ),
+ horizontalArrangement = Arrangement.Center,
+ ) {
+ items(items = cardsBlockState.cards) { item ->
+ TangemPayCardView(
+ isReissuing = item.isReissuing,
+ lastDigits = item.lastDigits,
+ onClick = item.onClick,
+ )
+ SpacerW(TangemTheme.dimens2.x2)
+ }
+ item {
+ TangemPayAddCardView(onClick = cardsBlockState.onAddCardClick)
+ }
+ }
+}
+
+@Composable
+private fun LazyItemScope.ActionBlock(
+ actionButtons: ImmutableList,
+ modifier: Modifier = Modifier,
+) {
+ Row(
+ modifier = modifier
+ .fillMaxWidth()
+ .padding(vertical = TangemTheme.dimens2.x6),
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.Center,
+ ) {
+ actionButtons.fastForEach { actionConfig ->
+ TangemPayActionButton(
+ iconRes = actionConfig.iconResId,
+ onClick = actionConfig.onClick,
+ isEnabled = actionConfig.isEnabled,
+ isLoading = actionConfig.isInProgress,
+ title = actionConfig.text,
+ )
+ }
+ }
+}
+
+// region preview
+
+@Preview(device = Devices.PIXEL_7_PRO)
+@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES, device = Devices.PIXEL_7_PRO)
+@Composable
+private fun TangemPayDetailsScreenPreview(
+ @PreviewParameter(TangemPayDetailsUMProvider::class) state: TangemPayDetailsUM,
+) {
+ TangemThemePreviewRedesign {
+ TangemPayDetailsScreenV2(
+ state = state,
+ txHistoryComponent = PreviewTangemPayTxHistoryComponent(
+ txHistoryUM = PreviewTangemPayTxHistoryComponent.contentUM,
+ ),
+ expressTransactionsComponent = PreviewEmptyExpressTransactionsComponent(),
+ )
+ }
+}
+
+@Preview(device = Devices.PIXEL_7_PRO)
+@Composable
+private fun TangemPayDetailsTxHistoryScreenPreview(
+ @PreviewParameter(TangemPayDetailsTxHistoryProvider::class) state: TangemPayTxHistoryUM,
+) {
+ TangemThemePreviewRedesign {
+ TangemPayDetailsScreenV2(
+ state = TangemPayDetailsUMProvider().values.first(),
+ txHistoryComponent = PreviewTangemPayTxHistoryComponent(txHistoryUM = state),
+ expressTransactionsComponent = PreviewEmptyExpressTransactionsComponent(),
+ )
+ }
+}
+
+// end region preview
\ No newline at end of file
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/components/PayContextMenuBlock.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/components/PayContextMenuBlock.kt
new file mode 100644
index 0000000000..88dd7ca342
--- /dev/null
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/components/PayContextMenuBlock.kt
@@ -0,0 +1,57 @@
+package com.tangem.features.tangempay.ui.components
+
+import androidx.compose.foundation.layout.*
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.DpOffset
+import androidx.compose.ui.util.fastForEach
+import com.tangem.core.ui.ds.contextmenu.TangemContextMenu
+import com.tangem.core.ui.ds.image.TangemIcon
+import com.tangem.core.ui.extensions.clickableSingle
+import com.tangem.core.ui.extensions.resolveReference
+import com.tangem.core.ui.res.TangemTheme
+import com.tangem.features.tangempay.entity.TangemPayDropDownItemUM
+import kotlinx.collections.immutable.ImmutableList
+
+@Composable
+internal fun PayContextMenuBlock(
+ items: ImmutableList,
+ isDropdownMenuShown: Boolean,
+ onMenuDismiss: () -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ TangemContextMenu(
+ expanded = isDropdownMenuShown,
+ onDismissRequest = onMenuDismiss,
+ offset = DpOffset.Zero,
+ modifier = modifier,
+ ) {
+ items.fastForEach { item ->
+ Column {
+ Row(
+ horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x2),
+ modifier = Modifier
+ .clickableSingle(
+ onClick = {
+ item.onClick()
+ onMenuDismiss()
+ },
+ )
+ .padding(vertical = TangemTheme.dimens2.x3, horizontal = TangemTheme.dimens2.x4),
+ ) {
+ TangemIcon(
+ modifier = Modifier.size(TangemTheme.dimens2.x5),
+ tangemIconUM = item.icon,
+ )
+ Text(
+ text = item.title.resolveReference(),
+ style = TangemTheme.typography3.body.medium,
+ color = TangemTheme.colors3.text.primary,
+ maxLines = 1,
+ )
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/components/TangemPayActionButton.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/components/TangemPayActionButton.kt
new file mode 100644
index 0000000000..924d154d90
--- /dev/null
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/components/TangemPayActionButton.kt
@@ -0,0 +1,66 @@
+package com.tangem.features.tangempay.ui.components
+
+import android.content.res.Configuration
+import androidx.annotation.DrawableRes
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.tooling.preview.Preview
+import com.tangem.core.ui.R
+import com.tangem.core.ui.ds.image.TangemIconUM
+import com.tangem.core.ui.ds2.button.TangemButton
+import com.tangem.core.ui.extensions.TextReference
+import com.tangem.core.ui.extensions.resolveAnnotatedReference
+import com.tangem.core.ui.extensions.stringReference
+import com.tangem.core.ui.res.TangemTheme
+import com.tangem.core.ui.res.TangemThemePreviewRedesign
+
+@Composable
+internal fun TangemPayActionButton(
+ title: TextReference,
+ @DrawableRes iconRes: Int,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ isEnabled: Boolean = true,
+ isLoading: Boolean = false,
+) {
+ Column(
+ modifier = modifier.padding(horizontal = TangemTheme.dimens2.x4),
+ verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x2),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ TangemButton(
+ variant = TangemButton.Variant.Material,
+ size = TangemButton.Size.X14,
+ onClick = onClick,
+ iconStart = TangemIconUM.Icon(
+ iconRes = iconRes,
+ tintReference = { TangemTheme.colors3.icon.primary },
+ ),
+ isLoading = isLoading,
+ isEnabled = isEnabled,
+ )
+
+ Text(
+ text = title.resolveAnnotatedReference(),
+ style = TangemTheme.typography3.subheading.medium,
+ color = TangemTheme.colors3.text.primary,
+ )
+ }
+}
+
+@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
+@Composable
+private fun TangemPayActionButtonPreview() {
+ TangemThemePreviewRedesign {
+ TangemPayActionButton(
+ title = stringReference("Action"),
+ iconRes = R.drawable.ic_arrow_down_24,
+ onClick = {},
+ )
+ }
+}
\ No newline at end of file
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/components/TangemPayCardView.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/components/TangemPayCardView.kt
new file mode 100644
index 0000000000..0663d4bd6d
--- /dev/null
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/components/TangemPayCardView.kt
@@ -0,0 +1,215 @@
+package com.tangem.features.tangempay.ui.components
+
+import android.content.res.Configuration
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Icon
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.draw.drawBehind
+import androidx.compose.ui.geometry.Offset
+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.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 com.tangem.core.ui.R
+import com.tangem.core.ui.components.SpacerH
+import com.tangem.core.ui.extensions.clickableSingle
+import com.tangem.core.ui.res.TangemTheme
+import com.tangem.core.ui.res.TangemThemePreviewRedesign
+import com.tangem.core.ui.res.generated.icons.Icons
+import com.tangem.core.ui.res.generated.icons.ic_clock_12
+import com.tangem.core.ui.res.generated.icons.ic_cloud_12
+import com.tangem.core.ui.test.TangemPayTestTags
+
+private const val DEFAULT_CARD_BG = 0xFF1C1F29
+private const val REISSUING_CARD_BG = 0xFF1E1E1E
+
+@Composable
+internal fun TangemPayCardView(
+ isReissuing: Boolean,
+ lastDigits: String,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ CardBackground(
+ modifier = modifier
+ .size(
+ height = TangemTheme.dimens2.x10,
+ width = TangemTheme.dimens2.x14,
+ )
+ .testTag(TangemPayTestTags.PAYMENT_ACCOUNT_CARD_BUTTON),
+ isReissuing = isReissuing,
+ onClick = onClick,
+ ) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(horizontal = TangemTheme.dimens2.x1)
+ .padding(top = TangemTheme.dimens2.x1),
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.SpaceBetween,
+ ) {
+ Icon(
+ modifier = Modifier.size(TangemTheme.dimens2.x3),
+ imageVector = if (isReissuing) {
+ Icons.ic_clock_12
+ } else {
+ Icons.ic_cloud_12
+ },
+ 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),
+ tint = TangemTheme.colors3.icon.staticDark,
+ contentDescription = null,
+ )
+ }
+
+ Text(
+ modifier = Modifier
+ .align(Alignment.BottomEnd)
+ .padding(end = TangemTheme.dimens2.x1, bottom = TangemTheme.dimens2.x1),
+ text = lastDigits,
+ style = TangemTheme.typography3.caption.medium.copy(fontSize = 10.sp),
+ color = TangemTheme.colors3.text.staticDark.primary,
+ )
+ }
+}
+
+@Composable
+internal fun TangemPayAddCardView(onClick: () -> Unit, modifier: Modifier = Modifier) {
+ Box(
+ modifier = modifier
+ .size(
+ height = TangemTheme.dimens2.x10,
+ width = TangemTheme.dimens2.x14,
+ )
+ .clip(RoundedCornerShape(TangemTheme.dimens3.borderRadius.b075))
+ .background(TangemTheme.colors3.bg.opaque.primary)
+ .clickableSingle(onClick = onClick),
+ contentAlignment = Alignment.Center,
+ ) {
+ Icon(
+ modifier = Modifier.size(20.dp),
+ imageVector = ImageVector.vectorResource(R.drawable.ic_plus_default_24),
+ contentDescription = null,
+ tint = TangemTheme.colors3.icon.secondary,
+ )
+ }
+}
+
+@Suppress("MagicNumber")
+@Composable
+private fun CardBackground(
+ isReissuing: Boolean,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ content: @Composable BoxScope.() -> Unit,
+) {
+ val bgColor = remember(isReissuing) {
+ if (isReissuing) {
+ Color(REISSUING_CARD_BG)
+ } else {
+ Color(DEFAULT_CARD_BG)
+ }
+ }
+
+ Box(
+ modifier = modifier
+ .clip(RoundedCornerShape(TangemTheme.dimens3.borderRadius.b075))
+ .drawBehind {
+ drawRect(bgColor)
+
+ val w = size.width
+ val h = size.height
+ val radiusScaleRightCorner = h / 2f
+ val radiusScaleLeftCorner = h / 1.27f
+
+ drawRect(
+ brush = Brush.radialGradient(
+ colors = listOf(
+ Color(
+ if (isReissuing) 0xFFB0B4BC else 0xFF38587F,
+ ).copy(
+ if (isReissuing) .1f else .41f,
+ ),
+ Color.Transparent,
+ ),
+ center = Offset(w - 20f, h * .05f),
+ radius = radiusScaleRightCorner,
+ tileMode = TileMode.Clamp,
+ ),
+ )
+
+ if (!isReissuing) {
+ drawRect(
+ brush = Brush.radialGradient(
+ colors = listOf(
+ Color(0xFF2881FF).copy(.25f),
+ Color.Transparent,
+ ),
+ center = Offset(0f, h + h * .1f),
+ radius = radiusScaleLeftCorner,
+ ),
+ )
+ }
+ }
+ .border(
+ width = 1.dp,
+ color = TangemTheme.colors3.border.primary,
+ shape = RoundedCornerShape(TangemTheme.dimens3.borderRadius.b075),
+ )
+ .clickableSingle(onClick = onClick),
+ content = content,
+ )
+}
+
+@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES, device = Devices.PIXEL_7_PRO)
+@Composable
+private fun CardBackgroundPreview() {
+ TangemThemePreviewRedesign {
+ Column(modifier = Modifier.fillMaxWidth(), verticalArrangement = Arrangement.Center) {
+ CardBackground(
+ modifier = Modifier.size(
+ height = TangemTheme.dimens2.x10,
+ width = TangemTheme.dimens2.x14,
+ ),
+ isReissuing = false,
+ onClick = {},
+ content = {},
+ )
+ SpacerH(TangemTheme.dimens2.x4)
+ CardBackground(
+ modifier = Modifier.size(
+ height = TangemTheme.dimens2.x10,
+ width = TangemTheme.dimens2.x14,
+ ),
+ isReissuing = true,
+ onClick = {},
+ content = {},
+ )
+ SpacerH(TangemTheme.dimens2.x4)
+ TangemPayCardView(isReissuing = false, onClick = {}, lastDigits = "1234")
+ SpacerH(TangemTheme.dimens2.x4)
+ TangemPayCardView(isReissuing = true, onClick = {}, lastDigits = "")
+ SpacerH(TangemTheme.dimens2.x4)
+ TangemPayAddCardView(onClick = {})
+ }
+ }
+}
\ No newline at end of file
diff --git a/features/tangempay/details/impl/src/main/res/drawable-night-hdpi/img_bg_pay_details.webp b/features/tangempay/details/impl/src/main/res/drawable-night-hdpi/img_bg_pay_details.webp
new file mode 100644
index 0000000000..190f51ba02
Binary files /dev/null and b/features/tangempay/details/impl/src/main/res/drawable-night-hdpi/img_bg_pay_details.webp differ
diff --git a/features/tangempay/details/impl/src/main/res/drawable-night-xhdpi/img_bg_pay_details.webp b/features/tangempay/details/impl/src/main/res/drawable-night-xhdpi/img_bg_pay_details.webp
new file mode 100644
index 0000000000..c9b4084734
Binary files /dev/null and b/features/tangempay/details/impl/src/main/res/drawable-night-xhdpi/img_bg_pay_details.webp differ
diff --git a/features/tangempay/details/impl/src/main/res/drawable-night-xxhdpi/img_bg_pay_details.webp b/features/tangempay/details/impl/src/main/res/drawable-night-xxhdpi/img_bg_pay_details.webp
new file mode 100644
index 0000000000..d8aedcf855
Binary files /dev/null and b/features/tangempay/details/impl/src/main/res/drawable-night-xxhdpi/img_bg_pay_details.webp differ
diff --git a/features/tangempay/details/impl/src/main/res/drawable-night-xxxhdpi/img_bg_pay_details.webp b/features/tangempay/details/impl/src/main/res/drawable-night-xxxhdpi/img_bg_pay_details.webp
new file mode 100644
index 0000000000..7671f73787
Binary files /dev/null and b/features/tangempay/details/impl/src/main/res/drawable-night-xxxhdpi/img_bg_pay_details.webp differ
diff --git a/features/tangempay/details/impl/src/main/res/drawable-notnight-hdpi/img_bg_pay_details.webp b/features/tangempay/details/impl/src/main/res/drawable-notnight-hdpi/img_bg_pay_details.webp
new file mode 100644
index 0000000000..dcc819b567
Binary files /dev/null and b/features/tangempay/details/impl/src/main/res/drawable-notnight-hdpi/img_bg_pay_details.webp differ
diff --git a/features/tangempay/details/impl/src/main/res/drawable-notnight-xhdpi/img_bg_pay_details.webp b/features/tangempay/details/impl/src/main/res/drawable-notnight-xhdpi/img_bg_pay_details.webp
new file mode 100644
index 0000000000..8f47020f26
Binary files /dev/null and b/features/tangempay/details/impl/src/main/res/drawable-notnight-xhdpi/img_bg_pay_details.webp differ
diff --git a/features/tangempay/details/impl/src/main/res/drawable-notnight-xxhdpi/img_bg_pay_details.webp b/features/tangempay/details/impl/src/main/res/drawable-notnight-xxhdpi/img_bg_pay_details.webp
new file mode 100644
index 0000000000..1a91ca2907
Binary files /dev/null and b/features/tangempay/details/impl/src/main/res/drawable-notnight-xxhdpi/img_bg_pay_details.webp differ
diff --git a/features/tangempay/details/impl/src/main/res/drawable-notnight-xxxhdpi/img_bg_pay_details.webp b/features/tangempay/details/impl/src/main/res/drawable-notnight-xxxhdpi/img_bg_pay_details.webp
new file mode 100644
index 0000000000..0122654158
Binary files /dev/null and b/features/tangempay/details/impl/src/main/res/drawable-notnight-xxxhdpi/img_bg_pay_details.webp differ