Updated on 2026-08-14

This commit is contained in:
Tangem 2026-06-01 07:59:48 +02:00
parent 9c1d2f2cf2
commit a1a82d3ece
25 changed files with 976 additions and 60 deletions

View file

@ -0,0 +1,27 @@
<!--
~ Copyright (C) 2026 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:pathData="M15.75,9.25C16.164,9.25 16.5,9.586 16.5,10C16.5,13.59 13.59,16.5 10,16.5C7.986,16.5 6.19,15.581 5,14.144V14.791C5,15.205 4.664,15.541 4.25,15.541C3.836,15.541 3.5,15.205 3.5,14.791V12.396C3.5,11.981 3.836,11.646 4.25,11.646H6.646C7.06,11.646 7.395,11.981 7.396,12.396C7.396,12.81 7.06,13.146 6.646,13.146H6.123C7.04,14.276 8.434,15 10,15C12.762,15 15,12.762 15,10C15,9.586 15.336,9.25 15.75,9.25Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M10,3.5C12.014,3.5 13.81,4.419 15,5.855V5.208C15,4.794 15.336,4.458 15.75,4.458C16.164,4.458 16.5,4.794 16.5,5.208V7.604C16.5,8.018 16.164,8.354 15.75,8.354H13.354C12.94,8.353 12.604,8.018 12.604,7.604C12.605,7.19 12.941,6.854 13.354,6.854H13.876C12.96,5.723 11.565,5 10,5C7.238,5 5,7.238 5,10C5,10.414 4.664,10.75 4.25,10.75C3.836,10.75 3.5,10.414 3.5,10C3.5,6.41 6.41,3.5 10,3.5Z"
android:fillColor="#ffffff"/>
</vector>

View file

@ -0,0 +1,29 @@
<!--
~ Copyright (C) 2026 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="22dp"
android:height="8dp"
android:viewportWidth="22"
android:viewportHeight="8">
<group>
<clip-path
android:pathData="M0,0h22v8h-22z"/>
<path
android:pathData="M5.503,7.217H3.709L2.364,2.086C2.3,1.849 2.164,1.641 1.965,1.542C1.467,1.295 0.919,1.099 0.321,0.999V0.802H3.21C3.609,0.802 3.908,1.099 3.958,1.443L4.656,5.145L6.449,0.802H8.193L5.503,7.217ZM9.189,7.217H7.495L8.89,0.802H10.585L9.189,7.217ZM12.777,2.578C12.827,2.233 13.126,2.035 13.475,2.035C14.023,1.986 14.62,2.085 15.119,2.331L15.418,0.95C14.92,0.753 14.371,0.653 13.873,0.653C12.229,0.653 11.033,1.542 11.033,2.775C11.033,3.713 11.88,4.206 12.479,4.503C13.126,4.798 13.375,4.996 13.325,5.292C13.325,5.736 12.827,5.933 12.329,5.933C11.731,5.933 11.132,5.785 10.585,5.538L10.286,6.92C10.884,7.167 11.531,7.266 12.13,7.266C13.973,7.314 15.119,6.427 15.119,5.094C15.119,3.416 12.777,3.318 12.777,2.578ZM21.048,7.217L19.703,0.802H18.258C17.959,0.802 17.66,0.999 17.56,1.295L15.069,7.217H16.813L17.161,6.279H19.304L19.503,7.217H21.048ZM18.507,2.529L19.004,4.946H17.609L18.507,2.529Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
</group>
</vector>

View file

@ -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()
}

View file

@ -17,6 +17,7 @@ internal data class TangemPayCardPageUM(
val dailyLimitState: TangemPayDailyLimitBlockState,
val addToWalletBlockState: AddToWalletBlockState? = null,
val isReissueInProgress: Boolean = false,
val menuItems: ImmutableList<TangemPayDropDownItemUM>,
) {
companion object {
fun stub(
@ -40,6 +41,7 @@ internal data class TangemPayCardPageUM(
onBackClick = {},
isReissueInProgress = isReissueInProgress,
dailyLimitState = dailyLimitState,
menuItems = persistentListOf(),
)
}
}

View file

@ -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<TangemPayDropDownItemUM> {
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
),
)
}
}

View file

@ -7,4 +7,5 @@ internal data class TangemPayDetailsTopBarConfig(
val onBackClick: () -> Unit,
val onOpenMenu: () -> Unit,
val items: ImmutableList<TangemDropdownMenuItem>,
val itemsV2: ImmutableList<TangemPayDropDownItemUM>,
)

View file

@ -77,7 +77,7 @@ internal sealed class TangemPayDetailsBalanceBlockState {
data class Content(
override val actionButtons: ImmutableList<ActionButtonConfig>,
override val cardsBlockState: CardsBlockState?,
val fiatBalance: String,
val fiatBalance: TextReference,
val isBalanceFlickering: Boolean,
) : TangemPayDetailsBalanceBlockState()

View file

@ -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,
)

View file

@ -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<TangemPayDropDownItemUM> {
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)

View file

@ -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() },
)
}
}
}

View file

@ -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<TangemPayDropDownItemUM>,
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,

View file

@ -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

View file

@ -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<TangemPayDetailsUM>(
internal class TangemPayDetailsUMProvider : CollectionPreviewParameterProvider<TangemPayDetailsUM>(
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<Ta
onClick = {},
),
),
fiatBalance = "$1234.56",
fiatBalance = combinedReference(
stringReference("1,234"),
styledStringReference(
".56",
{ SpanStyle(color = TangemTheme.colors3.text.primary) },
),
stringReference(" $"),
),
isBalanceFlickering = false,
cardsBlockState = TangemPayDetailsBalanceBlockState.CardsBlockState(
cards = persistentListOf(
@ -465,7 +476,12 @@ private class TangemPayDetailsUMProvider : CollectionPreviewParameterProvider<Ta
accountDeactivatedNotificationConfig = null,
),
TangemPayDetailsUM(
topBarConfig = TangemPayDetailsTopBarConfig(onBackClick = {}, onOpenMenu = {}, items = persistentListOf()),
topBarConfig = TangemPayDetailsTopBarConfig(
onBackClick = {},
onOpenMenu = {},
items = persistentListOf(),
itemsV2 = persistentListOf(),
),
pullToRefreshConfig = PullToRefreshConfig(isRefreshing = false, onRefresh = {}),
balanceBlockState = TangemPayDetailsBalanceBlockState.Loading(
actionButtons = persistentListOf(),
@ -502,7 +518,7 @@ private fun TangemPayDetailsTxHistoryScreenPreview(
}
}
private class TangemPayDetailsTxHistoryProvider : CollectionPreviewParameterProvider<TangemPayTxHistoryUM>(
internal class TangemPayDetailsTxHistoryProvider : CollectionPreviewParameterProvider<TangemPayTxHistoryUM>(
collection = listOf(
PreviewTangemPayTxHistoryComponent.loadingUM,
PreviewTangemPayTxHistoryComponent.contentUM,

View file

@ -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<ActionButtonConfig>,
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

View file

@ -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<TangemPayDropDownItemUM>,
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,
)
}
}
}
}
}

View file

@ -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 = {},
)
}
}

View file

@ -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 = {})
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB