Updated on 2026-08-14
This commit is contained in:
parent
865bf08157
commit
7945ad6c57
10 changed files with 146 additions and 109 deletions
|
|
@ -1,29 +0,0 @@
|
|||
package com.tangem.core.ui.utils
|
||||
|
||||
/**
|
||||
* Formats input [String] for InputField, to remove wrong symbols, letters etc
|
||||
* Use [decimals] for cut this number symbols after floating point
|
||||
*
|
||||
* Example (with 8 decimals):
|
||||
* input string - ab123.46377372ab53
|
||||
* result string 123.46377372
|
||||
*/
|
||||
fun getValidatedNumberWithFixedDecimals(text: String, decimals: Int): String {
|
||||
val comma = ','
|
||||
val dot = '.'
|
||||
val filteredChars = text.replace(comma, dot).filterIndexed { index, c ->
|
||||
val isOneOrZeroPoint = c == dot && index != 0 && text.count { it == dot } <= 1
|
||||
val isIndexPointIndex = c == dot && index != 0 && text.indexOf(dot) == index
|
||||
c.isDigit() || isIndexPointIndex || isOneOrZeroPoint
|
||||
}
|
||||
// If dot is present, take first 3 digits before decimal and first decimals digits after decimal
|
||||
return if (filteredChars.count { it == dot } == 1) {
|
||||
val beforeDecimal = filteredChars.substringBefore(dot)
|
||||
val afterDecimal = filteredChars.substringAfter(dot)
|
||||
beforeDecimal + dot + afterDecimal.take(decimals)
|
||||
}
|
||||
// If there is no dot, just take all digits
|
||||
else {
|
||||
filteredChars
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
package com.tangem.core.ui.utils
|
||||
|
||||
import java.text.DecimalFormat
|
||||
|
||||
class InputNumberFormatter(
|
||||
numberFormat: DecimalFormat,
|
||||
) {
|
||||
|
||||
private val symbols = numberFormat.decimalFormatSymbols
|
||||
|
||||
/**
|
||||
* Formats input [String] for InputField, to remove wrong symbols, letters etc
|
||||
* Use [decimals] for cut this number symbols after floating point
|
||||
*
|
||||
* Example (with 8 decimals):
|
||||
* input string - ab123.46377372ab53
|
||||
* result string 123.46377372
|
||||
*/
|
||||
fun getValidatedNumberWithFixedDecimals(text: String, decimals: Int): String {
|
||||
val thousandsSeparator = symbols.groupingSeparator
|
||||
val decimalSeparator = symbols.decimalSeparator
|
||||
|
||||
if (text.startsWith("0") && text.length > 1 && text[1] != decimalSeparator) {
|
||||
return "0"
|
||||
}
|
||||
|
||||
val filteredChars = text.replace(thousandsSeparator.toString(), "").filterIndexed { index, c ->
|
||||
val isOneOrZeroPoint = c == decimalSeparator && index != 0 && text.count { it == decimalSeparator } <= 1
|
||||
val isIndexPointIndex = c == decimalSeparator && index != 0 && text.indexOf(decimalSeparator) == index
|
||||
c.isDigit() || isIndexPointIndex || isOneOrZeroPoint
|
||||
}
|
||||
// If dot is present, take first digits before decimal and first decimals digits after decimal
|
||||
return if (filteredChars.count { it == decimalSeparator } == 1) {
|
||||
val beforeDecimal = filteredChars.substringBefore(decimalSeparator)
|
||||
val afterDecimal = filteredChars.substringAfter(decimalSeparator)
|
||||
beforeDecimal + decimalSeparator + afterDecimal.take(decimals)
|
||||
}
|
||||
// If there is no dot, just take all digits
|
||||
else {
|
||||
filteredChars
|
||||
}
|
||||
}
|
||||
|
||||
fun formatWithThousands(text: String, decimals: Int): String {
|
||||
val thousandsSeparator = symbols.groupingSeparator
|
||||
val decimalSeparator = symbols.decimalSeparator
|
||||
return if (text.count { it == decimalSeparator } == 1) {
|
||||
val beforeDecimal = text.substringBefore(decimalSeparator)
|
||||
.reversed()
|
||||
.chunked(TEXT_CHUNK_THOUSAND)
|
||||
.joinToString(thousandsSeparator.toString())
|
||||
.reversed()
|
||||
val afterDecimal = text.substringAfter(decimalSeparator)
|
||||
beforeDecimal + decimalSeparator + afterDecimal.take(decimals)
|
||||
}
|
||||
// If there is no dot, just take all digits
|
||||
else {
|
||||
text.reversed()
|
||||
.chunked(TEXT_CHUNK_THOUSAND)
|
||||
.joinToString(thousandsSeparator.toString())
|
||||
.reversed()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TEXT_CHUNK_THOUSAND = 3
|
||||
}
|
||||
}
|
||||
|
|
@ -3,24 +3,23 @@ package com.tangem.utils
|
|||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
import java.text.DecimalFormat
|
||||
import java.text.DecimalFormatSymbols
|
||||
import java.text.NumberFormat
|
||||
import java.util.*
|
||||
|
||||
// todo determine where to place this extensions
|
||||
fun BigDecimal.toFormattedString(
|
||||
decimals: Int,
|
||||
roundingMode: RoundingMode = RoundingMode.DOWN,
|
||||
locale: Locale = Locale.US,
|
||||
locale: Locale = Locale.getDefault(),
|
||||
): String {
|
||||
val symbols = DecimalFormatSymbols(locale)
|
||||
val df = DecimalFormat().apply {
|
||||
decimalFormatSymbols = symbols
|
||||
val formatter = NumberFormat.getInstance(locale) as? DecimalFormat
|
||||
val df = formatter?.apply {
|
||||
maximumFractionDigits = decimals
|
||||
minimumFractionDigits = 0
|
||||
isGroupingUsed = false
|
||||
isGroupingUsed = true
|
||||
this.roundingMode = roundingMode
|
||||
}
|
||||
return df.format(this)
|
||||
return df?.format(this) ?: this.toPlainString()
|
||||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
|
|
@ -48,44 +47,17 @@ fun BigDecimal.toFiatString(
|
|||
formatWithSpaces: Boolean = false,
|
||||
): String {
|
||||
val fiatValue = rateValue.multiply(this)
|
||||
return fiatValue.toFormattedFiatValue(fiatCurrencyName, formatWithSpaces)
|
||||
}
|
||||
|
||||
fun BigDecimal.toFormattedFiatValue(
|
||||
fiatCurrencyName: String,
|
||||
formatWithSpaces: Boolean = false,
|
||||
): String {
|
||||
val fiatValue = this.setScale(2, RoundingMode.HALF_UP)
|
||||
.let { if (formatWithSpaces) it.formatWithSpaces() else it }
|
||||
return " $fiatValue $fiatCurrencyName"
|
||||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
fun BigDecimal.formatWithSpaces(): String {
|
||||
val str = this.toString()
|
||||
var integerStr = str.substringBefore('.')
|
||||
val reminderStr = str.substringAfter('.')
|
||||
val packets = arrayListOf<String>()
|
||||
|
||||
var index: Int = integerStr.length
|
||||
while (0 < index) {
|
||||
if (index <= 3) {
|
||||
packets.add(integerStr)
|
||||
break
|
||||
}
|
||||
index -= 3
|
||||
packets.add(integerStr.substring(startIndex = index))
|
||||
integerStr = integerStr.substring(startIndex = 0, endIndex = index)
|
||||
val formatter = NumberFormat.getInstance(Locale.getDefault()) as? DecimalFormat
|
||||
val df = formatter?.apply {
|
||||
maximumFractionDigits = 2
|
||||
minimumFractionDigits = 0
|
||||
isGroupingUsed = true
|
||||
this.roundingMode = roundingMode
|
||||
}
|
||||
|
||||
return buildString {
|
||||
packets.reversed().forEachIndexed { index, packet ->
|
||||
append(packet)
|
||||
if (index != packets.lastIndex) append(' ')
|
||||
}
|
||||
if (reminderStr.isNotBlank()) {
|
||||
append('.')
|
||||
append(reminderStr)
|
||||
}
|
||||
val formatted = if (formatWithSpaces) {
|
||||
"${df?.format(fiatValue)} $fiatCurrencyName"
|
||||
} else {
|
||||
"${df?.format(fiatValue)}$fiatCurrencyName"
|
||||
}
|
||||
return formatted
|
||||
}
|
||||
|
|
@ -146,7 +146,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
amountToSwap: String,
|
||||
): SwapState {
|
||||
syncWalletBalanceForTokens(networkId, listOf(fromToken, toToken))
|
||||
val amountDecimal = amountToSwap.toBigDecimalOrNull()
|
||||
val amountDecimal = toBigDecimalOrNull(amountToSwap)
|
||||
if (amountDecimal == null || amountDecimal.compareTo(BigDecimal.ZERO) == 0) {
|
||||
return createEmptyAmountState(fromToken, toToken)
|
||||
}
|
||||
|
|
@ -196,7 +196,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
currencyToGet: Currency,
|
||||
amountToSwap: String,
|
||||
): TxState {
|
||||
val amount = requireNotNull(amountToSwap.toBigDecimalOrNull()) { "wrong amount format, use only digits" }
|
||||
val amount = requireNotNull(toBigDecimalOrNull(amountToSwap)) { "wrong amount format, use only digits" }
|
||||
val estimatedGas =
|
||||
increaseByPercents(TWENTY_FIVE_PERCENTS, swapData.transaction.gas.toIntOrNull() ?: DEFAULT_GAS)
|
||||
val fee = transactionManager.calculateFee(
|
||||
|
|
@ -596,6 +596,10 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
return value * (percents / 100 + 1)
|
||||
}
|
||||
|
||||
private fun toBigDecimalOrNull(amountToSwap: String): BigDecimal? {
|
||||
return amountToSwap.replace(",", ".").toBigDecimalOrNull()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val DEFAULT_SLIPPAGE = 2
|
||||
private const val ZERO_BALANCE = "0"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package com.tangem.feature.swap.models
|
||||
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
|
||||
data class SwapStateHolder(
|
||||
val sendCardData: SwapCardData,
|
||||
val receiveCardData: SwapCardData,
|
||||
|
|
@ -30,9 +32,9 @@ data class SwapStateHolder(
|
|||
|
||||
data class SwapCardData(
|
||||
val type: TransactionCardType,
|
||||
val amount: String?,
|
||||
val amountEquivalent: String?,
|
||||
val coinId: String?,
|
||||
val amountTextFieldValue: TextFieldValue?,
|
||||
val tokenIconUrl: String,
|
||||
val tokenCurrency: String,
|
||||
val balance: String,
|
||||
|
|
|
|||
|
|
@ -24,12 +24,13 @@ import androidx.compose.ui.text.ParagraphIntrinsics
|
|||
import androidx.compose.ui.text.font.createFontFamilyResolver
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
@Suppress("MagicNumber", "LongMethod")
|
||||
@Composable
|
||||
internal fun AutoSizeTextField(
|
||||
amount: String,
|
||||
textFieldValue: TextFieldValue,
|
||||
onAmountChange: (String) -> Unit,
|
||||
onFocusChange: (Boolean) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
|
|
@ -40,7 +41,7 @@ internal fun AutoSizeTextField(
|
|||
var shrunkFontSize = TangemTheme.typography.h2.fontSize
|
||||
val calculateIntrinsics = @Composable {
|
||||
ParagraphIntrinsics(
|
||||
text = amount,
|
||||
text = textFieldValue.text,
|
||||
style = TangemTheme.typography.h2.copy(
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
fontSize = shrunkFontSize,
|
||||
|
|
@ -63,8 +64,10 @@ internal fun AutoSizeTextField(
|
|||
)
|
||||
CompositionLocalProvider(LocalTextSelectionColors provides customTextSelectionColors) {
|
||||
BasicTextField(
|
||||
value = amount,
|
||||
onValueChange = onAmountChange,
|
||||
value = textFieldValue,
|
||||
onValueChange = {
|
||||
onAmountChange.invoke(it.text)
|
||||
},
|
||||
singleLine = true,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
|
|
@ -76,7 +79,7 @@ internal fun AutoSizeTextField(
|
|||
),
|
||||
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
|
||||
decorationBox = { innerTextField ->
|
||||
if (amount.isBlank()) {
|
||||
if (textFieldValue.text.isBlank()) {
|
||||
Text(
|
||||
text = "0",
|
||||
color = TangemTheme.colors.text.disabled,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package com.tangem.feature.swap.ui
|
||||
|
||||
import androidx.compose.ui.text.TextRange
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import com.tangem.feature.swap.converters.TokensDataConverter
|
||||
import com.tangem.feature.swap.domain.models.DataError
|
||||
import com.tangem.feature.swap.domain.models.domain.Currency
|
||||
|
|
@ -37,8 +39,8 @@ internal class StateBuilder(val actions: UiActions) {
|
|||
blockchainId = networkInfo.blockchainId,
|
||||
sendCardData = SwapCardData(
|
||||
type = TransactionCardType.SendCard(actions.onAmountChanged, actions.onAmountSelected),
|
||||
amount = null,
|
||||
amountEquivalent = null,
|
||||
amountTextFieldValue = null,
|
||||
tokenIconUrl = initialCurrency.logoUrl,
|
||||
tokenCurrency = initialCurrency.symbol,
|
||||
coinId = initialCurrency.id,
|
||||
|
|
@ -48,10 +50,10 @@ internal class StateBuilder(val actions: UiActions) {
|
|||
),
|
||||
receiveCardData = SwapCardData(
|
||||
type = TransactionCardType.ReceiveCard(),
|
||||
amount = null,
|
||||
amountEquivalent = null,
|
||||
tokenIconUrl = "",
|
||||
tokenCurrency = "",
|
||||
amountTextFieldValue = null,
|
||||
canSelectAnotherToken = false,
|
||||
balance = "",
|
||||
isNotNativeToken = false,
|
||||
|
|
@ -80,7 +82,7 @@ internal class StateBuilder(val actions: UiActions) {
|
|||
return uiStateHolder.copy(
|
||||
sendCardData = SwapCardData(
|
||||
type = requireNotNull(uiStateHolder.sendCardData.type as? TransactionCardType.SendCard),
|
||||
amount = uiStateHolder.sendCardData.amount,
|
||||
amountTextFieldValue = uiStateHolder.sendCardData.amountTextFieldValue,
|
||||
amountEquivalent = null,
|
||||
tokenIconUrl = fromToken.logoUrl,
|
||||
tokenCurrency = fromToken.symbol,
|
||||
|
|
@ -91,7 +93,7 @@ internal class StateBuilder(val actions: UiActions) {
|
|||
),
|
||||
receiveCardData = SwapCardData(
|
||||
type = TransactionCardType.ReceiveCard(),
|
||||
amount = null,
|
||||
amountTextFieldValue = null,
|
||||
amountEquivalent = null,
|
||||
tokenIconUrl = toToken.logoUrl,
|
||||
tokenCurrency = toToken.symbol,
|
||||
|
|
@ -130,7 +132,7 @@ internal class StateBuilder(val actions: UiActions) {
|
|||
return uiStateHolder.copy(
|
||||
sendCardData = SwapCardData(
|
||||
type = requireNotNull(uiStateHolder.sendCardData.type as? TransactionCardType.SendCard),
|
||||
amount = uiStateHolder.sendCardData.amount,
|
||||
amountTextFieldValue = uiStateHolder.sendCardData.amountTextFieldValue,
|
||||
amountEquivalent = quoteModel.fromTokenInfo.tokenFiatBalance,
|
||||
tokenIconUrl = uiStateHolder.sendCardData.tokenIconUrl,
|
||||
coinId = quoteModel.fromTokenInfo.coinId,
|
||||
|
|
@ -141,7 +143,7 @@ internal class StateBuilder(val actions: UiActions) {
|
|||
),
|
||||
receiveCardData = SwapCardData(
|
||||
type = TransactionCardType.ReceiveCard(),
|
||||
amount = quoteModel.toTokenInfo.tokenAmount.formatToUIRepresentation(),
|
||||
amountTextFieldValue = TextFieldValue(quoteModel.toTokenInfo.tokenAmount.formatToUIRepresentation()),
|
||||
amountEquivalent = quoteModel.toTokenInfo.tokenFiatBalance,
|
||||
tokenIconUrl = uiStateHolder.receiveCardData.tokenIconUrl,
|
||||
coinId = quoteModel.toTokenInfo.coinId,
|
||||
|
|
@ -172,7 +174,7 @@ internal class StateBuilder(val actions: UiActions) {
|
|||
return uiStateHolder.copy(
|
||||
sendCardData = SwapCardData(
|
||||
type = requireNotNull(uiStateHolder.sendCardData.type as? TransactionCardType.SendCard),
|
||||
amount = uiStateHolder.sendCardData.amount,
|
||||
amountTextFieldValue = uiStateHolder.sendCardData.amountTextFieldValue,
|
||||
amountEquivalent = emptyAmountState.zeroAmountEquivalent,
|
||||
tokenIconUrl = uiStateHolder.sendCardData.tokenIconUrl,
|
||||
coinId = uiStateHolder.sendCardData.coinId,
|
||||
|
|
@ -183,7 +185,7 @@ internal class StateBuilder(val actions: UiActions) {
|
|||
),
|
||||
receiveCardData = SwapCardData(
|
||||
type = TransactionCardType.ReceiveCard(),
|
||||
amount = "0",
|
||||
amountTextFieldValue = TextFieldValue("0"),
|
||||
amountEquivalent = emptyAmountState.zeroAmountEquivalent,
|
||||
tokenIconUrl = uiStateHolder.receiveCardData.tokenIconUrl,
|
||||
coinId = uiStateHolder.receiveCardData.coinId,
|
||||
|
|
@ -252,7 +254,10 @@ internal class StateBuilder(val actions: UiActions) {
|
|||
fun updateSwapAmount(uiState: SwapStateHolder, amount: String): SwapStateHolder {
|
||||
return uiState.copy(
|
||||
sendCardData = uiState.sendCardData.copy(
|
||||
amount = amount,
|
||||
amountTextFieldValue = TextFieldValue(
|
||||
text = amount,
|
||||
selection = TextRange(amount.length),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.constraintlayout.compose.ConstraintLayout
|
||||
|
|
@ -163,7 +164,7 @@ private fun MainInfo(state: SwapStateHolder) {
|
|||
TransactionCard(
|
||||
type = state.sendCardData.type,
|
||||
balance = state.sendCardData.balance,
|
||||
amount = state.sendCardData.amount,
|
||||
textFieldValue = state.sendCardData.amountTextFieldValue,
|
||||
amountEquivalent = state.sendCardData.amountEquivalent,
|
||||
tokenIconUrl = state.sendCardData.tokenIconUrl,
|
||||
tokenCurrency = state.sendCardData.tokenCurrency,
|
||||
|
|
@ -180,7 +181,7 @@ private fun MainInfo(state: SwapStateHolder) {
|
|||
TransactionCard(
|
||||
type = state.receiveCardData.type,
|
||||
balance = state.receiveCardData.balance,
|
||||
amount = state.receiveCardData.amount,
|
||||
textFieldValue = state.receiveCardData.amountTextFieldValue,
|
||||
amountEquivalent = state.receiveCardData.amountEquivalent,
|
||||
tokenIconUrl = state.receiveCardData.tokenIconUrl,
|
||||
tokenCurrency = state.receiveCardData.tokenCurrency,
|
||||
|
|
@ -360,7 +361,7 @@ private fun MainButton(state: SwapStateHolder, onPermissionWarningClick: () -> U
|
|||
|
||||
private val sendCard = SwapCardData(
|
||||
type = TransactionCardType.SendCard({}) {},
|
||||
amount = "1 000 000",
|
||||
amountTextFieldValue = TextFieldValue(),
|
||||
amountEquivalent = "1 000 000",
|
||||
tokenIconUrl = "",
|
||||
tokenCurrency = "DAI",
|
||||
|
|
@ -372,7 +373,7 @@ private val sendCard = SwapCardData(
|
|||
|
||||
private val receiveCard = SwapCardData(
|
||||
type = TransactionCardType.ReceiveCard(),
|
||||
amount = "1 000 000",
|
||||
amountTextFieldValue = TextFieldValue(),
|
||||
amountEquivalent = "1 000 000",
|
||||
tokenIconUrl = "",
|
||||
tokenCurrency = "DAI",
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import androidx.compose.ui.graphics.Color
|
|||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
|
@ -55,8 +56,8 @@ fun TransactionCard(
|
|||
balance: String,
|
||||
tokenIconUrl: String,
|
||||
tokenCurrency: String,
|
||||
amount: String?,
|
||||
amountEquivalent: String?,
|
||||
textFieldValue: TextFieldValue?,
|
||||
modifier: Modifier = Modifier,
|
||||
@DrawableRes iconPlaceholder: Int? = null,
|
||||
@DrawableRes networkIconRes: Int? = null,
|
||||
|
|
@ -79,8 +80,8 @@ fun TransactionCard(
|
|||
|
||||
Content(
|
||||
type = type,
|
||||
amount = amount,
|
||||
amountEquivalent = amountEquivalent,
|
||||
textFieldValue = textFieldValue,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -169,8 +170,8 @@ private fun Header(
|
|||
@Composable
|
||||
private fun Content(
|
||||
type: TransactionCardType,
|
||||
amount: String?,
|
||||
amountEquivalent: String?,
|
||||
textFieldValue: TextFieldValue?,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
|
|
@ -192,9 +193,9 @@ private fun Content(
|
|||
val sumTextModifier = Modifier.defaultMinSize(minHeight = TangemTheme.dimens.size32)
|
||||
when (type) {
|
||||
is TransactionCardType.ReceiveCard -> {
|
||||
if (amount != null) {
|
||||
if (textFieldValue != null) {
|
||||
ResizableText(
|
||||
text = amount,
|
||||
text = textFieldValue.text,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.h2,
|
||||
fontSizeRange = FontSizeRange(min = 16.sp, max = TangemTheme.typography.h2.fontSize),
|
||||
|
|
@ -216,7 +217,7 @@ private fun Content(
|
|||
is TransactionCardType.SendCard -> {
|
||||
AutoSizeTextField(
|
||||
modifier = sumTextModifier,
|
||||
amount = amount ?: "",
|
||||
textFieldValue = textFieldValue ?: TextFieldValue(),
|
||||
onAmountChange = { type.onAmountChanged(it) },
|
||||
onFocusChange = type.onFocusChanged,
|
||||
)
|
||||
|
|
@ -376,13 +377,13 @@ private fun Preview_SwapMainCard_InDarkTheme() {
|
|||
private fun TransactionCardPreview() {
|
||||
TransactionCard(
|
||||
type = TransactionCardType.SendCard({}) {},
|
||||
amount = "1 000 000",
|
||||
amountEquivalent = "1 000 000",
|
||||
tokenIconUrl = "",
|
||||
tokenCurrency = "DAI",
|
||||
networkIconRes = R.drawable.img_polygon_22,
|
||||
onChangeTokenClick = {},
|
||||
balance = "123",
|
||||
textFieldValue = TextFieldValue(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import androidx.lifecycle.SavedStateHandle
|
|||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.ui.utils.getValidatedNumberWithFixedDecimals
|
||||
import com.tangem.core.ui.utils.InputNumberFormatter
|
||||
import com.tangem.feature.swap.analytics.SwapEvents
|
||||
import com.tangem.feature.swap.domain.BlockchainInteractor
|
||||
import com.tangem.feature.swap.domain.SwapInteractor
|
||||
|
|
@ -32,6 +32,9 @@ import dagger.hilt.android.lifecycle.HiltViewModel
|
|||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
import java.text.DecimalFormat
|
||||
import java.text.NumberFormat
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
|
|
@ -53,6 +56,8 @@ internal class SwapViewModel @Inject constructor(
|
|||
private val stateBuilder = StateBuilder(
|
||||
actions = createUiActions(),
|
||||
)
|
||||
private val inputNumberFormatter =
|
||||
InputNumberFormatter(NumberFormat.getInstance(Locale.getDefault()) as DecimalFormat)
|
||||
private val amountDebouncer = Debouncer()
|
||||
private val singleTaskScheduler = SingleTaskScheduler<SwapState>()
|
||||
|
||||
|
|
@ -332,9 +337,12 @@ internal class SwapViewModel @Inject constructor(
|
|||
toCurrency = newToToken,
|
||||
)
|
||||
isOrderReversed = !isOrderReversed
|
||||
lastAmount.value =
|
||||
cutAmountWithDecimals(blockchainInteractor.getTokenDecimals(newFromToken), lastAmount.value)
|
||||
uiState = stateBuilder.updateSwapAmount(uiState, lastAmount.value)
|
||||
val decimals = blockchainInteractor.getTokenDecimals(newFromToken)
|
||||
lastAmount.value = cutAmountWithDecimals(decimals, lastAmount.value)
|
||||
uiState = stateBuilder.updateSwapAmount(
|
||||
uiState,
|
||||
inputNumberFormatter.formatWithThousands(lastAmount.value, decimals),
|
||||
)
|
||||
startLoadingQuotes(newFromToken, newToToken, lastAmount.value)
|
||||
}
|
||||
}
|
||||
|
|
@ -343,9 +351,11 @@ internal class SwapViewModel @Inject constructor(
|
|||
val fromToken = dataState.fromCurrency
|
||||
val toToken = dataState.toCurrency
|
||||
if (fromToken != null && toToken != null) {
|
||||
val cutValue = cutAmountWithDecimals(blockchainInteractor.getTokenDecimals(fromToken), value)
|
||||
uiState = stateBuilder.updateSwapAmount(uiState, cutValue)
|
||||
val decimals = blockchainInteractor.getTokenDecimals(fromToken)
|
||||
val cutValue = cutAmountWithDecimals(decimals, value)
|
||||
lastAmount.value = cutValue
|
||||
uiState =
|
||||
stateBuilder.updateSwapAmount(uiState, inputNumberFormatter.formatWithThousands(cutValue, decimals))
|
||||
amountDebouncer.debounce(DEBOUNCE_AMOUNT_DELAY, viewModelScope) {
|
||||
startLoadingQuotes(fromToken, toToken, lastAmount.value)
|
||||
}
|
||||
|
|
@ -367,7 +377,7 @@ internal class SwapViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun cutAmountWithDecimals(maxDecimals: Int, amount: String): String {
|
||||
return getValidatedNumberWithFixedDecimals(amount, maxDecimals)
|
||||
return inputNumberFormatter.getValidatedNumberWithFixedDecimals(amount, maxDecimals)
|
||||
}
|
||||
|
||||
private fun makeDefaultAlert() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue