Updated on 2026-08-14
This commit is contained in:
parent
2e8d0bc03b
commit
298e7a5565
29 changed files with 687 additions and 43 deletions
|
|
@ -25,6 +25,14 @@ internal sealed class SwapChooseTokenNetworkContentUM : TangemBottomSheetConfigC
|
|||
override val messageContent: MessageBottomSheetUM,
|
||||
) : SwapChooseTokenNetworkContentUM()
|
||||
|
||||
/**
|
||||
* Token has no networks available for Send with Swap, but the pair is available in the regular Swap flow.
|
||||
* Informs the user (rendered like [Error], with a different message).
|
||||
*/
|
||||
data class SwapAvailable(
|
||||
override val messageContent: MessageBottomSheetUM,
|
||||
) : SwapChooseTokenNetworkContentUM()
|
||||
|
||||
data class Content(
|
||||
override val messageContent: MessageBottomSheetUM,
|
||||
val swapNetworks: ImmutableList<SwapChooseNetworkUM>,
|
||||
|
|
|
|||
|
|
@ -23,4 +23,24 @@ internal object SwapChooseTokenFactory {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getSwapAvailableMessage(tokenName: String, onSwapClick: () -> Unit): MessageBottomSheetUM {
|
||||
return messageBottomSheetUM {
|
||||
infoBlock {
|
||||
icon(R.drawable.ic_alert_triangle_20) {
|
||||
type = MessageBottomSheetUM.Icon.Type.Attention
|
||||
backgroundType = MessageBottomSheetUM.Icon.BackgroundType.SameAsTint
|
||||
}
|
||||
title = resourceReference(
|
||||
R.string.express_send_with_swap_not_supported_title,
|
||||
wrappedList(tokenName),
|
||||
)
|
||||
body = resourceReference(R.string.express_send_with_swap_not_supported_text)
|
||||
}
|
||||
primaryButton {
|
||||
text = resourceReference(R.string.express_send_with_swap_not_supported_button)
|
||||
onClick { onSwapClick() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -99,12 +99,18 @@ internal class SwapChooseTokenNetworkModel @Inject constructor(
|
|||
}
|
||||
delay(MINIMUM_LOADING_TIME)
|
||||
if (pairs.fromGroup.available.isEmpty()) {
|
||||
analyticsEventHandler.send(
|
||||
val analyticsEvent = if (pairs.fromGroup.availableForSwap.isNotEmpty()) {
|
||||
SendWithSwapAnalyticEvents.NoticeSwapAvailable(
|
||||
fromToken = params.initialCurrency,
|
||||
toTokenSymbol = params.token.symbol,
|
||||
)
|
||||
} else {
|
||||
SendWithSwapAnalyticEvents.NoticeCanNotSwapToken(
|
||||
fromToken = params.initialCurrency,
|
||||
toTokenSymbol = params.token.symbol,
|
||||
),
|
||||
)
|
||||
)
|
||||
}
|
||||
analyticsEventHandler.send(analyticsEvent)
|
||||
}
|
||||
uiState.update(
|
||||
SwapChooseContentStateTransformer(
|
||||
|
|
@ -112,6 +118,7 @@ internal class SwapChooseTokenNetworkModel @Inject constructor(
|
|||
onNetworkClick = ::onSwapTokenClick,
|
||||
tokenName = params.token.name,
|
||||
onDismiss = params.onDismiss,
|
||||
onSwapClick = params.onSwapClick,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import com.tangem.features.swap.v2.impl.choosetoken.fromSupported.entity.SwapCho
|
|||
import com.tangem.features.swap.v2.impl.choosetoken.fromSupported.entity.SwapChooseTokenNetworkContentUM
|
||||
import com.tangem.features.swap.v2.impl.choosetoken.fromSupported.entity.SwapChooseTokenNetworkUM
|
||||
import com.tangem.features.swap.v2.impl.choosetoken.fromSupported.model.SwapChooseTokenFactory.getErrorMessage
|
||||
import com.tangem.features.swap.v2.impl.choosetoken.fromSupported.model.SwapChooseTokenFactory.getSwapAvailableMessage
|
||||
import com.tangem.lib.crypto.BlockchainUtils
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
|
@ -21,6 +22,7 @@ internal class SwapChooseContentStateTransformer(
|
|||
private val tokenName: String,
|
||||
private val onNetworkClick: (SwapCurrencies, CryptoCurrency) -> Unit,
|
||||
private val onDismiss: () -> Unit,
|
||||
private val onSwapClick: (CryptoCurrency) -> Unit,
|
||||
) : Transformer<SwapChooseTokenNetworkUM> {
|
||||
override fun transform(prevState: SwapChooseTokenNetworkUM): SwapChooseTokenNetworkUM {
|
||||
val swapNetworks = pairs.fromGroup.available.map { availableCurrency ->
|
||||
|
|
@ -51,16 +53,26 @@ internal class SwapChooseContentStateTransformer(
|
|||
|
||||
return prevState.copy(
|
||||
bottomSheetConfig = prevState.bottomSheetConfig.copy(
|
||||
content = if (swapNetworks.isNotEmpty()) {
|
||||
SwapChooseTokenNetworkContentUM.Content(
|
||||
content = when {
|
||||
swapNetworks.isNotEmpty() -> SwapChooseTokenNetworkContentUM.Content(
|
||||
swapNetworks = swapNetworks,
|
||||
messageContent = getErrorMessage(
|
||||
tokenName = tokenName,
|
||||
onDismiss = onDismiss,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
SwapChooseTokenNetworkContentUM.Error(
|
||||
// No networks for Send with Swap, but the pair is available in the regular Swap flow
|
||||
pairs.fromGroup.availableForSwap.isNotEmpty() -> {
|
||||
val firstAvailableForSwap = pairs.fromGroup.availableForSwap.first()
|
||||
val swapTargetCurrency = firstAvailableForSwap.currencyStatus.currency
|
||||
SwapChooseTokenNetworkContentUM.SwapAvailable(
|
||||
messageContent = getSwapAvailableMessage(
|
||||
tokenName = tokenName,
|
||||
onSwapClick = { onSwapClick(swapTargetCurrency) },
|
||||
),
|
||||
)
|
||||
}
|
||||
else -> SwapChooseTokenNetworkContentUM.Error(
|
||||
messageContent = getErrorMessage(
|
||||
tokenName = tokenName,
|
||||
onDismiss = onDismiss,
|
||||
|
|
|
|||
|
|
@ -112,6 +112,19 @@ internal sealed class SendWithSwapAnalyticEvents(
|
|||
),
|
||||
)
|
||||
|
||||
/** Token can't be used in Send with Swap, but is available in the regular Swap flow */
|
||||
data class NoticeSwapAvailable(
|
||||
val fromToken: CryptoCurrency,
|
||||
val toTokenSymbol: String,
|
||||
) : SendWithSwapAnalyticEvents(
|
||||
event = "Notice - Swap Available",
|
||||
params = mapOf(
|
||||
SEND_TOKEN to fromToken.symbol,
|
||||
RECEIVE_TOKEN to toTokenSymbol,
|
||||
SEND_BLOCKCHAIN to fromToken.network.name,
|
||||
),
|
||||
)
|
||||
|
||||
data object NoticeFixedRate : SendWithSwapAnalyticEvents(
|
||||
event = "Notice - Fixed Rate",
|
||||
params = emptyMap(),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
package com.tangem.features.swap.v2.impl.choosetoken.fromSupported.model.transformers
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.swap.models.SwapCryptoCurrency
|
||||
import com.tangem.domain.swap.models.SwapCurrencies
|
||||
import com.tangem.domain.swap.models.SwapCurrenciesGroup
|
||||
import com.tangem.features.swap.v2.impl.choosetoken.fromSupported.entity.SwapChooseTokenNetworkContentUM
|
||||
import com.tangem.features.swap.v2.impl.choosetoken.fromSupported.entity.SwapChooseTokenNetworkUM
|
||||
import com.tangem.features.swap.v2.impl.choosetoken.fromSupported.model.SwapChooseTokenFactory
|
||||
import io.mockk.mockk
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
internal class SwapChooseContentStateTransformerTest {
|
||||
|
||||
private val tokenName = "Shiba Inu"
|
||||
|
||||
@Test
|
||||
fun `GIVEN no available but availableForSwap present WHEN transform THEN content is SwapAvailable`() {
|
||||
// Arrange
|
||||
val pairs = swapCurrencies(available = emptyList(), availableForSwap = listOf(swapCryptoCurrency()))
|
||||
|
||||
// Act
|
||||
val result = transformer(pairs).transform(prevState())
|
||||
|
||||
// Assert
|
||||
assertThat(result.bottomSheetConfig.content)
|
||||
.isInstanceOf(SwapChooseTokenNetworkContentUM.SwapAvailable::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN no available and no availableForSwap WHEN transform THEN content is Error`() {
|
||||
// Arrange
|
||||
val pairs = swapCurrencies(available = emptyList(), availableForSwap = emptyList())
|
||||
|
||||
// Act
|
||||
val result = transformer(pairs).transform(prevState())
|
||||
|
||||
// Assert
|
||||
assertThat(result.bottomSheetConfig.content)
|
||||
.isInstanceOf(SwapChooseTokenNetworkContentUM.Error::class.java)
|
||||
}
|
||||
|
||||
private fun transformer(pairs: SwapCurrencies) = SwapChooseContentStateTransformer(
|
||||
pairs = pairs,
|
||||
tokenName = tokenName,
|
||||
onNetworkClick = { _, _ -> },
|
||||
onDismiss = {},
|
||||
onSwapClick = {},
|
||||
)
|
||||
|
||||
private fun swapCurrencies(
|
||||
available: List<SwapCryptoCurrency>,
|
||||
availableForSwap: List<SwapCryptoCurrency>,
|
||||
): SwapCurrencies = SwapCurrencies.EMPTY.copy(
|
||||
fromGroup = SwapCurrenciesGroup(
|
||||
available = available,
|
||||
unavailable = emptyList(),
|
||||
isAfterSearch = false,
|
||||
availableForSwap = availableForSwap,
|
||||
),
|
||||
)
|
||||
|
||||
private fun swapCryptoCurrency(): SwapCryptoCurrency = SwapCryptoCurrency(
|
||||
currencyStatus = CryptoCurrencyStatus(currency = mockk<CryptoCurrency>(relaxed = true), value = mockk(relaxed = true)),
|
||||
providers = emptyList(),
|
||||
)
|
||||
|
||||
private fun prevState(): SwapChooseTokenNetworkUM = SwapChooseTokenNetworkUM(
|
||||
bottomSheetConfig = TangemBottomSheetConfig(
|
||||
isShown = true,
|
||||
onDismissRequest = {},
|
||||
content = SwapChooseTokenNetworkContentUM.Loading(
|
||||
messageContent = SwapChooseTokenFactory.getErrorMessage(tokenName = tokenName, onDismiss = {}),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue