From 08f011c46e910fcc05766d76c5c5dd1bafad7e39 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 19 May 2026 11:44:08 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../common/ui/tokenaction/TokenActionRow.kt | 13 ++- .../token/block/impl/ui/TokenMarketBlock.kt | 4 +- .../tokendetails/model/TokenDetailsModel.kt | 4 + .../transformer/UpdateAddFundsTransformer.kt | 4 +- .../transformer/UpdateTransferTransformer.kt | 9 +- .../UpdateZeroBalanceActionsTransformer.kt | 6 +- .../UpdateAddFundsTransformerTest.kt | 64 ++++++++++++- .../UpdateTransferTransformerTest.kt | 96 ++++++++++++++++++- ...UpdateZeroBalanceActionsTransformerTest.kt | 50 +++++++++- 9 files changed, 237 insertions(+), 13 deletions(-) diff --git a/common/ui/src/main/java/com/tangem/common/ui/tokenaction/TokenActionRow.kt b/common/ui/src/main/java/com/tangem/common/ui/tokenaction/TokenActionRow.kt index 487f87db7b..7d8e87530d 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/tokenaction/TokenActionRow.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/tokenaction/TokenActionRow.kt @@ -38,9 +38,12 @@ private const val ACTION_BACKGROUND_ALPHA = .1f * @param iconRes leading 20dp icon drawn over an accent-colored circle * @param title row primary text * @param description row secondary text - * @param onClick single-click callback; row is non-interactive if `null` - * @param onLongClick long-press callback; pass `null` to disable long-press - * @param isEnabled when `false`, the row uses disabled-tier colors and ignores clicks + * @param onClick single-click callback; row is non-interactive if `null`. Fires regardless + * of [isEnabled] — gating is the caller's responsibility (pass `null` to + * make the row non-interactive) + * @param onLongClick long-press callback; pass `null` to disable long-press. Fires regardless + * of [isEnabled] + * @param isEnabled controls visual styling only (disabled-tier colors when `false`) * @param tailContent content placed at the row's end. Defaults to a chevron-right icon. */ @Composable @@ -63,8 +66,8 @@ fun TokenActionRow( shape = RoundedCornerShape(TangemTheme.dimens2.x5), ) .clickableWithHaptic( - onClick = onClick.takeIf { isEnabled }, - onLongClick = onLongClick.takeIf { isEnabled }, + onClick = onClick, + onLongClick = onLongClick, hapticManager = hapticManager, ), ) { diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/ui/TokenMarketBlock.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/ui/TokenMarketBlock.kt index d2a8cc8ea6..a260c3616c 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/ui/TokenMarketBlock.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/ui/TokenMarketBlock.kt @@ -2,6 +2,7 @@ package com.tangem.features.markets.token.block.impl.ui import android.content.res.Configuration import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth @@ -51,7 +52,8 @@ internal fun TokenMarketBlock(tokenMarketBlockUM: TokenMarketBlockUM, modifier: modifier = modifier .fillMaxWidth() .clip(RoundedCornerShape(TangemTheme.dimens2.x5)) - .background(TangemTheme.colors2.surface.level3), + .background(TangemTheme.colors2.surface.level3) + .clickable(onClick = tokenMarketBlockUM.onClick), ) { Text( text = stringResourceSafe(id = R.string.markets_common_market_price), diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt index 71859ae320..37e5982733 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt @@ -340,6 +340,7 @@ internal class TokenDetailsModel @Inject constructor( sendButtonsEvents(state.states) uiState.value = stateFactory.getManageButtonsState(actions = state.states) if (designFeatureToggles.isRedesignEnabled) { + val networkSource = currencyStatus.value.sources.networkSource redesignStateController.update( UpdateActionButtonsTransformer( actions = state.states, @@ -349,6 +350,7 @@ internal class TokenDetailsModel @Inject constructor( redesignStateController.update( UpdateAddFundsTransformer( actions = state.states, + networkSource = networkSource, clickIntents = this@TokenDetailsModel, onActionDispatched = bottomSheetNavigation::dismiss, ), @@ -356,6 +358,7 @@ internal class TokenDetailsModel @Inject constructor( redesignStateController.update( UpdateTransferTransformer( actions = state.states, + networkSource = networkSource, clickIntents = this@TokenDetailsModel, onActionDispatched = bottomSheetNavigation::dismiss, ), @@ -363,6 +366,7 @@ internal class TokenDetailsModel @Inject constructor( redesignStateController.update( UpdateZeroBalanceActionsTransformer( actions = state.states, + networkSource = networkSource, clickIntents = this@TokenDetailsModel, ), ) diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateAddFundsTransformer.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateAddFundsTransformer.kt index 0252ad38a3..26b0608682 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateAddFundsTransformer.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateAddFundsTransformer.kt @@ -1,5 +1,6 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.state.transformer +import com.tangem.domain.models.StatusSource import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason import com.tangem.domain.tokens.model.TokenActionsState import com.tangem.domain.tokens.model.isLoading @@ -10,6 +11,7 @@ import com.tangem.utils.transformer.Transformer internal class UpdateAddFundsTransformer( private val actions: List, + private val networkSource: StatusSource, private val clickIntents: TokenDetailsClickIntents, private val onActionDispatched: () -> Unit, ) : Transformer { @@ -43,7 +45,7 @@ internal class UpdateAddFundsTransformer( } val receiveRow = receiveAction?.let { action -> AddFundsUM.Row( - isLoading = action.unavailabilityReason.isLoading, + isLoading = action.unavailabilityReason.isLoading || networkSource == StatusSource.CACHE, isEnabled = action.unavailabilityReason == ScenarioUnavailabilityReason.None, onClick = { onActionDispatched() diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateTransferTransformer.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateTransferTransformer.kt index 5e2b102c2c..c87c35954e 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateTransferTransformer.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateTransferTransformer.kt @@ -1,5 +1,6 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.state.transformer +import com.tangem.domain.models.StatusSource import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason import com.tangem.domain.tokens.model.TokenActionsState import com.tangem.domain.tokens.model.isLoading @@ -10,6 +11,7 @@ import com.tangem.utils.transformer.Transformer internal class UpdateTransferTransformer( private val actions: List, + private val networkSource: StatusSource, private val clickIntents: TokenDetailsClickIntents, private val onActionDispatched: () -> Unit, ) : Transformer { @@ -23,7 +25,7 @@ internal class UpdateTransferTransformer( val sendRow = sendAction?.let { action -> TransferUM.Row( - isLoading = action.unavailabilityReason.isLoading, + isLoading = action.unavailabilityReason.isOutdatedLoading(), isEnabled = action.unavailabilityReason == ScenarioUnavailabilityReason.None, onClick = { onActionDispatched() @@ -43,7 +45,7 @@ internal class UpdateTransferTransformer( } val sellRow = sellAction?.let { action -> TransferUM.Row( - isLoading = action.unavailabilityReason.isLoading, + isLoading = action.unavailabilityReason.isOutdatedLoading(), isEnabled = action.unavailabilityReason == ScenarioUnavailabilityReason.None, onClick = { onActionDispatched() @@ -56,4 +58,7 @@ internal class UpdateTransferTransformer( transferUM = TransferUM.Content(send = sendRow, swap = swapRow, sell = sellRow), ) } + + private fun ScenarioUnavailabilityReason.isOutdatedLoading(): Boolean = + isLoading || this == ScenarioUnavailabilityReason.UsedOutdatedData && networkSource == StatusSource.CACHE } \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateZeroBalanceActionsTransformer.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateZeroBalanceActionsTransformer.kt index 5ec1dd92d2..097379958e 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateZeroBalanceActionsTransformer.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateZeroBalanceActionsTransformer.kt @@ -1,5 +1,6 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.state.transformer +import com.tangem.domain.models.StatusSource import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason import com.tangem.domain.tokens.model.TokenActionsState import com.tangem.domain.tokens.model.isLoading @@ -10,6 +11,7 @@ import com.tangem.utils.transformer.Transformer internal class UpdateZeroBalanceActionsTransformer( private val actions: List, + private val networkSource: StatusSource, private val clickIntents: TokenDetailsClickIntents, ) : Transformer { @@ -27,6 +29,7 @@ internal class UpdateZeroBalanceActionsTransformer( receive = receiveAction?.toRow( onClick = clickIntents::onReceiveClick, onLongClick = { clickIntents.onCopyAddress() }, + forceLoading = networkSource == StatusSource.CACHE, ), ), ) @@ -35,10 +38,11 @@ internal class UpdateZeroBalanceActionsTransformer( private fun TokenActionsState.ActionState.toRow( onClick: (ScenarioUnavailabilityReason) -> Unit, onLongClick: (() -> Unit)? = null, + forceLoading: Boolean = false, ): ZeroBalanceActionsUM.Row { val reason = unavailabilityReason return ZeroBalanceActionsUM.Row( - isLoading = reason.isLoading, + isLoading = reason.isLoading || forceLoading, isEnabled = reason == ScenarioUnavailabilityReason.None, onClick = { onClick(reason) }, onLongClick = onLongClick, diff --git a/features/tokendetails/impl/src/test/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateAddFundsTransformerTest.kt b/features/tokendetails/impl/src/test/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateAddFundsTransformerTest.kt index 3e4eb0e634..455b041287 100644 --- a/features/tokendetails/impl/src/test/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateAddFundsTransformerTest.kt +++ b/features/tokendetails/impl/src/test/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateAddFundsTransformerTest.kt @@ -4,6 +4,7 @@ import com.google.common.truth.Truth.assertThat import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig import com.tangem.core.ui.components.marketprice.MarketPriceBlockState import com.tangem.core.ui.extensions.stringReference +import com.tangem.domain.models.StatusSource import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason import com.tangem.domain.tokens.model.TokenActionsState import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents @@ -246,6 +247,63 @@ class UpdateAddFundsTransformerTest { } } + @Test + fun `GIVEN Receive with None reason AND networkSource is CACHE WHEN transform THEN Receive row is marked isLoading`() { + // GIVEN — Receive never carries a Loading reason of its own; networkSource=CACHE is the + // signal that the initial data fetch is still in flight, so the row keeps the spinner. + val transformer = createTransformer( + actions = listOf(TokenActionsState.ActionState.Receive(ScenarioUnavailabilityReason.None)), + networkSource = StatusSource.CACHE, + ) + + // WHEN + val result = transformer.transform(initialState()) + + // THEN + val content = result.addFundsUM as AddFundsUM.Content + assertThat(content.receive?.isLoading).isTrue() + assertThat(content.receive?.isEnabled).isTrue() + } + + @Test + fun `GIVEN Receive with None reason AND networkSource is ONLY_CACHE WHEN transform THEN Receive row is not loading`() { + // GIVEN — ONLY_CACHE means the refresh failed (terminal state). Receive should drop the + // spinner and render as a normal enabled row using the cached address. + val transformer = createTransformer( + actions = listOf(TokenActionsState.ActionState.Receive(ScenarioUnavailabilityReason.None)), + networkSource = StatusSource.ONLY_CACHE, + ) + + // WHEN + val result = transformer.transform(initialState()) + + // THEN + val content = result.addFundsUM as AddFundsUM.Content + assertThat(content.receive?.isLoading).isFalse() + assertThat(content.receive?.isEnabled).isTrue() + } + + @Test + fun `GIVEN Buy AND Swap WHEN networkSource is CACHE THEN their loading stays driven by reason only`() { + // GIVEN — CACHE only opens the Loading branch for Receive; Buy/Swap rely on their own + // reasons (ExpressLoading / DataLoading). Buy(None)+CACHE must NOT show a spinner. + val transformer = createTransformer( + actions = listOf( + TokenActionsState.ActionState.Buy(ScenarioUnavailabilityReason.None), + TokenActionsState.ActionState.Swap(ScenarioUnavailabilityReason.None, false), + ), + networkSource = StatusSource.CACHE, + ) + + // WHEN + val result = transformer.transform(initialState()) + + // THEN + val content = result.addFundsUM as AddFundsUM.Content + assertThat(content.buy?.isLoading).isFalse() + assertThat(content.swap?.isLoading).isFalse() + } + @Test fun `GIVEN row WHEN not clicked THEN no callbacks fire`() { // GIVEN @@ -261,8 +319,12 @@ class UpdateAddFundsTransformerTest { verify(exactly = 0) { clickIntents.onBuyClick(any()) } } - private fun createTransformer(actions: List) = UpdateAddFundsTransformer( + private fun createTransformer( + actions: List, + networkSource: StatusSource = StatusSource.ACTUAL, + ) = UpdateAddFundsTransformer( actions = actions, + networkSource = networkSource, clickIntents = clickIntents, onActionDispatched = onActionDispatched, ) diff --git a/features/tokendetails/impl/src/test/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateTransferTransformerTest.kt b/features/tokendetails/impl/src/test/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateTransferTransformerTest.kt index ebcaa0fb16..6391fb3cef 100644 --- a/features/tokendetails/impl/src/test/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateTransferTransformerTest.kt +++ b/features/tokendetails/impl/src/test/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateTransferTransformerTest.kt @@ -4,6 +4,7 @@ import com.google.common.truth.Truth.assertThat import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig import com.tangem.core.ui.components.marketprice.MarketPriceBlockState import com.tangem.core.ui.extensions.stringReference +import com.tangem.domain.models.StatusSource import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason import com.tangem.domain.tokens.model.TokenActionsState import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents @@ -229,6 +230,95 @@ class UpdateTransferTransformerTest { } } + @Test + fun `GIVEN Send AND Sell carry UsedOutdatedData AND networkSource is CACHE WHEN transform THEN both rows are marked isLoading`() { + // GIVEN — OutdatedDataActionsFactory emits UsedOutdatedData for Send/Sell when the network + // source is not ACTUAL. CACHE specifically means "still loading", so the row UM upgrades + // that pair into a Loading row (preserving disabled state for clicks). + val transformer = createTransformer( + actions = listOf( + TokenActionsState.ActionState.Send(ScenarioUnavailabilityReason.UsedOutdatedData), + TokenActionsState.ActionState.Sell(ScenarioUnavailabilityReason.UsedOutdatedData), + ), + networkSource = StatusSource.CACHE, + ) + + // WHEN + val result = transformer.transform(initialState()) + + // THEN + val content = result.transferUM as TransferUM.Content + assertThat(content.send?.isLoading).isTrue() + assertThat(content.send?.isEnabled).isFalse() + assertThat(content.sell?.isLoading).isTrue() + assertThat(content.sell?.isEnabled).isFalse() + } + + @Test + fun `GIVEN Send AND Sell carry UsedOutdatedData AND networkSource is ONLY_CACHE WHEN transform THEN rows stay disabled but not loading`() { + // GIVEN — ONLY_CACHE is the terminal "refresh failed" state. UsedOutdatedData remains the + // reason but the spinner must drop so the UI signals "stale, not loading". + val transformer = createTransformer( + actions = listOf( + TokenActionsState.ActionState.Send(ScenarioUnavailabilityReason.UsedOutdatedData), + TokenActionsState.ActionState.Sell(ScenarioUnavailabilityReason.UsedOutdatedData), + ), + networkSource = StatusSource.ONLY_CACHE, + ) + + // WHEN + val result = transformer.transform(initialState()) + + // THEN + val content = result.transferUM as TransferUM.Content + assertThat(content.send?.isLoading).isFalse() + assertThat(content.send?.isEnabled).isFalse() + assertThat(content.sell?.isLoading).isFalse() + assertThat(content.sell?.isEnabled).isFalse() + } + + @Test + fun `GIVEN Send AND Sell carry non-Outdated disabled reason AND networkSource is CACHE WHEN transform THEN rows are not loading`() { + // GIVEN — the CACHE branch upgrades ONLY UsedOutdatedData to Loading. Any other disabled + // reason (e.g. EmptyBalance from a fully resolved status, or Unreachable) keeps the + // ordinary disabled-row rendering even if networkSource somehow says CACHE. + val transformer = createTransformer( + actions = listOf( + TokenActionsState.ActionState.Send(ScenarioUnavailabilityReason.Unreachable), + TokenActionsState.ActionState.Sell(ScenarioUnavailabilityReason.NotSupportedBySellService("USDT")), + ), + networkSource = StatusSource.CACHE, + ) + + // WHEN + val result = transformer.transform(initialState()) + + // THEN + val content = result.transferUM as TransferUM.Content + assertThat(content.send?.isLoading).isFalse() + assertThat(content.sell?.isLoading).isFalse() + } + + @Test + fun `GIVEN Swap available WHEN networkSource is CACHE THEN Swap loading stays driven by reason only`() { + // GIVEN — Swap has its own DataLoading reason for CACHE produced by OutdatedDataActionsFactory. + // The transformer must not double-mark via networkSource for non-Outdated reasons. + val transformer = createTransformer( + actions = listOf( + TokenActionsState.ActionState.Swap(ScenarioUnavailabilityReason.None, false), + ), + networkSource = StatusSource.CACHE, + ) + + // WHEN + val result = transformer.transform(initialState()) + + // THEN + val content = result.transferUM as TransferUM.Content + assertThat(content.swap?.isLoading).isFalse() + assertThat(content.swap?.isEnabled).isTrue() + } + @Test fun `GIVEN row WHEN not clicked THEN no callbacks fire`() { // GIVEN @@ -244,8 +334,12 @@ class UpdateTransferTransformerTest { verify(exactly = 0) { clickIntents.onSendClick(any()) } } - private fun createTransformer(actions: List) = UpdateTransferTransformer( + private fun createTransformer( + actions: List, + networkSource: StatusSource = StatusSource.ACTUAL, + ) = UpdateTransferTransformer( actions = actions, + networkSource = networkSource, clickIntents = clickIntents, onActionDispatched = onActionDispatched, ) diff --git a/features/tokendetails/impl/src/test/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateZeroBalanceActionsTransformerTest.kt b/features/tokendetails/impl/src/test/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateZeroBalanceActionsTransformerTest.kt index 087a3246a7..d0649f4dac 100644 --- a/features/tokendetails/impl/src/test/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateZeroBalanceActionsTransformerTest.kt +++ b/features/tokendetails/impl/src/test/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateZeroBalanceActionsTransformerTest.kt @@ -4,6 +4,7 @@ import com.google.common.truth.Truth.assertThat import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig import com.tangem.core.ui.components.marketprice.MarketPriceBlockState import com.tangem.core.ui.extensions.stringReference +import com.tangem.domain.models.StatusSource import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason import com.tangem.domain.tokens.model.TokenActionsState import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents @@ -191,6 +192,49 @@ class UpdateZeroBalanceActionsTransformerTest { assertThat(content.receive?.isLoading).isFalse() } + @Test + fun `GIVEN Receive with None reason AND networkSource is CACHE WHEN transform THEN only Receive is marked isLoading`() { + // GIVEN — networkSource=CACHE is the "still loading" signal for Receive (which has no + // Loading reason of its own). Buy/Swap rely on their own reasons and must not be flipped. + val transformer = createTransformer( + actions = listOf( + TokenActionsState.ActionState.Buy(ScenarioUnavailabilityReason.None), + TokenActionsState.ActionState.Swap(ScenarioUnavailabilityReason.None, false), + TokenActionsState.ActionState.Receive(ScenarioUnavailabilityReason.None), + ), + networkSource = StatusSource.CACHE, + ) + + // WHEN + val result = transformer.transform(initialState()) + + // THEN + val content = result.zeroBalanceActionsUM as ZeroBalanceActionsUM.Content + assertThat(content.receive?.isLoading).isTrue() + assertThat(content.receive?.isEnabled).isTrue() + assertThat(content.buy?.isLoading).isFalse() + assertThat(content.swap?.isLoading).isFalse() + } + + @Test + fun `GIVEN Receive with None reason AND networkSource is ONLY_CACHE WHEN transform THEN Receive is not loading`() { + // GIVEN — ONLY_CACHE is the terminal "refresh failed" state; Receive drops the spinner. + val transformer = createTransformer( + actions = listOf( + TokenActionsState.ActionState.Receive(ScenarioUnavailabilityReason.None), + ), + networkSource = StatusSource.ONLY_CACHE, + ) + + // WHEN + val result = transformer.transform(initialState()) + + // THEN + val content = result.zeroBalanceActionsUM as ZeroBalanceActionsUM.Content + assertThat(content.receive?.isLoading).isFalse() + assertThat(content.receive?.isEnabled).isTrue() + } + @Test fun `GIVEN row WHEN not clicked THEN no callbacks fire`() { // GIVEN @@ -205,8 +249,12 @@ class UpdateZeroBalanceActionsTransformerTest { verify(exactly = 0) { clickIntents.onBuyClick(any()) } } - private fun createTransformer(actions: List) = UpdateZeroBalanceActionsTransformer( + private fun createTransformer( + actions: List, + networkSource: StatusSource = StatusSource.ACTUAL, + ) = UpdateZeroBalanceActionsTransformer( actions = actions, + networkSource = networkSource, clickIntents = clickIntents, )