diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index c48f118fe4..383bdf1b24 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -207,6 +207,8 @@ dependencies {
implementation(projects.features.nft.impl)
implementation(projects.features.walletconnect.api)
implementation(projects.features.walletconnect.impl)
+ implementation(projects.features.feeSelector.api)
+ implementation(projects.features.feeSelector.impl)
/** AndroidX libraries */
implementation(deps.androidx.core.ktx)
diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/fields/AmountTextField.kt b/core/ui/src/main/java/com/tangem/core/ui/components/fields/AmountTextField.kt
index c985d43cfc..017523fbbc 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/components/fields/AmountTextField.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/components/fields/AmountTextField.kt
@@ -59,6 +59,7 @@ fun AmountTextField(
textStyle: TextStyle,
modifier: Modifier = Modifier,
color: Color = TangemTheme.colors.text.primary1,
+ backgroundColor: Color = TangemTheme.colors.background.action,
visualTransformation: VisualTransformation = AmountVisualTransformation(decimals),
keyboardOptions: KeyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number,
@@ -117,7 +118,7 @@ fun AmountTextField(
singleLine = true,
readOnly = !isEnabled,
visualTransformation = visualTransformation,
- modifier = Modifier.background(TangemTheme.colors.background.action),
+ modifier = Modifier.background(backgroundColor),
)
}
}
diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowEnterInfoAmount.kt b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowEnterInfoAmount.kt
index bf0e7bb5ed..5a92d21899 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowEnterInfoAmount.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowEnterInfoAmount.kt
@@ -1,16 +1,17 @@
package com.tangem.core.ui.components.inputrow
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.unit.dp
+import com.tangem.core.ui.R
import com.tangem.core.ui.components.fields.AmountTextField
import com.tangem.core.ui.components.fields.visualtransformations.AmountVisualTransformation
import com.tangem.core.ui.components.inputrow.inner.DividerContainer
@@ -105,4 +106,77 @@ fun InputRowEnterInfoAmount(
}
}
}
+}
+
+@Composable
+fun InputRowEnterInfoAmountV2(
+ title: TextReference,
+ text: String,
+ decimals: Int,
+ onValueChange: (String) -> Unit,
+ modifier: Modifier = Modifier,
+ symbol: String? = null,
+ info: TextReference? = null,
+ titleColor: Color = TangemTheme.colors.text.secondary,
+ textColor: Color = TangemTheme.colors.text.primary1,
+ infoColor: Color = TangemTheme.colors.text.tertiary,
+ keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
+ keyboardActions: KeyboardActions = KeyboardActions.Default,
+ showDivider: Boolean = false,
+ isReadOnly: Boolean = false,
+) {
+ DividerContainer(
+ modifier = modifier,
+ showDivider = showDivider,
+ paddingValues = PaddingValues(horizontal = 12.dp),
+ ) {
+ Column(
+ modifier = Modifier.fillMaxWidth().padding(16.dp),
+ ) {
+ Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(2.dp)) {
+ Text(
+ text = title.resolveReference(),
+ style = TangemTheme.typography.subtitle2,
+ color = titleColor,
+ )
+ Icon(
+ modifier = Modifier.size(16.dp),
+ painter = painterResource(R.drawable.ic_union_16),
+ tint = TangemTheme.colors.icon.informative,
+ contentDescription = null,
+ )
+ }
+ Row {
+ AmountTextField(
+ value = text,
+ decimals = decimals,
+ visualTransformation = AmountVisualTransformation(
+ decimals = decimals,
+ symbol = symbol,
+ decimalFormat = rememberDecimalFormat(),
+ ),
+ onValueChange = onValueChange,
+ color = textColor,
+ isEnabled = !isReadOnly,
+ textStyle = TangemTheme.typography.body2,
+ keyboardOptions = keyboardOptions,
+ keyboardActions = keyboardActions,
+ backgroundColor = Color.Transparent,
+ modifier = Modifier
+ .padding(top = TangemTheme.dimens.spacing8)
+ .weight(1f),
+ )
+ info?.let {
+ Text(
+ text = it.resolveReference(),
+ style = TangemTheme.typography.body2,
+ color = infoColor,
+ modifier = Modifier
+ .padding(start = TangemTheme.dimens.spacing8)
+ .align(Alignment.Bottom),
+ )
+ }
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/core/ui/src/main/res/drawable/ic_edit_v2_24.xml b/core/ui/src/main/res/drawable/ic_edit_v2_24.xml
new file mode 100644
index 0000000000..5cdd16423c
--- /dev/null
+++ b/core/ui/src/main/res/drawable/ic_edit_v2_24.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/core/ui/src/main/res/drawable/ic_star_mini_24.xml b/core/ui/src/main/res/drawable/ic_star_mini_24.xml
new file mode 100644
index 0000000000..99a400477c
--- /dev/null
+++ b/core/ui/src/main/res/drawable/ic_star_mini_24.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/core/ui/src/main/res/drawable/ic_union_16.xml b/core/ui/src/main/res/drawable/ic_union_16.xml
new file mode 100644
index 0000000000..3281f5e0ff
--- /dev/null
+++ b/core/ui/src/main/res/drawable/ic_union_16.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/features/fee-selector/api/.gitignore b/features/fee-selector/api/.gitignore
new file mode 100644
index 0000000000..42afabfd2a
--- /dev/null
+++ b/features/fee-selector/api/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/features/fee-selector/api/build.gradle.kts b/features/fee-selector/api/build.gradle.kts
new file mode 100644
index 0000000000..f224bf5622
--- /dev/null
+++ b/features/fee-selector/api/build.gradle.kts
@@ -0,0 +1,27 @@
+plugins {
+ alias(deps.plugins.android.library)
+ alias(deps.plugins.kotlin.android)
+ id("configuration")
+}
+
+android {
+ namespace = "com.tangem.features.feeselector.api"
+}
+
+dependencies {
+ /** Project - Core */
+ implementation(projects.core.ui)
+ implementation(projects.core.decompose)
+
+ /** Domain models */
+ // api(projects.domain.models)
+ implementation(projects.domain.appCurrency.models)
+ // implementation(projects.domain.wallets.models)
+
+ /** Compose */
+ implementation(deps.compose.runtime)
+ implementation(deps.compose.foundation)
+
+ /** Other */
+ implementation(deps.kotlin.immutable.collections)
+}
\ No newline at end of file
diff --git a/features/fee-selector/api/src/main/kotlin/com/tangem/features/feeselector/api/component/FeeSelectorComponent.kt b/features/fee-selector/api/src/main/kotlin/com/tangem/features/feeselector/api/component/FeeSelectorComponent.kt
new file mode 100644
index 0000000000..726aab533a
--- /dev/null
+++ b/features/fee-selector/api/src/main/kotlin/com/tangem/features/feeselector/api/component/FeeSelectorComponent.kt
@@ -0,0 +1,12 @@
+package com.tangem.features.feeselector.api.component
+
+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
+
+interface FeeSelectorComponent : ComposableContentComponent, ComposableBottomSheetComponent {
+ data class Params(val appCurrency: AppCurrency)
+
+ interface Factory : ComponentFactory
+}
\ No newline at end of file
diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/ui/state/CustomFeeFieldUM.kt b/features/fee-selector/api/src/main/kotlin/com/tangem/features/feeselector/api/entity/CustomFeeFieldUM.kt
similarity index 84%
rename from features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/ui/state/CustomFeeFieldUM.kt
rename to features/fee-selector/api/src/main/kotlin/com/tangem/features/feeselector/api/entity/CustomFeeFieldUM.kt
index 5b52d2c6b8..cc823ad6d6 100644
--- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/ui/state/CustomFeeFieldUM.kt
+++ b/features/fee-selector/api/src/main/kotlin/com/tangem/features/feeselector/api/entity/CustomFeeFieldUM.kt
@@ -1,4 +1,4 @@
-package com.tangem.features.send.v2.subcomponents.fee.ui.state
+package com.tangem.features.feeselector.api.entity
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
@@ -6,7 +6,7 @@ import androidx.compose.runtime.Immutable
import com.tangem.core.ui.extensions.TextReference
@Immutable
-internal data class CustomFeeFieldUM(
+data class CustomFeeFieldUM(
val value: String,
val onValueChange: (String) -> Unit,
val keyboardOptions: KeyboardOptions,
diff --git a/features/fee-selector/impl/.gitignore b/features/fee-selector/impl/.gitignore
new file mode 100644
index 0000000000..42afabfd2a
--- /dev/null
+++ b/features/fee-selector/impl/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/features/fee-selector/impl/build.gradle.kts b/features/fee-selector/impl/build.gradle.kts
new file mode 100644
index 0000000000..90c8927b9b
--- /dev/null
+++ b/features/fee-selector/impl/build.gradle.kts
@@ -0,0 +1,57 @@
+plugins {
+ alias(deps.plugins.android.library)
+ alias(deps.plugins.kotlin.android)
+ alias(deps.plugins.kotlin.serialization)
+ alias(deps.plugins.kotlin.kapt)
+ alias(deps.plugins.hilt.android)
+ id("configuration")
+}
+
+android {
+ namespace = "com.tangem.features.feeselector.impl"
+}
+
+dependencies {
+ /** Project - API */
+ implementation(projects.features.feeSelector.api)
+
+ /** Project - Core */
+ implementation(projects.common.ui)
+ implementation(projects.common.routing)
+ implementation(projects.core.decompose)
+ implementation(projects.core.ui)
+ implementation(projects.core.pagination)
+ implementation(projects.core.navigation)
+
+ /** Project - Domain */
+ implementation(projects.domain.appCurrency.models)
+ implementation(projects.domain.models)
+ implementation(projects.domain.tokens)
+ implementation(projects.domain.tokens.models)
+ implementation(projects.domain.wallets)
+ implementation(projects.domain.wallets.models)
+
+ /** AndroidX */
+ implementation(deps.androidx.activity.compose)
+ implementation(deps.lifecycle.compose)
+
+ /** Compose */
+ implementation(deps.compose.ui)
+ implementation(deps.compose.ui.tooling)
+ implementation(deps.compose.foundation)
+ implementation(deps.compose.material3)
+ implementation(deps.compose.shimmer)
+
+ /*** Tangem SDK */
+ implementation(tangemDeps.blockchain)
+
+ /** DI */
+ implementation(deps.hilt.android)
+ kapt(deps.hilt.kapt)
+
+ /** Other */
+ implementation(deps.arrow.core)
+ implementation(deps.kotlin.immutable.collections)
+ implementation(deps.decompose.ext.compose)
+ implementation(deps.timber)
+}
\ No newline at end of file
diff --git a/features/fee-selector/impl/src/main/kotlin/com/tangem/features/feeselector/impl/component/DefaultFeeSelectorComponent.kt b/features/fee-selector/impl/src/main/kotlin/com/tangem/features/feeselector/impl/component/DefaultFeeSelectorComponent.kt
new file mode 100644
index 0000000000..0fda871e10
--- /dev/null
+++ b/features/fee-selector/impl/src/main/kotlin/com/tangem/features/feeselector/impl/component/DefaultFeeSelectorComponent.kt
@@ -0,0 +1,45 @@
+package com.tangem.features.feeselector.impl.component
+
+import androidx.activity.compose.BackHandler
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import com.tangem.core.decompose.context.AppComponentContext
+import com.tangem.core.decompose.model.getOrCreateModel
+import com.tangem.features.feeselector.api.component.FeeSelectorComponent
+import com.tangem.features.feeselector.impl.model.FeeSelectorModel
+import com.tangem.features.feeselector.impl.ui.FeeSelectorModalBottomSheet
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+
+internal class DefaultFeeSelectorComponent @AssistedInject constructor(
+ @Assisted appComponentContext: AppComponentContext,
+ @Assisted private val params: FeeSelectorComponent.Params,
+) : FeeSelectorComponent, AppComponentContext by appComponentContext {
+
+ private val model: FeeSelectorModel = getOrCreateModel(params = params)
+
+ override fun dismiss() {
+ model.dismiss()
+ }
+
+ @Composable
+ override fun BottomSheet() {
+ FeeSelectorModalBottomSheet(onDismiss = ::dismiss, state = TODO())
+ }
+
+ // Temporary workaround, to use test this component
+ @Composable
+ override fun Content(modifier: Modifier) {
+ BackHandler(onBack = router::pop)
+ FeeSelectorModalBottomSheet(onDismiss = ::dismiss, state = TODO())
+ }
+
+ @AssistedFactory
+ interface Factory : FeeSelectorComponent.Factory {
+ override fun create(
+ context: AppComponentContext,
+ params: FeeSelectorComponent.Params,
+ ): DefaultFeeSelectorComponent
+ }
+}
\ No newline at end of file
diff --git a/features/fee-selector/impl/src/main/kotlin/com/tangem/features/feeselector/impl/di/FeeSelectorFeatureModule.kt b/features/fee-selector/impl/src/main/kotlin/com/tangem/features/feeselector/impl/di/FeeSelectorFeatureModule.kt
new file mode 100644
index 0000000000..d47efb12e3
--- /dev/null
+++ b/features/fee-selector/impl/src/main/kotlin/com/tangem/features/feeselector/impl/di/FeeSelectorFeatureModule.kt
@@ -0,0 +1,18 @@
+package com.tangem.features.feeselector.impl.di
+
+import com.tangem.features.feeselector.api.component.FeeSelectorComponent
+import com.tangem.features.feeselector.impl.component.DefaultFeeSelectorComponent
+import dagger.Binds
+import dagger.Module
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import javax.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+internal interface FeeSelectorFeatureModule {
+
+ @Binds
+ @Singleton
+ fun bindComponentFactory(factory: DefaultFeeSelectorComponent.Factory): FeeSelectorComponent.Factory
+}
\ No newline at end of file
diff --git a/features/fee-selector/impl/src/main/kotlin/com/tangem/features/feeselector/impl/di/FeeSelectorModelModule.kt b/features/fee-selector/impl/src/main/kotlin/com/tangem/features/feeselector/impl/di/FeeSelectorModelModule.kt
new file mode 100644
index 0000000000..2144133681
--- /dev/null
+++ b/features/fee-selector/impl/src/main/kotlin/com/tangem/features/feeselector/impl/di/FeeSelectorModelModule.kt
@@ -0,0 +1,19 @@
+package com.tangem.features.feeselector.impl.di
+
+import com.tangem.core.decompose.di.ModelComponent
+import com.tangem.core.decompose.model.Model
+import com.tangem.features.feeselector.impl.model.FeeSelectorModel
+import dagger.Binds
+import dagger.Module
+import dagger.hilt.InstallIn
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+
+@Module
+@InstallIn(ModelComponent::class)
+internal interface FeeSelectorModelModule {
+ @Binds
+ @IntoMap
+ @ClassKey(FeeSelectorModel::class)
+ fun bindModel(model: FeeSelectorModel): Model
+}
\ No newline at end of file
diff --git a/features/fee-selector/impl/src/main/kotlin/com/tangem/features/feeselector/impl/entity/FeeSelectorUM.kt b/features/fee-selector/impl/src/main/kotlin/com/tangem/features/feeselector/impl/entity/FeeSelectorUM.kt
new file mode 100644
index 0000000000..9fba9272a5
--- /dev/null
+++ b/features/fee-selector/impl/src/main/kotlin/com/tangem/features/feeselector/impl/entity/FeeSelectorUM.kt
@@ -0,0 +1,40 @@
+package com.tangem.features.feeselector.impl.entity
+
+import androidx.compose.runtime.Immutable
+import com.tangem.blockchain.common.Amount
+import com.tangem.core.ui.extensions.TextReference
+import com.tangem.domain.appcurrency.model.AppCurrency
+import com.tangem.features.feeselector.api.entity.CustomFeeFieldUM
+import kotlinx.collections.immutable.ImmutableList
+import java.math.BigDecimal
+
+@Immutable
+internal sealed class FeeSelectorUM {
+
+ data object Loading : FeeSelectorUM()
+
+ data class Content(
+ val isDoneEnabled: Boolean,
+ val feeItems: ImmutableList,
+ val selectedFeeItem: FeeItem,
+ val isFeeApproximate: Boolean,
+ val feeFiatRateDataHolder: FeeFiatRateDataHolder?,
+ ) : FeeSelectorUM()
+}
+
+@Immutable
+data class FeeFiatRateDataHolder(
+ val rate: BigDecimal,
+ val appCurrency: AppCurrency,
+)
+
+@Immutable
+internal sealed class FeeItem {
+ abstract val onSelect: () -> Unit
+
+ data class Suggested(val title: TextReference, val amount: Amount, override val onSelect: () -> Unit) : FeeItem()
+ data class Slow(val amount: Amount, override val onSelect: () -> Unit) : FeeItem()
+ data class Market(val amount: Amount, override val onSelect: () -> Unit) : FeeItem()
+ data class Fast(val amount: Amount, override val onSelect: () -> Unit) : FeeItem()
+ data class Custom(val customValues: ImmutableList, override val onSelect: () -> Unit) : FeeItem()
+}
\ No newline at end of file
diff --git a/features/fee-selector/impl/src/main/kotlin/com/tangem/features/feeselector/impl/model/FeeSelectorModel.kt b/features/fee-selector/impl/src/main/kotlin/com/tangem/features/feeselector/impl/model/FeeSelectorModel.kt
new file mode 100644
index 0000000000..ea2ae3c857
--- /dev/null
+++ b/features/fee-selector/impl/src/main/kotlin/com/tangem/features/feeselector/impl/model/FeeSelectorModel.kt
@@ -0,0 +1,31 @@
+package com.tangem.features.feeselector.impl.model
+
+import androidx.compose.runtime.Stable
+import com.tangem.core.decompose.di.ModelScoped
+import com.tangem.core.decompose.model.Model
+import com.tangem.core.decompose.model.ParamsContainer
+import com.tangem.core.decompose.navigation.Router
+import com.tangem.features.feeselector.api.component.FeeSelectorComponent
+import com.tangem.features.feeselector.impl.entity.FeeSelectorUM
+import com.tangem.utils.coroutines.CoroutineDispatcherProvider
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import javax.inject.Inject
+
+@Stable
+@ModelScoped
+internal class FeeSelectorModel @Inject constructor(
+ paramsContainer: ParamsContainer,
+ private val router: Router,
+ override val dispatchers: CoroutineDispatcherProvider,
+) : Model() {
+
+ @Suppress("UnusedPrivateMember")
+ private val params = paramsContainer.require()
+ val uiState: StateFlow
+ field = MutableStateFlow(FeeSelectorUM.Loading)
+
+ fun dismiss() {
+ router.pop()
+ }
+}
\ No newline at end of file
diff --git a/features/fee-selector/impl/src/main/kotlin/com/tangem/features/feeselector/impl/ui/FeeSelectorModalBottomSheet.kt b/features/fee-selector/impl/src/main/kotlin/com/tangem/features/feeselector/impl/ui/FeeSelectorModalBottomSheet.kt
new file mode 100644
index 0000000000..4b6215a295
--- /dev/null
+++ b/features/fee-selector/impl/src/main/kotlin/com/tangem/features/feeselector/impl/ui/FeeSelectorModalBottomSheet.kt
@@ -0,0 +1,510 @@
+package com.tangem.features.feeselector.impl.ui
+
+import android.content.res.Configuration
+import androidx.annotation.DrawableRes
+import androidx.compose.animation.*
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.text.KeyboardActions
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.material3.HorizontalDivider
+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
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.tooling.preview.Devices
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.tooling.preview.PreviewParameter
+import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.util.fastForEachIndexed
+import com.tangem.blockchain.common.Amount
+import com.tangem.blockchain.common.Blockchain
+import com.tangem.common.ui.amountScreen.utils.getFiatReference
+import com.tangem.core.ui.components.PrimaryButton
+import com.tangem.core.ui.components.atoms.text.EllipsisText
+import com.tangem.core.ui.components.atoms.text.TextEllipsis
+import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
+import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
+import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetTitle
+import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetWithFooter
+import com.tangem.core.ui.components.inputrow.InputRowEnterInfoAmountV2
+import com.tangem.core.ui.extensions.*
+import com.tangem.core.ui.format.bigdecimal.crypto
+import com.tangem.core.ui.format.bigdecimal.fee
+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.feeselector.api.entity.CustomFeeFieldUM
+import com.tangem.features.feeselector.impl.R
+import com.tangem.features.feeselector.impl.entity.FeeFiatRateDataHolder
+import com.tangem.features.feeselector.impl.entity.FeeItem
+import com.tangem.features.feeselector.impl.entity.FeeSelectorUM
+import com.tangem.utils.StringsSigns
+import kotlinx.collections.immutable.ImmutableList
+import kotlinx.collections.immutable.persistentListOf
+import java.math.BigDecimal
+
+@Composable
+internal fun FeeSelectorModalBottomSheet(state: FeeSelectorUM.Content, onDismiss: () -> Unit) {
+ TangemModalBottomSheetWithFooter(
+ config = TangemBottomSheetConfig(
+ isShown = true,
+ onDismissRequest = onDismiss,
+ content = TangemBottomSheetConfigContent.Empty,
+ ),
+ containerColor = TangemTheme.colors.background.primary,
+ title = {
+ TangemModalBottomSheetTitle(
+ title = resourceReference(R.string.common_network_fee_title),
+ startIconRes = R.drawable.ic_back_24,
+ onStartClick = onDismiss,
+ )
+ },
+ content = {
+ FeeSelectorItems(state = state, modifier = Modifier.padding(vertical = 4.dp, horizontal = 16.dp))
+ },
+ footer = {
+ PrimaryButton(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(16.dp),
+ text = stringResourceSafe(R.string.common_done),
+ onClick = onDismiss,
+ enabled = state.isDoneEnabled,
+ )
+ },
+ )
+}
+
+@Suppress("LongMethod", "CyclomaticComplexMethod")
+@Composable
+private fun FeeSelectorItems(state: FeeSelectorUM.Content, modifier: Modifier = Modifier) {
+ Column(modifier = modifier) {
+ state.feeItems.fastForEachIndexed { index, item ->
+ val isSelected = item == 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,
+ label = "Fee selector icon tint change",
+ )
+ val iconBackgroundColor by animateColorAsState(
+ targetValue = if (isSelected) {
+ TangemTheme.colors.icon.accent.copy(alpha = 0.1F)
+ } else {
+ TangemTheme.colors.background.secondary
+ },
+ label = "Fee selector icon background change",
+ )
+ val onSelect by rememberUpdatedState(item.onSelect)
+ val itemModifier = Modifier
+ .fillMaxWidth()
+ .background(TangemTheme.colors.background.primary)
+ .then(
+ if (isSelected) {
+ Modifier
+ .border(
+ width = 2.5.dp,
+ color = iconTint.copy(alpha = 0.2F),
+ shape = RoundedCornerShape(16.dp),
+ )
+ .padding(2.5.dp)
+ .border(width = 1.dp, color = iconTint, shape = RoundedCornerShape(14.dp))
+ .clip(RoundedCornerShape(14.dp))
+ } else {
+ Modifier
+ },
+ )
+ .clickableSingle(onClick = onSelect)
+ when (item) {
+ is FeeItem.Suggested -> RegularFeeItemContent(
+ modifier = itemModifier,
+ title = item.title,
+ iconRes = R.drawable.ic_star_mini_24,
+ iconBackgroundColor = iconBackgroundColor,
+ iconTint = iconTint,
+ preDot = stringReference(
+ item.amount.value.format {
+ crypto(
+ symbol = item.amount.currencySymbol,
+ decimals = item.amount.decimals,
+ ).fee(canBeLower = state.isFeeApproximate)
+ },
+ ),
+ postDot = if (state.feeFiatRateDataHolder != null) {
+ getFiatReference(
+ value = item.amount.value,
+ rate = state.feeFiatRateDataHolder.rate,
+ appCurrency = state.feeFiatRateDataHolder.appCurrency,
+ )
+ } else {
+ null
+ },
+ ellipsizeOffset = item.amount.currencySymbol.length,
+ showDivider = !isSelected && !lastItem,
+ )
+ is FeeItem.Slow -> RegularFeeItemContent(
+ modifier = itemModifier,
+ title = resourceReference(R.string.common_fee_selector_option_slow),
+ iconRes = R.drawable.ic_tortoise_24,
+ iconBackgroundColor = iconBackgroundColor,
+ iconTint = iconTint,
+ preDot = stringReference(
+ item.amount.value.format {
+ crypto(
+ symbol = item.amount.currencySymbol,
+ decimals = item.amount.decimals,
+ ).fee(canBeLower = state.isFeeApproximate)
+ },
+ ),
+ postDot = if (state.feeFiatRateDataHolder != null) {
+ getFiatReference(
+ value = item.amount.value,
+ rate = state.feeFiatRateDataHolder.rate,
+ appCurrency = state.feeFiatRateDataHolder.appCurrency,
+ )
+ } else {
+ null
+ },
+ ellipsizeOffset = item.amount.currencySymbol.length,
+ showDivider = !isSelected && !lastItem,
+ )
+ is FeeItem.Market -> RegularFeeItemContent(
+ modifier = itemModifier,
+ title = resourceReference(R.string.common_fee_selector_option_market),
+ iconRes = R.drawable.ic_bird_24,
+ iconBackgroundColor = iconBackgroundColor,
+ iconTint = iconTint,
+ preDot = stringReference(
+ item.amount.value.format {
+ crypto(
+ symbol = item.amount.currencySymbol,
+ decimals = item.amount.decimals,
+ ).fee(canBeLower = state.isFeeApproximate)
+ },
+ ),
+ postDot = if (state.feeFiatRateDataHolder != null) {
+ getFiatReference(
+ value = item.amount.value,
+ rate = state.feeFiatRateDataHolder.rate,
+ appCurrency = state.feeFiatRateDataHolder.appCurrency,
+ )
+ } else {
+ null
+ },
+ ellipsizeOffset = item.amount.currencySymbol.length,
+ showDivider = !isSelected && !lastItem,
+ )
+ is FeeItem.Fast -> RegularFeeItemContent(
+ modifier = itemModifier,
+ title = resourceReference(R.string.common_fee_selector_option_fast),
+ iconRes = R.drawable.ic_hare_24,
+ iconBackgroundColor = iconBackgroundColor,
+ iconTint = iconTint,
+ preDot = stringReference(
+ item.amount.value.format {
+ crypto(
+ symbol = item.amount.currencySymbol,
+ decimals = item.amount.decimals,
+ ).fee(canBeLower = state.isFeeApproximate)
+ },
+ ),
+ postDot = if (state.feeFiatRateDataHolder != null) {
+ getFiatReference(
+ value = item.amount.value,
+ rate = state.feeFiatRateDataHolder.rate,
+ appCurrency = state.feeFiatRateDataHolder.appCurrency,
+ )
+ } else {
+ null
+ },
+ ellipsizeOffset = item.amount.currencySymbol.length,
+ showDivider = !isSelected && !lastItem,
+ )
+ is FeeItem.Custom -> CustomFeeBlock(
+ modifier = itemModifier,
+ customFee = item,
+ isSelected = isSelected,
+ iconBackgroundColor = iconBackgroundColor,
+ iconTint = iconTint,
+ )
+ }
+ }
+ }
+}
+
+@Composable
+private fun CustomFeeBlock(
+ customFee: FeeItem.Custom,
+ isSelected: Boolean,
+ iconBackgroundColor: Color,
+ iconTint: Color,
+ modifier: Modifier = Modifier,
+) {
+ Column(modifier = modifier) {
+ Row(
+ modifier = Modifier.padding(all = 12.dp),
+ horizontalArrangement = Arrangement.spacedBy(12.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Icon(
+ modifier = Modifier
+ .size(36.dp)
+ .background(color = iconBackgroundColor, shape = CircleShape)
+ .padding(6.dp),
+ painter = painterResource(R.drawable.ic_edit_v2_24),
+ tint = iconTint,
+ contentDescription = null,
+ )
+ Text(
+ text = stringResourceSafe(R.string.common_custom),
+ color = TangemTheme.colors.text.primary1,
+ style = TangemTheme.typography.subtitle2,
+ )
+ }
+ AnimatedVisibility(
+ visible = isSelected,
+ label = "Custom Fee Selected Animation",
+ enter = expandVertically().plus(fadeIn()),
+ exit = shrinkVertically().plus(fadeOut()),
+ ) {
+ ExpandedCustomFeeItems(customFeeFields = customFee.customValues, onValueChange = { _, _ -> })
+ }
+ }
+}
+
+@Composable
+private fun ExpandedCustomFeeItems(
+ customFeeFields: ImmutableList,
+ onValueChange: (Int, String) -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ Column(modifier = modifier) {
+ customFeeFields.fastForEachIndexed { index, field ->
+ val showDivider = index != customFeeFields.size - 1
+ if (field.label != null) {
+ InputRowEnterInfoAmountV2(
+ text = field.value,
+ decimals = field.decimals,
+ symbol = field.symbol,
+ title = field.title,
+ titleColor = TangemTheme.colors.text.tertiary,
+ info = field.label,
+ keyboardOptions = field.keyboardOptions,
+ keyboardActions = field.keyboardActions,
+ onValueChange = { onValueChange(index, it) },
+ showDivider = showDivider,
+ isReadOnly = field.isReadonly,
+ )
+ } else {
+ InputRowEnterInfoAmountV2(
+ text = field.value,
+ decimals = field.decimals,
+ title = field.title,
+ titleColor = TangemTheme.colors.text.tertiary,
+ symbol = field.symbol,
+ onValueChange = { onValueChange(index, it) },
+ keyboardOptions = field.keyboardOptions,
+ keyboardActions = field.keyboardActions,
+ showDivider = showDivider,
+ )
+ }
+ }
+ }
+}
+
+@Composable
+private fun RegularFeeItemContent(
+ title: TextReference,
+ @DrawableRes iconRes: Int,
+ iconBackgroundColor: Color,
+ iconTint: Color,
+ modifier: Modifier = Modifier,
+ preDot: TextReference? = null,
+ postDot: TextReference? = null,
+ ellipsizeOffset: Int? = null,
+ showDivider: Boolean = true,
+) {
+ Column(modifier = modifier) {
+ Row(
+ modifier = Modifier.padding(all = 12.dp),
+ horizontalArrangement = Arrangement.spacedBy(12.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Icon(
+ modifier = Modifier
+ .size(36.dp)
+ .background(color = iconBackgroundColor, shape = CircleShape)
+ .padding(6.dp),
+ painter = painterResource(iconRes),
+ tint = iconTint,
+ contentDescription = null,
+ )
+ FeeDescription(
+ title = title,
+ preDot = preDot,
+ postDot = postDot,
+ ellipsizeOffset = ellipsizeOffset,
+ )
+ }
+ if (showDivider) {
+ HorizontalDivider(
+ modifier = Modifier.padding(start = 60.dp, end = 12.dp),
+ color = TangemTheme.colors.stroke.primary,
+ thickness = 0.5.dp,
+ )
+ }
+ }
+}
+
+@Composable
+private fun FeeDescription(
+ title: TextReference,
+ modifier: Modifier = Modifier,
+ preDot: TextReference? = null,
+ postDot: TextReference? = null,
+ ellipsizeOffset: Int? = null,
+) {
+ Column(modifier = modifier, verticalArrangement = Arrangement.spacedBy(2.dp)) {
+ Text(
+ text = title.resolveReference(),
+ color = TangemTheme.colors.text.primary1,
+ style = TangemTheme.typography.subtitle2,
+ )
+ if (preDot != null) {
+ FeeValueContent(preDot = preDot, postDot = postDot, ellipsizeOffset = ellipsizeOffset)
+ }
+ }
+}
+
+@Composable
+private fun FeeValueContent(preDot: TextReference, postDot: TextReference?, ellipsizeOffset: Int? = null) {
+ val ellipsis = if (ellipsizeOffset == null) {
+ TextEllipsis.End
+ } else {
+ TextEllipsis.OffsetEnd(ellipsizeOffset)
+ }
+ val textColor = TangemTheme.colors.text.tertiary
+ val textStyle = TangemTheme.typography.caption1
+ Row {
+ EllipsisText(
+ text = preDot.resolveReference(),
+ style = textStyle,
+ color = textColor,
+ textAlign = TextAlign.End,
+ ellipsis = ellipsis,
+ )
+ if (postDot != null) {
+ Text(
+ text = StringsSigns.DOT,
+ style = textStyle,
+ color = textColor,
+ textAlign = TextAlign.Center,
+ modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing4),
+ )
+ Text(text = postDot.resolveReference(), style = textStyle, color = textColor)
+ }
+ }
+}
+
+@Preview(showBackground = true, device = Devices.PIXEL_7_PRO)
+@Preview(showBackground = true, device = Devices.PIXEL_7_PRO, uiMode = Configuration.UI_MODE_NIGHT_YES)
+@Composable
+private fun FeeSelectorBS_Preview(
+ @PreviewParameter(FeeSelectorUMContentProvider::class)
+ state: FeeSelectorUM.Content,
+) {
+ TangemThemePreview {
+ FeeSelectorModalBottomSheet(onDismiss = {}, state = state)
+ }
+}
+
+private class FeeSelectorUMContentProvider : CollectionPreviewParameterProvider(
+ collection = listOf(
+ FeeSelectorUM.Content(
+ isDoneEnabled = false,
+ feeItems = persistentListOf(
+ FeeItem.Suggested(
+ title = stringReference("Suggested by Tangem"),
+ amount = Amount(value = BigDecimal("0.1"), blockchain = Blockchain.Ethereum),
+ onSelect = onSelectStub,
+ ),
+ FeeItem.Slow(
+ amount = Amount(value = BigDecimal("0.01"), blockchain = Blockchain.Ethereum),
+ onSelect = onSelectStub,
+ ),
+ FeeItem.Market(
+ amount = Amount(value = BigDecimal("0.02"), blockchain = Blockchain.Ethereum),
+ onSelect = onSelectStub,
+ ),
+ FeeItem.Fast(
+ amount = Amount(value = BigDecimal("0.3"), blockchain = Blockchain.Ethereum),
+ onSelect = onSelectStub,
+ ),
+ FeeItem.Custom(customValues = customFeeFields, onSelect = onSelectStub),
+ ),
+ // selectedFeeItem = FeeItem.Market(
+ // amount = Amount(value = BigDecimal("0.02"), blockchain = Blockchain.Ethereum),
+ // onSelect = onSelectStub
+ // ),
+ selectedFeeItem = FeeItem.Custom(customValues = customFeeFields, onSelect = onSelectStub),
+ isFeeApproximate = true,
+ feeFiatRateDataHolder = FeeFiatRateDataHolder(
+ rate = BigDecimal.TEN,
+ appCurrency = AppCurrency.Default,
+ ),
+ ),
+ ),
+)
+
+private val onSelectStub: () -> Unit = {}
+
+private val customFeeFields = persistentListOf(
+ CustomFeeFieldUM(
+ value = "0.119806",
+ onValueChange = {},
+ keyboardOptions = KeyboardOptions(),
+ keyboardActions = KeyboardActions(),
+ symbol = "ETH",
+ decimals = 8,
+ title = resourceReference(R.string.send_max_fee),
+ footer = resourceReference(R.string.send_custom_amount_fee_footer),
+ label = stringReference("~ 0,03 \$"),
+ isReadonly = false,
+ ),
+ CustomFeeFieldUM(
+ value = "40000",
+ onValueChange = {},
+ keyboardOptions = KeyboardOptions(),
+ keyboardActions = KeyboardActions(),
+ symbol = "GWEI",
+ decimals = 8,
+ title = resourceReference(R.string.send_gas_price),
+ footer = resourceReference(R.string.send_gas_price_footer),
+ label = null,
+ isReadonly = false,
+ ),
+ CustomFeeFieldUM(
+ value = "31400",
+ onValueChange = {},
+ keyboardOptions = KeyboardOptions(),
+ keyboardActions = KeyboardActions(),
+ symbol = null,
+ decimals = 8,
+ title = resourceReference(R.string.send_gas_limit),
+ footer = resourceReference(R.string.send_gas_limit_footer),
+ label = null,
+ isReadonly = false,
+ ),
+)
\ No newline at end of file
diff --git a/features/send-v2/impl/build.gradle.kts b/features/send-v2/impl/build.gradle.kts
index edc948f7c6..15d1d01b0b 100644
--- a/features/send-v2/impl/build.gradle.kts
+++ b/features/send-v2/impl/build.gradle.kts
@@ -16,6 +16,7 @@ dependencies {
implementation(projects.features.sendV2.api)
implementation(projects.features.txhistory.api)
implementation(projects.features.nft.api)
+ implementation(projects.features.feeSelector.api)
/** Libs */
implementation(projects.libs.crypto)
diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/FeeConverter.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/FeeConverter.kt
index 2a5863ed1d..b8c9fecfcf 100644
--- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/FeeConverter.kt
+++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/FeeConverter.kt
@@ -4,8 +4,8 @@ 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.tokens.model.CryptoCurrencyStatus
+import com.tangem.features.feeselector.api.entity.CustomFeeFieldUM
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.subcomponents.fee.ui.state.FeeType
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.ImmutableList
diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/SendFeeCustomFieldConverter.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/SendFeeCustomFieldConverter.kt
index 78304904a5..26603db4d2 100644
--- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/SendFeeCustomFieldConverter.kt
+++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/SendFeeCustomFieldConverter.kt
@@ -5,11 +5,11 @@ import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.core.ui.utils.parseToBigDecimal
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
+import com.tangem.features.feeselector.api.entity.CustomFeeFieldUM
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.subcomponents.fee.ui.state.FeeSelectorUM
import com.tangem.utils.converter.TwoWayConverter
import kotlinx.collections.immutable.ImmutableList
diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/CustomFeeConverter.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/CustomFeeConverter.kt
index 4250d48580..19645e440b 100644
--- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/CustomFeeConverter.kt
+++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/CustomFeeConverter.kt
@@ -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.feeselector.api.entity.CustomFeeFieldUM
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.ImmutableList
diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/bitcoin/BitcoinCustomFeeConverter.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/bitcoin/BitcoinCustomFeeConverter.kt
index a2f5349672..548887f56d 100644
--- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/bitcoin/BitcoinCustomFeeConverter.kt
+++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/bitcoin/BitcoinCustomFeeConverter.kt
@@ -11,11 +11,11 @@ import com.tangem.core.ui.utils.parseBigDecimal
import com.tangem.core.ui.utils.parseToBigDecimal
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
+import com.tangem.features.feeselector.api.entity.CustomFeeFieldUM
import com.tangem.features.send.v2.impl.R
import com.tangem.features.send.v2.subcomponents.fee.model.SendFeeClickIntents
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.lib.crypto.BlockchainUtils
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/ethereum/BaseEthereumCustomFeeConverter.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/ethereum/BaseEthereumCustomFeeConverter.kt
index c0828d3d60..fbdd94c589 100644
--- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/ethereum/BaseEthereumCustomFeeConverter.kt
+++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/ethereum/BaseEthereumCustomFeeConverter.kt
@@ -1,8 +1,8 @@
package com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.ethereum
import com.tangem.blockchain.common.transaction.Fee
+import com.tangem.features.feeselector.api.entity.CustomFeeFieldUM
import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.CustomFeeConverter
-import com.tangem.features.send.v2.subcomponents.fee.ui.state.CustomFeeFieldUM
import kotlinx.collections.immutable.ImmutableList
/**
diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/ethereum/EthereumCustomFeeConverter.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/ethereum/EthereumCustomFeeConverter.kt
index ce2ba52261..f083aaa40c 100644
--- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/ethereum/EthereumCustomFeeConverter.kt
+++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/ethereum/EthereumCustomFeeConverter.kt
@@ -10,10 +10,10 @@ import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.utils.parseBigDecimal
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
+import com.tangem.features.feeselector.api.entity.CustomFeeFieldUM
import com.tangem.features.send.v2.impl.R
import com.tangem.features.send.v2.subcomponents.fee.model.SendFeeClickIntents
import com.tangem.features.send.v2.subcomponents.fee.model.checkExceedBalance
-import com.tangem.features.send.v2.subcomponents.fee.ui.state.CustomFeeFieldUM
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/ethereum/EthereumEIPCustomFeeConverter.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/ethereum/EthereumEIPCustomFeeConverter.kt
index 2a7d389e13..4a40819826 100644
--- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/ethereum/EthereumEIPCustomFeeConverter.kt
+++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/ethereum/EthereumEIPCustomFeeConverter.kt
@@ -11,6 +11,7 @@ import com.tangem.core.ui.utils.parseBigDecimal
import com.tangem.core.ui.utils.parseToBigDecimal
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
+import com.tangem.features.feeselector.api.entity.CustomFeeFieldUM
import com.tangem.features.send.v2.impl.R
import com.tangem.features.send.v2.subcomponents.fee.model.SendFeeClickIntents
import com.tangem.features.send.v2.subcomponents.fee.model.checkExceedBalance
@@ -19,7 +20,6 @@ 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 kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/ethereum/EthereumLegacyCustomFeeConverter.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/ethereum/EthereumLegacyCustomFeeConverter.kt
index 8b2f86beb7..fe9af7c37b 100644
--- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/ethereum/EthereumLegacyCustomFeeConverter.kt
+++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/ethereum/EthereumLegacyCustomFeeConverter.kt
@@ -11,6 +11,7 @@ import com.tangem.core.ui.utils.parseBigDecimal
import com.tangem.core.ui.utils.parseToBigDecimal
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
+import com.tangem.features.feeselector.api.entity.CustomFeeFieldUM
import com.tangem.features.send.v2.impl.R
import com.tangem.features.send.v2.subcomponents.fee.model.SendFeeClickIntents
import com.tangem.features.send.v2.subcomponents.fee.model.checkExceedBalance
@@ -19,7 +20,6 @@ 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 kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/kaspa/KaspaCustomFeeConverter.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/kaspa/KaspaCustomFeeConverter.kt
index 2714e7d9f6..af0c7a97b4 100644
--- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/kaspa/KaspaCustomFeeConverter.kt
+++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/kaspa/KaspaCustomFeeConverter.kt
@@ -11,10 +11,10 @@ import com.tangem.core.ui.utils.parseBigDecimal
import com.tangem.core.ui.utils.parseToBigDecimal
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
+import com.tangem.features.feeselector.api.entity.CustomFeeFieldUM
import com.tangem.features.send.v2.impl.R
import com.tangem.features.send.v2.subcomponents.fee.model.SendFeeClickIntents
import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.CustomFeeConverter
-import com.tangem.features.send.v2.subcomponents.fee.ui.state.CustomFeeFieldUM
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/ui/SendCustomFee.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/ui/SendCustomFee.kt
index cf31789446..d597bdd4b3 100644
--- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/ui/SendCustomFee.kt
+++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/ui/SendCustomFee.kt
@@ -12,7 +12,7 @@ import com.tangem.core.ui.components.containers.FooterContainer
import com.tangem.core.ui.components.inputrow.InputRowEnterAmount
import com.tangem.core.ui.components.inputrow.InputRowEnterInfoAmount
import com.tangem.core.ui.res.TangemTheme
-import com.tangem.features.send.v2.subcomponents.fee.ui.state.CustomFeeFieldUM
+import com.tangem.features.feeselector.api.entity.CustomFeeFieldUM
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeType
import kotlinx.collections.immutable.ImmutableList
diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/ui/state/FeeSelectorUM.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/ui/state/FeeSelectorUM.kt
index a9f5aae1b4..ee4677b452 100644
--- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/ui/state/FeeSelectorUM.kt
+++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/ui/state/FeeSelectorUM.kt
@@ -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.feeselector.api.entity.CustomFeeFieldUM
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/ui/state/FeeUM.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/ui/state/FeeUM.kt
index 6bf499e1c4..e310e424af 100644
--- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/ui/state/FeeUM.kt
+++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/ui/state/FeeUM.kt
@@ -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.feeselector.api.entity.CustomFeeFieldUM
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import java.math.BigDecimal
diff --git a/settings.gradle.kts b/settings.gradle.kts
index d096b06988..f34d536ed8 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -239,6 +239,9 @@ include(":features:nft:impl")
include(":features:walletconnect:api")
include(":features:walletconnect:impl")
+
+include(":features:fee-selector:api")
+include(":features:fee-selector:impl")
// endregion Feature modules
// region Domain modules