From 37a224169cff35034f72e0a511adeef7da52a3bc Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 23 Apr 2024 17:27:39 +0500 Subject: [PATCH 1/2] Updated on 2026-08-14 --- .../ui/components/fields/AmountTextField.kt | 4 ++ .../ui/components/fields/SimpleTextField.kt | 58 ++++++++----------- .../state/amount/AmountStateFactory.kt | 7 +++ .../amount/SendAmountCurrencyConverter.kt | 1 + ...SendAmountPastedTriggerDismissConverter.kt | 21 +++++++ .../state/fields/SendAmountFieldConverter.kt | 2 + .../SendAmountFieldMaxAmountConverter.kt | 1 + .../state/fields/SendTextField.kt | 2 + .../previewdata/AmountStatePreviewData.kt | 2 + .../state/previewdata/SendClickIntentsStub.kt | 2 + .../presentation/ui/amount/AmountField.kt | 2 + .../viewmodel/SendClickIntents.kt | 2 + .../presentation/viewmodel/SendViewModel.kt | 4 ++ 13 files changed, 75 insertions(+), 33 deletions(-) create mode 100644 features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/SendAmountPastedTriggerDismissConverter.kt 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 75836f873a..c095c2b8fd 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 @@ -64,6 +64,8 @@ fun AmountTextField( keyboardActions: KeyboardActions = KeyboardActions.Default, isEnabled: Boolean = true, isAutoResize: Boolean = false, + isValuePasted: Boolean = false, + onValuePastedTriggerDismiss: () -> Unit = {}, @FloatRange(from = 0.0, to = 1.0, fromInclusive = false, toInclusive = false) reduceFactor: Double = 0.9, ) { @@ -101,6 +103,8 @@ fun AmountTextField( fontSize = fontSize, textDirection = TextDirection.ContentOrLtr, ), + isValuePasted = isValuePasted, + onValuePastedTriggerDismiss = onValuePastedTriggerDismiss, color = textColor, keyboardOptions = keyboardOptions, keyboardActions = keyboardActions, diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/fields/SimpleTextField.kt b/core/ui/src/main/java/com/tangem/core/ui/components/fields/SimpleTextField.kt index b9cba56550..238b773614 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/fields/SimpleTextField.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/fields/SimpleTextField.kt @@ -39,15 +39,13 @@ fun SimpleTextField( color: Color = TangemTheme.colors.text.primary1, textStyle: TextStyle = TangemTheme.typography.body2.copy(color = color), readOnly: Boolean = false, + isValuePasted: Boolean = false, + onValuePastedTriggerDismiss: () -> Unit = {}, decorationBox: (@Composable (innerTextField: @Composable () -> Unit) -> Unit)? = null, ) { + val proxyValue by remember(value) { derivedStateOf { value } } var textFieldValueState by remember { - mutableStateOf( - TextFieldValue( - text = value, - selection = getValueRange(value), - ), - ) + mutableStateOf(TextFieldValue(text = value)) } val focusRequester = remember { FocusRequester.Default } val customTextSelectionColors = TextSelectionColors( @@ -55,36 +53,28 @@ fun SimpleTextField( backgroundColor = TangemTheme.colors.text.accent.copy(alpha = 0.3f), ) - val textFieldValue = textFieldValueState.copy(text = value) - - val isSelectionChanged by remember { - derivedStateOf { - textFieldValue.selection != textFieldValueState.selection || - textFieldValue.composition != textFieldValueState.composition || - textFieldValue.text != textFieldValueState.text - } + var lastTextValue by remember(proxyValue, isValuePasted) { + textFieldValueState = textFieldValueState.copy( + text = proxyValue, + selection = if (isValuePasted) { + TextRange(proxyValue.length, proxyValue.length) + } else { + textFieldValueState.selection + }, + ) + mutableStateOf(proxyValue) } - LaunchedEffect(key1 = isSelectionChanged) { - if (isSelectionChanged) { - textFieldValueState = textFieldValue + // resets paste value cursor trigger + LaunchedEffect(key1 = isValuePasted) { + if (isValuePasted) { + onValuePastedTriggerDismiss() } } - var lastTextValue by remember(value) { - val isSelectionLastIndex = textFieldValueState.selection.end == textFieldValueState.text.lastIndex - if (textFieldValueState.text.isBlank() || isSelectionLastIndex) { - textFieldValueState = textFieldValueState.copy( - text = value, - selection = getValueRange(value), - ) - } - mutableStateOf(value) - } - CompositionLocalProvider(LocalTextSelectionColors provides customTextSelectionColors) { BasicTextField( - value = textFieldValue, + value = textFieldValueState, onValueChange = { newTextFieldValueState -> textFieldValueState = newTextFieldValueState @@ -114,10 +104,12 @@ fun SimpleTextField( } } -private fun getValueRange(value: String) = when { - value.isEmpty() -> TextRange.Zero - else -> TextRange(value.length, value.length) -} +// private fun TextRange.getValueRange(oldValue: String, newValue: String) = when { +// newValue.isEmpty() -> TextRange.Zero +// newValue.length - oldValue.length > 1 -> TextRange(newValue.length, newValue.length) +// newValue.length - oldValue.length > 0 -> TextRange(this.start.inc(), this.end.inc()) +// else -> this +// } @Composable private fun SimpleTextPlaceholder( diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/AmountStateFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/AmountStateFactory.kt index 6f56b6aff3..3321568099 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/AmountStateFactory.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/AmountStateFactory.kt @@ -33,6 +33,11 @@ internal class AmountStateFactory( cryptoCurrencyStatusProvider = cryptoCurrencyStatusProvider, ) } + private val amountPasteConverter by lazy(LazyThreadSafetyMode.NONE) { + SendAmountPastedTriggerDismissConverter( + currentStateProvider = currentStateProvider, + ) + } fun getOnAmountValueChange(value: String) = amountFieldChangeConverter.convert(value) @@ -41,4 +46,6 @@ internal class AmountStateFactory( } fun getOnCurrencyChangedState(isFiat: Boolean) = amountCurrencyConverter.convert(isFiat) + + fun getOnAmountPastedTriggerDismiss() = amountPasteConverter.convert(false) } \ No newline at end of file diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/SendAmountCurrencyConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/SendAmountCurrencyConverter.kt index 0f95e9fad7..f6ff524e9f 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/SendAmountCurrencyConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/SendAmountCurrencyConverter.kt @@ -24,6 +24,7 @@ internal class SendAmountCurrencyConverter( amountState = amountState.copy( amountTextField = amountTextField.copy( isFiatValue = value, + isValuePasted = true, ), ), ) diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/SendAmountPastedTriggerDismissConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/SendAmountPastedTriggerDismissConverter.kt new file mode 100644 index 0000000000..497629bdd5 --- /dev/null +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/SendAmountPastedTriggerDismissConverter.kt @@ -0,0 +1,21 @@ +package com.tangem.features.send.impl.presentation.state.amount + +import com.tangem.features.send.impl.presentation.state.SendUiState +import com.tangem.utils.Provider +import com.tangem.utils.converter.Converter + +internal class SendAmountPastedTriggerDismissConverter( + private val currentStateProvider: Provider, +) : Converter { + override fun convert(value: Boolean): SendUiState { + val state = currentStateProvider() + val amountState = state.amountState ?: return state + return state.copy( + amountState = amountState.copy( + amountTextField = amountState.amountTextField.copy( + isValuePasted = false, + ), + ), + ) + } +} \ No newline at end of file diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldConverter.kt index 332a736cd0..f2ad4e7e71 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldConverter.kt @@ -55,6 +55,8 @@ internal class SendAmountFieldConverter( isError = false, error = TextReference.Res(R.string.swapping_insufficient_funds), isFiatUnavailable = fiatRate == null, + isValuePasted = false, + onValuePastedTriggerDismiss = clickIntents::onAmountPasteTriggerDismiss, ) } diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldMaxAmountConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldMaxAmountConverter.kt index b29459e757..bb69b15be3 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldMaxAmountConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldMaxAmountConverter.kt @@ -35,6 +35,7 @@ internal class SendAmountFieldMaxAmountConverter( amountState = amountState.copy( isPrimaryButtonEnabled = true, amountTextField = amountTextField.copy( + isValuePasted = true, value = cryptoValue, fiatValue = fiatValue, isError = false, diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendTextField.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendTextField.kt index 266f9e8f6e..6cd4f8c31d 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendTextField.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendTextField.kt @@ -28,6 +28,8 @@ internal sealed class SendTextField { val isFiatValue: Boolean, val fiatValue: String, val isFiatUnavailable: Boolean, + val isValuePasted: Boolean, + val onValuePastedTriggerDismiss: () -> Unit, val isError: Boolean, val error: TextReference, ) : SendTextField() diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/previewdata/AmountStatePreviewData.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/previewdata/AmountStatePreviewData.kt index cbe162c0c5..d39cd3df01 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/previewdata/AmountStatePreviewData.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/previewdata/AmountStatePreviewData.kt @@ -45,6 +45,8 @@ internal object AmountStatePreviewData { isFiatUnavailable = false, isError = false, error = TextReference.EMPTY, + isValuePasted = false, + onValuePastedTriggerDismiss = {}, ), isSegmentedButtonsEnabled = true, ) diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/previewdata/SendClickIntentsStub.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/previewdata/SendClickIntentsStub.kt index 10a3142e61..5235588e51 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/previewdata/SendClickIntentsStub.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/previewdata/SendClickIntentsStub.kt @@ -30,6 +30,8 @@ internal object SendClickIntentsStub : SendClickIntents { override fun onMaxValueClick() {} + override fun onAmountPasteTriggerDismiss() {} + override fun onRecipientAddressValueChange(value: String, type: EnterAddressSource?) {} override fun onRecipientMemoValueChange(value: String) {} diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/AmountField.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/AmountField.kt index f92a93cdae..640189da93 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/AmountField.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/AmountField.kt @@ -53,6 +53,8 @@ internal fun AmountField(sendField: SendTextField.AmountField, appCurrencyCode: textAlign = TextAlign.Center, ), isAutoResize = true, + isValuePasted = sendField.isValuePasted, + onValuePastedTriggerDismiss = sendField.onValuePastedTriggerDismiss, modifier = Modifier .focusRequester(requester) .padding( diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendClickIntents.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendClickIntents.kt index 74e5d81128..a353059047 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendClickIntents.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendClickIntents.kt @@ -30,6 +30,8 @@ internal interface SendClickIntents { fun onCurrencyChangeClick(isFiat: Boolean) fun onMaxValueClick() + + fun onAmountPasteTriggerDismiss() // endregion // region Recipient diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt index caec97e044..90348ad8d5 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt @@ -551,6 +551,10 @@ internal class SendViewModel @Inject constructor( uiState = amountStateFactory.getOnMaxAmountClick() analyticsEventHandler.send(SendAnalyticEvents.MaxAmountButtonClicked) } + + override fun onAmountPasteTriggerDismiss() { + uiState = amountStateFactory.getOnAmountPastedTriggerDismiss() + } // endregion // region recipient state clicks From 585a213d985821bc817d65b9eced3be354f89f42 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 23 Apr 2024 17:28:10 +0500 Subject: [PATCH 2/2] Updated on 2026-08-14 --- .../tangem/core/ui/components/fields/SimpleTextField.kt | 7 ------- .../presentation/state/fields/SendAmountFieldConverter.kt | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/fields/SimpleTextField.kt b/core/ui/src/main/java/com/tangem/core/ui/components/fields/SimpleTextField.kt index 238b773614..e4737af0c1 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/fields/SimpleTextField.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/fields/SimpleTextField.kt @@ -104,13 +104,6 @@ fun SimpleTextField( } } -// private fun TextRange.getValueRange(oldValue: String, newValue: String) = when { -// newValue.isEmpty() -> TextRange.Zero -// newValue.length - oldValue.length > 1 -> TextRange(newValue.length, newValue.length) -// newValue.length - oldValue.length > 0 -> TextRange(this.start.inc(), this.end.inc()) -// else -> this -// } - @Composable private fun SimpleTextPlaceholder( placeholder: TextReference?, diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldConverter.kt index f2ad4e7e71..2070b8c633 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldConverter.kt @@ -53,7 +53,7 @@ internal class SendAmountFieldConverter( cryptoAmount = cryptoAmount, fiatAmount = getAppCurrencyAmount(fiatDecimal, appCurrencyProvider()), isError = false, - error = TextReference.Res(R.string.swapping_insufficient_funds), + error = TextReference.Res(R.string.send_validation_amount_exceeds_balance), isFiatUnavailable = fiatRate == null, isValuePasted = false, onValuePastedTriggerDismiss = clickIntents::onAmountPasteTriggerDismiss,