diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml
index 3345fb4f82..76f6aa404f 100644
--- a/core/res/src/main/res/values-ru/strings.xml
+++ b/core/res/src/main/res/values-ru/strings.xml
@@ -90,6 +90,7 @@
Нравится
Заблокирован
Основная сеть
+ Далее
Нет
Нет адреса
Нет данных
diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml
index 456401a4a4..3e043496b0 100644
--- a/core/res/src/main/res/values/strings.xml
+++ b/core/res/src/main/res/values/strings.xml
@@ -89,6 +89,7 @@
Like
Locked
Main network
+ Next
No
No address
No data
@@ -114,7 +115,6 @@
Submit
Success
Swap
- Next
terms and conditions
Transaction failed
Transactions
@@ -392,6 +392,7 @@
Normal
Priority
Maximum amount
+ Max
Network fee
Sending %s
Total
@@ -400,6 +401,7 @@
%s will be sent
Transaction has been successfully signed and sent to the blockchain node. Wallet balance will be updated in a while
Invalid address
+ Insufficient funds for transfer
Buy now
I have a promo code…
Tangem Wallet
diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/Buttons.kt b/core/ui/src/main/java/com/tangem/core/ui/components/Buttons.kt
index 385824799e..cac2add621 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/components/Buttons.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/components/Buttons.kt
@@ -7,11 +7,10 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.R
-import com.tangem.core.ui.components.buttons.common.TangemButton
-import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
-import com.tangem.core.ui.components.buttons.common.TangemButtonSize
+import com.tangem.core.ui.components.buttons.common.*
import com.tangem.core.ui.components.buttons.common.TangemButtonsDefaults
import com.tangem.core.ui.res.TangemTheme
@@ -146,6 +145,8 @@ fun SecondaryButton(
modifier: Modifier = Modifier,
showProgress: Boolean = false,
enabled: Boolean = true,
+ size: TangemButtonSize = TangemButtonSize.Default,
+ shape: Shape = size.toShape(),
) {
TangemButton(
modifier = modifier,
@@ -155,6 +156,8 @@ fun SecondaryButton(
colors = TangemButtonsDefaults.secondaryButtonColors,
enabled = enabled,
showProgress = showProgress,
+ size = size,
+ shape = shape,
)
}
diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/buttons/common/TangemButton.kt b/core/ui/src/main/java/com/tangem/core/ui/components/buttons/common/TangemButton.kt
index fc114059fe..f245558598 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/components/buttons/common/TangemButton.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/components/buttons/common/TangemButton.kt
@@ -6,6 +6,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
+import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle
@@ -29,13 +30,14 @@ fun TangemButton(
size: TangemButtonSize = TangemButtonSize.Default,
elevation: ButtonElevation = TangemButtonsDefaults.elevation,
textStyle: TextStyle = TangemTheme.typography.button,
+ shape: Shape = size.toShape(),
) {
Button(
modifier = modifier.heightIn(min = size.toHeightDp()),
onClick = { if (!showProgress) onClick() },
enabled = enabled,
elevation = elevation,
- shape = size.toShape(),
+ shape = shape,
colors = colors,
contentPadding = size.toContentPadding(icon = icon),
) {
diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/buttons/segmentedbutton/SegmentedButton.kt b/core/ui/src/main/java/com/tangem/core/ui/components/buttons/segmentedbutton/SegmentedButton.kt
new file mode 100644
index 0000000000..df18f78ab0
--- /dev/null
+++ b/core/ui/src/main/java/com/tangem/core/ui/components/buttons/segmentedbutton/SegmentedButton.kt
@@ -0,0 +1,161 @@
+package com.tangem.core.ui.components.buttons.segmentedbutton
+
+import androidx.compose.foundation.LocalIndication
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Text
+import androidx.compose.runtime.*
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.tooling.preview.PreviewParameter
+import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
+import com.tangem.core.ui.res.TangemTheme
+import kotlinx.collections.immutable.PersistentList
+import kotlinx.collections.immutable.persistentListOf
+
+/**
+ * Segmented buttons
+ *
+ * [Figma component](https://www.figma.com/file/14ISV23YB1yVW1uNVwqrKv/Android?type=design&node-id=1961-2004&mode=design&t=OFPQ18YhLHVAANab-4)
+ *
+ * @param config list of buttons in SegmentedButtons
+ * @param onClick button click
+ * @param modifier component modifier
+ * @param color default button color
+ * @param selectedColor selected button color
+ * @param dividerColor border and divider color
+ * @param showIndication show ripple indication
+ * @param buttonContent content as separate button
+ */
+@Composable
+inline fun SegmentedButtons(
+ config: PersistentList,
+ crossinline onClick: (T) -> Unit,
+ modifier: Modifier = Modifier,
+ color: Color = TangemTheme.colors.background.tertiary,
+ selectedColor: Color = TangemTheme.colors.background.action,
+ dividerColor: Color = TangemTheme.colors.stroke.primary,
+ showIndication: Boolean = true,
+ crossinline buttonContent: @Composable (T) -> Unit,
+) {
+ if (config.isEmpty() || config.size == 1) return
+
+ var selected by remember { mutableIntStateOf(0) }
+
+ Row(
+ modifier = modifier
+ .clip(RoundedCornerShape(TangemTheme.dimens.radius26))
+ .background(dividerColor)
+ .padding(TangemTheme.dimens.spacing1),
+ horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing1),
+ ) {
+ repeat(config.size) { index ->
+ val leftRadius = if (index == 0) TangemTheme.dimens.radius26 else TangemTheme.dimens.radius0
+ val rightRadius = if (index == config.lastIndex) TangemTheme.dimens.radius26 else TangemTheme.dimens.radius0
+
+ Box(
+ modifier = Modifier
+ .weight(1f)
+ .background(
+ color = if (index == selected) selectedColor else color,
+ shape = RoundedCornerShape(
+ topStart = leftRadius,
+ topEnd = rightRadius,
+ bottomEnd = rightRadius,
+ bottomStart = leftRadius,
+ ),
+ )
+ .clickable(
+ interactionSource = remember { MutableInteractionSource() },
+ indication = if (showIndication) LocalIndication.current else null,
+ ) {
+ onClick(config[index])
+ selected = index
+ },
+ ) {
+ buttonContent.invoke(config[index])
+ }
+ }
+ }
+}
+
+@Preview
+@Composable
+private fun SegmentedButtonsPreview_Light(
+ @PreviewParameter(SegmentedButtonsPreviewProvider::class) config: PersistentList,
+) {
+ TangemTheme {
+ SegmentedButtons(
+ config = config,
+ onClick = {},
+ ) {
+ Text(
+ text = it.text,
+ modifier = Modifier.padding(TangemTheme.dimens.spacing16),
+ )
+ }
+ }
+}
+
+@Preview
+@Composable
+private fun SegmentedButtonsPreview_Dark(
+ @PreviewParameter(SegmentedButtonsPreviewProvider::class) config: PersistentList,
+) {
+ TangemTheme(isDark = true) {
+ SegmentedButtons(
+ config = config,
+ onClick = {},
+ ) {
+ Text(
+ text = it.text,
+ modifier = Modifier.padding(TangemTheme.dimens.spacing16),
+ )
+ }
+ }
+}
+
+//region Preview config
+/**
+ * Segmented buttons preview model
+ *
+ * @param text button title
+ */
+internal data class SegmentedButtonsConfigPreview(
+ val text: String,
+)
+
+/**
+ * Segmented button preview provider
+ */
+internal class SegmentedButtonsPreviewProvider :
+ CollectionPreviewParameterProvider>(
+ collection = listOf(
+ persistentListOf(
+ SegmentedButtonsConfigPreview(
+ text = "Title 1",
+ ),
+ SegmentedButtonsConfigPreview(
+ text = "Title 2",
+ ),
+ SegmentedButtonsConfigPreview(
+ text = "Title 3",
+ ),
+ ),
+ persistentListOf(
+ SegmentedButtonsConfigPreview(
+ text = "Title 1",
+ ),
+ SegmentedButtonsConfigPreview(
+ text = "Title 2",
+ ),
+ ),
+ ),
+ )
+
+//endregion
\ No newline at end of file
diff --git a/features/send/impl/build.gradle.kts b/features/send/impl/build.gradle.kts
index 3c6f6bd7f7..c0cfcb3894 100644
--- a/features/send/impl/build.gradle.kts
+++ b/features/send/impl/build.gradle.kts
@@ -14,7 +14,11 @@ dependencies {
/** AndroidX */
implementation(deps.androidx.fragment.ktx)
implementation(deps.androidx.appCompat)
+
+ /** Other dependencies */
+ implementation(deps.kotlin.immutable.collections)
implementation(deps.material)
+ implementation(deps.arrow.core)
/** Compose */
implementation(deps.compose.accompanist.systemUiController)
@@ -23,13 +27,23 @@ dependencies {
implementation(deps.compose.ui)
implementation(deps.compose.ui.tooling)
implementation(deps.compose.navigation)
+ implementation(deps.compose.navigation.hilt)
+
+ /** Common */
+ implementation(projects.common)
/** Core modules */
implementation(projects.core.featuretoggles)
implementation(projects.core.ui)
+ implementation(projects.core.utils)
/** Domain modules */
+ implementation(projects.domain.tokens)
implementation(projects.domain.tokens.models)
+ implementation(projects.domain.wallets)
+ implementation(projects.domain.wallets.models)
+ implementation(projects.domain.appCurrency)
+ implementation(projects.domain.appCurrency.models)
/** Feature modules */
implementation(projects.features.send.api)
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/state/SendAmountSegmentedButtonsConfig.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/state/SendAmountSegmentedButtonsConfig.kt
new file mode 100644
index 0000000000..ea3220b6e6
--- /dev/null
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/state/SendAmountSegmentedButtonsConfig.kt
@@ -0,0 +1,21 @@
+package com.tangem.features.send.impl.presentation.send.state
+
+import androidx.compose.runtime.Immutable
+import com.tangem.core.ui.components.currency.tokenicon.TokenIconState
+import com.tangem.core.ui.extensions.TextReference
+
+/**
+ * Segmented buttons config
+ *
+ * @param title button title
+ * @param iconState currency icon state
+ * @param iconUrl currency icon url
+ * @param isFiat is fiat currency
+ */
+@Immutable
+internal data class SendAmountSegmentedButtonsConfig(
+ val title: TextReference,
+ val iconState: TokenIconState? = null,
+ val iconUrl: String? = null,
+ val isFiat: Boolean,
+)
\ No newline at end of file
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/state/SendUiState.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/state/SendUiState.kt
new file mode 100644
index 0000000000..10df3f1966
--- /dev/null
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/state/SendUiState.kt
@@ -0,0 +1,57 @@
+package com.tangem.features.send.impl.presentation.send.state
+
+import androidx.compose.runtime.Immutable
+import com.tangem.core.ui.components.currency.tokenicon.TokenIconState
+import com.tangem.domain.appcurrency.model.AppCurrency
+import com.tangem.domain.tokens.model.CryptoCurrencyStatus
+import com.tangem.features.send.impl.presentation.send.state.fields.SendTextField
+import kotlinx.collections.immutable.PersistentList
+
+/**
+ * Ui states of the send screen
+ */
+@Immutable
+internal sealed class SendUiState {
+
+ /** States with content */
+ sealed class Content : SendUiState() {
+
+ abstract val nextButtonEnabled: Boolean
+
+ /** Initial state */
+ data class Initial(
+ override val nextButtonEnabled: Boolean = false,
+ ) : Content()
+
+ /** Amount state */
+ data class AmountState(
+ override val nextButtonEnabled: Boolean = false,
+ val walletName: String,
+ val walletBalance: String,
+ val tokenIconState: TokenIconState,
+ val cryptoCurrencyStatus: CryptoCurrencyStatus,
+ val appCurrency: AppCurrency,
+ val isFiatValue: Boolean,
+ val segmentedButtonConfig: PersistentList,
+ val amountTextField: SendTextField.Amount,
+ ) : Content()
+
+ // todo [REDACTED_JIRA]
+ /** Recipient state */
+ data class RecipientState(
+ override val nextButtonEnabled: Boolean = false,
+ ) : Content()
+
+ // todo [REDACTED_JIRA]
+ /** Fee and speed state */
+ data class FeeState(
+ override val nextButtonEnabled: Boolean = false,
+ ) : Content()
+
+ // todo [REDACTED_JIRA]
+ /** Send state */
+ data class SendState(
+ override val nextButtonEnabled: Boolean = true,
+ ) : Content()
+ }
+}
\ No newline at end of file
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/state/fields/SendTextField.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/state/fields/SendTextField.kt
new file mode 100644
index 0000000000..e7677e747d
--- /dev/null
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/state/fields/SendTextField.kt
@@ -0,0 +1,35 @@
+package com.tangem.features.send.impl.presentation.send.state.fields
+
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.runtime.Immutable
+import com.tangem.core.ui.extensions.TextReference
+
+@Immutable
+internal sealed class SendTextField {
+
+ /** Current value */
+ abstract val value: String
+
+ /** Lambda be invoked when value is been changed */
+ abstract val onValueChange: (String) -> Unit
+
+ /** Keyboard options */
+ abstract val keyboardOptions: KeyboardOptions
+
+ /** Label */
+ abstract val label: TextReference
+
+ /** Placeholder (hint) */
+ abstract val placeholder: TextReference
+
+ data class Amount(
+ override val value: String,
+ override val onValueChange: (String) -> Unit,
+ override val keyboardOptions: KeyboardOptions,
+ override val label: TextReference,
+ override val placeholder: TextReference,
+ val fiatValue: String,
+ val isError: Boolean,
+ val error: TextReference,
+ ) : SendTextField()
+}
\ No newline at end of file
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/ui/SendBottomSheetConfig.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/ui/SendBottomSheetConfig.kt
deleted file mode 100644
index 73f5797f7b..0000000000
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/ui/SendBottomSheetConfig.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.tangem.features.send.impl.presentation.send.ui
-
-import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
-
-data class SendBottomSheetConfig(
- val currentState: SendStates,
-) : TangemBottomSheetConfigContent
\ No newline at end of file
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/ui/SendNavigationButtons.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/ui/SendNavigationButtons.kt
index 7630c89501..9604a47dfd 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/ui/SendNavigationButtons.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/ui/SendNavigationButtons.kt
@@ -18,17 +18,18 @@ import com.tangem.core.ui.R
import com.tangem.core.ui.components.PrimaryButton
import com.tangem.core.ui.components.PrimaryButtonIconEnd
import com.tangem.core.ui.res.TangemTheme
+import com.tangem.features.send.impl.presentation.send.state.SendUiState
@Composable
-internal fun SendNavigationButtons(currentState: SendStates) {
+internal fun SendNavigationButtons(uiState: SendUiState.Content) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(bottom = TangemTheme.dimens.spacing12),
) {
- SendSecondaryNavigationButton(currentState)
+ SendSecondaryNavigationButton(uiState)
SendPrimaryNavigationButton(
- currentState,
+ uiState = uiState,
modifier = Modifier
.weight(1f)
.padding(horizontal = TangemTheme.dimens.spacing16),
@@ -37,9 +38,9 @@ internal fun SendNavigationButtons(currentState: SendStates) {
}
@Composable
-private fun SendSecondaryNavigationButton(currentState: SendStates) {
+private fun SendSecondaryNavigationButton(uiState: SendUiState.Content) {
AnimatedVisibility(
- visible = currentState == SendStates.Recipient || currentState == SendStates.Fee,
+ visible = uiState is SendUiState.Content.RecipientState || uiState is SendUiState.Content.FeeState,
) {
Icon(
modifier = Modifier
@@ -57,40 +58,37 @@ private fun SendSecondaryNavigationButton(currentState: SendStates) {
}
@Composable
-private fun SendPrimaryNavigationButton(currentState: SendStates, modifier: Modifier = Modifier) {
- val buttonTextId = when (currentState) {
- SendStates.Amount,
- SendStates.Recipient,
- SendStates.Fee,
+private fun SendPrimaryNavigationButton(uiState: SendUiState.Content, modifier: Modifier = Modifier) {
+ val buttonTextId = when (uiState) {
+ is SendUiState.Content.AmountState,
+ is SendUiState.Content.RecipientState,
+ is SendUiState.Content.FeeState,
-> R.string.common_next
- SendStates.Filled -> R.string.common_send
- SendStates.Done -> R.string.common_close
+ is SendUiState.Content.SendState -> R.string.common_send
+ else -> R.string.common_close
}
AnimatedContent(
targetState = buttonTextId,
label = "Update send screen state",
modifier = modifier,
) { textId ->
- when (currentState) {
- SendStates.Amount,
- SendStates.Recipient,
- SendStates.Fee,
- SendStates.Done,
- -> PrimaryButton(
+ if (uiState is SendUiState.Content.SendState) {
+ PrimaryButtonIconEnd(
text = stringResource(textId),
+ iconResId = R.drawable.ic_tangem_24,
+ enabled = uiState.nextButtonEnabled,
+ onClick = {
+ // todo add next click
+ },
+ )
+ } else {
+ PrimaryButton(
+ text = stringResource(textId),
+ enabled = uiState.nextButtonEnabled,
onClick = {
// todo add next click
},
)
- SendStates.Filled -> {
- PrimaryButtonIconEnd(
- text = stringResource(textId),
- iconResId = R.drawable.ic_tangem_24,
- onClick = {
- // todo add next click
- },
- )
- }
}
}
}
\ No newline at end of file
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/ui/SendScreen.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/ui/SendScreen.kt
index 3ec40b3169..61351bd875 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/ui/SendScreen.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/ui/SendScreen.kt
@@ -9,17 +9,14 @@ import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetDraggableHeader
import com.tangem.core.ui.res.TangemTheme
+import com.tangem.features.send.impl.presentation.send.state.SendUiState
@Composable
fun SendScreen() {
- // todo will be removed
- val config = remember { SendBottomSheetConfig(SendStates.Amount) }
-
Column(
modifier = Modifier
.imePadding()
@@ -42,7 +39,7 @@ fun SendScreen() {
) {
SendScreenContent()
}
- SendNavigationButtons(config.currentState)
+ SendNavigationButtons(uiState = SendUiState.Content.Initial())
}
}
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/ui/SendStates.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/ui/SendStates.kt
deleted file mode 100644
index f0a3e9840b..0000000000
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/ui/SendStates.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.tangem.features.send.impl.presentation.send.ui
-
-/**
- * Screen states of Send
- */
-enum class SendStates {
- Amount,
- Recipient,
- Fee,
- Filled,
- Done,
- ;
-
- companion object {
-
- /** Get next [SendStates] */
- fun SendStates.next(): SendStates {
- return if (this.ordinal < SendStates.values().last().ordinal) {
- SendStates.values()[this.ordinal + 1]
- } else {
- this
- }
- }
-
- /** Get previous [SendStates] */
- fun SendStates.previous(): SendStates {
- return if (this.ordinal > 0) {
- SendStates.values()[this.ordinal - 1]
- } else {
- this
- }
- }
- }
-}
\ No newline at end of file
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/ui/amount/AmountField.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/ui/amount/AmountField.kt
new file mode 100644
index 0000000000..4eda379a95
--- /dev/null
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/ui/amount/AmountField.kt
@@ -0,0 +1,168 @@
+package com.tangem.features.send.impl.presentation.send.ui.amount
+
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.ColumnScope
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.text.BasicTextField
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Alignment.Companion.BottomCenter
+import androidx.compose.ui.Alignment.Companion.CenterHorizontally
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.buildAnnotatedString
+import androidx.compose.ui.text.input.OffsetMapping
+import androidx.compose.ui.text.input.TransformedText
+import androidx.compose.ui.text.input.VisualTransformation
+import androidx.compose.ui.text.style.TextAlign
+import com.tangem.core.ui.extensions.TextReference
+import com.tangem.core.ui.extensions.resolveReference
+import com.tangem.core.ui.res.TangemTheme
+import com.tangem.features.send.impl.presentation.send.state.fields.SendTextField
+
+@Composable
+internal fun ColumnScope.AmountField(
+ sendField: SendTextField.Amount,
+ cryptoSymbol: String,
+ fiatSymbol: String,
+ isFiat: Boolean,
+) {
+ val value = if (isFiat) sendField.fiatValue else sendField.value
+ val secondaryValue = if (!isFiat) sendField.fiatValue else sendField.value
+ val symbol = if (isFiat) fiatSymbol else cryptoSymbol
+ val secondarySymbol = if (!isFiat) fiatSymbol else cryptoSymbol
+
+ AmountFieldInner(
+ value = value,
+ placeholder = sendField.placeholder,
+ symbol = symbol,
+ onValueChange = sendField.onValueChange,
+ keyboardOptions = sendField.keyboardOptions,
+ modifier = Modifier
+ .align(CenterHorizontally)
+ .padding(
+ top = TangemTheme.dimens.spacing24,
+ start = TangemTheme.dimens.spacing12,
+ end = TangemTheme.dimens.spacing12,
+ ),
+ )
+
+ Box(
+ modifier = Modifier
+ .align(CenterHorizontally)
+ .padding(
+ top = TangemTheme.dimens.spacing8,
+ start = TangemTheme.dimens.spacing12,
+ end = TangemTheme.dimens.spacing12,
+ ),
+ ) {
+ Text(
+ text = "$secondaryValue $secondarySymbol",
+ style = TangemTheme.typography.caption2,
+ color = TangemTheme.colors.text.tertiary,
+ textAlign = TextAlign.Center,
+ modifier = Modifier
+ .align(BottomCenter)
+ .padding(bottom = TangemTheme.dimens.spacing32),
+ )
+ AmountFieldError(
+ isError = sendField.isError,
+ error = sendField.error,
+ modifier = Modifier
+ .align(BottomCenter)
+ .padding(bottom = TangemTheme.dimens.spacing12),
+ )
+ }
+}
+
+@Composable
+private fun AmountFieldInner(
+ value: String,
+ placeholder: TextReference,
+ symbol: String,
+ onValueChange: (String) -> Unit,
+ keyboardOptions: KeyboardOptions,
+ modifier: Modifier = Modifier,
+) {
+ val focusRequester = remember { FocusRequester() }
+ BasicTextField(
+ value = value,
+ onValueChange = onValueChange,
+ modifier = modifier
+ .focusRequester(focusRequester)
+ .background(TangemTheme.colors.background.action),
+ textStyle = TangemTheme.typography.h2.copy(
+ color = TangemTheme.colors.text.primary1,
+ textAlign = TextAlign.Center,
+ ),
+ keyboardOptions = keyboardOptions,
+ singleLine = true,
+ visualTransformation = AmountVisualTransformation(symbol),
+ decorationBox = { innerTextField ->
+ Box {
+ if (value.isBlank()) {
+ Text(
+ text = "${placeholder.resolveReference()} $symbol",
+ style = TangemTheme.typography.h2,
+ color = TangemTheme.colors.text.disabled,
+ textAlign = TextAlign.Center,
+ modifier = Modifier
+ .align(Alignment.TopCenter),
+ )
+ }
+ innerTextField()
+ }
+ },
+ )
+}
+
+@Composable
+private fun AmountFieldError(isError: Boolean, error: TextReference, modifier: Modifier = Modifier) {
+ AnimatedVisibility(
+ visible = isError,
+ enter = fadeIn(),
+ exit = fadeOut(),
+ modifier = modifier,
+ ) {
+ Text(
+ text = error.resolveReference(),
+ style = TangemTheme.typography.caption2,
+ color = TangemTheme.colors.text.warning,
+ textAlign = TextAlign.Center,
+ )
+ }
+}
+
+private class AmountVisualTransformation(
+ private val symbol: String,
+) : VisualTransformation {
+ override fun filter(text: AnnotatedString): TransformedText {
+ return TransformedText(
+ buildAnnotatedString {
+ append(text)
+ if (text.isNotBlank()) {
+ append(" ")
+ append(symbol)
+ }
+ },
+ object : OffsetMapping {
+ override fun originalToTransformed(offset: Int): Int {
+ return text.length
+ }
+
+ override fun transformedToOriginal(offset: Int): Int {
+ return text.length
+ }
+ },
+ )
+ }
+}
\ No newline at end of file
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/ui/amount/AmountFieldContainer.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/ui/amount/AmountFieldContainer.kt
new file mode 100644
index 0000000000..b7810d5acb
--- /dev/null
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/send/ui/amount/AmountFieldContainer.kt
@@ -0,0 +1,61 @@
+package com.tangem.features.send.impl.presentation.send.ui.amount
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.text.style.TextAlign
+import com.tangem.core.ui.components.currency.tokenicon.TokenIcon
+import com.tangem.core.ui.res.TangemTheme
+import com.tangem.features.send.impl.presentation.send.state.SendUiState
+
+@Composable
+internal fun AmountFieldContainer(amountState: SendUiState.Content.AmountState, modifier: Modifier = Modifier) {
+ Column(
+ modifier = modifier
+ .fillMaxWidth()
+ .padding(
+ top = TangemTheme.dimens.spacing4,
+ start = TangemTheme.dimens.spacing16,
+ end = TangemTheme.dimens.spacing16,
+ )
+ .clip(RoundedCornerShape(TangemTheme.dimens.radius16))
+ .background(TangemTheme.colors.background.action),
+ ) {
+ Text(
+ text = amountState.walletName,
+ style = TangemTheme.typography.subtitle2,
+ color = TangemTheme.colors.text.tertiary,
+ modifier = Modifier
+ .padding(top = TangemTheme.dimens.spacing14)
+ .align(Alignment.CenterHorizontally),
+ )
+ Text(
+ text = amountState.walletBalance,
+ style = TangemTheme.typography.caption2,
+ color = TangemTheme.colors.text.tertiary,
+ textAlign = TextAlign.Center,
+ modifier = Modifier
+ .padding(top = TangemTheme.dimens.spacing2)
+ .align(Alignment.CenterHorizontally),
+ )
+ TokenIcon(
+ state = amountState.tokenIconState,
+ modifier = Modifier
+ .padding(top = TangemTheme.dimens.spacing32)
+ .align(Alignment.CenterHorizontally),
+ )
+ AmountField(
+ sendField = amountState.amountTextField,
+ cryptoSymbol = amountState.cryptoCurrencyStatus.currency.symbol,
+ fiatSymbol = amountState.appCurrency.symbol,
+ isFiat = amountState.isFiatValue,
+ )
+ }
+}
\ No newline at end of file