Updated on 2026-08-14
This commit is contained in:
parent
b208c0dd7c
commit
640ba5af98
14 changed files with 268 additions and 127 deletions
|
|
@ -8,7 +8,6 @@
|
|||
<ID>BooleanPropertyNaming:TangemPayChangePinUM.kt$TangemPayChangePinUM$val submitButtonEnabled: Boolean</ID>
|
||||
<ID>BooleanPropertyNaming:TangemPayChangePinUM.kt$TangemPayChangePinUM$val submitButtonLoading: Boolean</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>CanBeNonNullable:TangemPayTxHistoryDetailsModel.kt$TangemPayTxHistoryDetailsModel$txHash: String?</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.generated.icons.Icons
|
||||
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.TangemPayCardState
|
||||
import com.tangem.domain.models.pay.isFrozen
|
||||
import com.tangem.features.tangempay.details.impl.R
|
||||
import com.tangem.features.tangempay.utils.TangemPayDetailIntents
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
|
@ -21,55 +24,127 @@ internal class TangemPayDetailsStateFactory(
|
|||
private val onBack: () -> Unit,
|
||||
private val onOpenMenu: () -> Unit,
|
||||
private val intents: TangemPayDetailIntents,
|
||||
private val cardFrozenState: TangemPayCardFrozenState,
|
||||
private val isRedesignEnabled: Boolean,
|
||||
) {
|
||||
@Suppress("LongMethod")
|
||||
fun getInitialState(
|
||||
isTangemPayDeactivated: Boolean,
|
||||
cardNumberEnd: String,
|
||||
isReissuing: Boolean,
|
||||
isFrozen: Boolean,
|
||||
): TangemPayDetailsUM {
|
||||
fun getLoadingState(): TangemPayDetailsUM {
|
||||
return TangemPayDetailsUM(
|
||||
topBarConfig = TangemPayDetailsTopBarConfig(
|
||||
onBackClick = onBack,
|
||||
onOpenMenu = onOpenMenu,
|
||||
items = getTopBarMenuItems(isTangemPayDeactivated),
|
||||
itemsV2 = getTopBarMenuItemsV2(isTangemPayDeactivated),
|
||||
items = getTopBarMenuItems(),
|
||||
itemsV2 = getTopBarMenuItemsV2(),
|
||||
),
|
||||
pullToRefreshConfig = PullToRefreshConfig(
|
||||
isRefreshing = false,
|
||||
onRefresh = intents::onRefreshSwipe,
|
||||
),
|
||||
balanceBlockState = TangemPayDetailsBalanceBlockState.Loading(
|
||||
actionButtons = getActionButtonsConfig(),
|
||||
actionButtons = persistentListOf(),
|
||||
cardsBlockState = TangemPayDetailsBalanceBlockState.CardsBlockState(
|
||||
cards = persistentListOf(
|
||||
TangemPayDetailsBalanceBlockState.Card(
|
||||
lastDigits = cardNumberEnd,
|
||||
onClick = {},
|
||||
isReissuing = isReissuing,
|
||||
isFrozen = isFrozen,
|
||||
),
|
||||
),
|
||||
cards = persistentListOf(),
|
||||
onAddCardClick = intents::onAddCardClick,
|
||||
).takeIf { !isTangemPayDeactivated },
|
||||
),
|
||||
),
|
||||
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),
|
||||
iconResId = R.drawable.img_attention_20,
|
||||
).takeIf { isTangemPayDeactivated },
|
||||
errorNotificationConfig = null,
|
||||
accountDeactivatedNotificationConfig = null,
|
||||
)
|
||||
}
|
||||
|
||||
private fun getTopBarMenuItems(isTangemPayDeactivated: Boolean): ImmutableList<TangemDropdownMenuItem> {
|
||||
if (isTangemPayDeactivated) return persistentListOf()
|
||||
fun getLoadedState(status: PaymentAccountStatusValue.Loaded): TangemPayDetailsUM {
|
||||
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(
|
||||
TangemDropdownMenuItem(
|
||||
title = resourceReference(R.string.tangem_pay_terms_limits),
|
||||
|
|
@ -84,9 +159,7 @@ internal class TangemPayDetailsStateFactory(
|
|||
)
|
||||
}
|
||||
|
||||
private fun getTopBarMenuItemsV2(isTangemPayDeactivated: Boolean): ImmutableList<TangemPayDropDownItemUM> {
|
||||
if (isTangemPayDeactivated) return persistentListOf()
|
||||
|
||||
private fun getTopBarMenuItemsV2(): ImmutableList<TangemPayDropDownItemUM> {
|
||||
return persistentListOf(
|
||||
TangemPayDropDownItemUM(
|
||||
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(
|
||||
ActionButtonConfig(
|
||||
text = resourceReference(id = R.string.tangempay_card_details_add_funds),
|
||||
|
|
@ -121,13 +194,13 @@ internal class TangemPayDetailsStateFactory(
|
|||
R.drawable.ic_plus_24
|
||||
},
|
||||
onClick = intents::onClickAddFunds,
|
||||
isEnabled = cardFrozenState == TangemPayCardFrozenState.Unfrozen,
|
||||
isEnabled = isEnabled,
|
||||
),
|
||||
ActionButtonConfig(
|
||||
text = resourceReference(id = R.string.tangempay_card_details_withdraw),
|
||||
iconResId = R.drawable.ic_arrow_up_24,
|
||||
onClick = intents::onClickWithdraw,
|
||||
isEnabled = cardFrozenState == TangemPayCardFrozenState.Unfrozen,
|
||||
isEnabled = isEnabled,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ internal data class TangemPayDetailsUM(
|
|||
val balanceBlockState: TangemPayDetailsBalanceBlockState,
|
||||
val addToWalletBlockState: AddToWalletBlockState?,
|
||||
val isBalanceHidden: Boolean,
|
||||
val addFundsEnabled: Boolean,
|
||||
val errorNotificationConfig: NotificationConfig?,
|
||||
val accountDeactivatedNotificationConfig: NotificationConfig?,
|
||||
)
|
||||
|
||||
|
|
@ -93,6 +93,7 @@ internal sealed class TangemPayDetailsBalanceBlockState {
|
|||
val onClick: () -> Unit,
|
||||
val isReissuing: 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.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.SnackbarMessage
|
||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
||||
import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||
import com.tangem.domain.feedback.models.WalletMetaInfo
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.models.TokenReceiveConfig
|
||||
import com.tangem.domain.models.account.PaymentAccountStatusValue
|
||||
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.PaymentAccountStatusSupplier
|
||||
import com.tangem.domain.pay.model.TangemPayTopUpData
|
||||
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
|
||||
import com.tangem.domain.pay.repository.TangemPayWithdrawRepository
|
||||
import com.tangem.domain.pay.usecase.ProduceTangemPayInitialDataUseCase
|
||||
import com.tangem.domain.tangempay.TangemPayAnalyticsEvents
|
||||
import com.tangem.domain.visa.model.TangemPayTxHistoryItem
|
||||
import com.tangem.features.tangempay.TangemPayConstants
|
||||
import com.tangem.features.tangempay.TangemPayFeatureToggles
|
||||
import com.tangem.features.tangempay.components.AddFundsListener
|
||||
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.TangemPayDetailsNavigation
|
||||
import com.tangem.features.tangempay.entity.TangemPayDetailsStateFactory
|
||||
|
|
@ -73,14 +74,11 @@ internal class TangemPayDetailsModel @Inject constructor(
|
|||
private val expressTransactionsEventListener: ExpressTransactionsEventListener,
|
||||
private val tangemPayFeatureToggles: TangemPayFeatureToggles,
|
||||
private val paymentAccountStatusFetcher: PaymentAccountStatusFetcher,
|
||||
private val produceTangemPayInitialDataUseCase: ProduceTangemPayInitialDataUseCase,
|
||||
) : Model(), TangemPayTxHistoryUiActions, TangemPayDetailIntents, AddFundsListener {
|
||||
|
||||
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 userWalletId
|
||||
|
|
@ -93,25 +91,20 @@ internal class TangemPayDetailsModel @Inject constructor(
|
|||
onBack = router::pop,
|
||||
onOpenMenu = ::onOpenMenu,
|
||||
intents = this,
|
||||
cardFrozenState = when {
|
||||
initialCard == null -> TangemPayCardFrozenState.Unfrozen
|
||||
else -> initialCard.frozenState
|
||||
},
|
||||
isRedesignEnabled = isRedesignEnabled(),
|
||||
)
|
||||
|
||||
val uiState: StateFlow<TangemPayDetailsUM>
|
||||
field = MutableStateFlow(
|
||||
stateFactory.getInitialState(
|
||||
isTangemPayDeactivated = isTangemPayDeactivated,
|
||||
cardNumberEnd = initialCard?.lastDigits.orEmpty(),
|
||||
isReissuing = initialCard == null || initialCard.state != TangemPayCardState.Active,
|
||||
isFrozen = initialCard?.frozenState == TangemPayCardFrozenState.Frozen,
|
||||
),
|
||||
when {
|
||||
params.initialStatus.isDeactivated -> stateFactory.getDeactivatedState()
|
||||
else -> stateFactory.getLoadingState()
|
||||
},
|
||||
)
|
||||
|
||||
private val refreshStateJobHolder = JobHolder()
|
||||
private val addToWalletBannerJobHolder = JobHolder()
|
||||
private val frozenStateJobHolder = JobHolder()
|
||||
|
||||
val bottomSheetNavigation: SlotNavigation<TangemPayDetailsNavigation> = SlotNavigation()
|
||||
|
||||
|
|
@ -119,38 +112,27 @@ internal class TangemPayDetailsModel @Inject constructor(
|
|||
analytics.send(TangemPayAnalyticsEvents.MainScreenOpened())
|
||||
handleBalanceHiding()
|
||||
|
||||
val statusFlow = paymentAccountStatusSupplier.invoke(userWalletId)
|
||||
paymentAccountStatusSupplier.invoke(userWalletId)
|
||||
.onEach { status -> currentStatus.update { status } }
|
||||
.map { it.value }
|
||||
|
||||
if (isTangemPayDeactivated) {
|
||||
statusFlow
|
||||
.filterIsInstance<PaymentAccountStatusValue.Deactivated>()
|
||||
.onEach { state ->
|
||||
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() },
|
||||
),
|
||||
)
|
||||
.onEach { state ->
|
||||
when (state) {
|
||||
is PaymentAccountStatusValue.Deactivated -> {
|
||||
uiState.update { stateFactory.getDeactivatedState() }
|
||||
uiState.update(DetailsBalanceTransformer(state.balance.fiatBalance))
|
||||
}
|
||||
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() {
|
||||
|
|
@ -168,10 +150,12 @@ internal class TangemPayDetailsModel @Inject constructor(
|
|||
fun isRedesignEnabled(): Boolean = tangemPayFeatureToggles.isRedesignEnabled
|
||||
|
||||
private fun subscribeToCardFrozenState(cardId: String) {
|
||||
frozenStateJobHolder.cancel()
|
||||
cardDetailsRepository
|
||||
.cardFrozenState(cardId)
|
||||
.onEach { uiState.update(TangemPayFreezeUnfreezeStateTransformer(cardFrozenState = it)) }
|
||||
.launchIn(modelScope)
|
||||
.saveIn(frozenStateJobHolder)
|
||||
}
|
||||
|
||||
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) {
|
||||
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.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
|
|
@ -61,6 +62,8 @@ import com.tangem.features.tokendetails.ExpressTransactionsComponent
|
|||
import com.tangem.utils.StringsSigns.DASH_SIGN
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
private const val DISABLED_ALPHA = 0.5f
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
internal fun TangemPayDetailsScreen(
|
||||
|
|
@ -100,6 +103,20 @@ internal fun TangemPayDetailsScreen(
|
|||
.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(
|
||||
key = TangemPayDetailsBalanceBlockState::class.java,
|
||||
content = {
|
||||
|
|
@ -300,11 +317,16 @@ private fun TangemPayCardItem(card: TangemPayDetailsBalanceBlockState.Card, modi
|
|||
Box(
|
||||
modifier = modifier
|
||||
.clip(RoundedCornerShape(4.dp))
|
||||
.clickable(onClick = card.onClick)
|
||||
.clickable(
|
||||
onClick = card.onClick,
|
||||
enabled = card.isEnabled,
|
||||
)
|
||||
.testTag(TangemPayTestTags.PAYMENT_ACCOUNT_CARD_BUTTON),
|
||||
) {
|
||||
Image(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
modifier = Modifier
|
||||
.alpha(if (card.isEnabled) 1f else DISABLED_ALPHA)
|
||||
.fillMaxSize(),
|
||||
painter = painterResource(
|
||||
if (card.isReissuing) {
|
||||
R.drawable.img_visa_card_inactive_48_32
|
||||
|
|
@ -464,12 +486,14 @@ internal class TangemPayDetailsUMProvider : CollectionPreviewParameterProvider<T
|
|||
lastDigits = "1234",
|
||||
onClick = {},
|
||||
isReissuing = false,
|
||||
isEnabled = false,
|
||||
isFrozen = false,
|
||||
),
|
||||
TangemPayDetailsBalanceBlockState.Card(
|
||||
lastDigits = "3456",
|
||||
onClick = {},
|
||||
isReissuing = false,
|
||||
isEnabled = true,
|
||||
isFrozen = false,
|
||||
),
|
||||
),
|
||||
|
|
@ -477,12 +501,12 @@ internal class TangemPayDetailsUMProvider : CollectionPreviewParameterProvider<T
|
|||
),
|
||||
),
|
||||
isBalanceHidden = false,
|
||||
addFundsEnabled = true,
|
||||
addToWalletBlockState = AddToWalletBlockState(
|
||||
onClick = {},
|
||||
onClickClose = {},
|
||||
),
|
||||
accountDeactivatedNotificationConfig = null,
|
||||
errorNotificationConfig = null,
|
||||
),
|
||||
TangemPayDetailsUM(
|
||||
topBarConfig = TangemPayDetailsTopBarConfig(
|
||||
|
|
@ -501,15 +525,16 @@ internal class TangemPayDetailsUMProvider : CollectionPreviewParameterProvider<T
|
|||
onClick = {},
|
||||
isReissuing = true,
|
||||
isFrozen = false,
|
||||
isEnabled = true,
|
||||
),
|
||||
),
|
||||
onAddCardClick = {},
|
||||
),
|
||||
),
|
||||
isBalanceHidden = false,
|
||||
addFundsEnabled = true,
|
||||
addToWalletBlockState = null,
|
||||
accountDeactivatedNotificationConfig = null,
|
||||
errorNotificationConfig = null,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -184,6 +184,14 @@ private fun LazyListScope.payDetailsBody(state: TangemPayDetailsUM) {
|
|||
}
|
||||
}
|
||||
else -> {
|
||||
if (state.errorNotificationConfig != null) {
|
||||
item("errorSessionBannerBlock") {
|
||||
TangemMessage(
|
||||
config = state.errorNotificationConfig,
|
||||
modifier = Modifier.padding(horizontal = TangemTheme.dimens2.x4),
|
||||
)
|
||||
}
|
||||
}
|
||||
if (state.addToWalletBlockState != null) {
|
||||
item("addToWalletBannerBlock") {
|
||||
TangemPayAddToWalletBlock(
|
||||
|
|
@ -340,6 +348,7 @@ private fun CardsBlock(
|
|||
isReissuing = item.isReissuing,
|
||||
lastDigits = item.lastDigits,
|
||||
onClick = item.onClick,
|
||||
isEnabled = item.isEnabled,
|
||||
isFrozen = item.isFrozen,
|
||||
)
|
||||
SpacerW(TangemTheme.dimens2.x2)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
|
|
@ -41,6 +42,7 @@ private const val REISSUING_CARD_BG = 0xFF1E1E1E
|
|||
@Composable
|
||||
internal fun TangemPayCardView(
|
||||
isReissuing: Boolean,
|
||||
isEnabled: Boolean,
|
||||
lastDigits: String,
|
||||
onClick: () -> Unit,
|
||||
isFrozen: Boolean,
|
||||
|
|
@ -54,6 +56,7 @@ internal fun TangemPayCardView(
|
|||
)
|
||||
.testTag(TangemPayTestTags.PAYMENT_ACCOUNT_CARD_BUTTON),
|
||||
isReissuing = isReissuing,
|
||||
isEnabled = isEnabled,
|
||||
onClick = onClick,
|
||||
) {
|
||||
Row(
|
||||
|
|
@ -120,6 +123,7 @@ internal fun TangemPayAddCardView(onClick: () -> Unit, modifier: Modifier = Modi
|
|||
@Composable
|
||||
private fun CardBackground(
|
||||
isReissuing: Boolean,
|
||||
isEnabled: Boolean,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
content: @Composable BoxScope.() -> Unit,
|
||||
|
|
@ -134,6 +138,7 @@ private fun CardBackground(
|
|||
|
||||
Box(
|
||||
modifier = modifier
|
||||
.alpha(if (isEnabled) 1f else 0.5f)
|
||||
.clip(RoundedCornerShape(6.dp))
|
||||
.drawBehind {
|
||||
drawRect(bgColor)
|
||||
|
|
@ -163,7 +168,7 @@ private fun CardBackground(
|
|||
color = TangemTheme.colors3.border.primary,
|
||||
shape = RoundedCornerShape(6.dp),
|
||||
)
|
||||
.clickableSingle(onClick = onClick),
|
||||
.clickableSingle(onClick = onClick, enabled = isEnabled),
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
|
|
@ -181,6 +186,7 @@ private fun CardBackgroundPreview() {
|
|||
isReissuing = false,
|
||||
onClick = {},
|
||||
content = {},
|
||||
isEnabled = true,
|
||||
)
|
||||
SpacerH(TangemTheme.dimens2.x4)
|
||||
CardBackground(
|
||||
|
|
@ -191,15 +197,28 @@ private fun CardBackgroundPreview() {
|
|||
isReissuing = true,
|
||||
onClick = {},
|
||||
content = {},
|
||||
isEnabled = true,
|
||||
)
|
||||
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)
|
||||
TangemPayCardView(isReissuing = true, onClick = {}, lastDigits = "", isFrozen = false)
|
||||
TangemPayCardView(
|
||||
isReissuing = true,
|
||||
onClick = {},
|
||||
lastDigits = "",
|
||||
isEnabled = true,
|
||||
isFrozen = false,
|
||||
)
|
||||
SpacerH(TangemTheme.dimens2.x4)
|
||||
TangemPayAddCardView(onClick = {})
|
||||
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 {
|
||||
fun onContactSupportClicked()
|
||||
fun onRefreshSwipe(refreshState: ShowRefreshState)
|
||||
fun onRenewSession()
|
||||
fun onClickAddFunds()
|
||||
fun onClickWithdraw()
|
||||
fun onClickTermsAndLimits()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue