diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 9e3feaa6e5..e20ccf50f8 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -1690,6 +1690,7 @@ Withdraw unavailable now You can\'t initiate swap or new withdrawal till the current one is finished Withdrawal in progress + Card name Set a limit from %s We couldn’t set the limit. Please try again Change diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/di/TangemPayDataModule.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/di/TangemPayDataModule.kt index 7f41dabc9c..ade825296a 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/di/TangemPayDataModule.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/di/TangemPayDataModule.kt @@ -29,6 +29,7 @@ import com.tangem.domain.pay.repository.* import com.tangem.domain.pay.usecase.GetPaymentAccountCryptoCurrencyStatusUseCase import com.tangem.domain.pay.usecase.ProduceTangemPayInitialDataUseCase import com.tangem.domain.pay.usecase.SetTangemPayCardLimitUseCase +import com.tangem.domain.pay.usecase.UpdateTangemPayCardNameUseCase import com.tangem.domain.tangempay.GetTangemPayCurrencyStatusUseCase import com.tangem.domain.tangempay.GetTangemPayCustomerIdUseCase import com.tangem.domain.tangempay.TangemPayWithdrawUseCase @@ -148,6 +149,14 @@ internal interface TangemPayDataModule { return SetTangemPayCardLimitUseCase(cardDetailsRepository, paymentAccountStatusFetcher) } + @Provides + fun provideUpdateTangemPayCardNameUseCase( + cardDetailsRepository: TangemPayCardDetailsRepository, + paymentAccountStatusFetcher: PaymentAccountStatusFetcher, + ): UpdateTangemPayCardNameUseCase { + return UpdateTangemPayCardNameUseCase(cardDetailsRepository, paymentAccountStatusFetcher) + } + @Provides @Singleton fun provideGetTangemPayCryptoCurrencyStatusUseCase( diff --git a/domain/visa/src/main/kotlin/com/tangem/domain/pay/flow/PaymentAccountStatusFetcher.kt b/domain/visa/src/main/kotlin/com/tangem/domain/pay/flow/PaymentAccountStatusFetcher.kt index 740d9d0824..eed0daaec2 100644 --- a/domain/visa/src/main/kotlin/com/tangem/domain/pay/flow/PaymentAccountStatusFetcher.kt +++ b/domain/visa/src/main/kotlin/com/tangem/domain/pay/flow/PaymentAccountStatusFetcher.kt @@ -1,8 +1,14 @@ package com.tangem.domain.pay.flow +import arrow.core.Either import com.tangem.domain.core.flow.FlowFetcher import com.tangem.domain.models.wallet.UserWalletId interface PaymentAccountStatusFetcher : FlowFetcher { + + suspend operator fun invoke(userWalletId: UserWalletId): Either { + return invoke(Params(userWalletId)) + } + data class Params(val userWalletId: UserWalletId) } \ No newline at end of file diff --git a/domain/visa/src/main/kotlin/com/tangem/domain/pay/usecase/SetTangemPayCardLimitUseCase.kt b/domain/visa/src/main/kotlin/com/tangem/domain/pay/usecase/SetTangemPayCardLimitUseCase.kt index 9c66f8d75e..b3fd1ebb56 100644 --- a/domain/visa/src/main/kotlin/com/tangem/domain/pay/usecase/SetTangemPayCardLimitUseCase.kt +++ b/domain/visa/src/main/kotlin/com/tangem/domain/pay/usecase/SetTangemPayCardLimitUseCase.kt @@ -17,9 +17,6 @@ class SetTangemPayCardLimitUseCase( amount: BigDecimal, ): Either { return cardDetailsRepository.updateCardLimit(cardId, userWalletId, amount.toPlainString()) - .onRight { - val params = PaymentAccountStatusFetcher.Params(userWalletId) - paymentAccountStatusFetcher.invoke(params) - } + .onRight { paymentAccountStatusFetcher.invoke(userWalletId) } } } \ No newline at end of file diff --git a/domain/visa/src/main/kotlin/com/tangem/domain/pay/usecase/UpdateTangemPayCardNameUseCase.kt b/domain/visa/src/main/kotlin/com/tangem/domain/pay/usecase/UpdateTangemPayCardNameUseCase.kt new file mode 100644 index 0000000000..5020313889 --- /dev/null +++ b/domain/visa/src/main/kotlin/com/tangem/domain/pay/usecase/UpdateTangemPayCardNameUseCase.kt @@ -0,0 +1,22 @@ +package com.tangem.domain.pay.usecase + +import arrow.core.Either +import com.tangem.core.error.UniversalError +import com.tangem.domain.models.account.CardDisplayName +import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.domain.pay.flow.PaymentAccountStatusFetcher +import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository + +class UpdateTangemPayCardNameUseCase( + private val cardDetailsRepository: TangemPayCardDetailsRepository, + private val paymentAccountStatusFetcher: PaymentAccountStatusFetcher, +) { + suspend operator fun invoke( + cardId: String, + userWalletId: UserWalletId, + displayName: CardDisplayName, + ): Either { + return cardDetailsRepository.updateCardDisplayName(cardId, userWalletId, displayName) + .onRight { paymentAccountStatusFetcher(userWalletId) } + } +} \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/DefaultTangemPayDetailsContainerComponent.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/DefaultTangemPayDetailsContainerComponent.kt index 52b0069572..94de672f75 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/DefaultTangemPayDetailsContainerComponent.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/DefaultTangemPayDetailsContainerComponent.kt @@ -69,6 +69,10 @@ internal class DefaultTangemPayDetailsContainerComponent @AssistedInject constru context = childByContext(componentContext = componentContext, router = innerRouter), params = TangemPayCardPageComponent.Params(userWalletId = params.userWalletId, config = params.config), ) + TangemPayAccountDetailsInnerRoute.AddToWallet -> TangemPayAddToWalletComponent( + appComponentContext = childByContext(componentContext = componentContext, router = innerRouter), + params = params, + ) } private fun onChildBack() { diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayAddToWalletComponent.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayAddToWalletComponent.kt index 91d394396e..f04ea0b8de 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayAddToWalletComponent.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayAddToWalletComponent.kt @@ -25,7 +25,7 @@ internal class TangemPayAddToWalletComponent( appComponentContext = child("cardDetailsBlockComponent"), params = TangemPayCardDetailsBlockComponent.Params( params = params, - isDisplayCardNameEnabled = false, + isEditingNameEnabled = false, ), ) diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayCardPageScreenComponent.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayCardPageScreenComponent.kt index 9d3e29f799..87a347f661 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayCardPageScreenComponent.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayCardPageScreenComponent.kt @@ -39,7 +39,7 @@ internal class TangemPayCardPageScreenComponent( appComponentContext = child("cardDetailsBlockComponent"), params = TangemPayCardDetailsBlockComponent.Params( params = containerParams, - isDisplayCardNameEnabled = true, + isEditingNameEnabled = true, ), ) diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayEditDisplayNameComponent.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayEditDisplayNameComponent.kt index 8b4bb6214d..571c294824 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayEditDisplayNameComponent.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayEditDisplayNameComponent.kt @@ -24,7 +24,7 @@ internal class TangemPayEditDisplayNameComponent( private val cardDetailsBlockComponent = DefaultTangemPayCardDetailsBlockComponent( appComponentContext = child("editDisplayNameCardDetails"), - params = TangemPayCardDetailsBlockComponent.Params(params = params, isDisplayCardNameEnabled = true), + params = TangemPayCardDetailsBlockComponent.Params(params = params, isEditingNameEnabled = false), ) @Composable @@ -33,7 +33,7 @@ internal class TangemPayEditDisplayNameComponent( val cardDetailsState by cardDetailsBlockComponent.state.collectAsStateWithLifecycle() val editingCardDetailsState = cardDetailsState.copy( displayNameState = DisplayNameState.Editing( - displayName = state.editingValue, + displayName = state.editingValue.text, editingValue = state.editingValue, onValueChanged = state.onValueChanged, onSubmit = state.onDoneClick, diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/cardDetails/TangemPayCardDetailsBlockComponent.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/cardDetails/TangemPayCardDetailsBlockComponent.kt index 9b80de3eb5..c877c6cddb 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/cardDetails/TangemPayCardDetailsBlockComponent.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/cardDetails/TangemPayCardDetailsBlockComponent.kt @@ -16,6 +16,6 @@ internal interface TangemPayCardDetailsBlockComponent { data class Params( val params: TangemPayDetailsContainerComponent.Params, - val isDisplayCardNameEnabled: Boolean, + val isEditingNameEnabled: Boolean, ) } \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayCardDetailsBlockStateFactory.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayCardDetailsBlockStateFactory.kt index d57030a177..698d35ec97 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayCardDetailsBlockStateFactory.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayCardDetailsBlockStateFactory.kt @@ -1,6 +1,7 @@ package com.tangem.features.tangempay.entity import com.tangem.core.ui.extensions.resourceReference +import com.tangem.domain.models.account.CardDisplayName import com.tangem.domain.visa.model.TangemPayCardFrozenState import com.tangem.features.tangempay.details.impl.R import com.tangem.features.tangempay.model.CardDataType @@ -8,21 +9,33 @@ import com.tangem.utils.StringsSigns internal class TangemPayCardDetailsBlockStateFactory( private val cardNumberEnd: String, - private val displayNameState: DisplayNameState?, + private val displayName: CardDisplayName?, + private val isEditingNameEnabled: Boolean, + private val onEditNameClick: () -> Unit, private val onReveal: () -> Unit, private val onCopy: (String, CardDataType) -> Unit, ) { - fun getInitialState() = TangemPayCardDetailsUM( - number = "", - numberShort = "${StringsSigns.ASTERISK}$cardNumberEnd", - expiry = "", - cvv = "", - buttonText = resourceReference(R.string.tangempay_card_details_reveal_text), - onClick = onReveal, - onCopy = onCopy, - isHidden = true, - cardFrozenState = TangemPayCardFrozenState.Unfrozen, - displayNameState = displayNameState, - ) + fun getInitialState(): TangemPayCardDetailsUM { + return TangemPayCardDetailsUM( + number = "", + numberShort = "${StringsSigns.ASTERISK}$cardNumberEnd", + expiry = "", + cvv = "", + buttonText = resourceReference(R.string.tangempay_card_details_reveal_text), + onClick = onReveal, + onCopy = onCopy, + isHidden = true, + cardFrozenState = TangemPayCardFrozenState.Unfrozen, + displayNameState = if (displayName != null) { + DisplayNameState.Display( + displayName = displayName.value, + onClick = onEditNameClick, + isEditingEnabled = isEditingNameEnabled, + ) + } else { + null + }, + ) + } } \ No newline at end of file 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 ea86449252..2f630968ac 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 @@ -59,6 +59,7 @@ internal class TangemPayDetailsStateFactory( ), isBalanceHidden = false, addFundsEnabled = true, + addToWalletBlockState = null, accountDeactivatedNotificationConfig = NotificationConfig( title = resourceReference(R.string.tangempay_account_deactivated_message_title), subtitle = resourceReference(R.string.tangempay_account_deactivated_message_subtitle), 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 b6b591544f..50fb7a2683 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 @@ -1,5 +1,6 @@ package com.tangem.features.tangempay.entity +import androidx.compose.ui.text.input.TextFieldValue import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig import com.tangem.core.ui.components.notifications.NotificationConfig @@ -12,6 +13,7 @@ internal data class TangemPayDetailsUM( val topBarConfig: TangemPayDetailsTopBarConfig, val pullToRefreshConfig: PullToRefreshConfig, val balanceBlockState: TangemPayDetailsBalanceBlockState, + val addToWalletBlockState: AddToWalletBlockState?, val isBalanceHidden: Boolean, val addFundsEnabled: Boolean, val accountDeactivatedNotificationConfig: NotificationConfig?, @@ -39,15 +41,23 @@ internal sealed interface DisplayNameState { data class Display( override val displayName: String, val onClick: () -> Unit, + val isEditingEnabled: Boolean, ) : DisplayNameState data class Editing( override val displayName: String, - val editingValue: String, - val onValueChanged: (String) -> Unit, + val editingValue: TextFieldValue, + val onValueChanged: (TextFieldValue) -> Unit, val onSubmit: () -> Unit, val onDismiss: () -> Unit, ) : DisplayNameState + + fun copySealed(displayName: String): DisplayNameState { + return when (this) { + is Display -> copy(displayName = displayName) + is Editing -> copy(displayName = displayName) + } + } } internal sealed class TangemPayDetailsBalanceBlockState { diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayEditDisplayNameUM.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayEditDisplayNameUM.kt index a13fdbc1d0..8d4c09a816 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayEditDisplayNameUM.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayEditDisplayNameUM.kt @@ -1,9 +1,11 @@ package com.tangem.features.tangempay.entity +import androidx.compose.ui.text.input.TextFieldValue + internal data class TangemPayEditDisplayNameUM( - val editingValue: String, + val editingValue: TextFieldValue, val isLoading: Boolean, - val onValueChanged: (String) -> Unit, + val onValueChanged: (TextFieldValue) -> Unit, val onDoneClick: () -> Unit, val onDismiss: () -> Unit, ) \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardDetailsBlockModel.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardDetailsBlockModel.kt index 9bcf1fcdd1..4e97b58c7d 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardDetailsBlockModel.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardDetailsBlockModel.kt @@ -10,11 +10,16 @@ import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.ui.clipboard.ClipboardManager import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.message.SnackbarMessage +import com.tangem.domain.models.StatusSource +import com.tangem.domain.models.account.PaymentAccountStatusValue +import com.tangem.domain.models.account.hasCardWithId +import com.tangem.domain.models.account.requireCardWithId +import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.domain.pay.flow.PaymentAccountStatusSupplier import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository import com.tangem.domain.tangempay.TangemPayAnalyticsEvents import com.tangem.features.tangempay.components.cardDetails.TangemPayCardDetailsBlockComponent import com.tangem.features.tangempay.details.impl.R -import com.tangem.features.tangempay.entity.DisplayNameState import com.tangem.features.tangempay.entity.TangemPayCardDetailsBlockStateFactory import com.tangem.features.tangempay.entity.TangemPayCardDetailsUM import com.tangem.features.tangempay.model.listener.CardDetailsEvent @@ -22,10 +27,12 @@ import com.tangem.features.tangempay.model.listener.CardDetailsEventListener import com.tangem.features.tangempay.model.transformers.DetailsHiddenStateTransformer import com.tangem.features.tangempay.model.transformers.DetailsRevealProgressStateTransformer import com.tangem.features.tangempay.model.transformers.DetailsRevealedStateTransformer +import com.tangem.features.tangempay.model.transformers.TangemPayCardDetailsUpdateNameTransformer import com.tangem.features.tangempay.navigation.TangemPayCardDetailsInnerRoute import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.JobHolder import com.tangem.utils.coroutines.saveIn +import com.tangem.utils.transformer.update import kotlinx.coroutines.delay import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch @@ -46,20 +53,16 @@ internal class TangemPayCardDetailsBlockModel @Inject constructor( private val cardDetailsEventListener: CardDetailsEventListener, private val analytics: AnalyticsEventHandler, private val router: Router, + private val paymentAccountStatusSupplier: PaymentAccountStatusSupplier, ) : Model() { private val params: TangemPayCardDetailsBlockComponent.Params = paramsContainer.require() private val stateFactory = TangemPayCardDetailsBlockStateFactory( cardNumberEnd = params.params.config.cardNumberEnd, - displayNameState = if (params.isDisplayCardNameEnabled && params.params.config.displayName != null) { - DisplayNameState.Display( - displayName = requireNotNull(params.params.config.displayName).value, - onClick = ::startEditingDisplayName, - ) - } else { - null - }, + displayName = params.params.config.displayName, + isEditingNameEnabled = params.isEditingNameEnabled, + onEditNameClick = ::startEditingDisplayName, onReveal = ::revealCardDetails, onCopy = ::copyData, ) @@ -71,6 +74,7 @@ internal class TangemPayCardDetailsBlockModel @Inject constructor( private val showCardDetailsTimerJobHolder = JobHolder() init { + subscribeToCardNameChanges(cardId = params.params.config.cardId, userWalletId = params.params.userWalletId) subscribeToCardFrozenState() modelScope.launch { cardDetailsEventListener.event.collectLatest { event -> @@ -82,6 +86,23 @@ internal class TangemPayCardDetailsBlockModel @Inject constructor( } } + private fun subscribeToCardNameChanges(cardId: String, userWalletId: UserWalletId) { + paymentAccountStatusSupplier.invoke(userWalletId) + .onEach { state -> + val status = state.value + if (status is PaymentAccountStatusValue.Loaded && + status.source == StatusSource.ACTUAL && + status.hasCardWithId(cardId) + ) { + val card = status.requireCardWithId(cardId) + val displayName = card.displayName ?: return@onEach + + uiState.update(TangemPayCardDetailsUpdateNameTransformer(displayName)) + } + } + .launchIn(modelScope) + } + private fun subscribeToCardFrozenState() { cardDetailsRepository .cardFrozenState(params.params.config.cardId) diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt index a500999cdc..dded4437b7 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt @@ -39,10 +39,7 @@ import com.tangem.features.tangempay.entity.TangemPayDetailsStateFactory import com.tangem.features.tangempay.entity.TangemPayDetailsUM import com.tangem.features.tangempay.model.listener.CardDetailsEvent import com.tangem.features.tangempay.model.listener.CardDetailsEventListener -import com.tangem.features.tangempay.model.transformers.DetailBalanceVisibilityTransformer -import com.tangem.features.tangempay.model.transformers.DetailsBalanceTransformer -import com.tangem.features.tangempay.model.transformers.TangemPayDetailsRefreshTransformer -import com.tangem.features.tangempay.model.transformers.TangemPayFreezeUnfreezeStateTransformer +import com.tangem.features.tangempay.model.transformers.* import com.tangem.features.tangempay.navigation.TangemPayAccountDetailsInnerRoute import com.tangem.features.tangempay.utils.TangemPayDetailIntents import com.tangem.features.tangempay.utils.TangemPayMessagesFactory @@ -56,7 +53,10 @@ import com.tangem.utils.coroutines.saveIn import com.tangem.utils.logging.TangemLogger import com.tangem.utils.transformer.update import kotlinx.coroutines.Job -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import javax.inject.Inject @@ -100,6 +100,7 @@ internal class TangemPayDetailsModel @Inject constructor( private val refreshStateJobHolder = JobHolder() private val fetchBalanceJobHolder = JobHolder() + private val addToWalletBannerJobHolder = JobHolder() private var balance: TangemPayCardBalance? = null @@ -116,6 +117,7 @@ internal class TangemPayDetailsModel @Inject constructor( fetchBalance() if (!params.config.isTangemPayDeactivated) { subscribeToCardFrozenState() + fetchAddToWalletBanner() } } @@ -231,6 +233,24 @@ internal class TangemPayDetailsModel @Inject constructor( }.saveIn(fetchBalanceJobHolder) } + private fun fetchAddToWalletBanner() { + modelScope.launch { + val isDone = try { + cardDetailsRepository.isAddToWalletDone(params.userWalletId).getOrNull() == true + } catch (e: Exception) { + TangemLogger.e("Error", e) + return@launch + } + uiState.update( + transformer = DetailsAddToWalletBannerTransformer( + onClickBanner = ::onClickAddToWalletBlock, + onClickCloseBanner = ::onClickCloseAddToWalletBlock, + isDone = isDone, + ), + ) + }.saveIn(addToWalletBannerJobHolder) + } + private fun handleBalanceHiding() { getBalanceHidingSettingsUseCase().onEach { uiState.update(DetailBalanceVisibilityTransformer(isHidden = it.isBalanceHidden)) @@ -260,6 +280,28 @@ internal class TangemPayDetailsModel @Inject constructor( }.saveIn(refreshStateJobHolder) } + private fun onClickAddToWalletBlock() { + analytics.send(TangemPayAnalyticsEvents.AddToWalletClicked()) + router.push(TangemPayAccountDetailsInnerRoute.AddToWallet) + } + + private fun onClickCloseAddToWalletBlock() { + modelScope.launch { + try { + cardDetailsRepository.setAddToWalletAsDone(params.userWalletId) + } catch (e: Exception) { + TangemLogger.e("Error", e) + } + uiState.update( + transformer = DetailsAddToWalletBannerTransformer( + onClickBanner = ::onClickAddToWalletBlock, + onClickCloseBanner = ::onClickCloseAddToWalletBlock, + isDone = true, + ), + ) + }.saveIn(addToWalletBannerJobHolder) + } + private fun onOpenMenu() { analytics.send(TangemPayAnalyticsEvents.CardSettingsClicked()) } diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayEditDisplayNameModel.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayEditDisplayNameModel.kt index f0ed2d6e98..352d5d1373 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayEditDisplayNameModel.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayEditDisplayNameModel.kt @@ -1,6 +1,8 @@ package com.tangem.features.tangempay.model import androidx.compose.runtime.Stable +import androidx.compose.ui.text.TextRange +import androidx.compose.ui.text.input.TextFieldValue import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer @@ -8,15 +10,19 @@ import com.tangem.core.decompose.navigation.Router import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.message.DialogMessage +import com.tangem.domain.models.StatusSource import com.tangem.domain.models.account.CardDisplayName -import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository +import com.tangem.domain.models.account.PaymentAccountStatusValue +import com.tangem.domain.models.account.hasCardWithId +import com.tangem.domain.models.account.requireCardWithId +import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.domain.pay.flow.PaymentAccountStatusSupplier +import com.tangem.domain.pay.usecase.UpdateTangemPayCardNameUseCase import com.tangem.features.tangempay.components.TangemPayDetailsContainerComponent import com.tangem.features.tangempay.details.impl.R import com.tangem.features.tangempay.entity.TangemPayEditDisplayNameUM import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.update +import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import javax.inject.Inject @@ -26,8 +32,9 @@ internal class TangemPayEditDisplayNameModel @Inject constructor( paramsContainer: ParamsContainer, override val dispatchers: CoroutineDispatcherProvider, private val router: Router, - private val cardDetailsRepository: TangemPayCardDetailsRepository, + private val updateCardNameUseCase: UpdateTangemPayCardNameUseCase, private val uiMessageSender: UiMessageSender, + private val paymentAccountStatusSupplier: PaymentAccountStatusSupplier, ) : Model() { private val params: TangemPayDetailsContainerComponent.Params = paramsContainer.require() @@ -37,7 +44,10 @@ internal class TangemPayEditDisplayNameModel @Inject constructor( val uiState: StateFlow field = MutableStateFlow( TangemPayEditDisplayNameUM( - editingValue = originalDisplayName, + editingValue = TextFieldValue( + text = originalDisplayName, + selection = TextRange(originalDisplayName.length), + ), isLoading = false, onValueChanged = ::onValueChanged, onDoneClick = ::onDoneClick, @@ -45,23 +55,51 @@ internal class TangemPayEditDisplayNameModel @Inject constructor( ), ) - private fun onValueChanged(value: String) { - if (value.length <= CardDisplayName.MAX_LENGTH) { + init { + subscribeToCardNameChanges(params.config.cardId, params.userWalletId) + } + + private fun subscribeToCardNameChanges(cardId: String, userWalletId: UserWalletId) { + paymentAccountStatusSupplier.invoke(userWalletId) + .onEach { state -> + val status = state.value + if (status is PaymentAccountStatusValue.Loaded && + status.source == StatusSource.ACTUAL && + status.hasCardWithId(cardId) + ) { + val card = status.requireCardWithId(cardId) + val displayName = card.displayName ?: return@onEach + + uiState.update { uiState -> + uiState.copy( + editingValue = TextFieldValue( + text = displayName.value, + selection = TextRange(displayName.value.length), + ), + ) + } + } + } + .launchIn(modelScope) + } + + private fun onValueChanged(value: TextFieldValue) { + if (value.text.length <= CardDisplayName.MAX_LENGTH) { uiState.update { it.copy(editingValue = value) } } } private fun onDoneClick() { - val currentValue = uiState.value.editingValue + val currentValue = uiState.value.editingValue.text if (currentValue.trim() == originalDisplayName.trim()) { router.pop() return } CardDisplayName(currentValue) .onRight { cardDisplayName -> - uiState.update { it.copy(isLoading = true) } modelScope.launch { - cardDetailsRepository.updateCardDisplayName( + uiState.update { it.copy(isLoading = true) } + updateCardNameUseCase( cardId = params.config.cardId, userWalletId = params.userWalletId, displayName = cardDisplayName, diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/DetailsAddToWalletBannerTransformer.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/DetailsAddToWalletBannerTransformer.kt new file mode 100644 index 0000000000..3fe7bddbf8 --- /dev/null +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/DetailsAddToWalletBannerTransformer.kt @@ -0,0 +1,22 @@ +package com.tangem.features.tangempay.model.transformers + +import com.tangem.features.tangempay.entity.AddToWalletBlockState +import com.tangem.features.tangempay.entity.TangemPayDetailsUM +import com.tangem.utils.transformer.Transformer + +internal class DetailsAddToWalletBannerTransformer( + private val onClickBanner: () -> Unit, + private val onClickCloseBanner: () -> Unit, + private val isDone: Boolean, +) : Transformer { + + override fun transform(prevState: TangemPayDetailsUM): TangemPayDetailsUM { + return prevState.copy( + addToWalletBlockState = if (isDone) { + null + } else { + AddToWalletBlockState(onClick = onClickBanner, onClickClose = onClickCloseBanner) + }, + ) + } +} \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayCardDetailsUpdateNameTransformer.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayCardDetailsUpdateNameTransformer.kt new file mode 100644 index 0000000000..9c7df001c2 --- /dev/null +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayCardDetailsUpdateNameTransformer.kt @@ -0,0 +1,15 @@ +package com.tangem.features.tangempay.model.transformers + +import com.tangem.domain.models.account.CardDisplayName +import com.tangem.features.tangempay.entity.TangemPayCardDetailsUM +import com.tangem.utils.transformer.Transformer + +internal class TangemPayCardDetailsUpdateNameTransformer( + private val displayName: CardDisplayName, +) : Transformer { + + override fun transform(prevState: TangemPayCardDetailsUM): TangemPayCardDetailsUM { + val displayNameState = prevState.displayNameState ?: return prevState + return prevState.copy(displayNameState = displayNameState.copySealed(displayName = displayName.value)) + } +} \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/navigation/TangemPayAccountDetailsInnerRoute.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/navigation/TangemPayAccountDetailsInnerRoute.kt index 6bc9172607..8ef5c5e9a3 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/navigation/TangemPayAccountDetailsInnerRoute.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/navigation/TangemPayAccountDetailsInnerRoute.kt @@ -10,4 +10,7 @@ internal sealed class TangemPayAccountDetailsInnerRoute : Route { @Serializable data object CardDetails : TangemPayAccountDetailsInnerRoute() + + @Serializable + data object AddToWallet : TangemPayAccountDetailsInnerRoute() } \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayCardDetailsBlock.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayCardDetailsBlock.kt index efe8c8a8dd..0a58c2672a 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayCardDetailsBlock.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayCardDetailsBlock.kt @@ -1,24 +1,22 @@ package com.tangem.features.tangempay.ui -import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.EaseInOut -import androidx.compose.animation.core.MutableTransitionState import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.* -import androidx.compose.runtime.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -46,6 +44,7 @@ import com.tangem.core.ui.components.SpacerWMax import com.tangem.core.ui.components.buttons.common.TangemButton import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition import com.tangem.core.ui.components.buttons.common.TangemButtonSize +import com.tangem.core.ui.extensions.conditional import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.stringResourceSafe import com.tangem.core.ui.res.TangemTheme @@ -58,7 +57,7 @@ import com.tangem.features.tangempay.entity.DisplayNameState import com.tangem.features.tangempay.entity.TangemPayCardDetailsUM import com.tangem.features.tangempay.model.CardDataType -private const val ICON_FADE_DURATION_MS = 300 +private const val TEXT_WIDTH_PADDING = 2 private val CustomCardBlockColor = Color(0x1F828282) @Suppress("MagicNumber") @@ -228,80 +227,55 @@ private fun TangemPayCardDetailsHiddenBlock(state: TangemPayCardDetailsUM, modif @Composable private fun CardDisplayName(state: DisplayNameState, modifier: Modifier = Modifier) { - val isDisplayMode = state is DisplayNameState.Display - - Row( - modifier = modifier.then( - if (state is DisplayNameState.Display) { - Modifier.clickable( - interactionSource = remember { MutableInteractionSource() }, - indication = null, - onClick = state.onClick, - ) - } else { - Modifier - }, - ), - verticalAlignment = Alignment.CenterVertically, - ) { - when (state) { - is DisplayNameState.Display -> DisplayOnlyCardDisplayName(state = state) - is DisplayNameState.Editing -> EditingCardDisplayName(state = state) - } - val iconVisibleState = remember { - MutableTransitionState(initialState = !isDisplayMode).apply { - targetState = isDisplayMode - } - } - AnimatedVisibility( - visibleState = iconVisibleState, - enter = fadeIn(animationSpec = tween(durationMillis = ICON_FADE_DURATION_MS)), - exit = fadeOut(animationSpec = tween(durationMillis = ICON_FADE_DURATION_MS)), - ) { - Row(verticalAlignment = Alignment.CenterVertically) { - Spacer(modifier = Modifier.width(6.dp)) - Icon( - painter = painterResource(id = com.tangem.core.ui.R.drawable.ic_edit_new_12), - contentDescription = null, - modifier = Modifier.size(10.dp), - tint = TangemTheme.colors.text.constantWhite, - ) - } - } + when (state) { + is DisplayNameState.Display -> DisplayOnlyCardDisplayName(modifier = modifier, state = state) + is DisplayNameState.Editing -> EditingCardDisplayName(modifier = modifier, state = state) } } @Composable private fun DisplayOnlyCardDisplayName(state: DisplayNameState.Display, modifier: Modifier = Modifier) { - Text( - text = state.displayName, - style = TangemTheme.typography.caption1.copy(color = TangemTheme.colors.text.constantWhite), - maxLines = 1, - modifier = modifier, - ) + Row( + modifier = modifier.conditional( + condition = state.isEditingEnabled, + modifier = { clickable(onClick = state.onClick) }, + ), + horizontalArrangement = Arrangement.spacedBy(6.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = state.displayName, + style = TangemTheme.typography.caption1.copy(color = TangemTheme.colors.text.constantWhite), + maxLines = 1, + ) + if (state.isEditingEnabled) { + Icon( + painter = painterResource(id = R.drawable.ic_edit_new_12), + contentDescription = null, + modifier = Modifier.size(10.dp), + tint = TangemTheme.colors.text.constantWhite, + ) + } + } } @Composable private fun EditingCardDisplayName(state: DisplayNameState.Editing, modifier: Modifier = Modifier) { val focusRequester = remember { FocusRequester() } - var textFieldValue by remember(state.editingValue) { - mutableStateOf( - TextFieldValue(text = state.editingValue, selection = TextRange(state.editingValue.length)), - ) - } + val placeholder = stringResourceSafe(R.string.tangempay_card_edit_name_placeholder) val textStyle = TangemTheme.typography.caption1.copy(color = TangemTheme.colors.text.constantWhite) val textMeasurer = rememberTextMeasurer() + val measuredText = state.editingValue.text.ifEmpty { placeholder } val textWidthDp = with(LocalDensity.current) { - textMeasurer.measure(textFieldValue.text, textStyle).size.width.toDp() + 2.dp + textMeasurer.measure(measuredText, textStyle).size.width.toDp() + TEXT_WIDTH_PADDING.dp } BasicTextField( - value = textFieldValue, + value = state.editingValue, onValueChange = { newValue -> - if (newValue.text.length in 0..CardDisplayName.MAX_LENGTH) { - textFieldValue = newValue - state.onValueChanged(newValue.text) + if (newValue.text.length <= CardDisplayName.MAX_LENGTH) { + state.onValueChanged(newValue) } }, modifier = modifier @@ -312,6 +286,17 @@ private fun EditingCardDisplayName(state: DisplayNameState.Editing, modifier: Mo cursorBrush = SolidColor(TangemTheme.colors.text.constantWhite), keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = { state.onSubmit() }), + decorationBox = { innerTextField -> + Box { + if (state.editingValue.text.isEmpty()) { + Text( + text = placeholder, + style = textStyle.copy(color = TangemTheme.colors.text.tertiary), + ) + } + innerTextField() + } + }, ) LaunchedEffect(Unit) { focusRequester.requestFocus() } @@ -492,7 +477,13 @@ private class TangemPayCardDetailsUMProvider : CollectionPreviewParameterProvide onCopy = { _, _ -> }, isHidden = true, cardFrozenState = TangemPayCardFrozenState.Frozen, - displayNameState = DisplayNameState.Display(displayName = "Tangem", onClick = {}), + displayNameState = DisplayNameState.Editing( + displayName = "Tangem", + editingValue = TextFieldValue(text = "movet", selection = TextRange("movet".length)), + onValueChanged = {}, + onSubmit = {}, + onDismiss = {}, + ), ), TangemPayCardDetailsUM( isLoading = false, @@ -505,7 +496,13 @@ private class TangemPayCardDetailsUMProvider : CollectionPreviewParameterProvide onCopy = { _, _ -> }, isHidden = true, cardFrozenState = TangemPayCardFrozenState.Unfrozen, - displayNameState = DisplayNameState.Display(displayName = "Tangem Pay Card", onClick = {}), + displayNameState = DisplayNameState.Editing( + displayName = "Tangem", + editingValue = TextFieldValue(text = ""), + onValueChanged = {}, + onSubmit = {}, + onDismiss = {}, + ), ), TangemPayCardDetailsUM( isLoading = false, @@ -518,7 +515,11 @@ private class TangemPayCardDetailsUMProvider : CollectionPreviewParameterProvide onCopy = { _, _ -> }, isHidden = true, cardFrozenState = TangemPayCardFrozenState.Pending, - displayNameState = DisplayNameState.Display(displayName = "Tangem Pay Card", onClick = {}), + displayNameState = DisplayNameState.Display( + displayName = "Tangem Pay Card", + onClick = {}, + isEditingEnabled = true, + ), ), TangemPayCardDetailsUM( isLoading = false, @@ -531,7 +532,11 @@ private class TangemPayCardDetailsUMProvider : CollectionPreviewParameterProvide expiry = "12/34", cvv = "123", cardFrozenState = TangemPayCardFrozenState.Unfrozen, - displayNameState = DisplayNameState.Display(displayName = "Tangem Pay Card", onClick = {}), + displayNameState = DisplayNameState.Display( + displayName = "Tangem Pay Card", + onClick = {}, + isEditingEnabled = false, + ), ), ), ) \ 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 4b8dbc7446..5217c1be53 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 @@ -8,18 +8,7 @@ import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.background import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.exclude -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.navigationBars -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.statusBarsPadding -import androidx.compose.foundation.layout.systemBars +import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyItemScope import androidx.compose.foundation.lazy.LazyListScope @@ -46,11 +35,7 @@ import com.tangem.domain.visa.model.TangemPayCardFrozenState import com.tangem.features.tangempay.components.cardDetails.PreviewTangemPayCardDetailsBlockComponent import com.tangem.features.tangempay.components.cardDetails.TangemPayCardDetailsBlockComponent import com.tangem.features.tangempay.details.impl.R -import com.tangem.features.tangempay.entity.DisplayNameState -import com.tangem.features.tangempay.entity.TangemPayCardDetailsUM -import com.tangem.features.tangempay.entity.TangemPayCardPageSetting -import com.tangem.features.tangempay.entity.TangemPayCardPageUM -import com.tangem.features.tangempay.entity.TangemPayDailyLimitBlockState +import com.tangem.features.tangempay.entity.* import kotlinx.collections.immutable.ImmutableList private const val CONTENT_FADE_DURATION_MS = 300 @@ -217,7 +202,11 @@ private fun preview() = TangemThemePreview { onCopy = { _, _ -> }, onClick = {}, cardFrozenState = TangemPayCardFrozenState.Unfrozen, - displayNameState = DisplayNameState.Display(displayName = "Tangem Pay Card", onClick = {}), + displayNameState = DisplayNameState.Display( + displayName = "Tangem Pay Card", + onClick = {}, + isEditingEnabled = true, + ), ), ), cardDetailsState = TangemPayCardDetailsUM( @@ -228,7 +217,11 @@ private fun preview() = TangemThemePreview { onCopy = { _, _ -> }, onClick = {}, cardFrozenState = TangemPayCardFrozenState.Unfrozen, - displayNameState = DisplayNameState.Display(displayName = "Tangem Pay Card", onClick = {}), + displayNameState = DisplayNameState.Display( + displayName = "Tangem Pay Card", + onClick = {}, + isEditingEnabled = false, + ), ), ) } \ No newline at end of file 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 2349905b14..c6f426ec27 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 @@ -56,10 +56,7 @@ import com.tangem.features.tangempay.components.express.PreviewEmptyExpressTrans 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.entity.* import com.tangem.features.tokendetails.ExpressTransactionsComponent import com.tangem.utils.StringsSigns.DASH_SIGN import kotlinx.collections.immutable.persistentListOf @@ -116,6 +113,17 @@ internal fun TangemPayDetailsScreen( SpacerH12() }, ) + if (state.addToWalletBlockState != null) { + item( + key = AddToWalletBlockState::class.java, + content = { + TangemPayAddToWalletBlock( + state = state.addToWalletBlockState, + modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing16), + ) + }, + ) + } if (state.accountDeactivatedNotificationConfig != null) { item( key = "DEACTIVATION_MESSAGE", @@ -420,6 +428,7 @@ private class TangemPayDetailsUMProvider : CollectionPreviewParameterProvider