Updated on 2026-08-14
This commit is contained in:
parent
aa89d11b7c
commit
177176b3ee
7 changed files with 104 additions and 20 deletions
|
|
@ -1,9 +1,12 @@
|
|||
package com.tangem.common.ui.markets.action
|
||||
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.ImmutableSet
|
||||
import kotlinx.collections.immutable.persistentSetOf
|
||||
|
||||
data class QuickActions(
|
||||
val actions: ImmutableList<QuickActionUM>,
|
||||
val onQuickActionClick: (QuickActionUM) -> Unit,
|
||||
val onQuickActionLongClick: (QuickActionUM) -> Unit,
|
||||
val disabledActions: ImmutableSet<QuickActionUM> = persistentSetOf(),
|
||||
)
|
||||
|
|
@ -4,6 +4,7 @@ import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason
|
|||
import com.tangem.domain.tokens.model.TokenActionsState
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableSet
|
||||
|
||||
object QuickActionsConverter {
|
||||
|
||||
|
|
@ -13,8 +14,9 @@ object QuickActionsConverter {
|
|||
isRedesignEnabled: Boolean,
|
||||
context: TokenActionsContext = TokenActionsContext.Markets,
|
||||
): QuickActions {
|
||||
val states = toQuickActionStates(cryptoData.actions, isRedesignEnabled, context)
|
||||
return QuickActions(
|
||||
actions = toQuickActions(cryptoData.actions, isRedesignEnabled, context),
|
||||
actions = states.map { it.action }.toImmutableList(),
|
||||
onQuickActionClick = { quickActionUM ->
|
||||
tokenActionsHandler.handle(
|
||||
action = quickActionUM.toHandledAction(),
|
||||
|
|
@ -30,6 +32,7 @@ object QuickActionsConverter {
|
|||
)
|
||||
}
|
||||
},
|
||||
disabledActions = states.filterNot { it.isEnabled }.map { it.action }.toImmutableSet(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -45,30 +48,52 @@ object QuickActionsConverter {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns available actions filtered to [context]'s allow-list and ordered by it.
|
||||
* Omitting [context] (default [TokenActionsContext.Markets]) yields all available actions in source order;
|
||||
* a context with a non-null [TokenActionsContext.allowedActionsInOrder] filters to and orders by that list.
|
||||
* Returns actions filtered and ordered for [context].
|
||||
* Omitting [context] (default [TokenActionsContext.Markets]) yields only available actions in source order.
|
||||
* A context with a non-null [TokenActionsContext.allowedActionsInOrder] returns that list's actions in order,
|
||||
* including unavailable ones (they are meant to be shown disabled by the caller).
|
||||
*/
|
||||
fun toQuickActions(
|
||||
actions: List<TokenActionsState.ActionState>,
|
||||
isRedesignEnabled: Boolean,
|
||||
context: TokenActionsContext = TokenActionsContext.Markets,
|
||||
): ImmutableList<QuickActionUM> {
|
||||
val available = actions.filter { it.unavailabilityReason == ScenarioUnavailabilityReason.None }
|
||||
val allowed = context.allowedActionsInOrder
|
||||
?: return available.mapNotNull { it.toQuickActionUM(isRedesignEnabled) }.toImmutableList()
|
||||
): ImmutableList<QuickActionUM> =
|
||||
toQuickActionStates(actions, isRedesignEnabled, context).map { it.action }.toImmutableList()
|
||||
|
||||
val byBsAction = available.associateBy { it.toBsAction() }
|
||||
val hasExchange = byBsAction.containsKey(TokenActionsBSContentUM.Action.Exchange)
|
||||
private fun toQuickActionStates(
|
||||
actions: List<TokenActionsState.ActionState>,
|
||||
isRedesignEnabled: Boolean,
|
||||
context: TokenActionsContext,
|
||||
): List<QuickActionState> {
|
||||
val allowed = context.allowedActionsInOrder
|
||||
?: return actions
|
||||
.filter { it.unavailabilityReason == ScenarioUnavailabilityReason.None }
|
||||
.mapNotNull { action ->
|
||||
action.toQuickActionUM(isRedesignEnabled)?.let { QuickActionState(it, isEnabled = true) }
|
||||
}
|
||||
|
||||
val byBsAction = actions.associateBy { it.toBsAction() }
|
||||
val isExchangeAvailable = byBsAction[TokenActionsBSContentUM.Action.Exchange]
|
||||
?.unavailabilityReason == ScenarioUnavailabilityReason.None
|
||||
return allowed.mapNotNull { action ->
|
||||
when (action) {
|
||||
TokenActionsBSContentUM.Action.SendWithSwap ->
|
||||
if (hasExchange) swapAndSendUM(isRedesignEnabled) else null
|
||||
else -> byBsAction[action]?.toQuickActionUM(isRedesignEnabled)
|
||||
if (isExchangeAvailable) {
|
||||
QuickActionState(swapAndSendUM(isRedesignEnabled), isEnabled = true)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
else -> {
|
||||
val state = byBsAction[action] ?: return@mapNotNull null
|
||||
val um = state.toQuickActionUM(isRedesignEnabled) ?: return@mapNotNull null
|
||||
QuickActionState(um, isEnabled = state.unavailabilityReason == ScenarioUnavailabilityReason.None)
|
||||
}
|
||||
}
|
||||
}.toImmutableList()
|
||||
}
|
||||
}
|
||||
|
||||
private data class QuickActionState(val action: QuickActionUM, val isEnabled: Boolean)
|
||||
|
||||
private fun swapAndSendUM(isRedesignEnabled: Boolean): QuickActionUM =
|
||||
if (isRedesignEnabled) QuickActionUM.V2.SwapAndSend else QuickActionUM.V1.SwapAndSend
|
||||
|
||||
|
|
|
|||
|
|
@ -127,4 +127,55 @@ internal class QuickActionsConverterTest {
|
|||
assertThat(result).doesNotContain(QuickActionUM.V2.SwapAndSend)
|
||||
assertThat(result).doesNotContain(QuickActionUM.V2.Exchange(shouldShowBadge = false))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN buy and swap unavailable WHEN context is AddFunds THEN they are still shown (disabled) not hidden`() {
|
||||
// Arrange
|
||||
val actions = listOf(
|
||||
TokenActionsState.ActionState.Buy(ScenarioUnavailabilityReason.BuyUnavailable(cryptoCurrencyName = "BTC")),
|
||||
TokenActionsState.ActionState.Swap(ScenarioUnavailabilityReason.SingleWallet, shouldShowBadge = false),
|
||||
TokenActionsState.ActionState.Receive(ScenarioUnavailabilityReason.None),
|
||||
)
|
||||
|
||||
// Act
|
||||
val result = QuickActionsConverter.toQuickActions(
|
||||
actions = actions,
|
||||
isRedesignEnabled = true,
|
||||
context = TokenActionsContext.AddFunds,
|
||||
)
|
||||
|
||||
// Assert
|
||||
assertThat(result).containsExactly(
|
||||
QuickActionUM.V2.Buy,
|
||||
QuickActionUM.V2.Exchange(shouldShowBadge = false),
|
||||
QuickActionUM.V2.Receive,
|
||||
).inOrder()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN swap and sell unavailable WHEN context is Transfer THEN swap and sell shown disabled and no swapAndSend`() {
|
||||
// Arrange
|
||||
val actions = listOf(
|
||||
TokenActionsState.ActionState.Send(ScenarioUnavailabilityReason.None),
|
||||
TokenActionsState.ActionState.Swap(ScenarioUnavailabilityReason.SingleWallet, shouldShowBadge = false),
|
||||
TokenActionsState.ActionState.Sell(
|
||||
ScenarioUnavailabilityReason.NotSupportedBySellService(cryptoCurrencyName = "BTC"),
|
||||
),
|
||||
)
|
||||
|
||||
// Act
|
||||
val result = QuickActionsConverter.toQuickActions(
|
||||
actions = actions,
|
||||
isRedesignEnabled = true,
|
||||
context = TokenActionsContext.Transfer,
|
||||
)
|
||||
|
||||
// Assert
|
||||
assertThat(result).containsExactly(
|
||||
QuickActionUM.V2.Send,
|
||||
QuickActionUM.V2.Exchange(shouldShowBadge = false),
|
||||
QuickActionUM.V2.Sell,
|
||||
).inOrder()
|
||||
assertThat(result).doesNotContain(QuickActionUM.V2.SwapAndSend)
|
||||
}
|
||||
}
|
||||
|
|
@ -104,17 +104,20 @@ internal open class BaseActionsFactory(
|
|||
/**
|
||||
* Determines the unavailability reason for the SELL action
|
||||
*
|
||||
* @param userWalletId the ID of the user's wallet
|
||||
* @param userWallet the user's wallet
|
||||
* @param status the status of the cryptocurrency
|
||||
* @param sendUnavailabilityReason the reason for unavailability of the send action
|
||||
*/
|
||||
protected suspend fun getSellUnavailabilityReason(
|
||||
userWalletId: UserWalletId,
|
||||
userWallet: UserWallet,
|
||||
status: CryptoCurrencyStatus,
|
||||
sendUnavailabilityReason: ScenarioUnavailabilityReason,
|
||||
): ScenarioUnavailabilityReason {
|
||||
if (userWallet is UserWallet.Cold && userWallet.cardTypesResolver.isStart2Coin()) {
|
||||
return ScenarioUnavailabilityReason.NotSupportedBySellService(status.currency.name)
|
||||
}
|
||||
return rampStateManager.availableForSell(
|
||||
userWalletId = userWalletId,
|
||||
userWalletId = userWallet.walletId,
|
||||
status = status,
|
||||
sendUnavailabilityReason = sendUnavailabilityReason,
|
||||
).fold(
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ internal class CommonActionsFactory(
|
|||
|
||||
// region Sell
|
||||
val sellUnavailabilityReason = getSellUnavailabilityReason(
|
||||
userWalletId = userWallet.walletId,
|
||||
userWallet = userWallet,
|
||||
status = cryptoCurrencyStatus,
|
||||
sendUnavailabilityReason = sendUnavailabilityReason,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ internal class OutdatedDataActionsFactory(
|
|||
// region Sell
|
||||
if (sendUnavailabilityReason == ScenarioUnavailabilityReason.None) {
|
||||
val sellUnavailabilityReason = getSellUnavailabilityReason(
|
||||
userWalletId = userWallet.walletId,
|
||||
userWallet = userWallet,
|
||||
status = cryptoCurrencyStatus,
|
||||
sendUnavailabilityReason = sendUnavailabilityReason,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -127,14 +127,16 @@ private fun QuickActionsList(state: TokenActionsUM, modifier: Modifier = Modifie
|
|||
Modifier.testTag(TokenActionsTestTags.BUY_ACTION)
|
||||
else -> Modifier
|
||||
}
|
||||
val isEnabled = actionUM !in state.quickActions.disabledActions
|
||||
TokenActionRow(
|
||||
modifier = actionModifier,
|
||||
iconRes = actionUM.icon,
|
||||
title = actionUM.title,
|
||||
description = actionUM.description,
|
||||
onClick = { state.quickActions.onQuickActionClick(actionUM) },
|
||||
isEnabled = isEnabled,
|
||||
onClick = { state.quickActions.onQuickActionClick(actionUM) }.takeIf { isEnabled },
|
||||
onLongClick = { state.quickActions.onQuickActionLongClick(actionUM) }
|
||||
.takeIf { actionUM.isLongClickAvailable },
|
||||
.takeIf { actionUM.isLongClickAvailable && isEnabled },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue