Updated on 2026-08-14

This commit is contained in:
Tangem 2024-04-12 11:35:09 +02:00
parent d32b504a80
commit 4021127ae9
19 changed files with 543 additions and 160 deletions

View file

@ -73,9 +73,9 @@ class GetCryptoCurrencyActionsUseCase(
walletId = userWallet.walletId,
cryptoCurrencyStatus = cryptoCurrencyStatus,
states = createListOfActions(
userWallet,
coinStatus,
cryptoCurrencyStatus,
userWallet = userWallet,
coinStatus = coinStatus,
cryptoCurrencyStatus = cryptoCurrencyStatus,
),
)
}
@ -91,7 +91,7 @@ class GetCryptoCurrencyActionsUseCase(
): List<TokenActionsState.ActionState> {
val cryptoCurrency = cryptoCurrencyStatus.currency
if (cryptoCurrencyStatus.value is CryptoCurrencyStatus.MissedDerivation) {
return listOf(TokenActionsState.ActionState.HideToken(true))
return listOf(TokenActionsState.ActionState.HideToken(ScenarioUnavailabilityReason.None))
}
if (cryptoCurrencyStatus.value is CryptoCurrencyStatus.Unreachable) {
return getActionsForUnreachableCurrency(cryptoCurrencyStatus)
@ -102,52 +102,61 @@ class GetCryptoCurrencyActionsUseCase(
// copy address
if (isAddressAvailable(cryptoCurrencyStatus.value.networkAddress)) {
activeList.add(TokenActionsState.ActionState.CopyAddress(true))
activeList.add(TokenActionsState.ActionState.CopyAddress(ScenarioUnavailabilityReason.None))
}
// receive
if (isAddressAvailable(cryptoCurrencyStatus.value.networkAddress)) {
activeList.add(TokenActionsState.ActionState.Receive(true))
activeList.add(TokenActionsState.ActionState.Receive(ScenarioUnavailabilityReason.None))
}
// send
if (
isSendDisabled(
userWalletId = userWallet.walletId,
cryptoCurrencyStatus = cryptoCurrencyStatus,
coinStatus = coinStatus,
)
) {
disabledList.add(TokenActionsState.ActionState.Send(false))
val sendUnavailabilityReason = getSendUnavailabilityReason(
userWalletId = userWallet.walletId,
cryptoCurrencyStatus = cryptoCurrencyStatus,
coinStatus = coinStatus,
)
if (sendUnavailabilityReason == ScenarioUnavailabilityReason.None) {
activeList.add(TokenActionsState.ActionState.Send(sendUnavailabilityReason))
} else {
activeList.add(TokenActionsState.ActionState.Send(true))
disabledList.add(TokenActionsState.ActionState.Send(sendUnavailabilityReason))
}
// swap
if (userWallet.isMultiCurrency) {
if (marketCryptoCurrencyRepository.isExchangeable(userWallet.walletId, cryptoCurrency)) {
activeList.add(TokenActionsState.ActionState.Swap(true))
activeList.add(TokenActionsState.ActionState.Swap(ScenarioUnavailabilityReason.None))
} else {
disabledList.add(TokenActionsState.ActionState.Swap(false))
disabledList.add(
TokenActionsState.ActionState.Swap(
unavailabilityReason = ScenarioUnavailabilityReason.NotExchangeable(cryptoCurrency.name),
),
)
}
}
// buy
if (rampManager.availableForBuy(cryptoCurrency)) {
activeList.add(TokenActionsState.ActionState.Buy(true))
activeList.add(TokenActionsState.ActionState.Buy(ScenarioUnavailabilityReason.None))
} else {
disabledList.add(TokenActionsState.ActionState.Buy(false))
disabledList.add(
TokenActionsState.ActionState.Buy(ScenarioUnavailabilityReason.BuyUnavailable(cryptoCurrency.symbol)),
)
}
// sell
if (rampManager.availableForSell(cryptoCurrency)) {
activeList.add(TokenActionsState.ActionState.Sell(true))
activeList.add(TokenActionsState.ActionState.Sell(ScenarioUnavailabilityReason.None))
} else {
disabledList.add(TokenActionsState.ActionState.Sell(false))
disabledList.add(
TokenActionsState.ActionState.Sell(
unavailabilityReason = ScenarioUnavailabilityReason.SellUnavailable(cryptoCurrency.name),
),
)
}
// hide
activeList.add(TokenActionsState.ActionState.HideToken(true))
activeList.add(TokenActionsState.ActionState.HideToken(ScenarioUnavailabilityReason.None))
return activeList + disabledList
}
@ -155,63 +164,140 @@ class GetCryptoCurrencyActionsUseCase(
private fun getActionsForUnreachableCurrency(
cryptoCurrencyStatus: CryptoCurrencyStatus,
): List<TokenActionsState.ActionState> {
val activeList = mutableListOf<TokenActionsState.ActionState>()
val disabledList = mutableListOf<TokenActionsState.ActionState>()
val actionsList = mutableListOf<TokenActionsState.ActionState>()
if (isAddressAvailable(cryptoCurrencyStatus.value.networkAddress)) {
activeList.add(TokenActionsState.ActionState.CopyAddress(true))
actionsList.add(TokenActionsState.ActionState.CopyAddress(ScenarioUnavailabilityReason.None))
}
if (rampManager.availableForBuy(cryptoCurrencyStatus.currency)) {
activeList.add(TokenActionsState.ActionState.Buy(true))
actionsList.add(TokenActionsState.ActionState.Buy(ScenarioUnavailabilityReason.None))
} else {
disabledList.add(TokenActionsState.ActionState.Buy(false))
actionsList.add(
TokenActionsState.ActionState.Buy(
ScenarioUnavailabilityReason.BuyUnavailable(
cryptoCurrencyName = cryptoCurrencyStatus.currency.name,
),
),
)
}
disabledList.add(TokenActionsState.ActionState.Send(false))
disabledList.add(TokenActionsState.ActionState.Swap(false))
disabledList.add(TokenActionsState.ActionState.Sell(false))
actionsList.add(TokenActionsState.ActionState.Send(ScenarioUnavailabilityReason.NoQuotes))
actionsList.add(TokenActionsState.ActionState.Swap(ScenarioUnavailabilityReason.NoQuotes))
actionsList.add(TokenActionsState.ActionState.Sell(ScenarioUnavailabilityReason.NoQuotes))
if (isAddressAvailable(cryptoCurrencyStatus.value.networkAddress)) {
activeList.add(TokenActionsState.ActionState.Receive(true))
actionsList.add(TokenActionsState.ActionState.Receive(ScenarioUnavailabilityReason.None))
}
activeList.add(TokenActionsState.ActionState.HideToken(true))
return activeList + disabledList
actionsList.add(TokenActionsState.ActionState.HideToken(ScenarioUnavailabilityReason.None))
return actionsList
}
private suspend fun isSendDisabled(
private suspend fun getSendUnavailabilityReason(
userWalletId: UserWalletId,
cryptoCurrencyStatus: CryptoCurrencyStatus,
coinStatus: CryptoCurrencyStatus?,
): Boolean {
val feePaidCurrency = currenciesRepository.getFeePaidCurrency(userWalletId, cryptoCurrencyStatus.currency)
val notEnoughBalanceForFee = isNotEnoughBalanceForFee(
feePaidCurrency = feePaidCurrency,
): ScenarioUnavailabilityReason {
val insufficientFundsForFee = insufficientFundsForFee(
userWalletId = userWalletId,
tokenStatus = cryptoCurrencyStatus,
coinStatus = coinStatus,
)
return cryptoCurrencyStatus.value.amount.isNullOrZero() ||
notEnoughBalanceForFee ||
return when {
cryptoCurrencyStatus.value.amount.isNullOrZero() -> {
ScenarioUnavailabilityReason.EmptyBalance
}
insufficientFundsForFee != null -> {
ScenarioUnavailabilityReason.InsufficientFundsForFee(
currencyName = insufficientFundsForFee.currencyName,
networkName = insufficientFundsForFee.networkName,
feeCurrencyName = insufficientFundsForFee.feeCurrencyName,
feeCurrencySymbol = insufficientFundsForFee.feeCurrencySymbol,
)
}
currenciesRepository.hasPendingTransactions(
cryptoCurrencyStatus = cryptoCurrencyStatus,
coinStatus = coinStatus,
)
) -> {
ScenarioUnavailabilityReason.PendingTransaction(coinStatus?.currency?.symbol.orEmpty())
}
else -> {
ScenarioUnavailabilityReason.None
}
}
}
private fun isNotEnoughBalanceForFee(
feePaidCurrency: FeePaidCurrency,
private suspend fun insufficientFundsForFee(
userWalletId: UserWalletId,
tokenStatus: CryptoCurrencyStatus,
coinStatus: CryptoCurrencyStatus?,
): Boolean {
return if (sendFeatureToggles.isRedesignedSendEnabled) {
tokenStatus.value.amount.isZero()
} else {
when (feePaidCurrency) {
FeePaidCurrency.Coin -> !tokenStatus.value.amount.isZero() && coinStatus?.value?.amount.isZero()
FeePaidCurrency.SameCurrency -> tokenStatus.value.amount.isZero()
is FeePaidCurrency.Token -> {
val feePaidTokenBalance = feePaidCurrency.balance
!tokenStatus.value.amount.isZero() && feePaidTokenBalance.isZero()
): FeeInfo? {
val feePaidCurrency = currenciesRepository.getFeePaidCurrency(userWalletId, tokenStatus.currency)
coinStatus ?: return null
return when {
sendFeatureToggles.isRedesignedSendEnabled && !tokenStatus.value.amount.isZero() -> {
null
}
feePaidCurrency is FeePaidCurrency.Coin &&
!tokenStatus.value.amount.isZero() &&
coinStatus.value.amount.isZero() -> {
FeeInfo(
currencyName = tokenStatus.currency.name,
networkName = coinStatus.currency.network.name,
feeCurrencyName = coinStatus.currency.name,
feeCurrencySymbol = coinStatus.currency.symbol,
)
}
feePaidCurrency is FeePaidCurrency.SameCurrency && !tokenStatus.value.amount.isZero() -> {
FeeInfo(
currencyName = tokenStatus.currency.name,
networkName = coinStatus.currency.network.name,
feeCurrencyName = coinStatus.currency.name,
feeCurrencySymbol = coinStatus.currency.symbol,
)
}
feePaidCurrency is FeePaidCurrency.Token -> {
val feePaidTokenBalance = feePaidCurrency.balance
val amount = tokenStatus.value.amount ?: return null
if (!amount.isZero() && feePaidTokenBalance.isZero()) {
constructTokenBalanceNotEnoughWarning(
userWalletId = userWalletId,
tokenStatus = tokenStatus,
feePaidToken = feePaidCurrency,
)
} else {
null
}
}
else -> null
}
}
private suspend fun constructTokenBalanceNotEnoughWarning(
userWalletId: UserWalletId,
tokenStatus: CryptoCurrencyStatus,
feePaidToken: FeePaidCurrency.Token,
): FeeInfo {
val token = currenciesRepository
.getMultiCurrencyWalletCurrenciesSync(userWalletId)
.find {
it is CryptoCurrency.Token &&
it.contractAddress.equals(feePaidToken.contractAddress, ignoreCase = true) &&
it.network.derivationPath == tokenStatus.currency.network.derivationPath
}
return if (token != null) {
FeeInfo(
currencyName = tokenStatus.currency.name,
networkName = token.network.name,
feeCurrencyName = feePaidToken.name,
feeCurrencySymbol = feePaidToken.symbol,
)
} else {
FeeInfo(
currencyName = tokenStatus.currency.name,
networkName = tokenStatus.currency.network.name,
feeCurrencyName = feePaidToken.name,
feeCurrencySymbol = feePaidToken.symbol,
)
}
}
@ -222,4 +308,11 @@ class GetCryptoCurrencyActionsUseCase(
private fun BigDecimal?.isZero(): Boolean {
return this?.signum() == 0
}
data class FeeInfo(
val currencyName: String,
val networkName: String,
val feeCurrencyName: String,
val feeCurrencySymbol: String,
)
}

View file

@ -0,0 +1,26 @@
package com.tangem.domain.tokens.model
sealed class ScenarioUnavailabilityReason {
data object None : ScenarioUnavailabilityReason()
// send-specific
data class PendingTransaction(val cryptoCurrencySymbol: String) : ScenarioUnavailabilityReason()
data object EmptyBalance : ScenarioUnavailabilityReason()
data class InsufficientFundsForFee(
val currencyName: String,
val networkName: String,
val feeCurrencyName: String,
val feeCurrencySymbol: String,
) : ScenarioUnavailabilityReason()
// buy-specific
data class BuyUnavailable(val cryptoCurrencyName: String) : ScenarioUnavailabilityReason()
// swap-specific
data class NotExchangeable(val cryptoCurrencyName: String) : ScenarioUnavailabilityReason()
// sell-specific
data class SellUnavailable(val cryptoCurrencyName: String) : ScenarioUnavailabilityReason()
data object NoQuotes : ScenarioUnavailabilityReason()
}

View file

@ -10,20 +10,20 @@ data class TokenActionsState(
sealed class ActionState {
abstract val enabled: Boolean
abstract val unavailabilityReason: ScenarioUnavailabilityReason
data class Buy(override val enabled: Boolean) : ActionState()
data class Buy(override val unavailabilityReason: ScenarioUnavailabilityReason) : ActionState()
data class CopyAddress(override val enabled: Boolean) : ActionState()
data class CopyAddress(override val unavailabilityReason: ScenarioUnavailabilityReason) : ActionState()
data class Sell(override val enabled: Boolean) : ActionState()
data class Sell(override val unavailabilityReason: ScenarioUnavailabilityReason) : ActionState()
data class Receive(override val enabled: Boolean) : ActionState()
data class Receive(override val unavailabilityReason: ScenarioUnavailabilityReason) : ActionState()
data class Swap(override val enabled: Boolean) : ActionState()
data class Swap(override val unavailabilityReason: ScenarioUnavailabilityReason) : ActionState()
data class Send(override val enabled: Boolean) : ActionState()
data class Send(override val unavailabilityReason: ScenarioUnavailabilityReason) : ActionState()
data class HideToken(override val enabled: Boolean) : ActionState()
data class HideToken(override val unavailabilityReason: ScenarioUnavailabilityReason) : ActionState()
}
}

View file

@ -72,10 +72,10 @@ internal object TokenDetailsPreviewData {
)
private val actionButtons = persistentListOf(
TokenDetailsActionButton.Buy(enabled = true, onClick = {}),
TokenDetailsActionButton.Send(enabled = true, onClick = {}),
TokenDetailsActionButton.Buy(dimContent = false, onClick = {}),
TokenDetailsActionButton.Send(dimContent = false, onClick = {}),
TokenDetailsActionButton.Receive(onClick = {}),
TokenDetailsActionButton.Swap(enabled = true, onClick = {}),
TokenDetailsActionButton.Swap(dimContent = false, onClick = {}),
)
val balanceLoading = TokenDetailsBalanceBlockState.Loading(actionButtons = actionButtons)

View file

@ -14,36 +14,35 @@ internal sealed class TokenDetailsActionButton(val config: ActionButtonConfig) {
/**
* Buy
*
* @property enabled button click availability
* @property dimContent determines whether the button content will be dimmed
* @property onClick lambda be invoked when Buy button is clicked
*/
data class Buy(val enabled: Boolean, override val onClick: () -> Unit) : TokenDetailsActionButton(
data class Buy(val dimContent: Boolean, override val onClick: () -> Unit) : TokenDetailsActionButton(
config = ActionButtonConfig(
text = TextReference.Res(id = R.string.common_buy),
iconResId = R.drawable.ic_plus_24,
onClick = onClick,
enabled = enabled,
dimContent = dimContent,
),
)
/**
* Send
*
* @property enabled button click availability
* @property dimContent determines whether the button content will be dimmed
* @property onClick lambda be invoked when Send button is clicked
*/
data class Send(val enabled: Boolean, override val onClick: () -> Unit) : TokenDetailsActionButton(
data class Send(val dimContent: Boolean, override val onClick: () -> Unit) : TokenDetailsActionButton(
config = ActionButtonConfig(
text = TextReference.Res(id = R.string.common_send),
iconResId = R.drawable.ic_arrow_up_24,
onClick = onClick,
enabled = enabled,
dimContent = dimContent,
),
)
/**
* Receive
*
* @property onClick lambda be invoked when Receive button is clicked
*/
data class Receive(override val onClick: () -> Unit) : TokenDetailsActionButton(
@ -58,30 +57,30 @@ internal sealed class TokenDetailsActionButton(val config: ActionButtonConfig) {
/**
* Sell
*
* @property enabled button click availability
* @property dimContent determines whether the button content will be dimmed
* @property onClick lambda be invoked when Sell button is clicked
*/
data class Sell(val enabled: Boolean, override val onClick: () -> Unit) : TokenDetailsActionButton(
data class Sell(val dimContent: Boolean, override val onClick: () -> Unit) : TokenDetailsActionButton(
config = ActionButtonConfig(
text = TextReference.Res(id = R.string.common_sell),
iconResId = R.drawable.ic_currency_24,
onClick = onClick,
enabled = enabled,
dimContent = dimContent,
),
)
/**
* Swap
*
* @property enabled button click availability
* @property dimContent determines whether the button content will be dimmed
* @property onClick lambda be invoked when Swap button is clicked
*/
data class Swap(val enabled: Boolean, override val onClick: () -> Unit) : TokenDetailsActionButton(
data class Swap(val dimContent: Boolean, override val onClick: () -> Unit) : TokenDetailsActionButton(
config = ActionButtonConfig(
text = TextReference.Res(id = R.string.swapping_swap_action),
iconResId = R.drawable.ic_exchange_vertical_24,
onClick = onClick,
enabled = enabled,
dimContent = dimContent,
),
)
}

View file

@ -19,7 +19,7 @@ internal data class TokenDetailsDialogConfig(
sealed class DialogContentConfig {
abstract val title: TextReference
abstract val title: TextReference?
abstract val message: TextReference
abstract val confirmButtonConfig: ButtonConfig
abstract val cancelButtonConfig: ButtonConfig?
@ -77,5 +77,22 @@ internal data class TokenDetailsDialogConfig(
onClick = onConfirmClick,
)
}
data class DisabledButtonReasonDialogConfig(
val text: TextReference,
val onConfirmClick: () -> Unit,
) : DialogContentConfig() {
override val title = null
override val message: TextReference = text
override val cancelButtonConfig = null
override val confirmButtonConfig: ButtonConfig = ButtonConfig(
text = TextReference.Res(R.string.common_ok),
onClick = onConfirmClick,
)
}
}
}

View file

@ -1,5 +1,6 @@
package com.tangem.feature.tokendetails.presentation.tokendetails.state.factory
import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason
import com.tangem.domain.tokens.model.TokenActionsState
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsActionButton
@ -26,19 +27,33 @@ internal class TokenDetailsActionButtonsConverter(
.mapNotNull { action ->
when (action) {
is TokenActionsState.ActionState.Buy -> {
TokenDetailsActionButton.Buy(enabled = action.enabled, onClick = clickIntents::onBuyClick)
TokenDetailsActionButton.Buy(
dimContent = action.unavailabilityReason != ScenarioUnavailabilityReason.None,
onClick = { clickIntents.onBuyClick(action.unavailabilityReason) },
)
}
is TokenActionsState.ActionState.Receive -> {
TokenDetailsActionButton.Receive(onClick = clickIntents::onReceiveClick)
TokenDetailsActionButton.Receive(
onClick = { clickIntents.onReceiveClick(action.unavailabilityReason) },
)
}
is TokenActionsState.ActionState.Sell -> {
TokenDetailsActionButton.Sell(enabled = action.enabled, onClick = clickIntents::onSellClick)
TokenDetailsActionButton.Sell(
dimContent = action.unavailabilityReason != ScenarioUnavailabilityReason.None,
onClick = { clickIntents.onSellClick(action.unavailabilityReason) },
)
}
is TokenActionsState.ActionState.Send -> {
TokenDetailsActionButton.Send(enabled = action.enabled, onClick = clickIntents::onSendClick)
TokenDetailsActionButton.Send(
dimContent = action.unavailabilityReason != ScenarioUnavailabilityReason.None,
onClick = { clickIntents.onSendClick(action.unavailabilityReason) },
)
}
is TokenActionsState.ActionState.Swap -> {
TokenDetailsActionButton.Swap(enabled = action.enabled, onClick = clickIntents::onSwapClick)
TokenDetailsActionButton.Swap(
dimContent = action.unavailabilityReason != ScenarioUnavailabilityReason.None,
onClick = { clickIntents.onSwapClick(action.unavailabilityReason) },
)
}
else -> {
null

View file

@ -84,11 +84,11 @@ internal class TokenDetailsSkeletonStateConverter(
private fun createButtons(): ImmutableList<TokenDetailsActionButton> {
return persistentListOf(
TokenDetailsActionButton.Buy(enabled = false, onClick = {}),
TokenDetailsActionButton.Send(enabled = false, onClick = {}),
TokenDetailsActionButton.Buy(dimContent = false, onClick = {}),
TokenDetailsActionButton.Send(dimContent = false, onClick = {}),
TokenDetailsActionButton.Receive(onClick = {}),
TokenDetailsActionButton.Sell(enabled = false, onClick = {}),
TokenDetailsActionButton.Swap(enabled = false, onClick = {}),
TokenDetailsActionButton.Sell(dimContent = false, onClick = {}),
TokenDetailsActionButton.Swap(dimContent = false, onClick = {}),
)
}

View file

@ -10,16 +10,12 @@ import com.tangem.core.ui.components.transactions.state.TransactionState
import com.tangem.core.ui.components.transactions.state.TxHistoryState
import com.tangem.core.ui.event.consumedEvent
import com.tangem.core.ui.event.triggeredEvent
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.*
import com.tangem.core.ui.res.TangemTheme
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.tokens.error.CurrencyStatusError
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.NetworkAddress
import com.tangem.domain.tokens.model.TokenActionsState
import com.tangem.domain.tokens.model.*
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning
import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.domain.txhistory.models.TxHistoryListError
@ -39,8 +35,9 @@ import com.tangem.utils.Provider
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import java.lang.IllegalArgumentException
@Suppress("TooManyFunctions")
@Suppress("TooManyFunctions", "LargeClass")
internal class TokenDetailsStateFactory(
private val currentStateProvider: Provider<TokenDetailsState>,
private val appCurrencyProvider: Provider<AppCurrency>,
@ -177,6 +174,19 @@ internal class TokenDetailsStateFactory(
)
}
fun getStateWithActionButtonErrorDialog(unavailabilityReason: ScenarioUnavailabilityReason): TokenDetailsState {
return currentStateProvider().copy(
dialogConfig = TokenDetailsDialogConfig(
isShow = true,
onDismissRequest = clickIntents::onDismissDialog,
content = TokenDetailsDialogConfig.DialogContentConfig.DisabledButtonReasonDialogConfig(
text = getUnavailabilityReasonText(unavailabilityReason),
onConfirmClick = clickIntents::onDismissDialog,
),
),
)
}
fun getRefreshingState(): TokenDetailsState {
return refreshStateConverter.convert(true)
}
@ -321,4 +331,60 @@ internal class TokenDetailsStateFactory(
}.toImmutableList(),
)
}
private fun getUnavailabilityReasonText(unavailabilityReason: ScenarioUnavailabilityReason): TextReference {
return when (unavailabilityReason) {
// send
is ScenarioUnavailabilityReason.PendingTransaction -> {
resourceReference(
id = R.string.warning_send_blocked_pending_transactions_message,
formatArgs = wrappedList(unavailabilityReason.cryptoCurrencySymbol),
)
}
ScenarioUnavailabilityReason.EmptyBalance -> {
resourceReference(
id = R.string.token_button_unavailability_reason_empty_balance,
)
}
is ScenarioUnavailabilityReason.InsufficientFundsForFee -> {
resourceReference(
id = R.string.warning_send_blocked_funds_for_fee_message,
formatArgs = wrappedList(
unavailabilityReason.currencyName,
unavailabilityReason.networkName,
unavailabilityReason.currencyName,
unavailabilityReason.feeCurrencyName,
unavailabilityReason.feeCurrencySymbol,
),
)
}
is ScenarioUnavailabilityReason.BuyUnavailable -> {
resourceReference(
id = R.string.token_button_unavailability_reason_buy_unavailable,
formatArgs = wrappedList(unavailabilityReason.cryptoCurrencyName),
)
}
is ScenarioUnavailabilityReason.NotExchangeable -> {
resourceReference(
id = R.string.token_button_unavailability_reason_not_exchangeable,
formatArgs = wrappedList(unavailabilityReason.cryptoCurrencyName),
)
}
is ScenarioUnavailabilityReason.SellUnavailable -> {
resourceReference(
id = R.string.token_button_unavailability_reason_sell_unavailable,
formatArgs = wrappedList(unavailabilityReason.cryptoCurrencyName),
)
}
ScenarioUnavailabilityReason.NoQuotes -> {
resourceReference(
id = R.string.token_button_unavailability_reason_no_quotes,
)
}
ScenarioUnavailabilityReason.None -> {
throw IllegalArgumentException("The unavailability reason must be other than None")
}
}
}
}

View file

@ -25,7 +25,7 @@ private fun TokenDetailsDialog(config: TokenDetailsDialogConfig) {
onClick = config.content.confirmButtonConfig.onClick,
),
onDismissDialog = config.onDismissRequest,
title = config.content.title.resolveReference(),
title = config.content.title?.resolveReference(),
dismissButton = config.content.cancelButtonConfig?.let { cancelButtonConfig ->
DialogButton(
title = cancelButtonConfig.text.resolveReference(),

View file

@ -1,6 +1,7 @@
package com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels
import com.tangem.core.ui.components.bottomsheets.tokenreceive.AddressModel
import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason
import com.tangem.domain.tokens.model.CryptoCurrency
@Suppress("TooManyFunctions")
@ -8,13 +9,15 @@ interface TokenDetailsClickIntents {
fun onBackClick()
fun onSendClick()
fun onReceiveClick(unavailabilityReason: ScenarioUnavailabilityReason)
fun onReceiveClick()
fun onSendClick(unavailabilityReason: ScenarioUnavailabilityReason)
fun onSellClick()
fun onSwapClick(unavailabilityReason: ScenarioUnavailabilityReason)
fun onSwapClick()
fun onBuyClick(unavailabilityReason: ScenarioUnavailabilityReason)
fun onSellClick(unavailabilityReason: ScenarioUnavailabilityReason)
fun onDismissDialog()
@ -24,8 +27,6 @@ interface TokenDetailsClickIntents {
fun onRefreshSwipe()
fun onBuyClick()
fun onBuyCoinClick(cryptoCurrency: CryptoCurrency)
fun onReloadClick()

View file

@ -26,6 +26,7 @@ import com.tangem.domain.settings.ShouldShowSwapPromoTokenUseCase
import com.tangem.domain.tokens.*
import com.tangem.domain.tokens.legacy.TradeCryptoAction
import com.tangem.domain.tokens.legacy.TradeCryptoAction.TransactionInfo
import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.NetworkAddress
@ -388,9 +389,11 @@ internal class TokenDetailsViewModel @Inject constructor(
router.popBackStack()
}
override fun onBuyClick() {
override fun onBuyClick(unavailabilityReason: ScenarioUnavailabilityReason) {
analyticsEventsHandler.send(TokenScreenAnalyticsEvent.ButtonBuy(cryptoCurrency.symbol))
if (handleUnavailabilityReason(unavailabilityReason)) return
showErrorIfDemoModeOrElse {
val status = cryptoCurrencyStatus ?: return@showErrorIfDemoModeOrElse
@ -417,9 +420,11 @@ internal class TokenDetailsViewModel @Inject constructor(
updateTxHistory(refresh = true, showItemsLoading = true)
}
override fun onSendClick() {
override fun onSendClick(unavailabilityReason: ScenarioUnavailabilityReason) {
analyticsEventsHandler.send(TokenScreenAnalyticsEvent.ButtonSend(cryptoCurrency.symbol))
if (handleUnavailabilityReason(unavailabilityReason)) return
sendCurrency(status = cryptoCurrencyStatus ?: return)
}
@ -485,9 +490,11 @@ internal class TokenDetailsViewModel @Inject constructor(
}
}
override fun onReceiveClick() {
override fun onReceiveClick(unavailabilityReason: ScenarioUnavailabilityReason) {
val networkAddress = cryptoCurrencyStatus?.value?.networkAddress ?: return
if (handleUnavailabilityReason(unavailabilityReason)) return
viewModelScope.launch(dispatchers.io) {
analyticsEventsHandler.send(TokenScreenAnalyticsEvent.ButtonReceive(cryptoCurrency.symbol))
analyticsEventsHandler.send(TokenReceiveAnalyticsEvent.ReceiveScreenOpened)
@ -523,9 +530,11 @@ internal class TokenDetailsViewModel @Inject constructor(
}
}
override fun onSellClick() {
override fun onSellClick(unavailabilityReason: ScenarioUnavailabilityReason) {
analyticsEventsHandler.send(TokenScreenAnalyticsEvent.ButtonSell(cryptoCurrency.symbol))
if (handleUnavailabilityReason(unavailabilityReason)) return
showErrorIfDemoModeOrElse {
val status = cryptoCurrencyStatus ?: return@showErrorIfDemoModeOrElse
@ -538,9 +547,11 @@ internal class TokenDetailsViewModel @Inject constructor(
}
}
override fun onSwapClick() {
override fun onSwapClick(unavailabilityReason: ScenarioUnavailabilityReason) {
analyticsEventsHandler.send(TokenScreenAnalyticsEvent.ButtonExchange(cryptoCurrency.symbol))
if (handleUnavailabilityReason(unavailabilityReason)) return
reduxStateHolder.dispatch(TradeCryptoAction.Swap(cryptoCurrency))
}
@ -697,7 +708,15 @@ internal class TokenDetailsViewModel @Inject constructor(
shouldShowSwapPromoTokenUseCase.neverToShow()
analyticsEventsHandler.send(TokenSwapPromoAnalyticsEvent.Exchange(cryptoCurrency.symbol))
}
onSwapClick()
onSwapClick(ScenarioUnavailabilityReason.None)
}
private fun handleUnavailabilityReason(unavailabilityReason: ScenarioUnavailabilityReason): Boolean {
if (unavailabilityReason == ScenarioUnavailabilityReason.None) return false
uiState = stateFactory.getStateWithActionButtonErrorDialog(unavailabilityReason)
return true
}
private companion object {

View file

@ -28,7 +28,7 @@ internal sealed interface WalletAlertState {
}
data class DefaultAlert(
override val title: TextReference,
override val title: TextReference?,
override val message: TextReference,
override val onConfirmClick: (() -> Unit)?,
) : Basic()

View file

@ -18,6 +18,9 @@ internal sealed class WalletManageButton(val config: ActionButtonConfig) {
/** Is click enabled */
abstract val enabled: Boolean
/** Whether to dim content */
abstract val dimContent: Boolean
/** Lambda be invoked when manage button is clicked */
abstract val onClick: () -> Unit
@ -25,29 +28,40 @@ internal sealed class WalletManageButton(val config: ActionButtonConfig) {
* Buy
*
* @property enabled button click availability
* @property dimContent determines whether the button content will be dimmed
* @property onClick lambda be invoked when Buy button is clicked
*/
data class Buy(override val enabled: Boolean, override val onClick: () -> Unit) : WalletManageButton(
config = ActionButtonConfig(
text = TextReference.Res(id = R.string.common_buy),
iconResId = R.drawable.ic_plus_24,
onClick = onClick,
enabled = enabled,
),
)
data class Buy(
override val enabled: Boolean,
override val dimContent: Boolean,
override val onClick: () -> Unit,
) :
WalletManageButton(
config = ActionButtonConfig(
text = TextReference.Res(id = R.string.common_buy),
iconResId = R.drawable.ic_plus_24,
onClick = onClick,
dimContent = dimContent,
),
)
/**
* Send
*
* @property enabled button click availability
* @property dimContent determines whether the button content will be dimmed
* @property onClick lambda be invoked when Send button is clicked
*/
data class Send(override val enabled: Boolean, override val onClick: () -> Unit) : WalletManageButton(
data class Send(
override val enabled: Boolean,
override val dimContent: Boolean,
override val onClick: () -> Unit,
) : WalletManageButton(
config = ActionButtonConfig(
text = TextReference.Res(id = R.string.common_send),
iconResId = R.drawable.ic_arrow_up_24,
onClick = onClick,
enabled = enabled,
dimContent = dimContent,
),
)
@ -56,12 +70,16 @@ internal sealed class WalletManageButton(val config: ActionButtonConfig) {
*
* @property onClick lambda be invoked when Receive button is clicked
*/
data class Receive(override val enabled: Boolean, override val onClick: () -> Unit) : WalletManageButton(
data class Receive(
override val enabled: Boolean,
override val dimContent: Boolean,
override val onClick: () -> Unit,
) : WalletManageButton(
config = ActionButtonConfig(
text = TextReference.Res(id = R.string.common_receive),
iconResId = R.drawable.ic_arrow_down_24,
onClick = onClick,
enabled = enabled,
dimContent = dimContent,
),
)
@ -69,14 +87,19 @@ internal sealed class WalletManageButton(val config: ActionButtonConfig) {
* Sell
*
* @property enabled button click availability
* @property dimContent determines whether the button content will be dimmed
* @property onClick lambda be invoked when Sell button is clicked
*/
data class Sell(override val enabled: Boolean, override val onClick: () -> Unit) : WalletManageButton(
data class Sell(
override val enabled: Boolean,
override val dimContent: Boolean,
override val onClick: () -> Unit,
) : WalletManageButton(
config = ActionButtonConfig(
text = TextReference.Res(id = R.string.common_sell),
iconResId = R.drawable.ic_currency_24,
onClick = onClick,
enabled = enabled,
dimContent = dimContent,
),
)
@ -84,14 +107,19 @@ internal sealed class WalletManageButton(val config: ActionButtonConfig) {
* Swap
*
* @property enabled button click availability
* @property dimContent determines whether the button content will be dimmed
* @property onClick lambda be invoked when Swap button is clicked
*/
data class Swap(override val enabled: Boolean, override val onClick: () -> Unit) : WalletManageButton(
data class Swap(
override val enabled: Boolean,
override val dimContent: Boolean,
override val onClick: () -> Unit,
) : WalletManageButton(
config = ActionButtonConfig(
text = TextReference.Res(id = R.string.swapping_swap_action),
iconResId = R.drawable.ic_exchange_vertical_24,
onClick = onClick,
enabled = enabled,
dimContent = dimContent,
),
)
}

View file

@ -85,10 +85,10 @@ internal class InitializeWalletsTransformer(
private fun createDisabledButtons(): PersistentList<WalletManageButton> {
return persistentListOf(
WalletManageButton.Buy(enabled = false, onClick = {}),
WalletManageButton.Send(enabled = false, onClick = {}),
WalletManageButton.Receive(enabled = false, onClick = {}),
WalletManageButton.Sell(enabled = false, onClick = {}),
WalletManageButton.Receive(enabled = false, dimContent = false, onClick = {}),
WalletManageButton.Send(enabled = false, dimContent = false, onClick = {}),
WalletManageButton.Buy(enabled = false, dimContent = false, onClick = {}),
WalletManageButton.Sell(enabled = false, dimContent = false, onClick = {}),
)
}
}

View file

@ -1,6 +1,7 @@
package com.tangem.feature.wallet.presentation.wallet.state.transformers
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason
import com.tangem.domain.tokens.model.TokenActionsState
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletManageButton
@ -43,26 +44,47 @@ internal class SetCryptoCurrencyActionsTransformer(
when (action) {
is TokenActionsState.ActionState.Buy -> {
WalletManageButton.Buy(
enabled = action.enabled,
onClick = { clickIntents.onBuyClick(cryptoCurrencyStatus) },
enabled = action.unavailabilityReason == ScenarioUnavailabilityReason.None,
dimContent = action.unavailabilityReason != ScenarioUnavailabilityReason.None,
onClick = {
clickIntents.onBuyClick(
cryptoCurrencyStatus = cryptoCurrencyStatus,
unavailabilityReason = action.unavailabilityReason,
)
},
)
}
is TokenActionsState.ActionState.Receive -> {
WalletManageButton.Receive(
enabled = action.enabled,
onClick = { clickIntents.onReceiveClick(cryptoCurrencyStatus) },
enabled = action.unavailabilityReason == ScenarioUnavailabilityReason.None,
dimContent = action.unavailabilityReason != ScenarioUnavailabilityReason.None,
onClick = {
clickIntents.onReceiveClick(cryptoCurrencyStatus = cryptoCurrencyStatus)
},
)
}
is TokenActionsState.ActionState.Sell -> {
WalletManageButton.Sell(
enabled = action.enabled,
onClick = { clickIntents.onSellClick(cryptoCurrencyStatus) },
enabled = action.unavailabilityReason == ScenarioUnavailabilityReason.None,
dimContent = action.unavailabilityReason != ScenarioUnavailabilityReason.None,
onClick = {
clickIntents.onSellClick(
cryptoCurrencyStatus = cryptoCurrencyStatus,
unavailabilityReason = action.unavailabilityReason,
)
},
)
}
is TokenActionsState.ActionState.Send -> {
WalletManageButton.Send(
enabled = action.enabled,
onClick = { clickIntents.onSendClick(cryptoCurrencyStatus) },
enabled = action.unavailabilityReason == ScenarioUnavailabilityReason.None,
dimContent = action.unavailabilityReason != ScenarioUnavailabilityReason.None,
onClick = {
clickIntents.onSendClick(
cryptoCurrencyStatus = cryptoCurrencyStatus,
unavailabilityReason = action.unavailabilityReason,
)
},
)
}
else -> {

View file

@ -3,6 +3,7 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers.convert
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.TokenActionsState
import com.tangem.domain.wallets.models.UserWallet
@ -51,7 +52,7 @@ internal class MultiWalletCurrencyActionsConverter(
is TokenActionsState.ActionState.Buy -> {
title = resourceReference(R.string.common_buy)
icon = R.drawable.ic_plus_24
action = { clickIntents.onBuyClick(cryptoCurrencyStatus) }
action = { clickIntents.onBuyClick(cryptoCurrencyStatus, ScenarioUnavailabilityReason.None) }
}
is TokenActionsState.ActionState.Receive -> {
title = resourceReference(R.string.common_receive)
@ -61,17 +62,17 @@ internal class MultiWalletCurrencyActionsConverter(
is TokenActionsState.ActionState.Sell -> {
title = resourceReference(R.string.common_sell)
icon = R.drawable.ic_currency_24
action = { clickIntents.onSellClick(cryptoCurrencyStatus) }
action = { clickIntents.onSellClick(cryptoCurrencyStatus, ScenarioUnavailabilityReason.None) }
}
is TokenActionsState.ActionState.Send -> {
title = resourceReference(R.string.common_send)
icon = R.drawable.ic_arrow_up_24
action = { clickIntents.onSendClick(cryptoCurrencyStatus) }
action = { clickIntents.onSendClick(cryptoCurrencyStatus, ScenarioUnavailabilityReason.None) }
}
is TokenActionsState.ActionState.Swap -> {
title = resourceReference(R.string.swapping_swap_action)
icon = R.drawable.ic_exchange_horizontal_24
action = { clickIntents.onSwapClick(cryptoCurrencyStatus) }
action = { clickIntents.onSwapClick(cryptoCurrencyStatus, ScenarioUnavailabilityReason.None) }
}
is TokenActionsState.ActionState.CopyAddress -> {
title = resourceReference(R.string.common_copy_address)
@ -90,7 +91,7 @@ internal class MultiWalletCurrencyActionsConverter(
iconResId = icon,
onClick = action,
isWarning = actionsState is TokenActionsState.ActionState.HideToken,
enabled = actionsState.enabled,
enabled = actionsState.unavailabilityReason == ScenarioUnavailabilityReason.None,
)
}
}

View file

@ -45,7 +45,7 @@ internal class WalletLoadingStateFactory(private val clickIntents: WalletClickIn
walletCardState = userWallet.toLoadingWalletCardState(),
warnings = persistentListOf(),
bottomSheetConfig = null,
buttons = createDisabledButtons(),
buttons = createDimmedButtons(),
marketPriceBlockState = MarketPriceBlockState.Loading(currencySymbol = currencySymbol),
txHistoryState = TxHistoryState.Content(
contentItems = MutableStateFlow(
@ -86,12 +86,12 @@ internal class WalletLoadingStateFactory(private val clickIntents: WalletClickIn
)
}
private fun createDisabledButtons(): PersistentList<WalletManageButton> {
private fun createDimmedButtons(): PersistentList<WalletManageButton> {
return persistentListOf(
WalletManageButton.Buy(enabled = false, onClick = {}),
WalletManageButton.Send(enabled = false, onClick = {}),
WalletManageButton.Receive(enabled = false, onClick = {}),
WalletManageButton.Sell(enabled = false, onClick = {}),
WalletManageButton.Receive(enabled = true, dimContent = true, onClick = {}),
WalletManageButton.Send(enabled = true, dimContent = true, onClick = {}),
WalletManageButton.Buy(enabled = true, dimContent = true, onClick = {}),
WalletManageButton.Sell(enabled = true, dimContent = true, onClick = {}),
)
}
}

View file

@ -7,8 +7,7 @@ import com.tangem.core.ui.components.bottomsheets.chooseaddress.ChooseAddressBot
import com.tangem.core.ui.components.bottomsheets.tokenreceive.AddressModel
import com.tangem.core.ui.components.bottomsheets.tokenreceive.TokenReceiveBottomSheetConfig
import com.tangem.core.ui.components.bottomsheets.tokenreceive.mapToAddressModels
import com.tangem.core.ui.extensions.WrappedList
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.*
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.extenstions.unwrap
import com.tangem.domain.common.util.cardTypesResolver
@ -19,6 +18,7 @@ import com.tangem.domain.tokens.legacy.TradeCryptoAction
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.NetworkAddress
import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason
import com.tangem.domain.tokens.models.analytics.TokenReceiveAnalyticsEvent
import com.tangem.domain.tokens.models.analytics.TokenScreenAnalyticsEvent
import com.tangem.domain.walletmanager.WalletManagersFacade
@ -39,11 +39,18 @@ import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.take
import kotlinx.coroutines.launch
import java.lang.IllegalArgumentException
import javax.inject.Inject
interface WalletCurrencyActionsClickIntents {
fun onSendClick(cryptoCurrencyStatus: CryptoCurrencyStatus)
fun onSendClick(cryptoCurrencyStatus: CryptoCurrencyStatus, unavailabilityReason: ScenarioUnavailabilityReason)
fun onSellClick(cryptoCurrencyStatus: CryptoCurrencyStatus, unavailabilityReason: ScenarioUnavailabilityReason)
fun onBuyClick(cryptoCurrencyStatus: CryptoCurrencyStatus, unavailabilityReason: ScenarioUnavailabilityReason)
fun onSwapClick(cryptoCurrencyStatus: CryptoCurrencyStatus, unavailabilityReason: ScenarioUnavailabilityReason)
fun onReceiveClick(cryptoCurrencyStatus: CryptoCurrencyStatus)
@ -53,12 +60,6 @@ interface WalletCurrencyActionsClickIntents {
fun onPerformHideToken(cryptoCurrencyStatus: CryptoCurrencyStatus)
fun onSellClick(cryptoCurrencyStatus: CryptoCurrencyStatus)
fun onBuyClick(cryptoCurrencyStatus: CryptoCurrencyStatus)
fun onSwapClick(cryptoCurrencyStatus: CryptoCurrencyStatus)
fun onExploreClick()
}
@ -82,13 +83,18 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
private val reduxStateHolder: ReduxStateHolder,
) : BaseWalletClickIntents(), WalletCurrencyActionsClickIntents {
override fun onSendClick(cryptoCurrencyStatus: CryptoCurrencyStatus) {
override fun onSendClick(
cryptoCurrencyStatus: CryptoCurrencyStatus,
unavailabilityReason: ScenarioUnavailabilityReason,
) {
val userWallet = getSelectedWalletSyncUseCase.unwrap() ?: return
analyticsEventHandler.send(
event = TokenScreenAnalyticsEvent.ButtonSend(cryptoCurrencyStatus.currency.symbol),
)
if (handleUnavailabilityReason(unavailabilityReason)) return
stateHolder.update(CloseBottomSheetTransformer(userWalletId = userWallet.walletId))
viewModelScope.launch(dispatchers.main) {
val maybeFeeCurrencyStatus =
@ -274,11 +280,16 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
}
}
override fun onSellClick(cryptoCurrencyStatus: CryptoCurrencyStatus) {
override fun onSellClick(
cryptoCurrencyStatus: CryptoCurrencyStatus,
unavailabilityReason: ScenarioUnavailabilityReason,
) {
analyticsEventHandler.send(
event = TokenScreenAnalyticsEvent.ButtonSell(cryptoCurrencyStatus.currency.symbol),
)
if (handleUnavailabilityReason(unavailabilityReason)) return
showErrorIfDemoModeOrElse {
viewModelScope.launch(dispatchers.main) {
reduxStateHolder.dispatch(
@ -291,13 +302,18 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
}
}
override fun onBuyClick(cryptoCurrencyStatus: CryptoCurrencyStatus) {
override fun onBuyClick(
cryptoCurrencyStatus: CryptoCurrencyStatus,
unavailabilityReason: ScenarioUnavailabilityReason,
) {
val userWallet = getSelectedWalletSyncUseCase.unwrap() ?: return
analyticsEventHandler.send(
event = TokenScreenAnalyticsEvent.ButtonBuy(cryptoCurrencyStatus.currency.symbol),
)
if (handleUnavailabilityReason(unavailabilityReason)) return
showErrorIfDemoModeOrElse {
viewModelScope.launch(dispatchers.main) {
reduxStateHolder.dispatch(
@ -311,11 +327,16 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
}
}
override fun onSwapClick(cryptoCurrencyStatus: CryptoCurrencyStatus) {
override fun onSwapClick(
cryptoCurrencyStatus: CryptoCurrencyStatus,
unavailabilityReason: ScenarioUnavailabilityReason,
) {
analyticsEventHandler.send(
event = TokenScreenAnalyticsEvent.ButtonExchange(cryptoCurrencyStatus.currency.symbol),
)
if (handleUnavailabilityReason(unavailabilityReason)) return
reduxStateHolder.dispatch(TradeCryptoAction.Swap(cryptoCurrencyStatus.currency))
}
@ -402,4 +423,79 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
action()
}
}
private fun handleUnavailabilityReason(unavailabilityReason: ScenarioUnavailabilityReason): Boolean {
if (unavailabilityReason == ScenarioUnavailabilityReason.None) return false
val unavailabilityReasonText = getUnavailabilityReasonText(unavailabilityReason)
viewModelScope.launch(dispatchers.main) {
walletEventSender.send(
event = WalletEvent.ShowAlert(
state = WalletAlertState.DefaultAlert(
title = null,
message = unavailabilityReasonText,
onConfirmClick = null,
),
),
)
}
return true
}
private fun getUnavailabilityReasonText(unavailabilityReason: ScenarioUnavailabilityReason): TextReference {
return when (unavailabilityReason) {
// send
is ScenarioUnavailabilityReason.PendingTransaction -> {
resourceReference(
id = R.string.warning_send_blocked_pending_transactions_message,
formatArgs = wrappedList(unavailabilityReason.cryptoCurrencySymbol),
)
}
ScenarioUnavailabilityReason.EmptyBalance -> {
resourceReference(
id = R.string.token_button_unavailability_reason_empty_balance,
)
}
is ScenarioUnavailabilityReason.InsufficientFundsForFee -> {
resourceReference(
id = R.string.warning_send_blocked_funds_for_fee_message,
formatArgs = wrappedList(
unavailabilityReason.currencyName,
unavailabilityReason.networkName,
unavailabilityReason.currencyName,
unavailabilityReason.feeCurrencyName,
unavailabilityReason.feeCurrencySymbol,
),
)
}
is ScenarioUnavailabilityReason.BuyUnavailable -> {
resourceReference(
id = R.string.token_button_unavailability_reason_buy_unavailable,
formatArgs = wrappedList(unavailabilityReason.cryptoCurrencyName),
)
}
is ScenarioUnavailabilityReason.NotExchangeable -> {
resourceReference(
id = R.string.token_button_unavailability_reason_not_exchangeable,
formatArgs = wrappedList(unavailabilityReason.cryptoCurrencyName),
)
}
is ScenarioUnavailabilityReason.SellUnavailable -> {
resourceReference(
id = R.string.token_button_unavailability_reason_sell_unavailable,
formatArgs = wrappedList(unavailabilityReason.cryptoCurrencyName),
)
}
ScenarioUnavailabilityReason.NoQuotes -> {
resourceReference(
id = R.string.token_button_unavailability_reason_no_quotes,
)
}
ScenarioUnavailabilityReason.None -> {
throw IllegalArgumentException("The unavailability reason must be other than None")
}
}
}
}