Updated on 2026-08-14
This commit is contained in:
parent
b208c0dd7c
commit
640ba5af98
14 changed files with 268 additions and 127 deletions
|
|
@ -118,6 +118,7 @@ internal class PaymentAccountStatusValueDMConverter @Inject constructor(
|
||||||
state = TangemPayCardState.fromString(card.state),
|
state = TangemPayCardState.fromString(card.state),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
error = null,
|
||||||
)
|
)
|
||||||
is PaymentAccountStatusValueDM.UnderReview -> PaymentAccountStatusValue.UnderReview(
|
is PaymentAccountStatusValueDM.UnderReview -> PaymentAccountStatusValue.UnderReview(
|
||||||
source = StatusSource.CACHE,
|
source = StatusSource.CACHE,
|
||||||
|
|
@ -134,6 +135,7 @@ internal class PaymentAccountStatusValueDMConverter @Inject constructor(
|
||||||
),
|
),
|
||||||
cryptoCurrency = cryptoCurrency,
|
cryptoCurrency = cryptoCurrency,
|
||||||
fiatRate = value.fiatRate,
|
fiatRate = value.fiatRate,
|
||||||
|
error = null,
|
||||||
)
|
)
|
||||||
null -> PaymentAccountStatusValue.Error.Unavailable
|
null -> PaymentAccountStatusValue.Error.Unavailable
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import com.tangem.domain.models.StatusSource
|
||||||
import com.tangem.domain.models.account.Account
|
import com.tangem.domain.models.account.Account
|
||||||
import com.tangem.domain.models.account.AccountStatus
|
import com.tangem.domain.models.account.AccountStatus
|
||||||
import com.tangem.domain.models.account.PaymentAccountStatusValue
|
import com.tangem.domain.models.account.PaymentAccountStatusValue
|
||||||
|
import com.tangem.domain.models.account.hasAccountData
|
||||||
import com.tangem.domain.models.kyc.KycStatus
|
import com.tangem.domain.models.kyc.KycStatus
|
||||||
import com.tangem.domain.models.pay.TangemPayCard
|
import com.tangem.domain.models.pay.TangemPayCard
|
||||||
import com.tangem.domain.models.pay.TangemPayCardLimitData
|
import com.tangem.domain.models.pay.TangemPayCardLimitData
|
||||||
|
|
@ -156,8 +157,19 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
||||||
private suspend fun proceedWithoutOrder(account: Account.Payment): PaymentAccountStatusValue {
|
private suspend fun proceedWithoutOrder(account: Account.Payment): PaymentAccountStatusValue {
|
||||||
return onboardingRepository.getCustomerInfo(account.userWalletId).fold(
|
return onboardingRepository.getCustomerInfo(account.userWalletId).fold(
|
||||||
ifLeft = { error ->
|
ifLeft = { error ->
|
||||||
logger.e("proceedWithoutOrder ${account.userWalletId} error: $error")
|
val cache = paymentAccountStatusesStore.getSyncOrNull(account.userWalletId)
|
||||||
error.mapToPaymentAccountStatus(account.userWalletId)
|
if (cache != null && cache.value.hasAccountData()) {
|
||||||
|
cache.value.copySealed(
|
||||||
|
source = StatusSource.ONLY_CACHE,
|
||||||
|
error = when (error) {
|
||||||
|
is VisaApiError.RefreshTokenExpired -> PaymentAccountStatusValue.Error.NotSynced
|
||||||
|
else -> PaymentAccountStatusValue.Error.Unavailable
|
||||||
|
},
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
logger.e("proceedWithoutOrder ${account.userWalletId} error: $error")
|
||||||
|
error.mapToPaymentAccountStatus(account.userWalletId)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
ifRight = { customerInfo ->
|
ifRight = { customerInfo ->
|
||||||
logger.i("proceedWithoutOrder data customerInfo ${account.userWalletId}")
|
logger.i("proceedWithoutOrder data customerInfo ${account.userWalletId}")
|
||||||
|
|
@ -300,6 +312,7 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
||||||
),
|
),
|
||||||
cryptoCurrency = tangemPayCurrencyFactory.create(userWalletId),
|
cryptoCurrency = tangemPayCurrencyFactory.create(userWalletId),
|
||||||
fiatRate = quotesData?.fiatRate,
|
fiatRate = quotesData?.fiatRate,
|
||||||
|
error = null,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
cardInfo != null && productInstance != null && !customerId.isNullOrEmpty() -> convertToContentState(
|
cardInfo != null && productInstance != null && !customerId.isNullOrEmpty() -> convertToContentState(
|
||||||
|
|
@ -353,6 +366,7 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
||||||
state = cardState,
|
state = cardState,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
error = null,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,7 @@ internal class PaymentAccountStatusValueDMConverterTest {
|
||||||
),
|
),
|
||||||
cryptoCurrency = cryptoCurrency,
|
cryptoCurrency = cryptoCurrency,
|
||||||
fiatRate = BigDecimal("1.05"),
|
fiatRate = BigDecimal("1.05"),
|
||||||
|
error = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
// WHEN
|
// WHEN
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package com.tangem.domain.models.account
|
||||||
import com.tangem.domain.models.StatusSource
|
import com.tangem.domain.models.StatusSource
|
||||||
import com.tangem.domain.models.TotalFiatBalance
|
import com.tangem.domain.models.TotalFiatBalance
|
||||||
import com.tangem.domain.models.account.PaymentAccountStatusValue.Loaded
|
import com.tangem.domain.models.account.PaymentAccountStatusValue.Loaded
|
||||||
|
import com.tangem.domain.models.account.PaymentAccountStatusValue.Deactivated
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||||
import com.tangem.domain.models.kyc.KycStatus
|
import com.tangem.domain.models.kyc.KycStatus
|
||||||
|
|
@ -46,12 +47,12 @@ sealed class PaymentAccountStatusValue {
|
||||||
*
|
*
|
||||||
* @param source The new source of the status information.
|
* @param source The new source of the status information.
|
||||||
*/
|
*/
|
||||||
fun copySealed(source: StatusSource): PaymentAccountStatusValue {
|
fun copySealed(source: StatusSource, error: Error? = null): PaymentAccountStatusValue {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is IssuingCard -> copy(source = source)
|
is IssuingCard -> copy(source = source)
|
||||||
is Loaded -> copy(source = source)
|
is Loaded -> copy(source = source, error = error ?: this.error)
|
||||||
is UnderReview -> copy(source = source)
|
is UnderReview -> copy(source = source)
|
||||||
is Deactivated -> copy(source = source)
|
is Deactivated -> copy(source = source, error = error ?: this.error)
|
||||||
is Loading,
|
is Loading,
|
||||||
is Empty,
|
is Empty,
|
||||||
is NotCreated,
|
is NotCreated,
|
||||||
|
|
@ -110,6 +111,8 @@ sealed class PaymentAccountStatusValue {
|
||||||
* @property fiatRate Exchange rate of [cryptoCurrency] to the account's fiat currency,
|
* @property fiatRate Exchange rate of [cryptoCurrency] to the account's fiat currency,
|
||||||
* or `null` if the quote is not yet available. When `null`,
|
* or `null` if the quote is not yet available. When `null`,
|
||||||
* [totalFiatBalance] resolves to [TotalFiatBalance.Failed].
|
* [totalFiatBalance] resolves to [TotalFiatBalance.Failed].
|
||||||
|
* @property error Transient error overlaid on top of cached data when a refresh fails
|
||||||
|
* (see [copySealed]), or `null` when the status is up to date. Not persisted.
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Deactivated(
|
data class Deactivated(
|
||||||
|
|
@ -118,6 +121,7 @@ sealed class PaymentAccountStatusValue {
|
||||||
val balance: Balance,
|
val balance: Balance,
|
||||||
val cryptoCurrency: CryptoCurrency.Token,
|
val cryptoCurrency: CryptoCurrency.Token,
|
||||||
val fiatRate: SerializedBigDecimal?,
|
val fiatRate: SerializedBigDecimal?,
|
||||||
|
val error: Error?,
|
||||||
) : PaymentAccountStatusValue() {
|
) : PaymentAccountStatusValue() {
|
||||||
val cryptoCurrencyStatus: CryptoCurrencyStatus = CryptoCurrencyStatus(
|
val cryptoCurrencyStatus: CryptoCurrencyStatus = CryptoCurrencyStatus(
|
||||||
currency = cryptoCurrency,
|
currency = cryptoCurrency,
|
||||||
|
|
@ -143,6 +147,8 @@ sealed class PaymentAccountStatusValue {
|
||||||
* @property fiatRate Exchange rate of [cryptoCurrency] to the account's fiat currency,
|
* @property fiatRate Exchange rate of [cryptoCurrency] to the account's fiat currency,
|
||||||
* or `null` if the quote is not yet available. When `null`,
|
* or `null` if the quote is not yet available. When `null`,
|
||||||
* [totalFiatBalance] resolves to [TotalFiatBalance.Failed].
|
* [totalFiatBalance] resolves to [TotalFiatBalance.Failed].
|
||||||
|
* @property error Transient error overlaid on top of cached data when a refresh fails
|
||||||
|
* (see [copySealed]), or `null` when the status is up to date. Not persisted.
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Loaded(
|
data class Loaded(
|
||||||
|
|
@ -153,6 +159,7 @@ sealed class PaymentAccountStatusValue {
|
||||||
val cryptoCurrency: CryptoCurrency.Token,
|
val cryptoCurrency: CryptoCurrency.Token,
|
||||||
val cards: List<TangemPayCard>,
|
val cards: List<TangemPayCard>,
|
||||||
val fiatRate: SerializedBigDecimal?,
|
val fiatRate: SerializedBigDecimal?,
|
||||||
|
val error: Error?,
|
||||||
) : PaymentAccountStatusValue() {
|
) : PaymentAccountStatusValue() {
|
||||||
val cryptoCurrencyStatus: CryptoCurrencyStatus = CryptoCurrencyStatus(
|
val cryptoCurrencyStatus: CryptoCurrencyStatus = CryptoCurrencyStatus(
|
||||||
currency = cryptoCurrency,
|
currency = cryptoCurrency,
|
||||||
|
|
@ -278,6 +285,8 @@ private fun buildCryptoCurrencyStatusValue(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun PaymentAccountStatusValue.hasAccountData(): Boolean = this is Loaded || this is Deactivated
|
||||||
|
|
||||||
fun Loaded.hasCardWithId(cardId: String): Boolean = cards.any { it.id == cardId }
|
fun Loaded.hasCardWithId(cardId: String): Boolean = cards.any { it.id == cardId }
|
||||||
|
|
||||||
fun Loaded.findCardWithId(cardId: String): TangemPayCard? = cards.firstOrNull { it.id == cardId }
|
fun Loaded.findCardWithId(cardId: String): TangemPayCard? = cards.firstOrNull { it.id == cardId }
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@
|
||||||
<ID>BooleanPropertyNaming:TangemPayChangePinUM.kt$TangemPayChangePinUM$val submitButtonEnabled: Boolean</ID>
|
<ID>BooleanPropertyNaming:TangemPayChangePinUM.kt$TangemPayChangePinUM$val submitButtonEnabled: Boolean</ID>
|
||||||
<ID>BooleanPropertyNaming:TangemPayChangePinUM.kt$TangemPayChangePinUM$val submitButtonLoading: Boolean</ID>
|
<ID>BooleanPropertyNaming:TangemPayChangePinUM.kt$TangemPayChangePinUM$val submitButtonLoading: Boolean</ID>
|
||||||
<ID>BooleanPropertyNaming:TangemPayDetailsScreen.kt$var showDropdownMenu by rememberSaveable { mutableStateOf(false) }</ID>
|
<ID>BooleanPropertyNaming:TangemPayDetailsScreen.kt$var showDropdownMenu by rememberSaveable { mutableStateOf(false) }</ID>
|
||||||
<ID>BooleanPropertyNaming:TangemPayDetailsUM.kt$TangemPayDetailsUM$val addFundsEnabled: Boolean</ID>
|
|
||||||
<ID>BooleanPropertyNaming:TangemPayTxHistoryListManager.kt$TangemPayTxHistoryListManager$val clearUiBatches = state.status is PaginationStatus.InitialLoading && batchListState.status is PaginationStatus.Paginating</ID>
|
<ID>BooleanPropertyNaming:TangemPayTxHistoryListManager.kt$TangemPayTxHistoryListManager$val clearUiBatches = state.status is PaginationStatus.InitialLoading && batchListState.status is PaginationStatus.Paginating</ID>
|
||||||
<ID>CanBeNonNullable:TangemPayTxHistoryDetailsModel.kt$TangemPayTxHistoryDetailsModel$txHash: String?</ID>
|
<ID>CanBeNonNullable:TangemPayTxHistoryDetailsModel.kt$TangemPayTxHistoryDetailsModel$txHash: String?</ID>
|
||||||
<ID>MultilineLambdaItParameter:TangemPayAddFundsContent.kt${ key(it.title) { TangemPayTopUpItem(state = it) } }</ID>
|
<ID>MultilineLambdaItParameter:TangemPayAddFundsContent.kt${ key(it.title) { TangemPayTopUpItem(state = it) } }</ID>
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,10 @@ import com.tangem.core.ui.extensions.themedColor
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
import com.tangem.core.ui.res.generated.icons.Icons
|
import com.tangem.core.ui.res.generated.icons.Icons
|
||||||
import com.tangem.core.ui.res.generated.icons.ic_document_20
|
import com.tangem.core.ui.res.generated.icons.ic_document_20
|
||||||
|
import com.tangem.domain.models.account.PaymentAccountStatusValue
|
||||||
import com.tangem.domain.models.pay.TangemPayCardFrozenState
|
import com.tangem.domain.models.pay.TangemPayCardFrozenState
|
||||||
|
import com.tangem.domain.models.pay.TangemPayCardState
|
||||||
|
import com.tangem.domain.models.pay.isFrozen
|
||||||
import com.tangem.features.tangempay.details.impl.R
|
import com.tangem.features.tangempay.details.impl.R
|
||||||
import com.tangem.features.tangempay.utils.TangemPayDetailIntents
|
import com.tangem.features.tangempay.utils.TangemPayDetailIntents
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
@ -21,55 +24,127 @@ internal class TangemPayDetailsStateFactory(
|
||||||
private val onBack: () -> Unit,
|
private val onBack: () -> Unit,
|
||||||
private val onOpenMenu: () -> Unit,
|
private val onOpenMenu: () -> Unit,
|
||||||
private val intents: TangemPayDetailIntents,
|
private val intents: TangemPayDetailIntents,
|
||||||
private val cardFrozenState: TangemPayCardFrozenState,
|
|
||||||
private val isRedesignEnabled: Boolean,
|
private val isRedesignEnabled: Boolean,
|
||||||
) {
|
) {
|
||||||
@Suppress("LongMethod")
|
fun getLoadingState(): TangemPayDetailsUM {
|
||||||
fun getInitialState(
|
|
||||||
isTangemPayDeactivated: Boolean,
|
|
||||||
cardNumberEnd: String,
|
|
||||||
isReissuing: Boolean,
|
|
||||||
isFrozen: Boolean,
|
|
||||||
): TangemPayDetailsUM {
|
|
||||||
return TangemPayDetailsUM(
|
return TangemPayDetailsUM(
|
||||||
topBarConfig = TangemPayDetailsTopBarConfig(
|
topBarConfig = TangemPayDetailsTopBarConfig(
|
||||||
onBackClick = onBack,
|
onBackClick = onBack,
|
||||||
onOpenMenu = onOpenMenu,
|
onOpenMenu = onOpenMenu,
|
||||||
items = getTopBarMenuItems(isTangemPayDeactivated),
|
items = getTopBarMenuItems(),
|
||||||
itemsV2 = getTopBarMenuItemsV2(isTangemPayDeactivated),
|
itemsV2 = getTopBarMenuItemsV2(),
|
||||||
),
|
),
|
||||||
pullToRefreshConfig = PullToRefreshConfig(
|
pullToRefreshConfig = PullToRefreshConfig(
|
||||||
isRefreshing = false,
|
isRefreshing = false,
|
||||||
onRefresh = intents::onRefreshSwipe,
|
onRefresh = intents::onRefreshSwipe,
|
||||||
),
|
),
|
||||||
balanceBlockState = TangemPayDetailsBalanceBlockState.Loading(
|
balanceBlockState = TangemPayDetailsBalanceBlockState.Loading(
|
||||||
actionButtons = getActionButtonsConfig(),
|
actionButtons = persistentListOf(),
|
||||||
cardsBlockState = TangemPayDetailsBalanceBlockState.CardsBlockState(
|
cardsBlockState = TangemPayDetailsBalanceBlockState.CardsBlockState(
|
||||||
cards = persistentListOf(
|
cards = persistentListOf(),
|
||||||
TangemPayDetailsBalanceBlockState.Card(
|
|
||||||
lastDigits = cardNumberEnd,
|
|
||||||
onClick = {},
|
|
||||||
isReissuing = isReissuing,
|
|
||||||
isFrozen = isFrozen,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onAddCardClick = intents::onAddCardClick,
|
onAddCardClick = intents::onAddCardClick,
|
||||||
).takeIf { !isTangemPayDeactivated },
|
),
|
||||||
),
|
),
|
||||||
isBalanceHidden = false,
|
isBalanceHidden = false,
|
||||||
addFundsEnabled = true,
|
|
||||||
addToWalletBlockState = null,
|
addToWalletBlockState = null,
|
||||||
accountDeactivatedNotificationConfig = NotificationConfig(
|
errorNotificationConfig = null,
|
||||||
title = resourceReference(R.string.tangempay_account_deactivated_message_title),
|
accountDeactivatedNotificationConfig = null,
|
||||||
subtitle = resourceReference(R.string.tangempay_account_deactivated_message_subtitle),
|
|
||||||
iconResId = R.drawable.img_attention_20,
|
|
||||||
).takeIf { isTangemPayDeactivated },
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getTopBarMenuItems(isTangemPayDeactivated: Boolean): ImmutableList<TangemDropdownMenuItem> {
|
fun getLoadedState(status: PaymentAccountStatusValue.Loaded): TangemPayDetailsUM {
|
||||||
if (isTangemPayDeactivated) return persistentListOf()
|
val card = status.cards.firstOrNull()
|
||||||
|
val errorNotificationConfig = when (status.error) {
|
||||||
|
null -> null
|
||||||
|
PaymentAccountStatusValue.Error.NotSynced -> createRenewSessionNotificationConfig()
|
||||||
|
else -> createAccountUnavailableConfig()
|
||||||
|
}
|
||||||
|
return TangemPayDetailsUM(
|
||||||
|
topBarConfig = TangemPayDetailsTopBarConfig(
|
||||||
|
onBackClick = onBack,
|
||||||
|
onOpenMenu = onOpenMenu,
|
||||||
|
items = getTopBarMenuItems(),
|
||||||
|
itemsV2 = getTopBarMenuItemsV2(),
|
||||||
|
),
|
||||||
|
pullToRefreshConfig = PullToRefreshConfig(
|
||||||
|
isRefreshing = false,
|
||||||
|
onRefresh = intents::onRefreshSwipe,
|
||||||
|
),
|
||||||
|
balanceBlockState = TangemPayDetailsBalanceBlockState.Loading(
|
||||||
|
actionButtons = getActionButtonsConfig(
|
||||||
|
isEnabled = errorNotificationConfig == null &&
|
||||||
|
(card == null || card.frozenState == TangemPayCardFrozenState.Unfrozen),
|
||||||
|
),
|
||||||
|
cardsBlockState = TangemPayDetailsBalanceBlockState.CardsBlockState(
|
||||||
|
cards = card?.let {
|
||||||
|
persistentListOf(
|
||||||
|
TangemPayDetailsBalanceBlockState.Card(
|
||||||
|
lastDigits = card.lastDigits,
|
||||||
|
onClick = intents::onCardClick,
|
||||||
|
isReissuing = card.state != TangemPayCardState.Active,
|
||||||
|
isEnabled = errorNotificationConfig == null,
|
||||||
|
isFrozen = card.isFrozen,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
} ?: persistentListOf(),
|
||||||
|
onAddCardClick = intents::onAddCardClick,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
isBalanceHidden = false,
|
||||||
|
addToWalletBlockState = null,
|
||||||
|
errorNotificationConfig = errorNotificationConfig,
|
||||||
|
accountDeactivatedNotificationConfig = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getDeactivatedState(): TangemPayDetailsUM {
|
||||||
|
return TangemPayDetailsUM(
|
||||||
|
topBarConfig = TangemPayDetailsTopBarConfig(
|
||||||
|
onBackClick = onBack,
|
||||||
|
onOpenMenu = onOpenMenu,
|
||||||
|
items = persistentListOf(),
|
||||||
|
itemsV2 = persistentListOf(),
|
||||||
|
),
|
||||||
|
pullToRefreshConfig = PullToRefreshConfig(
|
||||||
|
isRefreshing = false,
|
||||||
|
onRefresh = intents::onRefreshSwipe,
|
||||||
|
),
|
||||||
|
balanceBlockState = TangemPayDetailsBalanceBlockState.Loading(
|
||||||
|
actionButtons = getActionButtonsConfig(isEnabled = true),
|
||||||
|
cardsBlockState = null,
|
||||||
|
),
|
||||||
|
isBalanceHidden = false,
|
||||||
|
addToWalletBlockState = null,
|
||||||
|
errorNotificationConfig = null,
|
||||||
|
accountDeactivatedNotificationConfig = createAccountDeactivatedConfig(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createAccountUnavailableConfig() = NotificationConfig(
|
||||||
|
title = resourceReference(R.string.tangempay_temporarily_unavailable),
|
||||||
|
subtitle = resourceReference(R.string.tangempay_service_unreachable_try_later),
|
||||||
|
iconResId = R.drawable.img_attention_20,
|
||||||
|
iconTint = NotificationConfig.IconTint.Attention,
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun createAccountDeactivatedConfig() = NotificationConfig(
|
||||||
|
title = resourceReference(R.string.tangempay_account_deactivated_message_title),
|
||||||
|
subtitle = resourceReference(R.string.tangempay_account_deactivated_message_subtitle),
|
||||||
|
iconResId = R.drawable.img_attention_20,
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun createRenewSessionNotificationConfig() = NotificationConfig(
|
||||||
|
title = resourceReference(R.string.tangempay_sync_needed_title),
|
||||||
|
subtitle = resourceReference(R.string.tangempay_sync_needed_body),
|
||||||
|
iconResId = R.drawable.img_attention_20,
|
||||||
|
iconTint = NotificationConfig.IconTint.Attention,
|
||||||
|
buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
|
||||||
|
text = resourceReference(R.string.tangempay_sync_needed_button),
|
||||||
|
onClick = intents::onRenewSession,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun getTopBarMenuItems(): ImmutableList<TangemDropdownMenuItem> {
|
||||||
return persistentListOf(
|
return persistentListOf(
|
||||||
TangemDropdownMenuItem(
|
TangemDropdownMenuItem(
|
||||||
title = resourceReference(R.string.tangem_pay_terms_limits),
|
title = resourceReference(R.string.tangem_pay_terms_limits),
|
||||||
|
|
@ -84,9 +159,7 @@ internal class TangemPayDetailsStateFactory(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getTopBarMenuItemsV2(isTangemPayDeactivated: Boolean): ImmutableList<TangemPayDropDownItemUM> {
|
private fun getTopBarMenuItemsV2(): ImmutableList<TangemPayDropDownItemUM> {
|
||||||
if (isTangemPayDeactivated) return persistentListOf()
|
|
||||||
|
|
||||||
return persistentListOf(
|
return persistentListOf(
|
||||||
TangemPayDropDownItemUM(
|
TangemPayDropDownItemUM(
|
||||||
title = resourceReference(R.string.tangem_pay_terms_limits),
|
title = resourceReference(R.string.tangem_pay_terms_limits),
|
||||||
|
|
@ -111,7 +184,7 @@ internal class TangemPayDetailsStateFactory(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getActionButtonsConfig(): ImmutableList<ActionButtonConfig> {
|
private fun getActionButtonsConfig(isEnabled: Boolean): ImmutableList<ActionButtonConfig> {
|
||||||
return persistentListOf(
|
return persistentListOf(
|
||||||
ActionButtonConfig(
|
ActionButtonConfig(
|
||||||
text = resourceReference(id = R.string.tangempay_card_details_add_funds),
|
text = resourceReference(id = R.string.tangempay_card_details_add_funds),
|
||||||
|
|
@ -121,13 +194,13 @@ internal class TangemPayDetailsStateFactory(
|
||||||
R.drawable.ic_plus_24
|
R.drawable.ic_plus_24
|
||||||
},
|
},
|
||||||
onClick = intents::onClickAddFunds,
|
onClick = intents::onClickAddFunds,
|
||||||
isEnabled = cardFrozenState == TangemPayCardFrozenState.Unfrozen,
|
isEnabled = isEnabled,
|
||||||
),
|
),
|
||||||
ActionButtonConfig(
|
ActionButtonConfig(
|
||||||
text = resourceReference(id = R.string.tangempay_card_details_withdraw),
|
text = resourceReference(id = R.string.tangempay_card_details_withdraw),
|
||||||
iconResId = R.drawable.ic_arrow_up_24,
|
iconResId = R.drawable.ic_arrow_up_24,
|
||||||
onClick = intents::onClickWithdraw,
|
onClick = intents::onClickWithdraw,
|
||||||
isEnabled = cardFrozenState == TangemPayCardFrozenState.Unfrozen,
|
isEnabled = isEnabled,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ internal data class TangemPayDetailsUM(
|
||||||
val balanceBlockState: TangemPayDetailsBalanceBlockState,
|
val balanceBlockState: TangemPayDetailsBalanceBlockState,
|
||||||
val addToWalletBlockState: AddToWalletBlockState?,
|
val addToWalletBlockState: AddToWalletBlockState?,
|
||||||
val isBalanceHidden: Boolean,
|
val isBalanceHidden: Boolean,
|
||||||
val addFundsEnabled: Boolean,
|
val errorNotificationConfig: NotificationConfig?,
|
||||||
val accountDeactivatedNotificationConfig: NotificationConfig?,
|
val accountDeactivatedNotificationConfig: NotificationConfig?,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -93,6 +93,7 @@ internal sealed class TangemPayDetailsBalanceBlockState {
|
||||||
val onClick: () -> Unit,
|
val onClick: () -> Unit,
|
||||||
val isReissuing: Boolean,
|
val isReissuing: Boolean,
|
||||||
val isFrozen: Boolean,
|
val isFrozen: Boolean,
|
||||||
|
val isEnabled: Boolean,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,27 +15,28 @@ import com.tangem.core.decompose.navigation.Router
|
||||||
import com.tangem.core.decompose.ui.UiMessageSender
|
import com.tangem.core.decompose.ui.UiMessageSender
|
||||||
import com.tangem.core.navigation.url.UrlOpener
|
import com.tangem.core.navigation.url.UrlOpener
|
||||||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig.ShowRefreshState
|
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig.ShowRefreshState
|
||||||
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
|
import com.tangem.core.ui.message.SnackbarMessage
|
||||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||||
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
||||||
import com.tangem.domain.feedback.models.FeedbackEmailType
|
import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||||
import com.tangem.domain.feedback.models.WalletMetaInfo
|
import com.tangem.domain.feedback.models.WalletMetaInfo
|
||||||
import com.tangem.domain.models.StatusSource
|
|
||||||
import com.tangem.domain.models.TokenReceiveConfig
|
import com.tangem.domain.models.TokenReceiveConfig
|
||||||
import com.tangem.domain.models.account.PaymentAccountStatusValue
|
import com.tangem.domain.models.account.PaymentAccountStatusValue
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.models.pay.TangemPayCardFrozenState
|
|
||||||
import com.tangem.domain.models.pay.TangemPayCardState
|
|
||||||
import com.tangem.domain.pay.flow.PaymentAccountStatusFetcher
|
import com.tangem.domain.pay.flow.PaymentAccountStatusFetcher
|
||||||
import com.tangem.domain.pay.flow.PaymentAccountStatusSupplier
|
import com.tangem.domain.pay.flow.PaymentAccountStatusSupplier
|
||||||
import com.tangem.domain.pay.model.TangemPayTopUpData
|
import com.tangem.domain.pay.model.TangemPayTopUpData
|
||||||
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
|
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
|
||||||
import com.tangem.domain.pay.repository.TangemPayWithdrawRepository
|
import com.tangem.domain.pay.repository.TangemPayWithdrawRepository
|
||||||
|
import com.tangem.domain.pay.usecase.ProduceTangemPayInitialDataUseCase
|
||||||
import com.tangem.domain.tangempay.TangemPayAnalyticsEvents
|
import com.tangem.domain.tangempay.TangemPayAnalyticsEvents
|
||||||
import com.tangem.domain.visa.model.TangemPayTxHistoryItem
|
import com.tangem.domain.visa.model.TangemPayTxHistoryItem
|
||||||
import com.tangem.features.tangempay.TangemPayConstants
|
import com.tangem.features.tangempay.TangemPayConstants
|
||||||
import com.tangem.features.tangempay.TangemPayFeatureToggles
|
import com.tangem.features.tangempay.TangemPayFeatureToggles
|
||||||
import com.tangem.features.tangempay.components.AddFundsListener
|
import com.tangem.features.tangempay.components.AddFundsListener
|
||||||
import com.tangem.features.tangempay.components.TangemPayDetailsContainerComponent
|
import com.tangem.features.tangempay.components.TangemPayDetailsContainerComponent
|
||||||
|
import com.tangem.features.tangempay.details.impl.R
|
||||||
import com.tangem.features.tangempay.entity.TangemPayDetailsErrorType
|
import com.tangem.features.tangempay.entity.TangemPayDetailsErrorType
|
||||||
import com.tangem.features.tangempay.entity.TangemPayDetailsNavigation
|
import com.tangem.features.tangempay.entity.TangemPayDetailsNavigation
|
||||||
import com.tangem.features.tangempay.entity.TangemPayDetailsStateFactory
|
import com.tangem.features.tangempay.entity.TangemPayDetailsStateFactory
|
||||||
|
|
@ -73,14 +74,11 @@ internal class TangemPayDetailsModel @Inject constructor(
|
||||||
private val expressTransactionsEventListener: ExpressTransactionsEventListener,
|
private val expressTransactionsEventListener: ExpressTransactionsEventListener,
|
||||||
private val tangemPayFeatureToggles: TangemPayFeatureToggles,
|
private val tangemPayFeatureToggles: TangemPayFeatureToggles,
|
||||||
private val paymentAccountStatusFetcher: PaymentAccountStatusFetcher,
|
private val paymentAccountStatusFetcher: PaymentAccountStatusFetcher,
|
||||||
|
private val produceTangemPayInitialDataUseCase: ProduceTangemPayInitialDataUseCase,
|
||||||
) : Model(), TangemPayTxHistoryUiActions, TangemPayDetailIntents, AddFundsListener {
|
) : Model(), TangemPayTxHistoryUiActions, TangemPayDetailIntents, AddFundsListener {
|
||||||
|
|
||||||
private val params: TangemPayDetailsContainerComponent.Params = paramsContainer.require()
|
private val params: TangemPayDetailsContainerComponent.Params = paramsContainer.require()
|
||||||
|
|
||||||
private val isTangemPayDeactivated = params.initialStatus.isDeactivated
|
|
||||||
|
|
||||||
private val initialCard = params.initialStatus.ifLoadedOrNull { it.cards.firstOrNull() }
|
|
||||||
|
|
||||||
private val currentStatus = MutableStateFlow(params.initialStatus)
|
private val currentStatus = MutableStateFlow(params.initialStatus)
|
||||||
|
|
||||||
private val userWalletId
|
private val userWalletId
|
||||||
|
|
@ -93,25 +91,20 @@ internal class TangemPayDetailsModel @Inject constructor(
|
||||||
onBack = router::pop,
|
onBack = router::pop,
|
||||||
onOpenMenu = ::onOpenMenu,
|
onOpenMenu = ::onOpenMenu,
|
||||||
intents = this,
|
intents = this,
|
||||||
cardFrozenState = when {
|
|
||||||
initialCard == null -> TangemPayCardFrozenState.Unfrozen
|
|
||||||
else -> initialCard.frozenState
|
|
||||||
},
|
|
||||||
isRedesignEnabled = isRedesignEnabled(),
|
isRedesignEnabled = isRedesignEnabled(),
|
||||||
)
|
)
|
||||||
|
|
||||||
val uiState: StateFlow<TangemPayDetailsUM>
|
val uiState: StateFlow<TangemPayDetailsUM>
|
||||||
field = MutableStateFlow(
|
field = MutableStateFlow(
|
||||||
stateFactory.getInitialState(
|
when {
|
||||||
isTangemPayDeactivated = isTangemPayDeactivated,
|
params.initialStatus.isDeactivated -> stateFactory.getDeactivatedState()
|
||||||
cardNumberEnd = initialCard?.lastDigits.orEmpty(),
|
else -> stateFactory.getLoadingState()
|
||||||
isReissuing = initialCard == null || initialCard.state != TangemPayCardState.Active,
|
},
|
||||||
isFrozen = initialCard?.frozenState == TangemPayCardFrozenState.Frozen,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
private val refreshStateJobHolder = JobHolder()
|
private val refreshStateJobHolder = JobHolder()
|
||||||
private val addToWalletBannerJobHolder = JobHolder()
|
private val addToWalletBannerJobHolder = JobHolder()
|
||||||
|
private val frozenStateJobHolder = JobHolder()
|
||||||
|
|
||||||
val bottomSheetNavigation: SlotNavigation<TangemPayDetailsNavigation> = SlotNavigation()
|
val bottomSheetNavigation: SlotNavigation<TangemPayDetailsNavigation> = SlotNavigation()
|
||||||
|
|
||||||
|
|
@ -119,38 +112,27 @@ internal class TangemPayDetailsModel @Inject constructor(
|
||||||
analytics.send(TangemPayAnalyticsEvents.MainScreenOpened())
|
analytics.send(TangemPayAnalyticsEvents.MainScreenOpened())
|
||||||
handleBalanceHiding()
|
handleBalanceHiding()
|
||||||
|
|
||||||
val statusFlow = paymentAccountStatusSupplier.invoke(userWalletId)
|
paymentAccountStatusSupplier.invoke(userWalletId)
|
||||||
.onEach { status -> currentStatus.update { status } }
|
.onEach { status -> currentStatus.update { status } }
|
||||||
.map { it.value }
|
.map { it.value }
|
||||||
|
.onEach { state ->
|
||||||
if (isTangemPayDeactivated) {
|
when (state) {
|
||||||
statusFlow
|
is PaymentAccountStatusValue.Deactivated -> {
|
||||||
.filterIsInstance<PaymentAccountStatusValue.Deactivated>()
|
uiState.update { stateFactory.getDeactivatedState() }
|
||||||
.onEach { state ->
|
uiState.update(DetailsBalanceTransformer(state.balance.fiatBalance))
|
||||||
uiState.update(DetailsBalanceTransformer(state.balance.fiatBalance))
|
|
||||||
}
|
|
||||||
.launchIn(modelScope)
|
|
||||||
} else {
|
|
||||||
if (initialCard != null) {
|
|
||||||
subscribeToCardFrozenState(initialCard.id)
|
|
||||||
}
|
|
||||||
fetchAddToWalletBanner()
|
|
||||||
statusFlow
|
|
||||||
.filterIsInstance<PaymentAccountStatusValue.Loaded>()
|
|
||||||
.filter { it.source == StatusSource.ACTUAL }
|
|
||||||
.onEach { state ->
|
|
||||||
uiState.update(DetailsBalanceTransformer(state.balance.fiatBalance))
|
|
||||||
state.cards.firstOrNull()?.let { card ->
|
|
||||||
uiState.update(
|
|
||||||
TangemPayCardDataTransformer(
|
|
||||||
card = card,
|
|
||||||
onCardClick = { onCardClick() },
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
is PaymentAccountStatusValue.Loaded -> {
|
||||||
|
fetchAddToWalletBanner()
|
||||||
|
uiState.update { stateFactory.getLoadedState(state) }
|
||||||
|
uiState.update(DetailsBalanceTransformer(state.balance.fiatBalance))
|
||||||
|
state.cards.firstOrNull()?.let { card ->
|
||||||
|
subscribeToCardFrozenState(card.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> uiState.update { stateFactory.getLoadingState() }
|
||||||
}
|
}
|
||||||
.launchIn(modelScope)
|
}
|
||||||
}
|
.launchIn(modelScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onResume() {
|
fun onResume() {
|
||||||
|
|
@ -168,10 +150,12 @@ internal class TangemPayDetailsModel @Inject constructor(
|
||||||
fun isRedesignEnabled(): Boolean = tangemPayFeatureToggles.isRedesignEnabled
|
fun isRedesignEnabled(): Boolean = tangemPayFeatureToggles.isRedesignEnabled
|
||||||
|
|
||||||
private fun subscribeToCardFrozenState(cardId: String) {
|
private fun subscribeToCardFrozenState(cardId: String) {
|
||||||
|
frozenStateJobHolder.cancel()
|
||||||
cardDetailsRepository
|
cardDetailsRepository
|
||||||
.cardFrozenState(cardId)
|
.cardFrozenState(cardId)
|
||||||
.onEach { uiState.update(TangemPayFreezeUnfreezeStateTransformer(cardFrozenState = it)) }
|
.onEach { uiState.update(TangemPayFreezeUnfreezeStateTransformer(cardFrozenState = it)) }
|
||||||
.launchIn(modelScope)
|
.launchIn(modelScope)
|
||||||
|
.saveIn(frozenStateJobHolder)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onClickAddFunds() {
|
override fun onClickAddFunds() {
|
||||||
|
|
@ -375,6 +359,21 @@ internal class TangemPayDetailsModel @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onRenewSession() {
|
||||||
|
uiState.update(TangemPayRenewSessionTransformer(shouldShowProgress = true))
|
||||||
|
modelScope.launch {
|
||||||
|
produceTangemPayInitialDataUseCase(userWalletId)
|
||||||
|
.onRight {
|
||||||
|
paymentAccountStatusFetcher.invoke(userWalletId)
|
||||||
|
uiState.update(TangemPayRenewSessionTransformer(shouldShowProgress = false))
|
||||||
|
}
|
||||||
|
.onLeft {
|
||||||
|
uiMessageSender.send(SnackbarMessage(resourceReference(R.string.common_error)))
|
||||||
|
uiState.update(TangemPayRenewSessionTransformer(shouldShowProgress = false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun showBottomSheetError(type: TangemPayDetailsErrorType) {
|
private fun showBottomSheetError(type: TangemPayDetailsErrorType) {
|
||||||
uiMessageSender.send(message = TangemPayMessagesFactory.createErrorMessage(errorType = type))
|
uiMessageSender.send(message = TangemPayMessagesFactory.createErrorMessage(errorType = type))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
package com.tangem.features.tangempay.model.transformers
|
|
||||||
|
|
||||||
import com.tangem.domain.models.pay.TangemPayCard
|
|
||||||
import com.tangem.domain.models.pay.TangemPayCardFrozenState
|
|
||||||
import com.tangem.domain.models.pay.TangemPayCardState
|
|
||||||
import com.tangem.features.tangempay.entity.TangemPayDetailsBalanceBlockState
|
|
||||||
import com.tangem.features.tangempay.entity.TangemPayDetailsUM
|
|
||||||
import com.tangem.utils.transformer.Transformer
|
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
|
||||||
|
|
||||||
internal class TangemPayCardDataTransformer(
|
|
||||||
private val card: TangemPayCard,
|
|
||||||
private val onCardClick: () -> Unit,
|
|
||||||
) : Transformer<TangemPayDetailsUM> {
|
|
||||||
|
|
||||||
override fun transform(prevState: TangemPayDetailsUM): TangemPayDetailsUM {
|
|
||||||
val updatedCard = TangemPayDetailsBalanceBlockState.Card(
|
|
||||||
lastDigits = card.lastDigits,
|
|
||||||
onClick = onCardClick,
|
|
||||||
isReissuing = card.state != TangemPayCardState.Active,
|
|
||||||
isFrozen = card.frozenState == TangemPayCardFrozenState.Frozen,
|
|
||||||
)
|
|
||||||
val cardsBlockState = prevState.balanceBlockState.cardsBlockState?.copy(
|
|
||||||
cards = persistentListOf(updatedCard),
|
|
||||||
)
|
|
||||||
val newBalanceBlockState = when (val bs = prevState.balanceBlockState) {
|
|
||||||
is TangemPayDetailsBalanceBlockState.Loading -> bs.copy(cardsBlockState = cardsBlockState)
|
|
||||||
is TangemPayDetailsBalanceBlockState.Content -> bs.copy(cardsBlockState = cardsBlockState)
|
|
||||||
is TangemPayDetailsBalanceBlockState.Error -> bs.copy(cardsBlockState = cardsBlockState)
|
|
||||||
}
|
|
||||||
return prevState.copy(balanceBlockState = newBalanceBlockState)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.tangem.features.tangempay.model.transformers
|
||||||
|
|
||||||
|
import com.tangem.core.ui.components.notifications.NotificationConfig
|
||||||
|
import com.tangem.features.tangempay.entity.TangemPayDetailsUM
|
||||||
|
import com.tangem.utils.transformer.Transformer
|
||||||
|
|
||||||
|
internal class TangemPayRenewSessionTransformer(
|
||||||
|
private val shouldShowProgress: Boolean,
|
||||||
|
) : Transformer<TangemPayDetailsUM> {
|
||||||
|
|
||||||
|
override fun transform(prevState: TangemPayDetailsUM): TangemPayDetailsUM {
|
||||||
|
val config = prevState.errorNotificationConfig ?: return prevState
|
||||||
|
val button = config.buttonsState as? NotificationConfig.ButtonsState.SecondaryButtonConfig
|
||||||
|
?: return prevState
|
||||||
|
|
||||||
|
return prevState.copy(
|
||||||
|
errorNotificationConfig = config.copy(
|
||||||
|
buttonsState = button.copy(shouldShowProgress = shouldShowProgress),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -19,6 +19,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.alpha
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
|
@ -61,6 +62,8 @@ import com.tangem.features.tokendetails.ExpressTransactionsComponent
|
||||||
import com.tangem.utils.StringsSigns.DASH_SIGN
|
import com.tangem.utils.StringsSigns.DASH_SIGN
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
|
||||||
|
private const val DISABLED_ALPHA = 0.5f
|
||||||
|
|
||||||
@Suppress("LongMethod")
|
@Suppress("LongMethod")
|
||||||
@Composable
|
@Composable
|
||||||
internal fun TangemPayDetailsScreen(
|
internal fun TangemPayDetailsScreen(
|
||||||
|
|
@ -100,6 +103,20 @@ internal fun TangemPayDetailsScreen(
|
||||||
.fillMaxWidth(),
|
.fillMaxWidth(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if (state.errorNotificationConfig != null) {
|
||||||
|
item(
|
||||||
|
key = "error_message",
|
||||||
|
content = {
|
||||||
|
Notification(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||||
|
.padding(top = 12.dp)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
config = state.errorNotificationConfig,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
item(
|
item(
|
||||||
key = TangemPayDetailsBalanceBlockState::class.java,
|
key = TangemPayDetailsBalanceBlockState::class.java,
|
||||||
content = {
|
content = {
|
||||||
|
|
@ -300,11 +317,16 @@ private fun TangemPayCardItem(card: TangemPayDetailsBalanceBlockState.Card, modi
|
||||||
Box(
|
Box(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.clip(RoundedCornerShape(4.dp))
|
.clip(RoundedCornerShape(4.dp))
|
||||||
.clickable(onClick = card.onClick)
|
.clickable(
|
||||||
|
onClick = card.onClick,
|
||||||
|
enabled = card.isEnabled,
|
||||||
|
)
|
||||||
.testTag(TangemPayTestTags.PAYMENT_ACCOUNT_CARD_BUTTON),
|
.testTag(TangemPayTestTags.PAYMENT_ACCOUNT_CARD_BUTTON),
|
||||||
) {
|
) {
|
||||||
Image(
|
Image(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier
|
||||||
|
.alpha(if (card.isEnabled) 1f else DISABLED_ALPHA)
|
||||||
|
.fillMaxSize(),
|
||||||
painter = painterResource(
|
painter = painterResource(
|
||||||
if (card.isReissuing) {
|
if (card.isReissuing) {
|
||||||
R.drawable.img_visa_card_inactive_48_32
|
R.drawable.img_visa_card_inactive_48_32
|
||||||
|
|
@ -464,12 +486,14 @@ internal class TangemPayDetailsUMProvider : CollectionPreviewParameterProvider<T
|
||||||
lastDigits = "1234",
|
lastDigits = "1234",
|
||||||
onClick = {},
|
onClick = {},
|
||||||
isReissuing = false,
|
isReissuing = false,
|
||||||
|
isEnabled = false,
|
||||||
isFrozen = false,
|
isFrozen = false,
|
||||||
),
|
),
|
||||||
TangemPayDetailsBalanceBlockState.Card(
|
TangemPayDetailsBalanceBlockState.Card(
|
||||||
lastDigits = "3456",
|
lastDigits = "3456",
|
||||||
onClick = {},
|
onClick = {},
|
||||||
isReissuing = false,
|
isReissuing = false,
|
||||||
|
isEnabled = true,
|
||||||
isFrozen = false,
|
isFrozen = false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -477,12 +501,12 @@ internal class TangemPayDetailsUMProvider : CollectionPreviewParameterProvider<T
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
isBalanceHidden = false,
|
isBalanceHidden = false,
|
||||||
addFundsEnabled = true,
|
|
||||||
addToWalletBlockState = AddToWalletBlockState(
|
addToWalletBlockState = AddToWalletBlockState(
|
||||||
onClick = {},
|
onClick = {},
|
||||||
onClickClose = {},
|
onClickClose = {},
|
||||||
),
|
),
|
||||||
accountDeactivatedNotificationConfig = null,
|
accountDeactivatedNotificationConfig = null,
|
||||||
|
errorNotificationConfig = null,
|
||||||
),
|
),
|
||||||
TangemPayDetailsUM(
|
TangemPayDetailsUM(
|
||||||
topBarConfig = TangemPayDetailsTopBarConfig(
|
topBarConfig = TangemPayDetailsTopBarConfig(
|
||||||
|
|
@ -501,15 +525,16 @@ internal class TangemPayDetailsUMProvider : CollectionPreviewParameterProvider<T
|
||||||
onClick = {},
|
onClick = {},
|
||||||
isReissuing = true,
|
isReissuing = true,
|
||||||
isFrozen = false,
|
isFrozen = false,
|
||||||
|
isEnabled = true,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onAddCardClick = {},
|
onAddCardClick = {},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
isBalanceHidden = false,
|
isBalanceHidden = false,
|
||||||
addFundsEnabled = true,
|
|
||||||
addToWalletBlockState = null,
|
addToWalletBlockState = null,
|
||||||
accountDeactivatedNotificationConfig = null,
|
accountDeactivatedNotificationConfig = null,
|
||||||
|
errorNotificationConfig = null,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -184,6 +184,14 @@ private fun LazyListScope.payDetailsBody(state: TangemPayDetailsUM) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
|
if (state.errorNotificationConfig != null) {
|
||||||
|
item("errorSessionBannerBlock") {
|
||||||
|
TangemMessage(
|
||||||
|
config = state.errorNotificationConfig,
|
||||||
|
modifier = Modifier.padding(horizontal = TangemTheme.dimens2.x4),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
if (state.addToWalletBlockState != null) {
|
if (state.addToWalletBlockState != null) {
|
||||||
item("addToWalletBannerBlock") {
|
item("addToWalletBannerBlock") {
|
||||||
TangemPayAddToWalletBlock(
|
TangemPayAddToWalletBlock(
|
||||||
|
|
@ -340,6 +348,7 @@ private fun CardsBlock(
|
||||||
isReissuing = item.isReissuing,
|
isReissuing = item.isReissuing,
|
||||||
lastDigits = item.lastDigits,
|
lastDigits = item.lastDigits,
|
||||||
onClick = item.onClick,
|
onClick = item.onClick,
|
||||||
|
isEnabled = item.isEnabled,
|
||||||
isFrozen = item.isFrozen,
|
isFrozen = item.isFrozen,
|
||||||
)
|
)
|
||||||
SpacerW(TangemTheme.dimens2.x2)
|
SpacerW(TangemTheme.dimens2.x2)
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.alpha
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.draw.drawBehind
|
import androidx.compose.ui.draw.drawBehind
|
||||||
import androidx.compose.ui.geometry.Offset
|
import androidx.compose.ui.geometry.Offset
|
||||||
|
|
@ -41,6 +42,7 @@ private const val REISSUING_CARD_BG = 0xFF1E1E1E
|
||||||
@Composable
|
@Composable
|
||||||
internal fun TangemPayCardView(
|
internal fun TangemPayCardView(
|
||||||
isReissuing: Boolean,
|
isReissuing: Boolean,
|
||||||
|
isEnabled: Boolean,
|
||||||
lastDigits: String,
|
lastDigits: String,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
isFrozen: Boolean,
|
isFrozen: Boolean,
|
||||||
|
|
@ -54,6 +56,7 @@ internal fun TangemPayCardView(
|
||||||
)
|
)
|
||||||
.testTag(TangemPayTestTags.PAYMENT_ACCOUNT_CARD_BUTTON),
|
.testTag(TangemPayTestTags.PAYMENT_ACCOUNT_CARD_BUTTON),
|
||||||
isReissuing = isReissuing,
|
isReissuing = isReissuing,
|
||||||
|
isEnabled = isEnabled,
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
|
|
@ -120,6 +123,7 @@ internal fun TangemPayAddCardView(onClick: () -> Unit, modifier: Modifier = Modi
|
||||||
@Composable
|
@Composable
|
||||||
private fun CardBackground(
|
private fun CardBackground(
|
||||||
isReissuing: Boolean,
|
isReissuing: Boolean,
|
||||||
|
isEnabled: Boolean,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
content: @Composable BoxScope.() -> Unit,
|
content: @Composable BoxScope.() -> Unit,
|
||||||
|
|
@ -134,6 +138,7 @@ private fun CardBackground(
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
|
.alpha(if (isEnabled) 1f else 0.5f)
|
||||||
.clip(RoundedCornerShape(6.dp))
|
.clip(RoundedCornerShape(6.dp))
|
||||||
.drawBehind {
|
.drawBehind {
|
||||||
drawRect(bgColor)
|
drawRect(bgColor)
|
||||||
|
|
@ -163,7 +168,7 @@ private fun CardBackground(
|
||||||
color = TangemTheme.colors3.border.primary,
|
color = TangemTheme.colors3.border.primary,
|
||||||
shape = RoundedCornerShape(6.dp),
|
shape = RoundedCornerShape(6.dp),
|
||||||
)
|
)
|
||||||
.clickableSingle(onClick = onClick),
|
.clickableSingle(onClick = onClick, enabled = isEnabled),
|
||||||
content = content,
|
content = content,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -181,6 +186,7 @@ private fun CardBackgroundPreview() {
|
||||||
isReissuing = false,
|
isReissuing = false,
|
||||||
onClick = {},
|
onClick = {},
|
||||||
content = {},
|
content = {},
|
||||||
|
isEnabled = true,
|
||||||
)
|
)
|
||||||
SpacerH(TangemTheme.dimens2.x4)
|
SpacerH(TangemTheme.dimens2.x4)
|
||||||
CardBackground(
|
CardBackground(
|
||||||
|
|
@ -191,15 +197,28 @@ private fun CardBackgroundPreview() {
|
||||||
isReissuing = true,
|
isReissuing = true,
|
||||||
onClick = {},
|
onClick = {},
|
||||||
content = {},
|
content = {},
|
||||||
|
isEnabled = true,
|
||||||
)
|
)
|
||||||
SpacerH(TangemTheme.dimens2.x4)
|
SpacerH(TangemTheme.dimens2.x4)
|
||||||
TangemPayCardView(isReissuing = false, onClick = {}, lastDigits = "1234", isFrozen = false)
|
TangemPayCardView(
|
||||||
|
isReissuing = false,
|
||||||
|
onClick = {},
|
||||||
|
lastDigits = "1234",
|
||||||
|
isEnabled = true,
|
||||||
|
isFrozen = false,
|
||||||
|
)
|
||||||
SpacerH(TangemTheme.dimens2.x4)
|
SpacerH(TangemTheme.dimens2.x4)
|
||||||
TangemPayCardView(isReissuing = true, onClick = {}, lastDigits = "", isFrozen = false)
|
TangemPayCardView(
|
||||||
|
isReissuing = true,
|
||||||
|
onClick = {},
|
||||||
|
lastDigits = "",
|
||||||
|
isEnabled = true,
|
||||||
|
isFrozen = false,
|
||||||
|
)
|
||||||
SpacerH(TangemTheme.dimens2.x4)
|
SpacerH(TangemTheme.dimens2.x4)
|
||||||
TangemPayAddCardView(onClick = {})
|
TangemPayAddCardView(onClick = {})
|
||||||
SpacerH(TangemTheme.dimens2.x4)
|
SpacerH(TangemTheme.dimens2.x4)
|
||||||
TangemPayCardView(isReissuing = false, onClick = {}, lastDigits = "1234", isFrozen = true)
|
TangemPayCardView(isReissuing = false, onClick = {}, lastDigits = "1234", isEnabled = true, isFrozen = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -5,6 +5,7 @@ import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfi
|
||||||
internal interface TangemPayDetailIntents {
|
internal interface TangemPayDetailIntents {
|
||||||
fun onContactSupportClicked()
|
fun onContactSupportClicked()
|
||||||
fun onRefreshSwipe(refreshState: ShowRefreshState)
|
fun onRefreshSwipe(refreshState: ShowRefreshState)
|
||||||
|
fun onRenewSession()
|
||||||
fun onClickAddFunds()
|
fun onClickAddFunds()
|
||||||
fun onClickWithdraw()
|
fun onClickWithdraw()
|
||||||
fun onClickTermsAndLimits()
|
fun onClickTermsAndLimits()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue