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