From 132924c8c74b29b2a4558aa8c44158c09d33cb3f Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 26 Jun 2026 14:10:40 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../entity/TangemPayDetailsStateFactory.kt | 4 +- .../tangempay/model/TangemPayDetailsModel.kt | 9 +- ...TangemPayFreezeUnfreezeStateTransformer.kt | 4 +- .../utils/PaymentAccountStatusExt.kt | 3 + ...emPayFreezeUnfreezeStateTransformerTest.kt | 108 ++++++++++++++++++ 5 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 features/tangempay/details/impl/src/test/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayFreezeUnfreezeStateTransformerTest.kt diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsStateFactory.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsStateFactory.kt index 735192a0ff..9eb2362844 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsStateFactory.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsStateFactory.kt @@ -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 diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt index 888788f83f..0b89ff84dd 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt @@ -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) } diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayFreezeUnfreezeStateTransformer.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayFreezeUnfreezeStateTransformer.kt index 0146ce7829..2644465ec6 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayFreezeUnfreezeStateTransformer.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayFreezeUnfreezeStateTransformer.kt @@ -8,12 +8,14 @@ import kotlinx.collections.immutable.toPersistentList internal class TangemPayFreezeUnfreezeStateTransformer( private val cardFrozenState: TangemPayCardFrozenState, + private val isDataFresh: Boolean, ) : Transformer { 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 { diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/utils/PaymentAccountStatusExt.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/utils/PaymentAccountStatusExt.kt index 56139acdaa..0398035dfc 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/utils/PaymentAccountStatusExt.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/utils/PaymentAccountStatusExt.kt @@ -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}") diff --git a/features/tangempay/details/impl/src/test/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayFreezeUnfreezeStateTransformerTest.kt b/features/tangempay/details/impl/src/test/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayFreezeUnfreezeStateTransformerTest.kt new file mode 100644 index 0000000000..44e221858c --- /dev/null +++ b/features/tangempay/details/impl/src/test/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayFreezeUnfreezeStateTransformerTest.kt @@ -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), + ) + } +} \ No newline at end of file