Updated on 2026-08-14
This commit is contained in:
parent
566c06095d
commit
8aa6ce0100
43 changed files with 274 additions and 146 deletions
|
|
@ -2,9 +2,12 @@ package com.tangem.features.send.v2.api
|
|||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.features.send.v2.api.entity.FeeSelectorUM
|
||||
import com.tangem.features.send.v2.api.params.FeeSelectorParams
|
||||
|
||||
interface FeeSelectorBlockComponent : ComposableContentComponent {
|
||||
|
||||
fun updateState(feeSelectorUM: FeeSelectorUM)
|
||||
|
||||
interface Factory : ComponentFactory<FeeSelectorParams.FeeSelectorBlockParams, FeeSelectorBlockComponent>
|
||||
}
|
||||
|
|
@ -2,11 +2,8 @@ package com.tangem.features.send.v2.api
|
|||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.features.send.v2.api.params.FeeSelectorParams
|
||||
|
||||
interface FeeSelectorComponent : ComposableContentComponent, ComposableBottomSheetComponent {
|
||||
data class Params(val appCurrency: AppCurrency)
|
||||
|
||||
interface Factory : ComponentFactory<Params, FeeSelectorComponent>
|
||||
interface FeeSelectorComponent : ComposableBottomSheetComponent {
|
||||
interface Factory : ComponentFactory<FeeSelectorParams.FeeSelectorDetailsParams, FeeSelectorComponent>
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package com.tangem.features.send.v2.api.callbacks
|
||||
|
||||
import com.tangem.features.send.v2.api.entity.FeeSelectorUM
|
||||
|
||||
interface FeeSelectorModelCallback {
|
||||
fun onFeeResult(feeSelectorUM: FeeSelectorUM)
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.features.send.v2.subcomponents.fee.ui.state
|
||||
package com.tangem.features.send.v2.api.entity
|
||||
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
|
|
@ -1,32 +1,23 @@
|
|||
package com.tangem.features.send.v2.feeselector.entity
|
||||
package com.tangem.features.send.v2.api.entity
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
import com.tangem.features.send.v2.subcomponents.fee.ui.state.CustomFeeFieldUM
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import java.math.BigDecimal
|
||||
import java.math.BigInteger
|
||||
|
||||
@Immutable
|
||||
internal sealed class FeeSelectorUM {
|
||||
sealed class FeeSelectorUM {
|
||||
|
||||
abstract val doneButtonConfig: PrimaryButtonConfig
|
||||
data object Loading : FeeSelectorUM()
|
||||
|
||||
data class Loading(private val onDone: () -> Unit) : FeeSelectorUM() {
|
||||
override val doneButtonConfig = PrimaryButtonConfig(enabled = false, onClick = onDone)
|
||||
}
|
||||
|
||||
data class Error(val error: GetFeeError, private val onDone: () -> Unit) : FeeSelectorUM() {
|
||||
override val doneButtonConfig = PrimaryButtonConfig(enabled = false, onClick = onDone)
|
||||
}
|
||||
data class Error(val error: GetFeeError) : FeeSelectorUM()
|
||||
|
||||
data class Content(
|
||||
override val doneButtonConfig: PrimaryButtonConfig,
|
||||
val feeItems: ImmutableList<FeeItem>,
|
||||
val onFeeSelected: (FeeItem) -> Unit,
|
||||
val selectedFeeItem: FeeItem,
|
||||
val isFeeApproximate: Boolean,
|
||||
val feeFiatRateUM: FeeFiatRateUM?,
|
||||
|
|
@ -36,18 +27,20 @@ internal sealed class FeeSelectorUM {
|
|||
) : FeeSelectorUM()
|
||||
}
|
||||
|
||||
internal data class PrimaryButtonConfig(val enabled: Boolean, val onClick: () -> Unit)
|
||||
|
||||
@Immutable
|
||||
internal data class FeeFiatRateUM(
|
||||
data class FeeFiatRateUM(
|
||||
val rate: BigDecimal,
|
||||
val appCurrency: AppCurrency,
|
||||
)
|
||||
|
||||
@Immutable
|
||||
internal sealed class FeeItem {
|
||||
sealed class FeeItem {
|
||||
abstract val fee: Fee
|
||||
|
||||
fun isSame(other: FeeItem): Boolean {
|
||||
return this::class == other::class
|
||||
}
|
||||
|
||||
data class Suggested(val title: TextReference, override val fee: Fee) : FeeItem()
|
||||
data class Slow(override val fee: Fee) : FeeItem()
|
||||
data class Market(override val fee: Fee) : FeeItem()
|
||||
|
|
@ -4,20 +4,32 @@ import arrow.core.Either
|
|||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
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 onLoadFee: suspend () -> Either<GetFeeError, TransactionFee>
|
||||
abstract val network: Network
|
||||
abstract val cryptoCurrencyStatus: CryptoCurrencyStatus
|
||||
abstract val callback: FeeSelectorModelCallback
|
||||
abstract val suggestedFeeState: SuggestedFeeState
|
||||
|
||||
data class FeeSelectorBlockParams(
|
||||
override val state: FeeSelectorUM,
|
||||
override val onLoadFee: suspend () -> Either<GetFeeError, TransactionFee>,
|
||||
override val network: Network,
|
||||
override val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
val suggestedFeeState: SuggestedFeeState,
|
||||
override val callback: FeeSelectorModelCallback,
|
||||
override val suggestedFeeState: SuggestedFeeState,
|
||||
) : FeeSelectorParams()
|
||||
|
||||
data class FeeSelectorDetailsParams(
|
||||
override val state: FeeSelectorUM,
|
||||
override val onLoadFee: suspend () -> Either<GetFeeError, TransactionFee>,
|
||||
override val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
override val callback: FeeSelectorModelCallback,
|
||||
override val suggestedFeeState: SuggestedFeeState,
|
||||
) : FeeSelectorParams()
|
||||
|
||||
sealed class SuggestedFeeState {
|
||||
|
|
|
|||
|
|
@ -33,17 +33,18 @@ import com.tangem.core.ui.res.TangemTheme
|
|||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.features.send.v2.api.FeeSelectorBlockComponent
|
||||
import com.tangem.features.send.v2.api.entity.FeeFiatRateUM
|
||||
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.entity.FeeFiatRateUM
|
||||
import com.tangem.features.send.v2.feeselector.entity.FeeItem
|
||||
import com.tangem.features.send.v2.feeselector.entity.FeeSelectorUM
|
||||
import com.tangem.features.send.v2.feeselector.entity.PrimaryButtonConfig
|
||||
import com.tangem.features.send.v2.feeselector.model.FeeSelectorModel
|
||||
import com.tangem.features.send.v2.impl.R
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal class DefaultFeeSelectorBlockComponent @AssistedInject constructor(
|
||||
|
|
@ -53,6 +54,16 @@ internal class DefaultFeeSelectorBlockComponent @AssistedInject constructor(
|
|||
|
||||
private val model: FeeSelectorModel = getOrCreateModel(params = params)
|
||||
|
||||
init {
|
||||
model.uiState
|
||||
.onEach(params.callback::onFeeResult)
|
||||
.launchIn(componentScope)
|
||||
}
|
||||
|
||||
override fun updateState(feeSelectorUM: FeeSelectorUM) {
|
||||
model.updateState(feeSelectorUM)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.uiState.collectAsStateWithLifecycle()
|
||||
|
|
@ -125,12 +136,13 @@ private fun RowScope.FeeLoading() {
|
|||
|
||||
@Composable
|
||||
private fun RowScope.FeeContent(state: FeeSelectorUM.Content) {
|
||||
val fiatRate = state.feeFiatRateUM
|
||||
EllipsisText(
|
||||
text = if (state.feeFiatRateUM != null) {
|
||||
text = if (fiatRate != null) {
|
||||
getFiatString(
|
||||
value = state.selectedFeeItem.fee.amount.value,
|
||||
rate = state.feeFiatRateUM.rate,
|
||||
appCurrency = state.feeFiatRateUM.appCurrency,
|
||||
rate = fiatRate.rate,
|
||||
appCurrency = fiatRate.appCurrency,
|
||||
approximate = state.isFeeApproximate,
|
||||
)
|
||||
} else {
|
||||
|
|
@ -167,9 +179,7 @@ private fun FeeSelectorBlockContent_Preview() {
|
|||
FeeSelectorBlockContent(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
state = FeeSelectorUM.Content(
|
||||
doneButtonConfig = PrimaryButtonConfig(enabled = true, onClick = {}),
|
||||
feeItems = persistentListOf(feeItem),
|
||||
onFeeSelected = {},
|
||||
selectedFeeItem = feeItem,
|
||||
isFeeApproximate = false,
|
||||
feeFiatRateUM = FeeFiatRateUM(
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
package com.tangem.features.send.v2.feeselector
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.features.send.v2.api.FeeSelectorComponent
|
||||
import com.tangem.features.send.v2.api.params.FeeSelectorParams
|
||||
import com.tangem.features.send.v2.feeselector.model.FeeSelectorModel
|
||||
import com.tangem.features.send.v2.feeselector.ui.FeeSelectorModalBottomSheet
|
||||
import dagger.assisted.Assisted
|
||||
|
|
@ -16,7 +15,7 @@ import dagger.assisted.AssistedInject
|
|||
|
||||
internal class DefaultFeeSelectorComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
@Assisted private val params: FeeSelectorComponent.Params,
|
||||
@Assisted private val params: FeeSelectorParams.FeeSelectorDetailsParams,
|
||||
) : FeeSelectorComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val model: FeeSelectorModel = getOrCreateModel(params = params)
|
||||
|
|
@ -27,22 +26,15 @@ internal class DefaultFeeSelectorComponent @AssistedInject constructor(
|
|||
|
||||
@Composable
|
||||
override fun BottomSheet() {
|
||||
FeeSelectorModalBottomSheet(onDismiss = ::dismiss, state = TODO())
|
||||
}
|
||||
|
||||
// Temporary workaround, to use test this component
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.uiState.collectAsStateWithLifecycle()
|
||||
BackHandler(onBack = router::pop)
|
||||
FeeSelectorModalBottomSheet(onDismiss = ::dismiss, state = state)
|
||||
FeeSelectorModalBottomSheet(onDismiss = ::dismiss, state = state, feeSelectorIntents = model)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : FeeSelectorComponent.Factory {
|
||||
override fun create(
|
||||
context: AppComponentContext,
|
||||
params: FeeSelectorComponent.Params,
|
||||
params: FeeSelectorParams.FeeSelectorDetailsParams,
|
||||
): DefaultFeeSelectorComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.tangem.features.send.v2.feeselector.model
|
||||
|
||||
import com.tangem.features.send.v2.api.entity.FeeItem
|
||||
|
||||
internal interface FeeSelectorIntents {
|
||||
fun onFeeItemSelected(feeItem: FeeItem)
|
||||
fun onCustomFeeValueChange(index: Int, value: String)
|
||||
fun onCustomFeeNextClick()
|
||||
fun onDoneClick()
|
||||
}
|
||||
|
||||
internal class StubFeeSelectorIntents : FeeSelectorIntents {
|
||||
override fun onFeeItemSelected(feeItem: FeeItem) {}
|
||||
override fun onCustomFeeValueChange(index: Int, value: String) {}
|
||||
override fun onCustomFeeNextClick() {}
|
||||
override fun onDoneClick() {}
|
||||
}
|
||||
|
|
@ -10,9 +10,9 @@ import com.tangem.core.decompose.navigation.Router
|
|||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.transaction.usecase.IsFeeApproximateUseCase
|
||||
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.entity.FeeItem
|
||||
import com.tangem.features.send.v2.feeselector.entity.FeeSelectorUM
|
||||
import com.tangem.features.send.v2.feeselector.model.transformers.FeeItemSelectedTransformer
|
||||
import com.tangem.features.send.v2.feeselector.model.transformers.FeeSelectorErrorTransformer
|
||||
import com.tangem.features.send.v2.feeselector.model.transformers.FeeSelectorLoadedTransformer
|
||||
|
|
@ -31,19 +31,23 @@ internal class FeeSelectorModel @Inject constructor(
|
|||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val router: Router,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
) : Model() {
|
||||
) : Model(), FeeSelectorIntents {
|
||||
|
||||
private val params = paramsContainer.require<FeeSelectorParams.FeeSelectorBlockParams>()
|
||||
private val params = paramsContainer.require<FeeSelectorParams>()
|
||||
private var appCurrency: AppCurrency = AppCurrency.Default
|
||||
|
||||
val uiState: StateFlow<FeeSelectorUM>
|
||||
field = MutableStateFlow<FeeSelectorUM>(FeeSelectorUM.Loading(onDone = ::onDone))
|
||||
field = MutableStateFlow<FeeSelectorUM>(params.state)
|
||||
|
||||
init {
|
||||
initAppCurrency()
|
||||
loadFee()
|
||||
}
|
||||
|
||||
fun updateState(feeSelectorUM: FeeSelectorUM) {
|
||||
uiState.value = feeSelectorUM
|
||||
}
|
||||
|
||||
fun dismiss() {
|
||||
router.pop()
|
||||
}
|
||||
|
|
@ -58,18 +62,16 @@ internal class FeeSelectorModel @Inject constructor(
|
|||
modelScope.launch {
|
||||
params.onLoadFee()
|
||||
.fold(
|
||||
ifLeft = { uiState.update(FeeSelectorErrorTransformer(it)) },
|
||||
ifRight = {
|
||||
ifLeft = { error -> uiState.update(FeeSelectorErrorTransformer(error)) },
|
||||
ifRight = { fee ->
|
||||
uiState.update(
|
||||
FeeSelectorLoadedTransformer(
|
||||
cryptoCurrencyStatus = params.cryptoCurrencyStatus,
|
||||
appCurrency = appCurrency,
|
||||
fees = it,
|
||||
fees = fee,
|
||||
suggestedFeeState = params.suggestedFeeState,
|
||||
isFeeApproximate = isFeeApproximate(it.normal.amount.type),
|
||||
onFeeSelected = ::onFeeItemSelected,
|
||||
onCustomFeeValueChange = ::onCustomFeeValueChange,
|
||||
onNextClick = ::onNextClick,
|
||||
isFeeApproximate = isFeeApproximate(fee.normal.amount.type),
|
||||
feeSelectorIntents = this@FeeSelectorModel,
|
||||
),
|
||||
)
|
||||
},
|
||||
|
|
@ -78,24 +80,24 @@ internal class FeeSelectorModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun isFeeApproximate(amountType: AmountType): Boolean {
|
||||
val networkId = params.network.id
|
||||
val networkId = params.cryptoCurrencyStatus.currency.network.id
|
||||
return isFeeApproximateUseCase(networkId = networkId, amountType = amountType)
|
||||
}
|
||||
|
||||
private fun onFeeItemSelected(feeItem: FeeItem) {
|
||||
override fun onFeeItemSelected(feeItem: FeeItem) {
|
||||
uiState.update(FeeItemSelectedTransformer(feeItem))
|
||||
}
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
private fun onCustomFeeValueChange(index: Int, value: String) {
|
||||
override fun onCustomFeeValueChange(index: Int, value: String) {
|
||||
// TODO: [REDACTED_JIRA]
|
||||
}
|
||||
|
||||
private fun onNextClick() {
|
||||
override fun onCustomFeeNextClick() {
|
||||
// TODO: [REDACTED_JIRA]
|
||||
}
|
||||
|
||||
private fun onDone() {
|
||||
// TODO: [REDACTED_JIRA]
|
||||
override fun onDoneClick() {
|
||||
params.callback.onFeeResult(uiState.value)
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,8 @@ import com.tangem.blockchain.common.transaction.TransactionFee
|
|||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.features.send.v2.api.params.FeeSelectorParams
|
||||
import com.tangem.features.send.v2.feeselector.entity.FeeItem
|
||||
import com.tangem.features.send.v2.api.entity.FeeItem
|
||||
import com.tangem.features.send.v2.feeselector.model.FeeSelectorIntents
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
|
@ -13,15 +14,13 @@ import kotlinx.collections.immutable.toImmutableList
|
|||
internal class FeeItemConverter(
|
||||
private val suggestedFeeState: FeeSelectorParams.SuggestedFeeState,
|
||||
private val normalFee: Fee,
|
||||
private val onCustomFeeValueChange: (Int, String) -> Unit,
|
||||
private val onNextClick: () -> Unit,
|
||||
private val feeSelectorIntents: FeeSelectorIntents,
|
||||
private val appCurrency: AppCurrency,
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
) : Converter<TransactionFee, ImmutableList<FeeItem>> {
|
||||
|
||||
private val customFeeFieldConverter = FeeSelectorCustomFieldConverter(
|
||||
onCustomFeeValueChange = onCustomFeeValueChange,
|
||||
onNextClick = onNextClick,
|
||||
feeSelectorIntents = feeSelectorIntents,
|
||||
appCurrency = appCurrency,
|
||||
feeCryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
normalFee = normalFee,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.features.send.v2.feeselector.model.transformers
|
||||
|
||||
import com.tangem.features.send.v2.feeselector.entity.FeeItem
|
||||
import com.tangem.features.send.v2.feeselector.entity.FeeSelectorUM
|
||||
import com.tangem.features.send.v2.api.entity.FeeItem
|
||||
import com.tangem.features.send.v2.api.entity.FeeSelectorUM
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
internal class FeeItemSelectedTransformer(private val selectedFeeItem: FeeItem) : Transformer<FeeSelectorUM> {
|
||||
|
|
|
|||
|
|
@ -8,15 +8,15 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
|||
import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.bitcoin.BitcoinCustomFeeConverter
|
||||
import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.ethereum.EthereumCustomFeeConverter
|
||||
import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.kaspa.KaspaCustomFeeConverter
|
||||
import com.tangem.features.send.v2.subcomponents.fee.ui.state.CustomFeeFieldUM
|
||||
import com.tangem.features.send.v2.api.entity.CustomFeeFieldUM
|
||||
import com.tangem.features.send.v2.feeselector.model.FeeSelectorIntents
|
||||
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeSelectorUM
|
||||
import com.tangem.utils.converter.TwoWayConverter
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
internal class FeeSelectorCustomFieldConverter(
|
||||
private val onCustomFeeValueChange: (Int, String) -> Unit,
|
||||
private val onNextClick: () -> Unit,
|
||||
private val feeSelectorIntents: FeeSelectorIntents,
|
||||
private val appCurrency: AppCurrency,
|
||||
private val feeCryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
private val normalFee: Fee,
|
||||
|
|
@ -24,8 +24,8 @@ internal class FeeSelectorCustomFieldConverter(
|
|||
|
||||
private val ethereumCustomFeeConverter by lazy(LazyThreadSafetyMode.NONE) {
|
||||
EthereumCustomFeeConverter(
|
||||
onCustomFeeValueChange = onCustomFeeValueChange,
|
||||
onNextClick = onNextClick,
|
||||
onCustomFeeValueChange = feeSelectorIntents::onCustomFeeValueChange,
|
||||
onNextClick = feeSelectorIntents::onCustomFeeNextClick,
|
||||
appCurrency = appCurrency,
|
||||
feeCryptoCurrencyStatus = feeCryptoCurrencyStatus,
|
||||
)
|
||||
|
|
@ -33,8 +33,8 @@ internal class FeeSelectorCustomFieldConverter(
|
|||
|
||||
private val bitcoinCustomFeeConverter by lazy(LazyThreadSafetyMode.NONE) {
|
||||
BitcoinCustomFeeConverter(
|
||||
onCustomFeeValueChange = onCustomFeeValueChange,
|
||||
onNextClick = onNextClick,
|
||||
onCustomFeeValueChange = feeSelectorIntents::onCustomFeeValueChange,
|
||||
onNextClick = feeSelectorIntents::onCustomFeeNextClick,
|
||||
appCurrency = appCurrency,
|
||||
feeCryptoCurrencyStatus = feeCryptoCurrencyStatus,
|
||||
)
|
||||
|
|
@ -42,7 +42,7 @@ internal class FeeSelectorCustomFieldConverter(
|
|||
|
||||
private val kaspaCustomFeeConverter by lazy(LazyThreadSafetyMode.NONE) {
|
||||
KaspaCustomFeeConverter(
|
||||
onCustomFeeValueChange = onCustomFeeValueChange,
|
||||
onCustomFeeValueChange = feeSelectorIntents::onCustomFeeValueChange,
|
||||
appCurrency = appCurrency,
|
||||
feeCryptoCurrencyStatus = feeCryptoCurrencyStatus,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
package com.tangem.features.send.v2.feeselector.model.transformers
|
||||
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
import com.tangem.features.send.v2.feeselector.entity.FeeSelectorUM
|
||||
import com.tangem.features.send.v2.api.entity.FeeSelectorUM
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
internal class FeeSelectorErrorTransformer(private val error: GetFeeError) : Transformer<FeeSelectorUM> {
|
||||
|
||||
override fun transform(prevState: FeeSelectorUM): FeeSelectorUM {
|
||||
return FeeSelectorUM.Error(error = error, onDone = prevState.doneButtonConfig.onClick)
|
||||
return FeeSelectorUM.Error(error = error)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,10 +3,11 @@ package com.tangem.features.send.v2.feeselector.model.transformers
|
|||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.features.send.v2.api.entity.FeeFiatRateUM
|
||||
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.entity.FeeFiatRateUM
|
||||
import com.tangem.features.send.v2.feeselector.entity.FeeItem
|
||||
import com.tangem.features.send.v2.feeselector.entity.FeeSelectorUM
|
||||
import com.tangem.features.send.v2.feeselector.model.FeeSelectorIntents
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
|
|
@ -17,29 +18,31 @@ internal class FeeSelectorLoadedTransformer(
|
|||
private val fees: TransactionFee,
|
||||
private val suggestedFeeState: FeeSelectorParams.SuggestedFeeState,
|
||||
private val isFeeApproximate: Boolean,
|
||||
private val onFeeSelected: (FeeItem) -> Unit,
|
||||
private val onCustomFeeValueChange: (Int, String) -> Unit,
|
||||
private val onNextClick: () -> Unit,
|
||||
private val feeSelectorIntents: FeeSelectorIntents,
|
||||
) : Transformer<FeeSelectorUM> {
|
||||
|
||||
private val feeItemsConverter = FeeItemConverter(
|
||||
suggestedFeeState = suggestedFeeState,
|
||||
normalFee = fees.normal,
|
||||
onCustomFeeValueChange = onCustomFeeValueChange,
|
||||
onNextClick = onNextClick,
|
||||
feeSelectorIntents = feeSelectorIntents,
|
||||
appCurrency = appCurrency,
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
)
|
||||
|
||||
override fun transform(prevState: FeeSelectorUM): FeeSelectorUM {
|
||||
val feeItems: ImmutableList<FeeItem> = feeItemsConverter.convert(fees)
|
||||
val selectedFee = feeItems.find { it is FeeItem.Suggested } ?: feeItems.first { it is FeeItem.Market }
|
||||
|
||||
val selectedFee = when (prevState) {
|
||||
is FeeSelectorUM.Content -> feeItems.first { it.isSame(prevState.selectedFeeItem) }
|
||||
is FeeSelectorUM.Error,
|
||||
FeeSelectorUM.Loading,
|
||||
-> feeItems.find { it is FeeItem.Suggested } ?: feeItems.first { it is FeeItem.Market }
|
||||
}
|
||||
|
||||
return FeeSelectorUM.Content(
|
||||
doneButtonConfig = prevState.doneButtonConfig.copy(enabled = true),
|
||||
feeItems = feeItems,
|
||||
selectedFeeItem = selectedFee,
|
||||
isFeeApproximate = isFeeApproximate,
|
||||
onFeeSelected = onFeeSelected,
|
||||
feeFiatRateUM = cryptoCurrencyStatus.value.fiatRate?.let { rate ->
|
||||
FeeFiatRateUM(
|
||||
rate = rate,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import androidx.compose.material3.Icon
|
|||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
|
|
@ -48,12 +47,13 @@ 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.features.send.v2.feeselector.entity.FeeFiatRateUM
|
||||
import com.tangem.features.send.v2.feeselector.entity.FeeItem
|
||||
import com.tangem.features.send.v2.feeselector.entity.FeeSelectorUM
|
||||
import com.tangem.features.send.v2.feeselector.entity.PrimaryButtonConfig
|
||||
import com.tangem.features.send.v2.api.entity.CustomFeeFieldUM
|
||||
import com.tangem.features.send.v2.api.entity.FeeFiatRateUM
|
||||
import com.tangem.features.send.v2.api.entity.FeeItem
|
||||
import com.tangem.features.send.v2.api.entity.FeeSelectorUM
|
||||
import com.tangem.features.send.v2.feeselector.model.FeeSelectorIntents
|
||||
import com.tangem.features.send.v2.feeselector.model.StubFeeSelectorIntents
|
||||
import com.tangem.features.send.v2.impl.R
|
||||
import com.tangem.features.send.v2.subcomponents.fee.ui.state.CustomFeeFieldUM
|
||||
import com.tangem.utils.StringsSigns
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
|
@ -61,7 +61,11 @@ import java.math.BigDecimal
|
|||
import java.math.BigInteger
|
||||
|
||||
@Composable
|
||||
internal fun FeeSelectorModalBottomSheet(state: FeeSelectorUM, onDismiss: () -> Unit) {
|
||||
internal fun FeeSelectorModalBottomSheet(
|
||||
state: FeeSelectorUM,
|
||||
feeSelectorIntents: FeeSelectorIntents,
|
||||
onDismiss: () -> Unit,
|
||||
) {
|
||||
if (state !is FeeSelectorUM.Content) return
|
||||
|
||||
TangemModalBottomSheetWithFooter<TangemBottomSheetConfigContent.Empty>(
|
||||
|
|
@ -81,6 +85,7 @@ internal fun FeeSelectorModalBottomSheet(state: FeeSelectorUM, onDismiss: () ->
|
|||
content = {
|
||||
FeeSelectorItems(
|
||||
state = state,
|
||||
feeSelectorIntents = feeSelectorIntents,
|
||||
modifier = Modifier.padding(vertical = 4.dp, horizontal = 16.dp),
|
||||
)
|
||||
},
|
||||
|
|
@ -90,8 +95,7 @@ internal fun FeeSelectorModalBottomSheet(state: FeeSelectorUM, onDismiss: () ->
|
|||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
text = stringResourceSafe(R.string.common_done),
|
||||
onClick = state.doneButtonConfig.onClick,
|
||||
enabled = state.doneButtonConfig.enabled,
|
||||
onClick = feeSelectorIntents::onDoneClick,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
|
@ -99,10 +103,15 @@ internal fun FeeSelectorModalBottomSheet(state: FeeSelectorUM, onDismiss: () ->
|
|||
|
||||
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
||||
@Composable
|
||||
private fun FeeSelectorItems(state: FeeSelectorUM.Content, modifier: Modifier = Modifier) {
|
||||
private fun FeeSelectorItems(
|
||||
state: FeeSelectorUM.Content,
|
||||
feeSelectorIntents: FeeSelectorIntents,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(modifier = modifier) {
|
||||
val feeFiatRateUM = state.feeFiatRateUM
|
||||
state.feeItems.fastForEachIndexed { index, item ->
|
||||
val isSelected = item == state.selectedFeeItem
|
||||
val isSelected = item.isSame(state.selectedFeeItem)
|
||||
val lastItem = index == state.feeItems.size - 1
|
||||
val iconTint by animateColorAsState(
|
||||
targetValue = if (isSelected) TangemTheme.colors.icon.accent else TangemTheme.colors.text.tertiary,
|
||||
|
|
@ -116,7 +125,6 @@ private fun FeeSelectorItems(state: FeeSelectorUM.Content, modifier: Modifier =
|
|||
},
|
||||
label = "Fee selector icon background change",
|
||||
)
|
||||
val onSelect by rememberUpdatedState(state.onFeeSelected)
|
||||
val itemModifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(TangemTheme.colors.background.primary)
|
||||
|
|
@ -135,7 +143,7 @@ private fun FeeSelectorItems(state: FeeSelectorUM.Content, modifier: Modifier =
|
|||
Modifier
|
||||
},
|
||||
)
|
||||
.clickableSingle(onClick = { onSelect(item) })
|
||||
.clickableSingle(onClick = { feeSelectorIntents.onFeeItemSelected(item) })
|
||||
when (item) {
|
||||
is FeeItem.Suggested -> RegularFeeItemContent(
|
||||
modifier = itemModifier,
|
||||
|
|
@ -151,11 +159,11 @@ private fun FeeSelectorItems(state: FeeSelectorUM.Content, modifier: Modifier =
|
|||
).fee(canBeLower = state.isFeeApproximate)
|
||||
},
|
||||
),
|
||||
postDot = if (state.feeFiatRateUM != null) {
|
||||
postDot = if (feeFiatRateUM != null) {
|
||||
getFiatReference(
|
||||
value = item.fee.amount.value,
|
||||
rate = state.feeFiatRateUM.rate,
|
||||
appCurrency = state.feeFiatRateUM.appCurrency,
|
||||
rate = feeFiatRateUM.rate,
|
||||
appCurrency = feeFiatRateUM.appCurrency,
|
||||
)
|
||||
} else {
|
||||
null
|
||||
|
|
@ -177,11 +185,11 @@ private fun FeeSelectorItems(state: FeeSelectorUM.Content, modifier: Modifier =
|
|||
).fee(canBeLower = state.isFeeApproximate)
|
||||
},
|
||||
),
|
||||
postDot = if (state.feeFiatRateUM != null) {
|
||||
postDot = if (feeFiatRateUM != null) {
|
||||
getFiatReference(
|
||||
value = item.fee.amount.value,
|
||||
rate = state.feeFiatRateUM.rate,
|
||||
appCurrency = state.feeFiatRateUM.appCurrency,
|
||||
rate = feeFiatRateUM.rate,
|
||||
appCurrency = feeFiatRateUM.appCurrency,
|
||||
)
|
||||
} else {
|
||||
null
|
||||
|
|
@ -203,11 +211,11 @@ private fun FeeSelectorItems(state: FeeSelectorUM.Content, modifier: Modifier =
|
|||
).fee(canBeLower = state.isFeeApproximate)
|
||||
},
|
||||
),
|
||||
postDot = if (state.feeFiatRateUM != null) {
|
||||
postDot = if (feeFiatRateUM != null) {
|
||||
getFiatReference(
|
||||
value = item.fee.amount.value,
|
||||
rate = state.feeFiatRateUM.rate,
|
||||
appCurrency = state.feeFiatRateUM.appCurrency,
|
||||
rate = feeFiatRateUM.rate,
|
||||
appCurrency = feeFiatRateUM.appCurrency,
|
||||
)
|
||||
} else {
|
||||
null
|
||||
|
|
@ -229,11 +237,11 @@ private fun FeeSelectorItems(state: FeeSelectorUM.Content, modifier: Modifier =
|
|||
).fee(canBeLower = state.isFeeApproximate)
|
||||
},
|
||||
),
|
||||
postDot = if (state.feeFiatRateUM != null) {
|
||||
postDot = if (feeFiatRateUM != null) {
|
||||
getFiatReference(
|
||||
value = item.fee.amount.value,
|
||||
rate = state.feeFiatRateUM.rate,
|
||||
appCurrency = state.feeFiatRateUM.appCurrency,
|
||||
rate = feeFiatRateUM.rate,
|
||||
appCurrency = feeFiatRateUM.appCurrency,
|
||||
)
|
||||
} else {
|
||||
null
|
||||
|
|
@ -466,14 +474,13 @@ private fun FeeSelectorBS_Preview(
|
|||
state: FeeSelectorUM.Content,
|
||||
) {
|
||||
TangemThemePreview {
|
||||
FeeSelectorModalBottomSheet(onDismiss = {}, state = state)
|
||||
FeeSelectorModalBottomSheet(onDismiss = {}, state = state, feeSelectorIntents = StubFeeSelectorIntents())
|
||||
}
|
||||
}
|
||||
|
||||
private class FeeSelectorUMContentProvider : CollectionPreviewParameterProvider<FeeSelectorUM.Content>(
|
||||
collection = listOf(
|
||||
FeeSelectorUM.Content(
|
||||
doneButtonConfig = PrimaryButtonConfig(enabled = true, onClick = {}),
|
||||
feeItems = persistentListOf(
|
||||
FeeItem.Suggested(
|
||||
title = stringReference("Suggested by Tangem"),
|
||||
|
|
@ -484,7 +491,6 @@ private class FeeSelectorUMContentProvider : CollectionPreviewParameterProvider<
|
|||
FeeItem.Fast(fee = Fee.Common(Amount(value = BigDecimal("0.03"), blockchain = Blockchain.Ethereum))),
|
||||
customFeeItem,
|
||||
),
|
||||
onFeeSelected = {},
|
||||
// selectedFeeItem = FeeItem.Market(
|
||||
// amount = Amount(value = BigDecimal("0.02"), blockchain = Blockchain.Ethereum),
|
||||
// ),
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import com.tangem.blockchain.common.transaction.TransactionFee
|
|||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.features.send.v2.subcomponents.fee.model.SendFeeClickIntents
|
||||
import com.tangem.features.send.v2.subcomponents.fee.ui.state.CustomFeeFieldUM
|
||||
import com.tangem.features.send.v2.api.entity.CustomFeeFieldUM
|
||||
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeType
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import com.tangem.features.send.v2.subcomponents.fee.model.SendFeeClickIntents
|
|||
import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.bitcoin.BitcoinCustomFeeConverter
|
||||
import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.ethereum.EthereumCustomFeeConverter
|
||||
import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.kaspa.KaspaCustomFeeConverter
|
||||
import com.tangem.features.send.v2.subcomponents.fee.ui.state.CustomFeeFieldUM
|
||||
import com.tangem.features.send.v2.api.entity.CustomFeeFieldUM
|
||||
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeSelectorUM
|
||||
import com.tangem.utils.converter.TwoWayConverter
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.features.send.v2.subcomponents.fee.model.converters.custom
|
||||
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.features.send.v2.subcomponents.fee.ui.state.CustomFeeFieldUM
|
||||
import com.tangem.features.send.v2.api.entity.CustomFeeFieldUM
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
|||
import com.tangem.features.send.v2.impl.R
|
||||
import com.tangem.features.send.v2.subcomponents.fee.model.checkExceedBalance
|
||||
import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.CustomFeeConverter
|
||||
import com.tangem.features.send.v2.subcomponents.fee.ui.state.CustomFeeFieldUM
|
||||
import com.tangem.features.send.v2.api.entity.CustomFeeFieldUM
|
||||
import com.tangem.lib.crypto.BlockchainUtils
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.et
|
|||
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.CustomFeeConverter
|
||||
import com.tangem.features.send.v2.subcomponents.fee.ui.state.CustomFeeFieldUM
|
||||
import com.tangem.features.send.v2.api.entity.CustomFeeFieldUM
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import com.tangem.domain.appcurrency.model.AppCurrency
|
|||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.features.send.v2.impl.R
|
||||
import com.tangem.features.send.v2.subcomponents.fee.model.checkExceedBalance
|
||||
import com.tangem.features.send.v2.subcomponents.fee.ui.state.CustomFeeFieldUM
|
||||
import com.tangem.features.send.v2.api.entity.CustomFeeFieldUM
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.eth
|
|||
import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.ethereum.EthereumCustomFeeConverter.Companion.GAS_DECIMALS
|
||||
import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.ethereum.EthereumCustomFeeConverter.Companion.GIGA_DECIMALS
|
||||
import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.setEmpty
|
||||
import com.tangem.features.send.v2.subcomponents.fee.ui.state.CustomFeeFieldUM
|
||||
import com.tangem.features.send.v2.api.entity.CustomFeeFieldUM
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.eth
|
|||
import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.ethereum.EthereumCustomFeeConverter.Companion.GAS_DECIMALS
|
||||
import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.ethereum.EthereumCustomFeeConverter.Companion.GIGA_DECIMALS
|
||||
import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.setEmpty
|
||||
import com.tangem.features.send.v2.subcomponents.fee.ui.state.CustomFeeFieldUM
|
||||
import com.tangem.features.send.v2.api.entity.CustomFeeFieldUM
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import com.tangem.domain.appcurrency.model.AppCurrency
|
|||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.features.send.v2.impl.R
|
||||
import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.CustomFeeConverter
|
||||
import com.tangem.features.send.v2.subcomponents.fee.ui.state.CustomFeeFieldUM
|
||||
import com.tangem.features.send.v2.api.entity.CustomFeeFieldUM
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import com.tangem.core.ui.components.inputrow.InputRowEnterInfoAmount
|
|||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.send.v2.impl.R
|
||||
import com.tangem.features.send.v2.subcomponents.fee.ui.state.CustomFeeFieldUM
|
||||
import com.tangem.features.send.v2.api.entity.CustomFeeFieldUM
|
||||
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeType
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import com.tangem.blockchain.common.transaction.Fee
|
|||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
import com.tangem.features.send.v2.api.entity.CustomFeeFieldUM
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import java.math.BigInteger
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.features.send.v2.subcomponents.fee.ui.state
|
|||
import androidx.compose.runtime.Stable
|
||||
import com.tangem.common.ui.notifications.NotificationUM
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.features.send.v2.api.entity.CustomFeeFieldUM
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import java.math.BigDecimal
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import com.tangem.core.decompose.context.childByContext
|
|||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.features.send.v2.api.FeeSelectorBlockComponent
|
||||
import com.tangem.features.send.v2.api.FeeSelectorComponent
|
||||
import com.tangem.features.walletconnect.components.WcRoutingComponent
|
||||
import com.tangem.features.walletconnect.connections.components.AlertsComponent
|
||||
import com.tangem.features.walletconnect.connections.components.WcPairComponent
|
||||
|
|
@ -31,6 +32,7 @@ internal class DefaultWcRoutingComponent @AssistedInject constructor(
|
|||
@Assisted private val appComponentContext: AppComponentContext,
|
||||
@Assisted params: Unit,
|
||||
private val feeSelectorBlockComponentFactory: FeeSelectorBlockComponent.Factory,
|
||||
private val feeSelectorComponentFactory: FeeSelectorComponent.Factory,
|
||||
) : AppComponentContext by appComponentContext, WcRoutingComponent {
|
||||
|
||||
private val model: WcRoutingModel = getOrCreateModel()
|
||||
|
|
@ -73,6 +75,7 @@ internal class DefaultWcRoutingComponent @AssistedInject constructor(
|
|||
appComponentContext = childContext,
|
||||
params = WcTransactionModelParams(config.rawRequest),
|
||||
feeSelectorBlockComponentFactory = feeSelectorBlockComponentFactory,
|
||||
feeSelectorComponentFactory = feeSelectorComponentFactory,
|
||||
)
|
||||
is WcInnerRoute.Pair -> WcPairComponent(
|
||||
appComponentContext = childContext,
|
||||
|
|
|
|||
|
|
@ -15,9 +15,14 @@ import androidx.compose.ui.unit.dp
|
|||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.send.v2.api.FeeSelectorBlockComponent
|
||||
import com.tangem.features.send.v2.api.entity.FeeSelectorUM
|
||||
import com.tangem.features.walletconnect.impl.R
|
||||
|
||||
internal class PreviewFeeSelectorBlockComponent : FeeSelectorBlockComponent {
|
||||
override fun updateState(feeSelectorUM: FeeSelectorUM) {
|
||||
/** No-op */
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
Row(
|
||||
|
|
|
|||
|
|
@ -61,8 +61,9 @@ internal abstract class WcCommonTransactionComponentDelegate(
|
|||
is WcTransactionRoutes.TransactionRequestInfo,
|
||||
is WcTransactionRoutes.Alert,
|
||||
is WcTransactionRoutes.CustomAllowance,
|
||||
is WcTransactionRoutes.SelectFee,
|
||||
-> stackNavigation?.pop()
|
||||
else -> Unit
|
||||
null -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,8 @@ package com.tangem.features.walletconnect.transaction.components.common
|
|||
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.features.send.v2.api.FeeSelectorComponent
|
||||
import com.tangem.features.send.v2.api.params.FeeSelectorParams
|
||||
import com.tangem.features.walletconnect.connections.components.AlertsComponentV2
|
||||
import com.tangem.features.walletconnect.connections.utils.WcAlertsFactory.createCommonTransactionAppInfoAlertUM
|
||||
import com.tangem.features.walletconnect.transaction.components.send.WcCustomAllowanceComponent
|
||||
|
|
@ -14,6 +16,7 @@ internal fun getWcCommonScreen(
|
|||
appComponentContext: AppComponentContext,
|
||||
transactionScreenConverter: () -> ComposableBottomSheetComponent,
|
||||
model: WcCommonTransactionModel,
|
||||
feeSelectorComponentFactory: FeeSelectorComponent.Factory? = null,
|
||||
): ComposableBottomSheetComponent {
|
||||
return when (config) {
|
||||
is WcTransactionRoutes.Transaction -> transactionScreenConverter()
|
||||
|
|
@ -32,5 +35,20 @@ internal fun getWcCommonScreen(
|
|||
(model as? WcSendTransactionModel)?.onClickDoneCustomAllowance(value, isUnlimited)
|
||||
},
|
||||
)
|
||||
is WcTransactionRoutes.SelectFee -> {
|
||||
requireNotNull(feeSelectorComponentFactory) { "feeSelectorComponentFactory must not be null" }
|
||||
val model = model as? WcSendTransactionModel ?: error("model must be WcSendTransactionModel")
|
||||
val state = model.uiState.value ?: error("in this step state should be not null")
|
||||
feeSelectorComponentFactory.create(
|
||||
context = appComponentContext,
|
||||
params = FeeSelectorParams.FeeSelectorDetailsParams(
|
||||
state = state.feeSelectorUM,
|
||||
onLoadFee = model::loadFee,
|
||||
cryptoCurrencyStatus = model.cryptoCurrencyStatus,
|
||||
callback = model,
|
||||
suggestedFeeState = model.suggestedFeeState,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,10 +3,12 @@ package com.tangem.features.walletconnect.transaction.components.send
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.arkivanov.essenty.lifecycle.doOnResume
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.features.send.v2.api.FeeSelectorBlockComponent
|
||||
import com.tangem.features.send.v2.api.params.FeeSelectorParams
|
||||
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionFeeState
|
||||
import com.tangem.features.walletconnect.transaction.model.WcSendTransactionModel
|
||||
import com.tangem.features.walletconnect.transaction.ui.send.WcSendTransactionModalBottomSheet
|
||||
|
||||
|
|
@ -17,17 +19,28 @@ internal class WcSendTransactionComponent(
|
|||
) : AppComponentContext by appComponentContext, ComposableBottomSheetComponent {
|
||||
|
||||
private val feeSelectorBlockComponent by lazy {
|
||||
val state = requireNotNull(model.uiState.value) { "in this step state should be not null" }
|
||||
feeSelectorBlockComponentFactory.create(
|
||||
context = appComponentContext,
|
||||
params = FeeSelectorParams.FeeSelectorBlockParams(
|
||||
state = state.feeSelectorUM,
|
||||
onLoadFee = model::loadFee,
|
||||
network = model.useCase.network,
|
||||
cryptoCurrencyStatus = model.cryptoCurrencyStatus,
|
||||
callback = model,
|
||||
suggestedFeeState = model.suggestedFeeState,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
init {
|
||||
lifecycle.doOnResume {
|
||||
val state = model.uiState.value
|
||||
if (state?.transaction?.feeState is WcTransactionFeeState.Success) {
|
||||
feeSelectorBlockComponent.updateState(state.feeSelectorUM)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun dismiss() {
|
||||
model.dismiss()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.core.decompose.context.childByContext
|
|||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.features.send.v2.api.FeeSelectorBlockComponent
|
||||
import com.tangem.features.send.v2.api.FeeSelectorComponent
|
||||
import com.tangem.features.walletconnect.transaction.components.common.WcCommonTransactionComponentDelegate
|
||||
import com.tangem.features.walletconnect.transaction.components.common.WcTransactionModelParams
|
||||
import com.tangem.features.walletconnect.transaction.components.common.getWcCommonScreen
|
||||
|
|
@ -16,6 +17,7 @@ internal class WcSendTransactionContainerComponent(
|
|||
appComponentContext: AppComponentContext,
|
||||
params: WcTransactionModelParams,
|
||||
private val feeSelectorBlockComponentFactory: FeeSelectorBlockComponent.Factory,
|
||||
private val feeSelectorComponentFactory: FeeSelectorComponent.Factory,
|
||||
) : WcCommonTransactionComponentDelegate(appComponentContext) {
|
||||
|
||||
private val model: WcSendTransactionModel = getOrCreateModel(params = params)
|
||||
|
|
@ -38,6 +40,7 @@ internal class WcSendTransactionContainerComponent(
|
|||
appComponentContext = appComponentContext,
|
||||
transactionScreenConverter = { createTransactionComponent(appComponentContext) },
|
||||
model = model,
|
||||
feeSelectorComponentFactory = feeSelectorComponentFactory,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.domain.walletconnect.usecase.method.WcMessageSignUseCase
|
|||
import com.tangem.domain.walletconnect.usecase.method.WcSignState
|
||||
import com.tangem.domain.walletconnect.usecase.method.WcSignUseCase
|
||||
import com.tangem.domain.walletconnect.usecase.method.WcTransactionUseCase
|
||||
import com.tangem.features.send.v2.api.entity.FeeSelectorUM
|
||||
import com.tangem.features.walletconnect.transaction.entity.common.WcCommonTransactionUM
|
||||
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionActionsUM
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
|
@ -45,6 +46,7 @@ internal class WcCommonTransactionUMConverter @Inject constructor(
|
|||
useCase = value.useCase,
|
||||
signState = value.signState,
|
||||
actions = value.actions,
|
||||
feeSelectorUM = value.feeSelectorUM,
|
||||
),
|
||||
)
|
||||
else -> null
|
||||
|
|
@ -55,5 +57,6 @@ internal class WcCommonTransactionUMConverter @Inject constructor(
|
|||
val useCase: WcSignUseCase<*>,
|
||||
val signState: WcSignState<*>,
|
||||
val actions: WcTransactionActionsUM,
|
||||
val feeSelectorUM: FeeSelectorUM? = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import com.tangem.domain.walletconnect.usecase.method.WcMutableFee
|
|||
import com.tangem.domain.walletconnect.usecase.method.WcSignState
|
||||
import com.tangem.domain.walletconnect.usecase.method.WcSignStep
|
||||
import com.tangem.domain.walletconnect.usecase.method.WcTransactionUseCase
|
||||
import com.tangem.features.send.v2.api.entity.FeeSelectorUM
|
||||
import com.tangem.features.walletconnect.impl.R
|
||||
import com.tangem.features.walletconnect.transaction.entity.blockaid.WcSendReceiveTransactionCheckResultsUM
|
||||
import com.tangem.features.walletconnect.transaction.entity.common.*
|
||||
|
|
@ -37,13 +38,14 @@ internal class WcSendTransactionUMConverter @Inject constructor(
|
|||
onShowVerifiedAlert = value.actions.onShowVerifiedAlert,
|
||||
),
|
||||
),
|
||||
feeState = constructFeeState(useCase = value.useCase),
|
||||
feeState = constructFeeState(useCase = value.useCase, actions = value.actions),
|
||||
walletName = value.useCase.session.wallet.name,
|
||||
networkInfo = networkInfoUMConverter.convert(value.useCase.network),
|
||||
address = value.useCase.walletAddress.toShortAddressText(),
|
||||
estimatedWalletChanges = WcSendReceiveTransactionCheckResultsUM(),
|
||||
isLoading = value.signState.domainStep == WcSignStep.Signing,
|
||||
),
|
||||
feeSelectorUM = value.feeSelectorUM ?: FeeSelectorUM.Loading,
|
||||
transactionRequestInfo = WcTransactionRequestInfoUM(
|
||||
blocks = buildList {
|
||||
add(
|
||||
|
|
@ -80,15 +82,19 @@ internal class WcSendTransactionUMConverter @Inject constructor(
|
|||
else -> null
|
||||
}
|
||||
|
||||
private fun constructFeeState(useCase: WcTransactionUseCase): WcTransactionFeeState {
|
||||
private fun constructFeeState(
|
||||
useCase: WcTransactionUseCase,
|
||||
actions: WcTransactionActionsUM,
|
||||
): WcTransactionFeeState {
|
||||
val mutableFee = useCase as? WcMutableFee ?: return WcTransactionFeeState.None
|
||||
val dAppFee = mutableFee.dAppFee()
|
||||
return if (dAppFee != null) WcTransactionFeeState.Success(dAppFee) else WcTransactionFeeState.Loading
|
||||
return WcTransactionFeeState.Success(dAppFee = dAppFee, onClick = actions.onShowFeeBottomSheet)
|
||||
}
|
||||
|
||||
data class Input(
|
||||
val useCase: WcTransactionUseCase,
|
||||
val signState: WcSignState<*>,
|
||||
val actions: WcTransactionActionsUM,
|
||||
val feeSelectorUM: FeeSelectorUM?,
|
||||
)
|
||||
}
|
||||
|
|
@ -8,4 +8,5 @@ internal data class WcTransactionActionsUM(
|
|||
val onDismiss: () -> Unit,
|
||||
val onSign: () -> Unit,
|
||||
val onCopy: () -> Unit,
|
||||
val onShowFeeBottomSheet: () -> Unit = {},
|
||||
)
|
||||
|
|
@ -3,7 +3,6 @@ package com.tangem.features.walletconnect.transaction.entity.common
|
|||
import com.tangem.blockchain.common.transaction.Fee
|
||||
|
||||
internal sealed class WcTransactionFeeState {
|
||||
object Loading : WcTransactionFeeState()
|
||||
data class Success(val fee: Fee) : WcTransactionFeeState()
|
||||
data class Success(val dAppFee: Fee?, val onClick: () -> Unit) : WcTransactionFeeState()
|
||||
data object None : WcTransactionFeeState()
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.features.walletconnect.transaction.entity.send
|
||||
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.features.send.v2.api.entity.FeeSelectorUM
|
||||
import com.tangem.features.walletconnect.transaction.entity.approve.WcSpendAllowanceUM
|
||||
import com.tangem.features.walletconnect.transaction.entity.blockaid.WcSendReceiveTransactionCheckResultsUM
|
||||
import com.tangem.features.walletconnect.transaction.entity.common.WcCommonTransactionUM
|
||||
|
|
@ -13,6 +14,7 @@ internal data class WcSendTransactionUM(
|
|||
val transaction: WcSendTransactionItemUM,
|
||||
override val transactionRequestInfo: WcTransactionRequestInfoUM,
|
||||
val spendAllowance: WcSpendAllowanceUM? = null,
|
||||
val feeSelectorUM: FeeSelectorUM,
|
||||
) : WcCommonTransactionUM
|
||||
|
||||
internal data class WcSendTransactionItemUM(
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ import com.tangem.domain.transaction.usecase.GetFeeUseCase
|
|||
import com.tangem.domain.walletconnect.WcRequestUseCaseFactory
|
||||
import com.tangem.domain.walletconnect.usecase.method.*
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
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.params.FeeSelectorParams
|
||||
import com.tangem.features.walletconnect.connections.routing.WcInnerRoute
|
||||
import com.tangem.features.walletconnect.transaction.components.common.WcTransactionModelParams
|
||||
|
|
@ -54,18 +56,18 @@ internal class WcSendTransactionModel @Inject constructor(
|
|||
private val blockAidUiConverter: WcSendAndReceiveBlockAidUiConverter,
|
||||
private val getFeeUseCase: GetFeeUseCase,
|
||||
private val getNetworkCoinUseCase: GetNetworkCoinStatusUseCase,
|
||||
) : Model(), WcCommonTransactionModel {
|
||||
) : Model(), WcCommonTransactionModel, FeeSelectorModelCallback {
|
||||
|
||||
private val params = paramsContainer.require<WcTransactionModelParams>()
|
||||
|
||||
private val _uiState = MutableStateFlow<WcSendTransactionUM?>(null)
|
||||
override val uiState: StateFlow<WcSendTransactionUM?> = _uiState
|
||||
override val uiState: StateFlow<WcSendTransactionUM?> = _uiState.asStateFlow()
|
||||
|
||||
val stackNavigation = StackNavigation<WcTransactionRoutes>()
|
||||
|
||||
internal var useCase: WcSignUseCase<*> by Delegates.notNull()
|
||||
internal var cryptoCurrencyStatus: CryptoCurrencyStatus by Delegates.notNull()
|
||||
internal var suggestedFeeState: FeeSelectorParams.SuggestedFeeState = FeeSelectorParams.SuggestedFeeState.None
|
||||
private var useCase: WcSignUseCase<*> by Delegates.notNull()
|
||||
private var signState: WcSignState<*> by Delegates.notNull()
|
||||
private var wcApproval: WcApproval? = null
|
||||
private var sign: () -> Unit = {}
|
||||
|
|
@ -116,6 +118,12 @@ internal class WcSendTransactionModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun onFeeResult(feeSelectorUM: FeeSelectorUM) {
|
||||
_uiState.update { it?.copy(feeSelectorUM = feeSelectorUM) }
|
||||
val fee = (feeSelectorUM as? FeeSelectorUM.Content)?.selectedFeeItem?.fee ?: return
|
||||
(useCase as? WcMutableFee)?.updateFee(fee)
|
||||
}
|
||||
|
||||
suspend fun loadFee(): Either<GetFeeError, TransactionFee> {
|
||||
val signModel = signState.signModel
|
||||
val transactionData = signModel as? TransactionData.Uncompiled ?: error("TransactionData must be Uncompiled")
|
||||
|
|
@ -162,7 +170,9 @@ internal class WcSendTransactionModel @Inject constructor(
|
|||
onDismiss = { cancel(useCase) },
|
||||
onSign = { onSign(securityCheck.getOrNull()) },
|
||||
onCopy = { copyData(useCase.rawSdkRequest.request.params) },
|
||||
onShowFeeBottomSheet = ::onShowFeeBottomSheet,
|
||||
),
|
||||
feeSelectorUM = uiState.value?.feeSelectorUM,
|
||||
),
|
||||
) as? WcSendTransactionUM
|
||||
transactionUM = transactionUM?.copy(
|
||||
|
|
@ -180,6 +190,10 @@ internal class WcSendTransactionModel @Inject constructor(
|
|||
stackNavigation.pushNew(WcTransactionRoutes.TransactionRequestInfo)
|
||||
}
|
||||
|
||||
private fun onShowFeeBottomSheet() {
|
||||
stackNavigation.pushNew(WcTransactionRoutes.SelectFee)
|
||||
}
|
||||
|
||||
private fun onSign(securityCheck: BlockAidTransactionCheck.Result?) {
|
||||
if (securityCheck?.result?.validation == ValidationResult.UNSAFE) {
|
||||
showMaliciousAlert(securityCheck.result.description)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@ internal sealed class WcTransactionRoutes : TangemBottomSheetConfigContent, Rout
|
|||
@Serializable
|
||||
data object CustomAllowance : WcTransactionRoutes()
|
||||
|
||||
@Serializable
|
||||
data object SelectFee : WcTransactionRoutes()
|
||||
|
||||
@Serializable
|
||||
data class Alert(val type: Type) : WcTransactionRoutes() {
|
||||
@Serializable
|
||||
|
|
|
|||
|
|
@ -7,10 +7,12 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.divider.DividerWithPadding
|
||||
import com.tangem.core.ui.extensions.clickableSingle
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.send.v2.api.FeeSelectorBlockComponent
|
||||
import com.tangem.features.walletconnect.transaction.entity.common.WcNetworkInfoUM
|
||||
|
|
@ -25,6 +27,12 @@ internal fun WcSendTransactionItems(
|
|||
modifier: Modifier = Modifier,
|
||||
address: String? = null,
|
||||
) {
|
||||
val onFeeBlockClicked = remember(feeState) {
|
||||
when (feeState) {
|
||||
WcTransactionFeeState.None -> null
|
||||
is WcTransactionFeeState.Success -> feeState.onClick
|
||||
}
|
||||
}
|
||||
Column(
|
||||
modifier = modifier
|
||||
.clip(RoundedCornerShape(TangemTheme.dimens.radius14))
|
||||
|
|
@ -55,7 +63,13 @@ internal fun WcSendTransactionItems(
|
|||
}
|
||||
DividerWithPadding(start = 40.dp, end = 12.dp)
|
||||
if (feeState != WcTransactionFeeState.None) {
|
||||
feeSelectorBlockComponent.Content(Modifier)
|
||||
feeSelectorBlockComponent.Content(
|
||||
modifier = if (onFeeBlockClicked != null) {
|
||||
Modifier.clickableSingle(onClick = onFeeBlockClicked)
|
||||
} else {
|
||||
Modifier
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -194,7 +194,7 @@ private class WcSendTransactionStateProvider : CollectionPreviewParameterProvide
|
|||
),
|
||||
walletName = "Tangem 2.0",
|
||||
networkInfo = WcNetworkInfoUM(name = "Ethereum", iconRes = R.drawable.img_eth_22),
|
||||
feeState = WcTransactionFeeState.Loading,
|
||||
feeState = WcTransactionFeeState.None,
|
||||
address = "0x345FF...34FA",
|
||||
),
|
||||
),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue