diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 900691f421..f583c64401 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -1469,6 +1469,9 @@ Freeze Your card is frozen. Get Help + Reason: %s + %s ยท %s + MCC %s Other Unable to use on rooted devices Completed diff --git a/data/visa/src/main/kotlin/com/tangem/data/visa/utils/TangemPayTxHistoryItemConverter.kt b/data/visa/src/main/kotlin/com/tangem/data/visa/utils/TangemPayTxHistoryItemConverter.kt index b8ecc58913..23187867a8 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/visa/utils/TangemPayTxHistoryItemConverter.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/visa/utils/TangemPayTxHistoryItemConverter.kt @@ -46,6 +46,7 @@ internal class TangemPayTxHistoryItemConverter(moshi: Moshi) : merchantCategory = spend.merchantCategory, status = TangemPayTxHistoryItemStatusConverter.convert(spend.status), enrichedMerchantIconUrl = spend.enrichedMerchantIcon, + declinedReason = spend.declinedReason, ) } diff --git a/domain/visa/models/src/main/kotlin/com/tangem/domain/visa/model/TangemPayTxHistoryItem.kt b/domain/visa/models/src/main/kotlin/com/tangem/domain/visa/model/TangemPayTxHistoryItem.kt index c272305d75..9741b0d593 100644 --- a/domain/visa/models/src/main/kotlin/com/tangem/domain/visa/model/TangemPayTxHistoryItem.kt +++ b/domain/visa/models/src/main/kotlin/com/tangem/domain/visa/model/TangemPayTxHistoryItem.kt @@ -29,6 +29,7 @@ sealed class TangemPayTxHistoryItem { val merchantCategory: String?, val status: Status, val enrichedMerchantIconUrl: String?, + val declinedReason: String?, ) : TangemPayTxHistoryItem() @Serializable diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayTxHistoryDetailsUM.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayTxHistoryDetailsUM.kt index 4d2aa7c66e..b240e9c159 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayTxHistoryDetailsUM.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayTxHistoryDetailsUM.kt @@ -17,10 +17,17 @@ internal data class TangemPayTxHistoryDetailsUM( val transactionAmountColor: ColorReference, val localTransactionText: String?, val labelState: LabelUM?, - val notification: NotificationConfig?, + val notification: NotificationState?, val buttons: ImmutableList, val dismiss: () -> Unit, ) { + data class NotificationState( + val config: NotificationConfig, + val titleColor: ColorReference, + val iconTint: ColorReference, + val containerColor: ColorReference?, + ) + data class ButtonState(val text: TextReference, val onClick: () -> Unit, val startIcon: ImageReference.Res? = null) } \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/PayDetailsSpendSubtitleConverter.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/PayDetailsSpendSubtitleConverter.kt new file mode 100644 index 0000000000..26f54a975c --- /dev/null +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/PayDetailsSpendSubtitleConverter.kt @@ -0,0 +1,46 @@ +package com.tangem.features.tangempay.model.transformers + +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.stringReference +import com.tangem.core.ui.extensions.wrappedList +import com.tangem.domain.visa.model.TangemPayTxHistoryItem +import com.tangem.features.tangempay.details.impl.R +import com.tangem.utils.converter.Converter + +internal object PayDetailsSpendSubtitleConverter : Converter { + + override fun convert(value: TangemPayTxHistoryItem.Spend): TextReference { + val merchantCategory = value.merchantCategory + val enrichedMerchantCategory = value.enrichedMerchantCategory + val merchantCategoryCode = value.merchantCategoryCode + + val categoryCodeText = if (!merchantCategoryCode.isNullOrEmpty()) { + resourceReference( + id = R.string.tangem_pay_history_item_spend_mcc, + formatArgs = wrappedList(merchantCategoryCode), + ) + } else { + null + } + + val categoryText = when { + // if merchantCategory isNotEmpty use this + !merchantCategory.isNullOrEmpty() -> stringReference(merchantCategory) + + // If merchantCategory empty or null but enrichedMerchantCategory is not empty + !enrichedMerchantCategory.isNullOrEmpty() -> stringReference(enrichedMerchantCategory) + + else -> resourceReference(R.string.tangem_pay_other) + } + + return if (categoryCodeText != null) { + resourceReference( + id = R.string.tangem_pay_history_item_spend_mc_title_format, + formatArgs = wrappedList(categoryText, categoryCodeText), + ) + } else { + categoryText + } + } +} \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayTxHistoryDetailsConverter.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayTxHistoryDetailsConverter.kt index 28706d2143..8269d2423a 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayTxHistoryDetailsConverter.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayTxHistoryDetailsConverter.kt @@ -7,6 +7,7 @@ import com.tangem.core.ui.extensions.* import com.tangem.core.ui.format.bigdecimal.fiat import com.tangem.core.ui.format.bigdecimal.format import com.tangem.core.ui.format.bigdecimal.price +import com.tangem.core.ui.res.TangemColorPalette import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.utils.DateTimeFormatters import com.tangem.domain.visa.model.TangemPayTxHistoryItem @@ -24,7 +25,7 @@ internal object TangemPayTxHistoryDetailsConverter : Converter { private val dateFormatter = DateTimeFormatters.getBestFormatterBySkeleton("dd MMMM") - private val paySpendSubtitleConverter = PaySpendSubtitleConverter + private val paySpendSubtitleConverter = PayDetailsSpendSubtitleConverter override fun convert(value: Input): TangemPayTxHistoryDetailsUM { val transaction = value.item @@ -140,13 +141,16 @@ internal object TangemPayTxHistoryDetailsConverter : private fun TangemPayTxHistoryItem.extractAmountColor(): ColorReference { return when (this) { is TangemPayTxHistoryItem.Fee, - is TangemPayTxHistoryItem.Spend, is TangemPayTxHistoryItem.Payment, -> themedColor { TangemTheme.colors.text.primary1 } is TangemPayTxHistoryItem.Collateral -> when (this.type) { TangemPayTxHistoryItem.Type.Deposit -> themedColor { TangemTheme.colors.text.accent } TangemPayTxHistoryItem.Type.Withdrawal -> themedColor { TangemTheme.colors.text.primary1 } } + is TangemPayTxHistoryItem.Spend -> when (this.status) { + TangemPayTxHistoryItem.Status.DECLINED -> themedColor { TangemTheme.colors.text.warning } + else -> themedColor { TangemTheme.colors.text.primary1 } + } } } @@ -200,21 +204,39 @@ internal object TangemPayTxHistoryDetailsConverter : } } - private fun TangemPayTxHistoryItem.extractNotification(): NotificationConfig? { + private fun TangemPayTxHistoryItem.extractNotification(): TangemPayTxHistoryDetailsUM.NotificationState? { return when (this) { is TangemPayTxHistoryItem.Payment -> null is TangemPayTxHistoryItem.Collateral -> null - is TangemPayTxHistoryItem.Fee -> NotificationConfig( - title = resourceReference(R.string.tangem_pay_transaction_fee_notification_text), - subtitle = TextReference.EMPTY, - iconResId = R.drawable.ic_token_info_24, - ) - is TangemPayTxHistoryItem.Spend -> when (this.status) { - TangemPayTxHistoryItem.Status.DECLINED -> NotificationConfig( - title = resourceReference(R.string.tangem_pay_transaction_declined_notification_text), + is TangemPayTxHistoryItem.Fee -> TangemPayTxHistoryDetailsUM.NotificationState( + config = NotificationConfig( + title = resourceReference(R.string.tangem_pay_transaction_fee_notification_text), subtitle = TextReference.EMPTY, iconResId = R.drawable.ic_token_info_24, - ) + ), + titleColor = themedColor { TangemTheme.colors.text.tertiary }, + iconTint = themedColor { TangemTheme.colors.icon.secondary }, + containerColor = null, + ) + is TangemPayTxHistoryItem.Spend -> when (this.status) { + TangemPayTxHistoryItem.Status.DECLINED -> + TangemPayTxHistoryDetailsUM.NotificationState( + config = NotificationConfig( + title = if (declinedReason.isNullOrEmpty()) { + resourceReference(R.string.tangem_pay_transaction_declined_notification_text) + } else { + resourceReference( + id = R.string.tangem_pay_history_item_spend_mc_declined_reason, + formatArgs = wrappedList(requireNotNull(declinedReason)), + ) + }, + subtitle = TextReference.EMPTY, + iconResId = R.drawable.ic_token_info_24, + ), + titleColor = themedColor { TangemTheme.colors.text.warning }, + iconTint = themedColor { TangemTheme.colors.icon.warning }, + containerColor = themedColor { TangemColorPalette.Amaranth.copy(alpha = 0.1F) }, + ) TangemPayTxHistoryItem.Status.PENDING, TangemPayTxHistoryItem.Status.COMPLETED, TangemPayTxHistoryItem.Status.RESERVED, diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayTxHistoryItemsConverter.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayTxHistoryItemsConverter.kt index a546d5abea..bf0f79c163 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayTxHistoryItemsConverter.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayTxHistoryItemsConverter.kt @@ -37,10 +37,10 @@ internal class TangemPayTxHistoryItemsConverter( val localDate = spend.date.withZone(DateTimeZone.getDefault()) val amountPrefix = when { spend.amount.isZero() -> "" - spend.status == TangemPayTxHistoryItem.Status.DECLINED -> "" - else -> StringsSigns.MINUS + spend.status == TangemPayTxHistoryItem.Status.DECLINED || spend.amount.isPositive() -> StringsSigns.MINUS + else -> StringsSigns.PLUS } - val amount = amountPrefix + spend.amount.format { + val amount = amountPrefix + spend.amount.abs().format { fiat(fiatCurrencyCode = spend.currency.currencyCode, fiatCurrencySymbol = spend.currency.symbol) } return TangemPayTransactionState.Content.Spend( @@ -48,8 +48,9 @@ internal class TangemPayTxHistoryItemsConverter( onClick = { txHistoryUiActions.onTransactionClick(spend) }, amount = amount, amountColor = themedColor { - when (spend.status) { - TangemPayTxHistoryItem.Status.DECLINED -> TangemTheme.colors.text.warning + when { + spend.status == TangemPayTxHistoryItem.Status.DECLINED -> TangemTheme.colors.text.warning + amountPrefix == StringsSigns.PLUS -> TangemTheme.colors.text.accent else -> TangemTheme.colors.text.primary1 } }, diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangempayTxDetailsUi.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangempayTxDetailsUi.kt index c406c83696..111edfb273 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangempayTxDetailsUi.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangempayTxDetailsUi.kt @@ -26,6 +26,7 @@ import com.tangem.core.ui.components.label.entity.LabelUM import com.tangem.core.ui.components.notifications.Notification import com.tangem.core.ui.components.notifications.NotificationConfig import com.tangem.core.ui.extensions.* +import com.tangem.core.ui.res.TangemColorPalette import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview import com.tangem.features.tangempay.details.impl.R @@ -83,21 +84,24 @@ internal fun TangemPayTxHistoryDetailsContent(state: TangemPayTxHistoryDetailsUM style = TangemTheme.typography.head, color = state.transactionAmountColor.resolveReference(), ) - state.localTransactionText?.let { localTransaction -> + if (state.localTransactionText != null) { Text( modifier = Modifier.padding(top = 4.dp), - text = localTransaction.orMaskWithStars(state.isBalanceHidden), + text = state.localTransactionText.orMaskWithStars(state.isBalanceHidden), style = TangemTheme.typography.body2, color = TangemTheme.colors.text.tertiary, ) } - state.labelState?.let { Label(state = state.labelState, modifier = Modifier.padding(top = 12.dp)) } + if (state.labelState != null) { + Label(state = state.labelState, modifier = Modifier.padding(top = 12.dp)) + } SpacerH32() - state.notification?.let { + if (state.notification != null) { Notification( - config = state.notification, - titleColor = TangemTheme.colors.text.tertiary, - iconTint = TangemTheme.colors.icon.secondary, + config = state.notification.config, + titleColor = state.notification.titleColor.resolveReference(), + iconTint = state.notification.iconTint.resolveReference(), + containerColor = state.notification.containerColor?.resolveReference(), ) } ButtonsContainer( @@ -195,10 +199,15 @@ private class TangemPayTxHistoryDetailsUMProvider : CollectionPreviewParameterPr text = resourceReference(R.string.tangem_pay_status_declined), style = LabelStyle.WARNING, ), - notification = NotificationConfig( - title = stringReference("The bank rejected this transaction request."), - subtitle = TextReference.EMPTY, - iconResId = R.drawable.ic_token_info_24, + notification = TangemPayTxHistoryDetailsUM.NotificationState( + config = NotificationConfig( + title = stringReference("The bank rejected this transaction request."), + subtitle = TextReference.EMPTY, + iconResId = R.drawable.ic_token_info_24, + ), + titleColor = themedColor { TangemTheme.colors.text.warning }, + iconTint = themedColor { TangemTheme.colors.icon.warning }, + containerColor = themedColor { TangemColorPalette.Amaranth.copy(alpha = 0.1F) }, ), buttons = persistentListOf( TangemPayTxHistoryDetailsUM.ButtonState( @@ -240,10 +249,15 @@ private class TangemPayTxHistoryDetailsUMProvider : CollectionPreviewParameterPr transactionAmountColor = themedColor { TangemTheme.colors.text.primary1 }, localTransactionText = null, labelState = null, - notification = NotificationConfig( - title = stringReference("This fee goes to cover the cost of handling your transfer."), - subtitle = TextReference.EMPTY, - iconResId = R.drawable.ic_token_info_24, + notification = TangemPayTxHistoryDetailsUM.NotificationState( + config = NotificationConfig( + title = stringReference("This fee goes to cover the cost of handling your transfer."), + subtitle = TextReference.EMPTY, + iconResId = R.drawable.ic_token_info_24, + ), + titleColor = themedColor { TangemTheme.colors.text.tertiary }, + iconTint = themedColor { TangemTheme.colors.icon.secondary }, + containerColor = null, ), buttons = persistentListOf( TangemPayTxHistoryDetailsUM.ButtonState(