diff --git a/core/config-toggles/src/main/assets/configs/feature_toggles_config.json b/core/config-toggles/src/main/assets/configs/feature_toggles_config.json
index f6bd556683..741569571b 100644
--- a/core/config-toggles/src/main/assets/configs/feature_toggles_config.json
+++ b/core/config-toggles/src/main/assets/configs/feature_toggles_config.json
@@ -135,6 +135,10 @@
"name": "AND_15364_VISA_PAY_CARD_CLOSE",
"version": "undefined"
},
+ {
+ "name": "AND_15741_VISA_PAY_REMOVE_ACCOUNT",
+ "version": "undefined"
+ },
{
"name": "TWI_83_ADDRESS_BOOK_ENABLED",
"version": "undefined"
diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml
index 3aef2ddfa3..4bf9538ce4 100644
--- a/core/res/src/main/res/values/strings.xml
+++ b/core/res/src/main/res/values/strings.xml
@@ -1930,6 +1930,9 @@
Deposit USDC to payment account to cover the issuing fee
Unable to cover fee
Replace your card?
+ Remove account
+ Tangem Pay will be removed from the main screen and won\'t appear again, even after reinstalling the app.
+ Remove account?
We’re fixing a technical issue. Please try again later.
Service temporarily unavailable
Service unreachable. However, card payments are still working.
diff --git a/features/tangempay/details/api/src/main/kotlin/com/tangem/features/tangempay/TangemPayFeatureToggles.kt b/features/tangempay/details/api/src/main/kotlin/com/tangem/features/tangempay/TangemPayFeatureToggles.kt
index aa6c289349..3aeb39bc0b 100644
--- a/features/tangempay/details/api/src/main/kotlin/com/tangem/features/tangempay/TangemPayFeatureToggles.kt
+++ b/features/tangempay/details/api/src/main/kotlin/com/tangem/features/tangempay/TangemPayFeatureToggles.kt
@@ -3,4 +3,5 @@ package com.tangem.features.tangempay
interface TangemPayFeatureToggles {
val isRedesignEnabled: Boolean
val isCloseCardEnabled: Boolean
+ val isRemoveAccountEnabled: Boolean
}
\ No newline at end of file
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/DefaultTangemPayFeatureToggles.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/DefaultTangemPayFeatureToggles.kt
index aa2166183f..8cf9c58dc1 100644
--- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/DefaultTangemPayFeatureToggles.kt
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/DefaultTangemPayFeatureToggles.kt
@@ -12,4 +12,7 @@ internal class DefaultTangemPayFeatureToggles(
override val isCloseCardEnabled: Boolean
get() = featureTogglesManager.isFeatureEnabled(FeatureToggles.AND_15364_VISA_PAY_CARD_CLOSE)
+
+ override val isRemoveAccountEnabled: Boolean
+ get() = featureTogglesManager.isFeatureEnabled(FeatureToggles.AND_15741_VISA_PAY_REMOVE_ACCOUNT)
}
\ 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 e0591414d9..ea4b2a37a6 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
@@ -18,6 +18,8 @@ import com.tangem.features.tangempay.details.impl.R
import com.tangem.features.tangempay.utils.TangemPayDetailIntents
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
+import kotlinx.collections.immutable.toImmutableList
+import com.tangem.core.ui.R as CoreUiR
@Suppress("LongParameterList")
internal class TangemPayDetailsStateFactory(
@@ -25,6 +27,7 @@ internal class TangemPayDetailsStateFactory(
private val onOpenMenu: () -> Unit,
private val intents: TangemPayDetailIntents,
private val isRedesignEnabled: Boolean,
+ private val isRemoveAccountEnabled: Boolean,
) {
fun getLoadingState(): TangemPayDetailsUM {
return TangemPayDetailsUM(
@@ -102,8 +105,8 @@ internal class TangemPayDetailsStateFactory(
topBarConfig = TangemPayDetailsTopBarConfig(
onBackClick = onBack,
onOpenMenu = onOpenMenu,
- items = persistentListOf(),
- itemsV2 = persistentListOf(),
+ items = getDeactivatedMenuItems(),
+ itemsV2 = getDeactivatedMenuItemsV2(),
),
pullToRefreshConfig = PullToRefreshConfig(
isRefreshing = false,
@@ -131,6 +134,14 @@ internal class TangemPayDetailsStateFactory(
title = resourceReference(R.string.tangempay_account_deactivated_message_title),
subtitle = resourceReference(R.string.tangempay_account_deactivated_message_subtitle),
iconResId = R.drawable.img_attention_20,
+ buttonsState = if (isRemoveAccountEnabled) {
+ NotificationConfig.ButtonsState.SecondaryButtonConfig(
+ text = resourceReference(R.string.tangempay_remove_account),
+ onClick = intents::onRemoveAccount,
+ )
+ } else {
+ null
+ },
)
private fun createRenewSessionNotificationConfig() = NotificationConfig(
@@ -159,6 +170,55 @@ internal class TangemPayDetailsStateFactory(
)
}
+ private fun getDeactivatedMenuItems(): ImmutableList {
+ return buildList {
+ add(
+ TangemDropdownMenuItem(
+ title = resourceReference(R.string.tangempay_pay_support),
+ textColor = themedColor { TangemTheme.colors.text.primary1 },
+ onClick = intents::onContactSupportClicked,
+ ),
+ )
+ if (isRemoveAccountEnabled) {
+ add(
+ TangemDropdownMenuItem(
+ title = resourceReference(R.string.tangempay_remove_account),
+ textColor = themedColor { TangemTheme.colors.text.warning },
+ onClick = intents::onRemoveAccount,
+ ),
+ )
+ }
+ }.toImmutableList()
+ }
+
+ private fun getDeactivatedMenuItemsV2(): ImmutableList {
+ return buildList {
+ add(
+ TangemPayDropDownItemUM(
+ title = resourceReference(R.string.tangempay_pay_support),
+ onClick = intents::onContactSupportClicked,
+ icon = TangemIconUM.Icon(
+ iconRes = R.drawable.ic_mail_20,
+ tintReference = { TangemTheme.colors3.icon.primary },
+ ),
+ ),
+ )
+ if (isRemoveAccountEnabled) {
+ add(
+ TangemPayDropDownItemUM(
+ title = resourceReference(R.string.tangempay_remove_account),
+ onClick = intents::onRemoveAccount,
+ icon = TangemIconUM.Icon(
+ iconRes = CoreUiR.drawable.ic_trash_24,
+ tintReference = { TangemTheme.colors3.icon.status.error },
+ ),
+ titleColor = { TangemTheme.colors3.text.status.error },
+ ),
+ )
+ }
+ }.toImmutableList()
+ }
+
private fun getTopBarMenuItemsV2(): ImmutableList {
return persistentListOf(
TangemPayDropDownItemUM(
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
index 904b272672..562ba310be 100644
--- 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
@@ -1,6 +1,7 @@
package com.tangem.features.tangempay.entity
import com.tangem.core.ui.ds.image.TangemIconUM
+import com.tangem.core.ui.extensions.ColorReference2
import com.tangem.core.ui.extensions.TextReference
internal data class TangemPayDropDownItemUM(
@@ -9,4 +10,5 @@ internal data class TangemPayDropDownItemUM(
val icon: TangemIconUM,
val subtitle: TextReference? = null,
val isEnabled: Boolean = true,
+ val titleColor: ColorReference2? = null,
)
\ No newline at end of file
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 2712ea3c99..60462a0036 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
@@ -16,6 +16,8 @@ import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.navigation.url.UrlOpener
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig.ShowRefreshState
import com.tangem.core.ui.extensions.resourceReference
+import com.tangem.core.ui.message.DialogMessage
+import com.tangem.core.ui.message.EventMessageAction
import com.tangem.core.ui.message.SnackbarMessage
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
@@ -27,6 +29,7 @@ import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.pay.flow.PaymentAccountStatusFetcher
import com.tangem.domain.pay.flow.PaymentAccountStatusSupplier
import com.tangem.domain.pay.model.TangemPayTopUpData
+import com.tangem.domain.pay.repository.OnboardingRepository
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
import com.tangem.domain.pay.repository.TangemPayWithdrawRepository
import com.tangem.domain.pay.usecase.ProduceTangemPayInitialDataUseCase
@@ -75,6 +78,7 @@ internal class TangemPayDetailsModel @Inject constructor(
private val tangemPayFeatureToggles: TangemPayFeatureToggles,
private val paymentAccountStatusFetcher: PaymentAccountStatusFetcher,
private val produceTangemPayInitialDataUseCase: ProduceTangemPayInitialDataUseCase,
+ private val onboardingRepository: OnboardingRepository,
) : Model(), TangemPayTxHistoryUiActions, TangemPayDetailIntents, AddFundsListener {
private val params: TangemPayDetailsContainerComponent.Params = paramsContainer.require()
@@ -92,6 +96,7 @@ internal class TangemPayDetailsModel @Inject constructor(
onOpenMenu = ::onOpenMenu,
intents = this,
isRedesignEnabled = isRedesignEnabled(),
+ isRemoveAccountEnabled = tangemPayFeatureToggles.isRemoveAccountEnabled,
)
val uiState: StateFlow
@@ -374,6 +379,36 @@ internal class TangemPayDetailsModel @Inject constructor(
}
}
+ override fun onRemoveAccount() {
+ uiMessageSender.send(
+ DialogMessage(
+ title = resourceReference(R.string.tangempay_remove_account_alert_title),
+ message = resourceReference(R.string.tangempay_remove_account_alert_description),
+ firstActionBuilder = {
+ EventMessageAction(
+ isWarning = true,
+ title = resourceReference(R.string.tangempay_remove_account),
+ onClick = ::removeAccount,
+ )
+ },
+ secondActionBuilder = { cancelAction() },
+ ),
+ )
+ }
+
+ private fun removeAccount() {
+ modelScope.launch {
+ onboardingRepository.disableTangemPay(userWalletId)
+ .onRight {
+ paymentAccountStatusFetcher.invoke(userWalletId)
+ router.pop()
+ }
+ .onLeft {
+ uiMessageSender.send(SnackbarMessage(resourceReference(R.string.common_error)))
+ }
+ }
+ }
+
private fun showBottomSheetError(type: TangemPayDetailsErrorType) {
uiMessageSender.send(message = TangemPayMessagesFactory.createErrorMessage(errorType = type))
}
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
index ab96ff04ec..96483e2399 100644
--- 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
@@ -34,8 +34,12 @@ 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.notifications.NotificationConfig
import com.tangem.core.ui.components.text.applyBladeBrush
import com.tangem.core.ui.components.topFade
+import com.tangem.core.ui.ds.button.PrimaryInverseTangemButton
+import com.tangem.core.ui.ds.button.TangemButtonShape
+import com.tangem.core.ui.ds.button.TangemButtonSize
import com.tangem.core.ui.ds.image.TangemIconUM
import com.tangem.core.ui.ds.message.TangemMessage
import com.tangem.core.ui.ds.message.TangemMessageEffect
@@ -43,7 +47,10 @@ 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.*
+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.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreviewRedesign
import com.tangem.core.ui.test.TangemPayTestTags
@@ -202,22 +209,35 @@ private fun LazyListScope.payDetailsBody(state: TangemPayDetailsUM) {
}
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,
- )
+ DeactivationBannerBlock(notificationConfig = state.accountDeactivatedNotificationConfig)
}
}
}
}
}
+@Composable
+private fun DeactivationBannerBlock(notificationConfig: NotificationConfig) {
+ val removeAccountButton = notificationConfig.buttonsState as? NotificationConfig.ButtonsState.SecondaryButtonConfig
+ TangemMessage(
+ modifier = Modifier.padding(horizontal = TangemTheme.dimens2.x4),
+ title = notificationConfig.title,
+ subtitle = notificationConfig.subtitle,
+ messageEffect = TangemMessageEffect.Warning,
+ buttons = removeAccountButton?.let { button ->
+ {
+ PrimaryInverseTangemButton(
+ text = button.text,
+ onClick = button.onClick,
+ size = TangemButtonSize.X9,
+ shape = TangemButtonShape.Rounded,
+ modifier = Modifier.weight(1f),
+ )
+ }
+ },
+ )
+}
+
@Composable
private fun PayDetailsTopBar(
config: TangemPayDetailsTopBarConfig,
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
index 7e914f42d5..79e46958f5 100644
--- 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
@@ -71,10 +71,10 @@ private fun PayContextMenuItem(item: TangemPayDropDownItemUM, onMenuDismiss: ()
Text(
text = item.title.resolveReference(),
style = TangemTheme.typography3.body.medium,
- color = if (item.isEnabled) {
- TangemTheme.colors3.text.primary
- } else {
- TangemTheme.colors3.text.tertiary
+ color = when {
+ !item.isEnabled -> TangemTheme.colors3.text.tertiary
+ item.titleColor != null -> item.titleColor.invoke()
+ else -> TangemTheme.colors3.text.primary
},
maxLines = 1,
)
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/utils/TangemPayDetailIntents.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/utils/TangemPayDetailIntents.kt
index c4bd523fcf..7d68426983 100644
--- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/utils/TangemPayDetailIntents.kt
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/utils/TangemPayDetailIntents.kt
@@ -11,4 +11,5 @@ internal interface TangemPayDetailIntents {
fun onClickTermsAndLimits()
fun onCardClick()
fun onAddCardClick()
+ fun onRemoveAccount()
}
\ No newline at end of file