Updated on 2026-08-14

This commit is contained in:
Tangem 2026-06-26 14:10:40 +03:00
parent ffa093007b
commit 132924c8c7
5 changed files with 124 additions and 4 deletions

View file

@ -10,7 +10,6 @@ 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.StatusSource
import com.tangem.domain.models.account.PaymentAccountStatusValue
import com.tangem.domain.models.pay.TangemPayCard
import com.tangem.domain.models.pay.TangemPayCardFrozenState
@ -18,6 +17,7 @@ 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 com.tangem.features.tangempay.utils.isFresh
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
@ -60,7 +60,7 @@ internal class TangemPayDetailsStateFactory(
}
fun getLoadedState(status: PaymentAccountStatusValue.Loaded): TangemPayDetailsUM {
val isFresh = status.source == StatusSource.ACTUAL && status.error == null
val isFresh = status.isFresh
val hasUnfrozenCard = status.cards.any { it.frozenState == TangemPayCardFrozenState.Unfrozen }
val hasIssuingCard = status.cards.any { it.state == TangemPayCardState.Issuing }
val isAddCardEnabled = isFresh && !hasIssuingCard

View file

@ -169,7 +169,14 @@ internal class TangemPayDetailsModel @Inject constructor(
frozenStateJobHolder.cancel()
cardDetailsRepository
.cardFrozenState(cardId)
.onEach { uiState.update(TangemPayFreezeUnfreezeStateTransformer(cardFrozenState = it)) }
.onEach { frozenState ->
uiState.update(
TangemPayFreezeUnfreezeStateTransformer(
cardFrozenState = frozenState,
isDataFresh = currentStatus.value.ifLoadedOrNull { it.isFresh } == true,
),
)
}
.launchIn(modelScope)
.saveIn(frozenStateJobHolder)
}

View file

@ -8,12 +8,14 @@ import kotlinx.collections.immutable.toPersistentList
internal class TangemPayFreezeUnfreezeStateTransformer(
private val cardFrozenState: TangemPayCardFrozenState,
private val isDataFresh: Boolean,
) : Transformer<TangemPayDetailsUM> {
override fun transform(prevState: TangemPayDetailsUM): TangemPayDetailsUM {
val balanceBlockState = if (prevState.balanceBlockState is TangemPayDetailsBalanceBlockState.Content) {
val isEnabled = isDataFresh && cardFrozenState == TangemPayCardFrozenState.Unfrozen
val actionButtons = prevState.balanceBlockState.actionButtons.map {
it.copy(isEnabled = cardFrozenState == TangemPayCardFrozenState.Unfrozen)
it.copy(isEnabled = isEnabled)
}
prevState.balanceBlockState.copy(actionButtons = actionButtons.toPersistentList())
} else {

View file

@ -21,6 +21,9 @@ internal val AccountStatus.Payment.cryptoCurrency: CryptoCurrency.Token
internal val AccountStatus.Payment.isDeactivated: Boolean
get() = value is PaymentAccountStatusValue.Deactivated
internal val PaymentAccountStatusValue.Loaded.isFresh: Boolean
get() = source == StatusSource.ACTUAL && error == null
internal fun AccountStatus.Payment.requireLoaded(): PaymentAccountStatusValue.Loaded =
value as? PaymentAccountStatusValue.Loaded
?: error("Card-detail subflow requires Loaded status, got ${value::class.simpleName}")

View file

@ -0,0 +1,108 @@
package com.tangem.features.tangempay.model.transformers
import com.google.common.truth.Truth.assertThat
import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
import com.tangem.core.ui.extensions.TextReference
import com.tangem.domain.models.pay.TangemPayCardFrozenState
import com.tangem.features.tangempay.entity.TangemPayDetailsBalanceBlockState
import com.tangem.features.tangempay.entity.TangemPayDetailsTopBarConfig
import com.tangem.features.tangempay.entity.TangemPayDetailsUM
import kotlinx.collections.immutable.persistentListOf
import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.MethodSource
internal class TangemPayFreezeUnfreezeStateTransformerTest {
@ParameterizedTest
@MethodSource("provideCases")
fun `GIVEN content state WHEN transform THEN buttons enabled only when fresh and unfrozen`(case: Case) {
// Arrange
val state = contentState(actionButtonsEnabled = true)
// Act
val result = TangemPayFreezeUnfreezeStateTransformer(
cardFrozenState = case.frozenState,
isDataFresh = case.isDataFresh,
).transform(state)
// Assert
val enabled = result.balanceBlockState.actionButtons.map { it.isEnabled }
assertThat(enabled).containsExactly(case.expectedEnabled, case.expectedEnabled)
}
@Test
fun `GIVEN non-content state WHEN transform THEN state is unchanged`() {
// Arrange
val state = loadingState()
// Act
val result = TangemPayFreezeUnfreezeStateTransformer(
cardFrozenState = TangemPayCardFrozenState.Unfrozen,
isDataFresh = true,
).transform(state)
// Assert
assertThat(result).isEqualTo(state)
}
private fun contentState(actionButtonsEnabled: Boolean): TangemPayDetailsUM = baseState(
balanceBlockState = TangemPayDetailsBalanceBlockState.Content(
actionButtons = persistentListOf(
actionButton(isEnabled = actionButtonsEnabled),
actionButton(isEnabled = actionButtonsEnabled),
),
cardsBlockState = null,
fiatBalance = TextReference.EMPTY,
isBalanceFlickering = false,
),
)
private fun loadingState(): TangemPayDetailsUM = baseState(
balanceBlockState = TangemPayDetailsBalanceBlockState.Loading(
actionButtons = persistentListOf(actionButton(isEnabled = true)),
cardsBlockState = null,
),
)
private fun baseState(balanceBlockState: TangemPayDetailsBalanceBlockState) = TangemPayDetailsUM(
topBarConfig = TangemPayDetailsTopBarConfig(
onBackClick = {},
onOpenMenu = {},
items = persistentListOf(),
itemsV2 = persistentListOf(),
),
pullToRefreshConfig = PullToRefreshConfig(isRefreshing = false, onRefresh = {}),
balanceBlockState = balanceBlockState,
addToWalletBlockState = null,
isBalanceHidden = false,
errorNotificationConfig = null,
accountDeactivatedNotificationConfig = null,
)
private fun actionButton(isEnabled: Boolean) = ActionButtonConfig(
text = TextReference.EMPTY,
iconResId = 0,
onClick = {},
isEnabled = isEnabled,
)
internal data class Case(
val frozenState: TangemPayCardFrozenState,
val isDataFresh: Boolean,
val expectedEnabled: Boolean,
)
private companion object {
@JvmStatic
fun provideCases() = listOf(
Case(frozenState = TangemPayCardFrozenState.Unfrozen, isDataFresh = true, expectedEnabled = true),
Case(frozenState = TangemPayCardFrozenState.Unfrozen, isDataFresh = false, expectedEnabled = false),
Case(frozenState = TangemPayCardFrozenState.Frozen, isDataFresh = true, expectedEnabled = false),
Case(frozenState = TangemPayCardFrozenState.Pending, isDataFresh = true, expectedEnabled = false),
Case(frozenState = TangemPayCardFrozenState.Frozen, isDataFresh = false, expectedEnabled = false),
Case(frozenState = TangemPayCardFrozenState.Pending, isDataFresh = false, expectedEnabled = false),
)
}
}