Updated on 2026-08-14
This commit is contained in:
parent
680794d447
commit
a61004a3c1
18 changed files with 459 additions and 106 deletions
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.core.decompose.utils
|
||||
|
||||
import com.arkivanov.decompose.router.stack.StackNavigation
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
/**
|
||||
* Retrieves the current stack of items from the [com.arkivanov.decompose.router.stack.ChildStack]
|
||||
* @return A list representing the current stack of items
|
||||
*/
|
||||
suspend fun <T : Any> StackNavigation<T>.stack(): List<T> {
|
||||
return suspendCancellableCoroutine { continuation ->
|
||||
this.navigate(
|
||||
transformer = { stack -> stack },
|
||||
onComplete = { newStack, oldStack -> continuation.resume(newStack) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -21,6 +21,9 @@ dependencies {
|
|||
/** Common */
|
||||
implementation(projects.common.ui)
|
||||
|
||||
/** Domain */
|
||||
implementation(projects.domain.transaction)
|
||||
|
||||
/** Domain models */
|
||||
api(projects.domain.models)
|
||||
implementation(projects.domain.appCurrency.models)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import com.tangem.core.analytics.models.AnalyticsParam
|
|||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
import com.tangem.features.send.v2.api.R
|
||||
import com.tangem.features.send.v2.api.entity.FeeItem.*
|
||||
|
|
@ -61,6 +62,7 @@ data class FeeExtraInfo(
|
|||
val isFeeApproximate: Boolean,
|
||||
val isFeeConvertibleToFiat: Boolean,
|
||||
val isTronToken: Boolean,
|
||||
val feeCryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
)
|
||||
|
||||
sealed class FeeNonce {
|
||||
|
|
|
|||
|
|
@ -6,12 +6,14 @@ import com.tangem.blockchain.common.transaction.TransactionFee
|
|||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
import com.tangem.domain.transaction.models.TransactionFeeExtended
|
||||
import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents
|
||||
import com.tangem.features.send.v2.api.callbacks.FeeSelectorModelCallback
|
||||
import com.tangem.features.send.v2.api.entity.FeeSelectorUM
|
||||
|
||||
sealed class FeeSelectorParams {
|
||||
abstract val state: FeeSelectorUM
|
||||
abstract val onLoadFeeExtended: (suspend () -> Either<GetFeeError, TransactionFeeExtended>)?
|
||||
abstract val onLoadFee: suspend () -> Either<GetFeeError, TransactionFee>
|
||||
abstract val cryptoCurrencyStatus: CryptoCurrencyStatus
|
||||
abstract val feeCryptoCurrencyStatus: CryptoCurrencyStatus
|
||||
|
|
@ -22,6 +24,7 @@ sealed class FeeSelectorParams {
|
|||
|
||||
data class FeeSelectorBlockParams(
|
||||
override val state: FeeSelectorUM,
|
||||
override val onLoadFeeExtended: (suspend () -> Either<GetFeeError, TransactionFeeExtended>)? = null,
|
||||
override val onLoadFee: suspend () -> Either<GetFeeError, TransactionFee>,
|
||||
override val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
override val feeCryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
|
|
@ -33,6 +36,7 @@ sealed class FeeSelectorParams {
|
|||
|
||||
data class FeeSelectorDetailsParams(
|
||||
override val state: FeeSelectorUM,
|
||||
override val onLoadFeeExtended: (suspend () -> Either<GetFeeError, TransactionFeeExtended>)? = null,
|
||||
override val onLoadFee: suspend () -> Either<GetFeeError, TransactionFee>,
|
||||
override val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
override val feeCryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
|
|
|
|||
|
|
@ -5,10 +5,8 @@ import androidx.compose.runtime.getValue
|
|||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.arkivanov.decompose.ComponentContext
|
||||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||
import com.arkivanov.decompose.router.stack.StackNavigation
|
||||
import com.arkivanov.decompose.router.stack.childStack
|
||||
import com.arkivanov.decompose.router.stack.pop
|
||||
import com.arkivanov.essenty.instancekeeper.getOrCreateSimple
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.childByContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
|
|
@ -26,7 +24,6 @@ import dagger.assisted.Assisted
|
|||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
@Suppress("PropertyUsedBeforeDeclaration")
|
||||
internal class DefaultFeeSelectorComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
@Assisted private val params: FeeSelectorParams.FeeSelectorDetailsParams,
|
||||
|
|
@ -35,22 +32,22 @@ internal class DefaultFeeSelectorComponent @AssistedInject constructor(
|
|||
private val feeSpeedSelectorComponentFactory: FeeSpeedSelectorComponent.Factory,
|
||||
) : FeeSelectorComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val stackNavigation = instanceKeeper.getOrCreateSimple { StackNavigation<FeeSelectorRoute>() }
|
||||
private val innerRouter = InnerRouter<FeeSelectorRoute>(
|
||||
stackNavigation = stackNavigation,
|
||||
private val model: FeeSelectorModel = getOrCreateModel(params = params)
|
||||
|
||||
val innerRouter = InnerRouter<FeeSelectorRoute>(
|
||||
stackNavigation = model.stackNavigation,
|
||||
popCallback = {
|
||||
stackNavigation.pop { success ->
|
||||
model.stackNavigation.pop { success ->
|
||||
if (!success) {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
private val model: FeeSelectorModel = getOrCreateModel(params = params, router = innerRouter)
|
||||
|
||||
private val contentStack = childStack(
|
||||
key = "FeeSelectorDetailsStack",
|
||||
source = stackNavigation,
|
||||
source = model.stackNavigation,
|
||||
serializer = FeeSelectorRoute.serializer(),
|
||||
initialConfiguration = model.getInitialRoute(),
|
||||
handleBackButton = false,
|
||||
|
|
@ -69,7 +66,7 @@ internal class DefaultFeeSelectorComponent @AssistedInject constructor(
|
|||
FeeSelectorModalBottomSheet(
|
||||
childStack = contentStack,
|
||||
state = state,
|
||||
feeSelectorIntents = model.intents,
|
||||
feeSelectorIntents = model,
|
||||
feeDisplaySource = params.feeDisplaySource,
|
||||
onDismiss = onDismiss,
|
||||
onBack = innerRouter::pop,
|
||||
|
|
@ -85,7 +82,7 @@ internal class DefaultFeeSelectorComponent @AssistedInject constructor(
|
|||
val componentParams = FeeSelectorComponentParams(
|
||||
parentParams = params,
|
||||
state = model.uiState,
|
||||
intents = model.intents,
|
||||
intents = model,
|
||||
)
|
||||
|
||||
return when (config) {
|
||||
|
|
|
|||
|
|
@ -1,23 +1,59 @@
|
|||
package com.tangem.features.send.v2.feeselector.component.extended.entity
|
||||
|
||||
import com.tangem.common.ui.tokens.TokenItemStateConverter
|
||||
import com.tangem.core.ui.components.icons.IconTint
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.features.send.v2.impl.R
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
internal class SelectedTokenItemConverter(
|
||||
appCurrency: AppCurrency,
|
||||
onTokenClick: () -> Unit,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val onTokenClick: () -> Unit,
|
||||
) : Converter<CryptoCurrencyStatus, TokenItemState> {
|
||||
|
||||
private val tokenItemConverter = TokenItemStateConverter(
|
||||
appCurrency = appCurrency,
|
||||
onItemClick = { _, _ -> onTokenClick() },
|
||||
)
|
||||
|
||||
override fun convert(value: CryptoCurrencyStatus): TokenItemState {
|
||||
// TODO
|
||||
return tokenItemConverter.convert(value)
|
||||
if (value.value !is CryptoCurrencyStatus.Loaded) {
|
||||
return TokenItemState.Loading(id = value.currency.id.value)
|
||||
}
|
||||
|
||||
val appCurrency = appCurrencyProvider()
|
||||
val tokenItemConverter = TokenItemStateConverter(
|
||||
appCurrency = appCurrencyProvider(),
|
||||
onItemClick = { _, _ -> onTokenClick() },
|
||||
)
|
||||
|
||||
val state = tokenItemConverter.convert(value)
|
||||
|
||||
return when (state) {
|
||||
is TokenItemState.Content -> {
|
||||
val balance = value.value.fiatAmount.format {
|
||||
fiat(fiatCurrencyCode = appCurrency.code, fiatCurrencySymbol = appCurrency.symbol)
|
||||
}
|
||||
|
||||
state.copy(
|
||||
fiatAmountState = TokenItemState.FiatAmountState.Icon(
|
||||
iconRes = R.drawable.ic_select_18_24,
|
||||
tint = IconTint.Informative,
|
||||
),
|
||||
subtitleState = TokenItemState.SubtitleState.TextContent(
|
||||
value = resourceReference(
|
||||
R.string.common_balance,
|
||||
wrappedList(balance),
|
||||
),
|
||||
isAvailable = false,
|
||||
),
|
||||
subtitle2State = null,
|
||||
|
||||
)
|
||||
}
|
||||
else -> state
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ import com.tangem.features.send.v2.feeselector.component.FeeSelectorComponentPar
|
|||
import com.tangem.features.send.v2.feeselector.component.extended.entity.FeeExtendedSelectorUM
|
||||
import com.tangem.features.send.v2.feeselector.component.extended.entity.SelectedTokenItemConverter
|
||||
import com.tangem.features.send.v2.feeselector.route.FeeSelectorRoute
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -29,44 +30,48 @@ class FeeExtendedSelectorModel @Inject constructor(
|
|||
|
||||
private val params = paramsContainer.require<FeeSelectorComponentParams>()
|
||||
private var appCurrency: AppCurrency = AppCurrency.Default
|
||||
private val tokenConverter = SelectedTokenItemConverter(
|
||||
appCurrencyProvider = Provider { appCurrency },
|
||||
onTokenClick = { router.push(FeeSelectorRoute.ChooseToken) },
|
||||
)
|
||||
|
||||
init {
|
||||
initAppCurrency()
|
||||
}
|
||||
|
||||
val uiState: StateFlow<FeeExtendedSelectorUM>
|
||||
field = MutableStateFlow<FeeExtendedSelectorUM>(getInitialState())
|
||||
|
||||
init {
|
||||
modelScope.launch {
|
||||
appCurrency = getSelectedAppCurrencyUseCase.invokeSync().getOrElse { AppCurrency.Default }
|
||||
uiState.value = getInitialState()
|
||||
}
|
||||
|
||||
params.state
|
||||
.filterIsInstance<FeeSelectorUM.Content>()
|
||||
.onEach(::onParentStateUpdated)
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun getInitialState(): FeeExtendedSelectorUM {
|
||||
val status = params.parentParams.feeCryptoCurrencyStatus
|
||||
val parentContentState = params.state.value as FeeSelectorUM.Content
|
||||
|
||||
return FeeExtendedSelectorUM(
|
||||
parent = parentContentState,
|
||||
token = SelectedTokenItemConverter(
|
||||
appCurrency = appCurrency,
|
||||
onTokenClick = {
|
||||
router.push(FeeSelectorRoute.ChooseToken)
|
||||
},
|
||||
).convert(status),
|
||||
token = tokenConverter.convert(parentContentState.feeExtraInfo.feeCryptoCurrencyStatus),
|
||||
fee = parentContentState.selectedFeeItem,
|
||||
onFeeClick = {
|
||||
router.push(FeeSelectorRoute.ChooseSpeed)
|
||||
},
|
||||
onFeeClick = { router.push(FeeSelectorRoute.ChooseSpeed) },
|
||||
)
|
||||
}
|
||||
|
||||
private fun onParentStateUpdated(state: FeeSelectorUM) {
|
||||
private fun initAppCurrency() {
|
||||
modelScope.launch {
|
||||
appCurrency = getSelectedAppCurrencyUseCase.invokeSync().getOrElse { AppCurrency.Default }
|
||||
}
|
||||
}
|
||||
|
||||
private fun onParentStateUpdated(state: FeeSelectorUM.Content) {
|
||||
uiState.update { current ->
|
||||
current.copy(
|
||||
parent = state as FeeSelectorUM.Content,
|
||||
parent = state,
|
||||
token = tokenConverter.convert(state.feeExtraInfo.feeCryptoCurrencyStatus),
|
||||
fee = state.selectedFeeItem,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@ import com.tangem.core.ui.format.bigdecimal.format
|
|||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.features.send.v2.api.entity.*
|
||||
import com.tangem.features.send.v2.feeselector.component.extended.entity.FeeExtendedSelectorUM
|
||||
import com.tangem.features.send.v2.feeselector.component.speed.ui.RegularFeeItemContent
|
||||
|
|
@ -95,6 +98,7 @@ fun FeeExtendedSelectorContent(state: FeeExtendedSelectorUM, modifier: Modifier
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Preview
|
||||
@Composable
|
||||
private fun Preview() {
|
||||
|
|
@ -115,6 +119,34 @@ private fun Preview() {
|
|||
onItemLongClick = {},
|
||||
)
|
||||
|
||||
val cryptoCurrencyStatus = CryptoCurrencyStatus(
|
||||
currency = CryptoCurrency.Coin(
|
||||
id = CryptoCurrency.ID.fromValue("coin⟨BITCOIN⟩bitcoin"),
|
||||
network = Network(
|
||||
id = Network.ID(
|
||||
value = "bitcoin",
|
||||
derivationPath = Network.DerivationPath.None,
|
||||
),
|
||||
backendId = "bitcoin",
|
||||
name = "Bitcoin",
|
||||
currencySymbol = "BTC",
|
||||
derivationPath = Network.DerivationPath.None,
|
||||
isTestnet = false,
|
||||
standardType = Network.StandardType.Unspecified("bitcoin"),
|
||||
hasFiatFeeRate = false,
|
||||
canHandleTokens = false,
|
||||
transactionExtrasType = Network.TransactionExtrasType.NONE,
|
||||
nameResolvingType = Network.NameResolvingType.NONE,
|
||||
),
|
||||
name = "Bitcoin",
|
||||
symbol = "BTC",
|
||||
decimals = 8,
|
||||
iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/medium/bitcoin.png",
|
||||
isCustom = false,
|
||||
),
|
||||
value = CryptoCurrencyStatus.Loading,
|
||||
)
|
||||
|
||||
val lowFeeItem =
|
||||
FeeItem.Market(Fee.Common(amount = Amount(value = BigDecimal("0.0002876"), blockchain = Blockchain.Ethereum)))
|
||||
|
||||
|
|
@ -130,6 +162,7 @@ private fun Preview() {
|
|||
isFeeApproximate = false,
|
||||
isFeeConvertibleToFiat = true,
|
||||
isTronToken = false,
|
||||
feeCryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
),
|
||||
feeNonce = FeeNonce.None,
|
||||
feeFiatRateUM = FeeFiatRateUM(
|
||||
|
|
|
|||
|
|
@ -50,6 +50,9 @@ import com.tangem.core.ui.res.TangemTheme
|
|||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.test.SendSelectNetworkFeeBottomSheetTestTags
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.features.send.v2.api.entity.*
|
||||
import com.tangem.features.send.v2.feeselector.component.speed.FeeSpeedSelectorIntents
|
||||
import com.tangem.features.send.v2.feeselector.component.speed.StubFeeSpeedSelectorIntents
|
||||
|
|
@ -473,6 +476,7 @@ private class FeeSpeedSelectorUMContentProvider : CollectionPreviewParameterProv
|
|||
isFeeApproximate = true,
|
||||
isFeeConvertibleToFiat = true,
|
||||
isTronToken = false,
|
||||
feeCryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
),
|
||||
feeFiatRateUM = FeeFiatRateUM(
|
||||
rate = BigDecimal.TEN,
|
||||
|
|
@ -484,44 +488,74 @@ private class FeeSpeedSelectorUMContentProvider : CollectionPreviewParameterProv
|
|||
),
|
||||
)
|
||||
|
||||
private val customFeeItem = FeeItem.Custom(
|
||||
fee = Fee.Common(Amount(value = BigDecimal("0.05"), blockchain = Blockchain.Ethereum)),
|
||||
customValues = persistentListOf(
|
||||
CustomFeeFieldUM(
|
||||
value = "0.119806",
|
||||
onValueChange = {},
|
||||
keyboardOptions = KeyboardOptions(),
|
||||
keyboardActions = KeyboardActions(),
|
||||
symbol = "ETH",
|
||||
private val cryptoCurrencyStatus
|
||||
get() = CryptoCurrencyStatus(
|
||||
currency = CryptoCurrency.Coin(
|
||||
id = CryptoCurrency.ID.fromValue("coin⟨BITCOIN⟩bitcoin"),
|
||||
network = Network(
|
||||
id = Network.ID(
|
||||
value = "bitcoin",
|
||||
derivationPath = Network.DerivationPath.None,
|
||||
),
|
||||
backendId = "bitcoin",
|
||||
name = "Bitcoin",
|
||||
currencySymbol = "BTC",
|
||||
derivationPath = Network.DerivationPath.None,
|
||||
isTestnet = false,
|
||||
standardType = Network.StandardType.Unspecified("bitcoin"),
|
||||
hasFiatFeeRate = false,
|
||||
canHandleTokens = false,
|
||||
transactionExtrasType = Network.TransactionExtrasType.NONE,
|
||||
nameResolvingType = Network.NameResolvingType.NONE,
|
||||
),
|
||||
name = "Bitcoin",
|
||||
symbol = "BTC",
|
||||
decimals = 8,
|
||||
title = resourceReference(R.string.send_max_fee),
|
||||
footer = resourceReference(R.string.send_custom_amount_fee_footer),
|
||||
label = stringReference("~ 0,03 \$"),
|
||||
isReadonly = false,
|
||||
iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/medium/bitcoin.png",
|
||||
isCustom = false,
|
||||
),
|
||||
CustomFeeFieldUM(
|
||||
value = "40000",
|
||||
onValueChange = {},
|
||||
keyboardOptions = KeyboardOptions(),
|
||||
keyboardActions = KeyboardActions(),
|
||||
symbol = "GWEI",
|
||||
decimals = 8,
|
||||
title = resourceReference(R.string.send_gas_price),
|
||||
footer = resourceReference(R.string.send_gas_price_footer),
|
||||
label = null,
|
||||
isReadonly = false,
|
||||
value = CryptoCurrencyStatus.Loading,
|
||||
)
|
||||
|
||||
private val customFeeItem
|
||||
get() = FeeItem.Custom(
|
||||
fee = Fee.Common(Amount(value = BigDecimal("0.05"), blockchain = Blockchain.Ethereum)),
|
||||
customValues = persistentListOf(
|
||||
CustomFeeFieldUM(
|
||||
value = "0.119806",
|
||||
onValueChange = {},
|
||||
keyboardOptions = KeyboardOptions(),
|
||||
keyboardActions = KeyboardActions(),
|
||||
symbol = "ETH",
|
||||
decimals = 8,
|
||||
title = resourceReference(R.string.send_max_fee),
|
||||
footer = resourceReference(R.string.send_custom_amount_fee_footer),
|
||||
label = stringReference("~ 0,03 \$"),
|
||||
isReadonly = false,
|
||||
),
|
||||
CustomFeeFieldUM(
|
||||
value = "40000",
|
||||
onValueChange = {},
|
||||
keyboardOptions = KeyboardOptions(),
|
||||
keyboardActions = KeyboardActions(),
|
||||
symbol = "GWEI",
|
||||
decimals = 8,
|
||||
title = resourceReference(R.string.send_gas_price),
|
||||
footer = resourceReference(R.string.send_gas_price_footer),
|
||||
label = null,
|
||||
isReadonly = false,
|
||||
),
|
||||
CustomFeeFieldUM(
|
||||
value = "31400",
|
||||
onValueChange = {},
|
||||
keyboardOptions = KeyboardOptions(),
|
||||
keyboardActions = KeyboardActions(),
|
||||
symbol = null,
|
||||
decimals = 8,
|
||||
title = resourceReference(R.string.send_gas_limit),
|
||||
footer = resourceReference(R.string.send_gas_limit_footer),
|
||||
label = null,
|
||||
isReadonly = false,
|
||||
),
|
||||
),
|
||||
CustomFeeFieldUM(
|
||||
value = "31400",
|
||||
onValueChange = {},
|
||||
keyboardOptions = KeyboardOptions(),
|
||||
keyboardActions = KeyboardActions(),
|
||||
symbol = null,
|
||||
decimals = 8,
|
||||
title = resourceReference(R.string.send_gas_limit),
|
||||
footer = resourceReference(R.string.send_gas_limit_footer),
|
||||
label = null,
|
||||
isReadonly = false,
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
|
|
@ -25,14 +25,14 @@ import javax.inject.Inject
|
|||
@ModelScoped
|
||||
internal class FeeSelectorBlockModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
feeSelectorLogicFactory: FeeSelectorLogic.Factory,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val feeSelectorLogicFactory: FeeSelectorLogic.Factory,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val neverShowTapHelpUseCase: NeverShowTapHelpUseCase,
|
||||
private val urlOpener: UrlOpener,
|
||||
) : Model(), FeeSelectorModelCallback {
|
||||
|
||||
private val params = paramsContainer.require<FeeSelectorParams>()
|
||||
private val params = paramsContainer.require<FeeSelectorParams.FeeSelectorBlockParams>()
|
||||
private val feeSelectorLogic = feeSelectorLogicFactory.create(
|
||||
params = params,
|
||||
modelScope = modelScope,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,18 @@
|
|||
package com.tangem.features.send.v2.feeselector.model
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.blockchain.common.AmountType
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
import com.tangem.domain.transaction.models.TransactionFeeExtended
|
||||
import com.tangem.domain.transaction.usecase.IsFeeApproximateUseCase
|
||||
import com.tangem.features.send.v2.api.SendFeatureToggles
|
||||
import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents.NonceInserted
|
||||
import com.tangem.features.send.v2.api.entity.FeeItem
|
||||
import com.tangem.features.send.v2.api.entity.FeeNonce
|
||||
|
|
@ -38,6 +45,8 @@ internal class FeeSelectorLogic @AssistedInject constructor(
|
|||
private val feeSelectorCheckReloadTrigger: FeeSelectorCheckReloadTrigger,
|
||||
private val feeSelectorAlertFactory: FeeSelectorAlertFactory,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val sendFeatureToggles: SendFeatureToggles,
|
||||
private val getSingleCryptoCurrencyStatusUseCase: GetSingleCryptoCurrencyStatusUseCase,
|
||||
) : FeeSelectorIntents {
|
||||
|
||||
private var appCurrency: AppCurrency = AppCurrency.Default
|
||||
|
|
@ -51,10 +60,6 @@ internal class FeeSelectorLogic @AssistedInject constructor(
|
|||
loadFee()
|
||||
}
|
||||
|
||||
fun updateState(feeSelectorUM: FeeSelectorUM) {
|
||||
uiState.value = feeSelectorUM
|
||||
}
|
||||
|
||||
private fun initAppCurrency() {
|
||||
modelScope.launch {
|
||||
appCurrency = getSelectedAppCurrencyUseCase.invokeSync().getOrElse { AppCurrency.Default }
|
||||
|
|
@ -66,18 +71,18 @@ internal class FeeSelectorLogic @AssistedInject constructor(
|
|||
uiState.update(FeeSelectorLoadingTransformer)
|
||||
}
|
||||
modelScope.launch {
|
||||
params.onLoadFee()
|
||||
callLoadFee()
|
||||
.fold(
|
||||
ifLeft = { error -> uiState.update(FeeSelectorErrorTransformer(error)) },
|
||||
ifRight = { fee ->
|
||||
uiState.update(
|
||||
FeeSelectorLoadedTransformer(
|
||||
cryptoCurrencyStatus = params.cryptoCurrencyStatus,
|
||||
feeCryptoCurrencyStatus = params.feeCryptoCurrencyStatus,
|
||||
feeCryptoCurrencyStatus = fee.selectedTokenOrNull ?: params.feeCryptoCurrencyStatus,
|
||||
appCurrency = appCurrency,
|
||||
fees = fee,
|
||||
feeStateConfiguration = params.feeStateConfiguration,
|
||||
isFeeApproximate = isFeeApproximate(fee.normal.amount.type),
|
||||
isFeeApproximate = isFeeApproximate(fee.transactionFee.normal.amount.type),
|
||||
feeSelectorIntents = this@FeeSelectorLogic,
|
||||
),
|
||||
)
|
||||
|
|
@ -98,9 +103,6 @@ internal class FeeSelectorLogic @AssistedInject constructor(
|
|||
)
|
||||
}
|
||||
uiState.update(FeeItemSelectedTransformer(feeItem))
|
||||
if (feeItem !is FeeItem.Custom) {
|
||||
onDoneClick()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCustomFeeValueChange(index: Int, value: String) {
|
||||
|
|
@ -141,8 +143,6 @@ internal class FeeSelectorLogic @AssistedInject constructor(
|
|||
),
|
||||
)
|
||||
}
|
||||
|
||||
(params as? FeeSelectorParams.FeeSelectorDetailsParams)?.callback?.onFeeResult(uiState.value)
|
||||
}
|
||||
|
||||
private fun subscribeOnFeeReloadTriggerUpdates() {
|
||||
|
|
@ -170,10 +170,10 @@ internal class FeeSelectorLogic @AssistedInject constructor(
|
|||
|
||||
private fun checkLoadFee() {
|
||||
modelScope.launch {
|
||||
params.onLoadFee().fold(
|
||||
callLoadFee().fold(
|
||||
ifRight = { newFee ->
|
||||
feeSelectorAlertFactory.getFeeUpdatedAlert(
|
||||
newTransactionFee = newFee,
|
||||
newTransactionFee = newFee.transactionFee,
|
||||
feeSelectorUM = uiState.value,
|
||||
proceedAction = {
|
||||
modelScope.launch {
|
||||
|
|
@ -195,6 +195,61 @@ internal class FeeSelectorLogic @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("UnreachableCode")
|
||||
private suspend fun callLoadFee(): Either<GetFeeError, LoadedFeeResult> {
|
||||
val extended = params.onLoadFeeExtended
|
||||
return if (extended != null && sendFeatureToggles.isGaslessTransactionsEnabled) {
|
||||
extended().fold(
|
||||
ifLeft = { error ->
|
||||
if (error is GetFeeError.GaslessError) {
|
||||
params.onLoadFee().map { LoadedFeeResult.Basic(it) }
|
||||
} else {
|
||||
Either.Left(error)
|
||||
}
|
||||
},
|
||||
ifRight = { fee ->
|
||||
Either.Right(
|
||||
LoadedFeeResult.Extended(
|
||||
fee = fee,
|
||||
selectedToken = if (params.feeCryptoCurrencyStatus.currency.id != fee.feeTokenId) {
|
||||
getSingleCryptoCurrencyStatusUseCase
|
||||
.invokeMultiWalletSync(
|
||||
userWalletId = TODO(),
|
||||
cryptoCurrencyId = fee.feeTokenId,
|
||||
).getOrNull()
|
||||
} else {
|
||||
params.feeCryptoCurrencyStatus
|
||||
},
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
} else {
|
||||
params.onLoadFee().map { LoadedFeeResult.Basic(it) }
|
||||
}
|
||||
}
|
||||
|
||||
sealed class LoadedFeeResult {
|
||||
data class Extended(
|
||||
val fee: TransactionFeeExtended,
|
||||
val selectedToken: CryptoCurrencyStatus?,
|
||||
) : LoadedFeeResult()
|
||||
|
||||
data class Basic(val fee: TransactionFee) : LoadedFeeResult()
|
||||
|
||||
val selectedTokenOrNull: CryptoCurrencyStatus?
|
||||
get() = when (this) {
|
||||
is Extended -> selectedToken
|
||||
is Basic -> null
|
||||
}
|
||||
|
||||
val transactionFee: TransactionFee
|
||||
get() = when (this) {
|
||||
is Extended -> fee.transactionFee
|
||||
is Basic -> fee
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(params: FeeSelectorParams, modelScope: CoroutineScope): FeeSelectorLogic
|
||||
|
|
|
|||
|
|
@ -1,13 +1,20 @@
|
|||
package com.tangem.features.send.v2.feeselector.model
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.arkivanov.decompose.router.stack.StackNavigation
|
||||
import com.arkivanov.decompose.router.stack.pop
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.utils.stack
|
||||
import com.tangem.features.send.v2.api.SendFeatureToggles
|
||||
import com.tangem.features.send.v2.api.entity.FeeItem
|
||||
import com.tangem.features.send.v2.api.entity.FeeSelectorUM
|
||||
import com.tangem.features.send.v2.api.params.FeeSelectorParams
|
||||
import com.tangem.features.send.v2.feeselector.route.FeeSelectorRoute
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.extensions.isSingleItem
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@Stable
|
||||
|
|
@ -17,16 +24,61 @@ internal class FeeSelectorModel @Inject constructor(
|
|||
feeSelectorLogicFactory: FeeSelectorLogic.Factory,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val sendFeatureToggles: SendFeatureToggles,
|
||||
) : Model() {
|
||||
) : Model(), FeeSelectorIntents {
|
||||
|
||||
private val params = paramsContainer.require<FeeSelectorParams>()
|
||||
private val params = paramsContainer.require<FeeSelectorParams.FeeSelectorDetailsParams>()
|
||||
private val feeSelectorLogic = feeSelectorLogicFactory.create(
|
||||
params = params,
|
||||
modelScope = modelScope,
|
||||
)
|
||||
|
||||
val stackNavigation = StackNavigation<FeeSelectorRoute>()
|
||||
val uiState = feeSelectorLogic.uiState
|
||||
val intents: FeeSelectorIntents = feeSelectorLogic
|
||||
|
||||
override fun onFeeItemSelected(feeItem: FeeItem) {
|
||||
feeSelectorLogic.onFeeItemSelected(feeItem)
|
||||
|
||||
if (contentState().selectedFeeItem is FeeItem.Custom) {
|
||||
return
|
||||
}
|
||||
|
||||
modelScope.launch {
|
||||
val stack = stackNavigation.stack()
|
||||
if (stack.isSingleItem() && stack[0] is FeeSelectorRoute.ChooseSpeed) {
|
||||
// In case of only speed selection, we finish the flow immediately after selection
|
||||
feeSelectorLogic.onDoneClick()
|
||||
params.callback.onFeeResult(uiState.value)
|
||||
} else {
|
||||
stackNavigation.pop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCustomFeeValueChange(index: Int, value: String) {
|
||||
feeSelectorLogic.onCustomFeeValueChange(index, value)
|
||||
}
|
||||
|
||||
override fun onNonceChange(value: String) {
|
||||
feeSelectorLogic.onNonceChange(value)
|
||||
}
|
||||
|
||||
override fun onDoneClick() {
|
||||
modelScope.launch {
|
||||
val stack = stackNavigation.stack()
|
||||
if (stack.isSingleItem()) {
|
||||
feeSelectorLogic.onDoneClick()
|
||||
params.callback.onFeeResult(uiState.value)
|
||||
} else {
|
||||
stackNavigation.pop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun contentState(): FeeSelectorUM.Content {
|
||||
val currentState = uiState.value
|
||||
require(currentState is FeeSelectorUM.Content) { "Current state must be FeeSelectorUM.Content" }
|
||||
return currentState
|
||||
}
|
||||
|
||||
fun getInitialRoute(): FeeSelectorRoute {
|
||||
if (sendFeatureToggles.isGaslessTransactionsEnabled.not()) {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
package com.tangem.features.send.v2.feeselector.model.transformers
|
||||
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.features.send.v2.api.entity.*
|
||||
import com.tangem.features.send.v2.api.params.FeeSelectorParams
|
||||
import com.tangem.features.send.v2.feeselector.model.FeeSelectorIntents
|
||||
import com.tangem.features.send.v2.feeselector.model.FeeSelectorLogic.LoadedFeeResult
|
||||
import com.tangem.lib.crypto.BlockchainUtils.isTron
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
|
@ -17,7 +17,7 @@ internal class FeeSelectorLoadedTransformer(
|
|||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
private val feeCryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
private val appCurrency: AppCurrency,
|
||||
private val fees: TransactionFee,
|
||||
private val fees: LoadedFeeResult,
|
||||
private val feeStateConfiguration: FeeSelectorParams.FeeStateConfiguration,
|
||||
private val isFeeApproximate: Boolean,
|
||||
private val feeSelectorIntents: FeeSelectorIntents,
|
||||
|
|
@ -25,7 +25,7 @@ internal class FeeSelectorLoadedTransformer(
|
|||
|
||||
private val feeItemsConverter = FeeItemConverter(
|
||||
feeStateConfiguration = feeStateConfiguration,
|
||||
normalFee = fees.normal,
|
||||
normalFee = fees.transactionFee.normal,
|
||||
feeSelectorIntents = feeSelectorIntents,
|
||||
appCurrency = appCurrency,
|
||||
cryptoCurrencyStatus = feeCryptoCurrencyStatus,
|
||||
|
|
@ -37,7 +37,9 @@ internal class FeeSelectorLoadedTransformer(
|
|||
} else {
|
||||
null
|
||||
}
|
||||
val feeItems: ImmutableList<FeeItem> = feeItemsConverter.convert(FeeItemConverter.Input(fees, prevCustomFee))
|
||||
val feeItems: ImmutableList<FeeItem> = feeItemsConverter.convert(
|
||||
FeeItemConverter.Input(fees.transactionFee, prevCustomFee),
|
||||
)
|
||||
|
||||
val selectedFee = when (prevState) {
|
||||
is FeeSelectorUM.Content -> feeItems.first { it.isSameClass(prevState.selectedFeeItem) }
|
||||
|
|
@ -50,7 +52,7 @@ internal class FeeSelectorLoadedTransformer(
|
|||
|
||||
return FeeSelectorUM.Content(
|
||||
isPrimaryButtonEnabled = true,
|
||||
fees = fees,
|
||||
fees = fees.transactionFee,
|
||||
feeItems = feeItems,
|
||||
selectedFeeItem = selectedFee,
|
||||
feeExtraInfo = FeeExtraInfo(
|
||||
|
|
@ -58,6 +60,7 @@ internal class FeeSelectorLoadedTransformer(
|
|||
isFeeConvertibleToFiat = feeCryptoCurrencyStatus.currency.network.hasFiatFeeRate,
|
||||
isTronToken = cryptoCurrencyStatus.currency is CryptoCurrency.Token &&
|
||||
isTron(cryptoCurrencyStatus.currency.network.rawId),
|
||||
feeCryptoCurrencyStatus = feeCryptoCurrencyStatus,
|
||||
),
|
||||
feeFiatRateUM = feeCryptoCurrencyStatus.value.fiatRate?.let { rate ->
|
||||
FeeFiatRateUM(
|
||||
|
|
@ -65,7 +68,7 @@ internal class FeeSelectorLoadedTransformer(
|
|||
appCurrency = appCurrency,
|
||||
)
|
||||
},
|
||||
feeNonce = if (fees.normal is Fee.Ethereum) {
|
||||
feeNonce = if (fees.transactionFee.normal is Fee.Ethereum) {
|
||||
FeeNonce.Nonce(
|
||||
nonce = nonce,
|
||||
onNonceChange = feeSelectorIntents::onNonceChange,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ internal sealed interface FeeSelectorRoute : Route {
|
|||
|
||||
@Serializable
|
||||
data object NetworkFee : FeeSelectorRoute {
|
||||
override val title: TextReference = resourceReference(R.string.common_fee_selector_title)
|
||||
override val title: TextReference = resourceReference(R.string.common_network_fee_title)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
|
|
|
|||
|
|
@ -42,6 +42,9 @@ import com.tangem.core.ui.res.TangemTheme
|
|||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.test.FeeSelectorBlockTestTags
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
import com.tangem.features.send.v2.api.entity.*
|
||||
import com.tangem.features.send.v2.impl.R
|
||||
|
|
@ -238,11 +241,48 @@ private fun FeeSelectorBlockContent_Preview(@PreviewParameter(FeeSelectorUMProvi
|
|||
}
|
||||
|
||||
private class FeeSelectorUMProvider : PreviewParameterProvider<FeeSelectorUM> {
|
||||
private val maxFeeItem = FeeItem.Market(
|
||||
fee = Fee.Common(amount = Amount(value = BigDecimal("100000000"), blockchain = Blockchain.Hedera)),
|
||||
)
|
||||
private val lowFeeItem =
|
||||
FeeItem.Market(Fee.Common(amount = Amount(value = BigDecimal("0.0002876"), blockchain = Blockchain.Ethereum)))
|
||||
private val maxFeeItem
|
||||
get() = FeeItem.Market(
|
||||
fee = Fee.Common(amount = Amount(value = BigDecimal("100000000"), blockchain = Blockchain.Hedera)),
|
||||
)
|
||||
private val lowFeeItem
|
||||
get() = FeeItem.Market(
|
||||
Fee.Common(
|
||||
amount = Amount(
|
||||
value = BigDecimal("0.0002876"),
|
||||
blockchain = Blockchain.Ethereum,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
val cryptoCurrencyStatus
|
||||
get() = CryptoCurrencyStatus(
|
||||
currency = CryptoCurrency.Coin(
|
||||
id = CryptoCurrency.ID.fromValue("coin⟨BITCOIN⟩bitcoin"),
|
||||
network = Network(
|
||||
id = Network.ID(
|
||||
value = "bitcoin",
|
||||
derivationPath = Network.DerivationPath.None,
|
||||
),
|
||||
backendId = "bitcoin",
|
||||
name = "Bitcoin",
|
||||
currencySymbol = "BTC",
|
||||
derivationPath = Network.DerivationPath.None,
|
||||
isTestnet = false,
|
||||
standardType = Network.StandardType.Unspecified("bitcoin"),
|
||||
hasFiatFeeRate = false,
|
||||
canHandleTokens = false,
|
||||
transactionExtrasType = Network.TransactionExtrasType.NONE,
|
||||
nameResolvingType = Network.NameResolvingType.NONE,
|
||||
),
|
||||
name = "Bitcoin",
|
||||
symbol = "BTC",
|
||||
decimals = 8,
|
||||
iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/medium/bitcoin.png",
|
||||
isCustom = false,
|
||||
),
|
||||
value = CryptoCurrencyStatus.Loading,
|
||||
)
|
||||
|
||||
override val values: Sequence<FeeSelectorUM> = sequenceOf(
|
||||
FeeSelectorUM.Content(
|
||||
|
|
@ -253,6 +293,7 @@ private class FeeSelectorUMProvider : PreviewParameterProvider<FeeSelectorUM> {
|
|||
isFeeApproximate = false,
|
||||
isFeeConvertibleToFiat = true,
|
||||
isTronToken = false,
|
||||
feeCryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
),
|
||||
feeNonce = FeeNonce.None,
|
||||
feeFiatRateUM = FeeFiatRateUM(
|
||||
|
|
@ -269,6 +310,7 @@ private class FeeSelectorUMProvider : PreviewParameterProvider<FeeSelectorUM> {
|
|||
isFeeApproximate = false,
|
||||
isFeeConvertibleToFiat = true,
|
||||
isTronToken = false,
|
||||
feeCryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
),
|
||||
feeNonce = FeeNonce.None,
|
||||
feeFiatRateUM = FeeFiatRateUM(
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import com.tangem.common.ui.notifications.NotificationUM
|
|||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.features.send.v2.api.entity.*
|
||||
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
|
||||
import com.tangem.features.send.v2.sendnft.confirm.model.transformers.NFTSendConfirmationNotificationsTransformerV2
|
||||
|
|
@ -28,6 +30,34 @@ class NFTSendConfirmationNotificationsTransformerV2Test {
|
|||
private val appCurrency = AppCurrency(name = "US Dollar", code = "USD", symbol = "$")
|
||||
private val analyticsCategoryName = "test_category"
|
||||
|
||||
val cryptoCurrencyStatus = CryptoCurrencyStatus(
|
||||
currency = CryptoCurrency.Coin(
|
||||
id = CryptoCurrency.ID.fromValue("coin⟨BITCOIN⟩bitcoin"),
|
||||
network = Network(
|
||||
id = Network.ID(
|
||||
value = "bitcoin",
|
||||
derivationPath = Network.DerivationPath.None,
|
||||
),
|
||||
backendId = "bitcoin",
|
||||
name = "Bitcoin",
|
||||
currencySymbol = "BTC",
|
||||
derivationPath = Network.DerivationPath.None,
|
||||
isTestnet = false,
|
||||
standardType = Network.StandardType.Unspecified("bitcoin"),
|
||||
hasFiatFeeRate = false,
|
||||
canHandleTokens = false,
|
||||
transactionExtrasType = Network.TransactionExtrasType.NONE,
|
||||
nameResolvingType = Network.NameResolvingType.NONE,
|
||||
),
|
||||
name = "Bitcoin",
|
||||
symbol = "BTC",
|
||||
decimals = 8,
|
||||
iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/medium/bitcoin.png",
|
||||
isCustom = false,
|
||||
),
|
||||
value = CryptoCurrencyStatus.Loading,
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `GIVEN non content state WHEN transform THEN returns original state`() = runTest {
|
||||
// GIVEN
|
||||
|
|
@ -191,6 +221,7 @@ class NFTSendConfirmationNotificationsTransformerV2Test {
|
|||
isFeeApproximate = false,
|
||||
isFeeConvertibleToFiat = false,
|
||||
isTronToken = false,
|
||||
feeCryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
),
|
||||
feeFiatRateUM = FeeFiatRateUM(
|
||||
rate = BigDecimal("50000"),
|
||||
|
|
@ -274,6 +305,7 @@ class NFTSendConfirmationNotificationsTransformerV2Test {
|
|||
isFeeApproximate = false,
|
||||
isFeeConvertibleToFiat = false,
|
||||
isTronToken = false,
|
||||
feeCryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
),
|
||||
feeFiatRateUM = FeeFiatRateUM(
|
||||
rate = BigDecimal("50000"),
|
||||
|
|
@ -345,6 +377,7 @@ class NFTSendConfirmationNotificationsTransformerV2Test {
|
|||
isFeeApproximate = false,
|
||||
isFeeConvertibleToFiat = false,
|
||||
isTronToken = false,
|
||||
feeCryptoCurrencyStatus = cryptoCurrencyStatus
|
||||
),
|
||||
feeFiatRateUM = FeeFiatRateUM(
|
||||
rate = BigDecimal("50000"),
|
||||
|
|
@ -428,6 +461,7 @@ class NFTSendConfirmationNotificationsTransformerV2Test {
|
|||
isFeeApproximate = false,
|
||||
isFeeConvertibleToFiat = false,
|
||||
isTronToken = false,
|
||||
feeCryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
),
|
||||
feeFiatRateUM = FeeFiatRateUM(
|
||||
rate = BigDecimal("50000"),
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import com.tangem.common.ui.notifications.NotificationUM
|
|||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.features.send.v2.api.entity.*
|
||||
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
|
||||
import io.mockk.mockk
|
||||
|
|
@ -30,6 +32,34 @@ class SendConfirmationNotificationsTransformerV2Test {
|
|||
private val appCurrency = AppCurrency(name = "US Dollar", code = "USD", symbol = "$")
|
||||
private val analyticsCategoryName = "test_category"
|
||||
|
||||
val cryptoCurrencyStatus = CryptoCurrencyStatus(
|
||||
currency = CryptoCurrency.Coin(
|
||||
id = CryptoCurrency.ID.fromValue("coin⟨BITCOIN⟩bitcoin"),
|
||||
network = Network(
|
||||
id = Network.ID(
|
||||
value = "bitcoin",
|
||||
derivationPath = Network.DerivationPath.None,
|
||||
),
|
||||
backendId = "bitcoin",
|
||||
name = "Bitcoin",
|
||||
currencySymbol = "BTC",
|
||||
derivationPath = Network.DerivationPath.None,
|
||||
isTestnet = false,
|
||||
standardType = Network.StandardType.Unspecified("bitcoin"),
|
||||
hasFiatFeeRate = false,
|
||||
canHandleTokens = false,
|
||||
transactionExtrasType = Network.TransactionExtrasType.NONE,
|
||||
nameResolvingType = Network.NameResolvingType.NONE,
|
||||
),
|
||||
name = "Bitcoin",
|
||||
symbol = "BTC",
|
||||
decimals = 8,
|
||||
iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/medium/bitcoin.png",
|
||||
isCustom = false,
|
||||
),
|
||||
value = CryptoCurrencyStatus.Loading,
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `GIVEN non content state WHEN transform THEN returns original state`() = runTest {
|
||||
// GIVEN
|
||||
|
|
@ -247,6 +277,7 @@ class SendConfirmationNotificationsTransformerV2Test {
|
|||
isFeeApproximate = false,
|
||||
isFeeConvertibleToFiat = false,
|
||||
isTronToken = false,
|
||||
feeCryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
),
|
||||
feeFiatRateUM = FeeFiatRateUM(
|
||||
rate = BigDecimal("50000"),
|
||||
|
|
@ -330,6 +361,7 @@ class SendConfirmationNotificationsTransformerV2Test {
|
|||
isFeeApproximate = false,
|
||||
isFeeConvertibleToFiat = false,
|
||||
isTronToken = false,
|
||||
feeCryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
),
|
||||
feeFiatRateUM = FeeFiatRateUM(
|
||||
rate = BigDecimal("50000"),
|
||||
|
|
@ -401,6 +433,7 @@ class SendConfirmationNotificationsTransformerV2Test {
|
|||
isFeeApproximate = false,
|
||||
isFeeConvertibleToFiat = false,
|
||||
isTronToken = false,
|
||||
feeCryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
),
|
||||
feeFiatRateUM = FeeFiatRateUM(
|
||||
rate = BigDecimal("50000"),
|
||||
|
|
@ -484,6 +517,7 @@ class SendConfirmationNotificationsTransformerV2Test {
|
|||
isFeeApproximate = false,
|
||||
isFeeConvertibleToFiat = false,
|
||||
isTronToken = false,
|
||||
feeCryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
),
|
||||
feeFiatRateUM = FeeFiatRateUM(
|
||||
rate = BigDecimal("50000"),
|
||||
|
|
|
|||
|
|
@ -333,6 +333,7 @@ private fun SendWithSwapSuccessContent_Preview() {
|
|||
isFeeApproximate = false,
|
||||
isFeeConvertibleToFiat = false,
|
||||
isTronToken = false,
|
||||
feeCryptoCurrencyStatus = SwapAmountContentPreview.cryptoCurrencyStatus,
|
||||
),
|
||||
feeFiatRateUM = null,
|
||||
feeNonce = FeeNonce.None,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue