diff --git a/app/src/debug/res/xml/network_security_config.xml b/app/src/debug/res/xml/network_security_config.xml
index 894912ac61..52c44ac992 100644
--- a/app/src/debug/res/xml/network_security_config.xml
+++ b/app/src/debug/res/xml/network_security_config.xml
@@ -1,9 +1,9 @@
-
+
-
+
diff --git a/app/src/external/res/xml/network_security_config.xml b/app/src/external/res/xml/network_security_config.xml
index 894912ac61..d49c0f70ba 100644
--- a/app/src/external/res/xml/network_security_config.xml
+++ b/app/src/external/res/xml/network_security_config.xml
@@ -1,9 +1,10 @@
-
+
-
+
+
diff --git a/app/src/internal/res/xml/network_security_config.xml b/app/src/internal/res/xml/network_security_config.xml
index 894912ac61..52c44ac992 100644
--- a/app/src/internal/res/xml/network_security_config.xml
+++ b/app/src/internal/res/xml/network_security_config.xml
@@ -1,9 +1,9 @@
-
+
-
+
diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml
index 22e9f8653e..683208ffda 100644
--- a/app/src/main/res/xml/network_security_config.xml
+++ b/app/src/main/res/xml/network_security_config.xml
@@ -1,11 +1,8 @@
-
-
- api.tangem.com
+
-
-
+
diff --git a/core/datasource/src/main/java/com/tangem/datasource/connection/RealInternetConnectionManager.kt b/core/datasource/src/main/java/com/tangem/datasource/connection/RealInternetConnectionManager.kt
index 8ca86a2587..7a3279d188 100644
--- a/core/datasource/src/main/java/com/tangem/datasource/connection/RealInternetConnectionManager.kt
+++ b/core/datasource/src/main/java/com/tangem/datasource/connection/RealInternetConnectionManager.kt
@@ -13,6 +13,7 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.reactive.asFlow
+private const val PING_SERVER = "https://clients3.google.com/generate_204"
private const val PING_INTERVAL = 5_000
internal class RealInternetConnectionManager : NetworkConnectionManager {
@@ -24,7 +25,12 @@ internal class RealInternetConnectionManager : NetworkConnectionManager {
private val initialNetworkResult: Boolean by lazy {
ReactiveNetwork
- .checkInternetConnectivity()
+ .checkInternetConnectivity(
+ InternetObservingSettings.builder()
+ .host(PING_SERVER)
+ .port(443)
+ .build(),
+ )
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.blockingGet()
@@ -33,6 +39,8 @@ internal class RealInternetConnectionManager : NetworkConnectionManager {
override val isOnlineFlow: StateFlow = ReactiveNetwork
.observeInternetConnectivity(
InternetObservingSettings.builder()
+ .host(PING_SERVER)
+ .port(443)
.interval(PING_INTERVAL)
.build(),
)
diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/appbar/AppBarWithBackButtonAndIconContent.kt b/core/ui/src/main/java/com/tangem/core/ui/components/appbar/AppBarWithBackButtonAndIconContent.kt
index 09b6158abb..c65bf02622 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/components/appbar/AppBarWithBackButtonAndIconContent.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/components/appbar/AppBarWithBackButtonAndIconContent.kt
@@ -63,7 +63,8 @@ fun AppBarWithBackButtonAndIconContent(
)
Column(
verticalArrangement = Arrangement.Center,
- modifier = Modifier.weight(1f),
+ modifier = Modifier.weight(1f)
+ .animateContentSize(),
) {
AnimatedVisibility(
visible = !text.isNullOrBlank(),
@@ -89,7 +90,6 @@ fun AppBarWithBackButtonAndIconContent(
color = TangemTheme.colors.text.secondary,
maxLines = 1,
style = TangemTheme.typography.caption2,
- modifier = Modifier.animateContentSize(),
)
}
}
diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/currency/tokenicon/TokenIconState.kt b/core/ui/src/main/java/com/tangem/core/ui/components/currency/tokenicon/TokenIconState.kt
index f51adb19b3..0f7ff350de 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/components/currency/tokenicon/TokenIconState.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/components/currency/tokenicon/TokenIconState.kt
@@ -60,24 +60,23 @@ sealed class TokenIconState {
* @property background The background color to be used for the icon.
* @property networkBadgeIconResId The drawable resource ID for the network badge.
* @property isGrayscale Specifies whether to show the icon in grayscale.
+ * @property showCustomBadge Specifies whether to show the custom token badge.
*/
data class CustomTokenIcon(
val tint: Color,
val background: Color,
@DrawableRes override val networkBadgeIconResId: Int,
override val isGrayscale: Boolean,
- ) : TokenIconState() {
+ override val showCustomBadge: Boolean = true,
+ ) : TokenIconState()
- override val showCustomBadge: Boolean = true
- }
-
- object Loading : TokenIconState() {
+ data object Loading : TokenIconState() {
override val isGrayscale: Boolean = false
override val showCustomBadge: Boolean = false
override val networkBadgeIconResId: Int? = null
}
- object Locked : TokenIconState() {
+ data object Locked : TokenIconState() {
override val isGrayscale: Boolean = false
override val showCustomBadge: Boolean = false
override val networkBadgeIconResId: Int? = null
diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/currency/tokenicon/converter/CryptoCurrencyToIconStateConverter.kt b/core/ui/src/main/java/com/tangem/core/ui/components/currency/tokenicon/converter/CryptoCurrencyToIconStateConverter.kt
index fbcc6e3caa..3e62e98992 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/components/currency/tokenicon/converter/CryptoCurrencyToIconStateConverter.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/components/currency/tokenicon/converter/CryptoCurrencyToIconStateConverter.kt
@@ -30,6 +30,7 @@ class CryptoCurrencyToIconStateConverter : Converter getIconStateForToken(
token = currency,
@@ -50,13 +51,14 @@ class CryptoCurrencyToIconStateConverter : Converter
textFieldValueState = newTextFieldValueState
@@ -126,4 +138,14 @@ private fun SimpleTextPlaceholder(
}
textValue()
}
+}
+
+@Composable
+private fun rememberSelectionChanged(textFieldValue: TextFieldValue, textFieldValueState: TextFieldValue) = remember {
+ derivedStateOf {
+ val isSelectionChanged = textFieldValue.selection != textFieldValueState.selection ||
+ textFieldValue.composition != textFieldValueState.composition
+ val isTextNotChanged = textFieldValue.text == textFieldValueState.text
+ isSelectionChanged && isTextNotChanged
+ }
}
\ No newline at end of file
diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/rows/SelectorRowItem.kt b/core/ui/src/main/java/com/tangem/core/ui/components/rows/SelectorRowItem.kt
index bedec66060..b919363574 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/components/rows/SelectorRowItem.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/components/rows/SelectorRowItem.kt
@@ -73,7 +73,7 @@ fun SelectorRowItem(
color = TangemTheme.colors.text.primary1,
modifier = Modifier.padding(start = TangemTheme.dimens.spacing8),
)
- if (preDot != null && postDot != null) {
+ if (preDot != null) {
SelectorValueContent(
preDot = preDot,
postDot = postDot,
@@ -97,7 +97,7 @@ fun SelectorRowItem(
@Composable
private fun RowScope.SelectorValueContent(
preDot: TextReference,
- postDot: TextReference,
+ postDot: TextReference?,
ellipsizeOffset: Int? = null,
) {
val ellipsis = if (ellipsizeOffset == null) {
@@ -115,18 +115,20 @@ private fun RowScope.SelectorValueContent(
.weight(1f)
.padding(start = TangemTheme.dimens.spacing4),
)
- Text(
- text = "•",
- style = TangemTheme.typography.caption2,
- color = TangemTheme.colors.text.primary1,
- textAlign = TextAlign.Center,
- modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing4),
- )
- Text(
- text = postDot.resolveReference(),
- style = TangemTheme.typography.body2,
- color = TangemTheme.colors.text.tertiary,
- )
+ if (postDot != null) {
+ Text(
+ text = "•",
+ style = TangemTheme.typography.caption2,
+ color = TangemTheme.colors.text.primary1,
+ textAlign = TextAlign.Center,
+ modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing4),
+ )
+ Text(
+ text = postDot.resolveReference(),
+ style = TangemTheme.typography.body2,
+ color = TangemTheme.colors.text.tertiary,
+ )
+ }
}
@Preview
diff --git a/data/transaction/src/main/java/com/tangem/data/transaction/DefaultTransactionRepository.kt b/data/transaction/src/main/java/com/tangem/data/transaction/DefaultTransactionRepository.kt
index 76b16b1409..3fe078eaad 100644
--- a/data/transaction/src/main/java/com/tangem/data/transaction/DefaultTransactionRepository.kt
+++ b/data/transaction/src/main/java/com/tangem/data/transaction/DefaultTransactionRepository.kt
@@ -71,7 +71,10 @@ internal class DefaultTransactionRepository(
}
Blockchain.Binance -> BinanceTransactionExtras(memo)
Blockchain.XRP -> memo.toLongOrNull()?.let { XrpTransactionBuilder.XrpTransactionExtras(it) }
- Blockchain.Cosmos -> CosmosTransactionExtras(memo)
+ Blockchain.Cosmos,
+ Blockchain.TerraV1,
+ Blockchain.TerraV2,
+ -> CosmosTransactionExtras(memo)
Blockchain.TON -> TonTransactionExtras(memo)
Blockchain.Hedera -> HederaTransactionBuilder.HederaTransactionExtras(memo)
Blockchain.Algorand -> AlgorandTransactionExtras(memo)
diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesOperations.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesOperations.kt
index fac9f7fc95..d12ca4c9ad 100644
--- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesOperations.kt
+++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesOperations.kt
@@ -264,10 +264,18 @@ internal class CurrenciesStatusesOperations(
var quotesRetrievingFailed = false
val networksStatuses = maybeNetworkStatuses?.bind()?.toNonEmptySetOrNull()
- val quotes = recover({ maybeQuotes?.bind()?.toNonEmptySetOrNull() }) {
- quotesRetrievingFailed = true
- null
- }
+ val quotes: Set? = maybeQuotes?.fold(
+ ifLeft = {
+ quotesRetrievingFailed = true
+ null
+ },
+ ifRight = {
+ it.ifEmpty {
+ quotesRetrievingFailed = true
+ null
+ }
+ },
+ )
currencies.map { currency ->
val quote = quotes?.firstOrNull { it.rawCurrencyId == currency.id.rawCurrencyId }
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/analytics/SendAnalyticEvents.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/analytics/SendAnalyticEvents.kt
index e99471d8de..feca8a0786 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/analytics/SendAnalyticEvents.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/analytics/SendAnalyticEvents.kt
@@ -16,6 +16,20 @@ internal sealed class SendAnalyticEvents(
params: Map = mapOf(),
) : AnalyticsEvent(category = "Token / Send", event = event, params = params) {
+ /** Close button clicked */
+ data class CloseButtonClicked(
+ val source: SendScreenSource,
+ val isFromSummary: Boolean,
+ val isValid: Boolean,
+ ) : SendAnalyticEvents(
+ event = "Button - Close",
+ params = mapOf(
+ SOURCE to source.name,
+ "FromSummary" to if (isFromSummary) "Yes" else "No",
+ "isValid" to if (isValid) "Yes" else "No",
+ ),
+ )
+
// region Address
/** Recipient address screen opened */
data object AddressScreenOpened : SendAnalyticEvents(event = "Address Screen Opened")
@@ -119,6 +133,7 @@ internal enum class SendScreenSource {
Address,
Amount,
Fee,
+ Confirm,
}
internal enum class EnterAddressSource {
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/analytics/utils/SendOnNextScreenAnalyticSender.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/analytics/utils/SendScreenAnalyticSender.kt
similarity index 69%
rename from features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/analytics/utils/SendOnNextScreenAnalyticSender.kt
rename to features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/analytics/utils/SendScreenAnalyticSender.kt
index 6fefbc87b8..27c93b9743 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/analytics/utils/SendOnNextScreenAnalyticSender.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/analytics/utils/SendScreenAnalyticSender.kt
@@ -5,15 +5,17 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.features.send.impl.presentation.analytics.SelectedCurrencyType
import com.tangem.features.send.impl.presentation.analytics.SelectedFeeType
import com.tangem.features.send.impl.presentation.analytics.SendAnalyticEvents
-import com.tangem.features.send.impl.presentation.state.*
+import com.tangem.features.send.impl.presentation.analytics.SendScreenSource
import com.tangem.features.send.impl.presentation.state.SendUiState
+import com.tangem.features.send.impl.presentation.state.SendUiStateType
import com.tangem.features.send.impl.presentation.state.StateRouter
import com.tangem.features.send.impl.presentation.state.fee.FeeSelectorState
import com.tangem.features.send.impl.presentation.state.fee.FeeType
import com.tangem.utils.Provider
-internal class SendOnNextScreenAnalyticSender(
+internal class SendScreenAnalyticSender(
private val stateRouterProvider: Provider,
+ private val currentStateProvider: Provider,
private val analyticsEventHandler: AnalyticsEventHandler,
) {
fun send(prevScreen: SendUiStateType, state: SendUiState) {
@@ -45,6 +47,32 @@ internal class SendOnNextScreenAnalyticSender(
}
}
+ fun sendOnClose() {
+ val routerState = stateRouterProvider().currentState.value
+ val state = currentStateProvider()
+
+ val (source, isValid) = when (routerState.type) {
+ SendUiStateType.Recipient,
+ SendUiStateType.EditRecipient,
+ -> SendScreenSource.Address to (state.editRecipientState?.isPrimaryButtonEnabled ?: false)
+ SendUiStateType.Amount,
+ SendUiStateType.EditAmount,
+ -> SendScreenSource.Amount to (state.editAmountState?.isPrimaryButtonEnabled ?: false)
+ SendUiStateType.Fee,
+ SendUiStateType.EditFee,
+ -> SendScreenSource.Fee to (state.editFeeState?.isPrimaryButtonEnabled ?: false)
+ else -> SendScreenSource.Confirm to true
+ }
+
+ analyticsEventHandler.send(
+ SendAnalyticEvents.CloseButtonClicked(
+ source = source,
+ isFromSummary = routerState.isFromConfirmation,
+ isValid = isValid,
+ ),
+ )
+ }
+
private fun sendSelectedFeeAnalytics(feeSelectorState: FeeSelectorState.Content) {
val type = when (feeSelectorState.fees) {
is TransactionFee.Single -> SelectedFeeType.Fixed
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendStateFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendStateFactory.kt
index a2b722b614..631cbdf100 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendStateFactory.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendStateFactory.kt
@@ -18,6 +18,7 @@ import com.tangem.features.send.impl.presentation.state.common.SendSyncEditConve
import com.tangem.features.send.impl.presentation.state.confirm.SendConfirmStateConverter
import com.tangem.features.send.impl.presentation.state.fee.FeeSelectorState
import com.tangem.features.send.impl.presentation.state.fee.SendFeeStateConverter
+import com.tangem.features.send.impl.presentation.state.fee.checkFeeCoverage
import com.tangem.features.send.impl.presentation.state.fields.SendAmountFieldConverter
import com.tangem.features.send.impl.presentation.state.recipient.SendRecipientHistoryListConverter
import com.tangem.features.send.impl.presentation.state.recipient.SendRecipientStateConverter
@@ -28,8 +29,9 @@ import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList
import timber.log.Timber
+import java.math.BigDecimal
-@Suppress("LongParameterList")
+@Suppress("LongParameterList", "LargeClass")
internal class SendStateFactory(
private val clickIntents: SendClickIntents,
private val stateRouterProvider: Provider,
@@ -46,6 +48,7 @@ internal class SendStateFactory(
private val amountFieldConverter by lazy(LazyThreadSafetyMode.NONE) {
SendAmountFieldConverter(
clickIntents = clickIntents,
+ stateRouterProvider = stateRouterProvider,
cryptoCurrencyStatusProvider = cryptoCurrencyStatusProvider,
appCurrencyProvider = appCurrencyProvider,
)
@@ -94,6 +97,7 @@ internal class SendStateFactory(
isEditingDisabled = false,
isBalanceHidden = false,
cryptoCurrencyName = "",
+ isSubtracted = false,
)
fun getReadyState(): SendUiState {
@@ -279,12 +283,33 @@ internal class SendStateFactory(
//endregion
//region send
+ fun getIsAmountSubtractedState(isAmountSubtractAvailable: Boolean): SendUiState {
+ val state = currentStateProvider()
+ val balance = cryptoCurrencyStatusProvider().value.amount ?: return state
+ val amountState = state.getAmountState(stateRouterProvider().isEditState) ?: return state
+ val feeState = state.getFeeState(stateRouterProvider().isEditState) ?: return state
+ val amountValue = amountState.amountTextField.cryptoAmount.value ?: return state
+ val feeValue = feeState.fee?.amount?.value ?: BigDecimal.ZERO
+ return state.copy(
+ isSubtracted = checkFeeCoverage(
+ isSubtractAvailable = isAmountSubtractAvailable,
+ balance = balance,
+ amountValue = amountValue,
+ feeValue = feeValue,
+ ),
+ )
+ }
+
fun getSendingStateUpdate(isSending: Boolean): SendUiState {
val state = currentStateProvider()
return state.copy(
sendState = state.sendState?.copy(
isSending = isSending,
- isPrimaryButtonEnabled = isPrimaryButtonEnabled(state, state.sendState.notifications),
+ isPrimaryButtonEnabled = isPrimaryButtonEnabled(
+ state = state,
+ isSending = isSending,
+ notifications = state.sendState.notifications,
+ ),
),
)
}
@@ -308,7 +333,11 @@ internal class SendStateFactory(
val sendState = state.sendState ?: return state
return state.copy(
sendState = sendState.copy(
- isPrimaryButtonEnabled = isPrimaryButtonEnabled(state, notifications),
+ isPrimaryButtonEnabled = isPrimaryButtonEnabled(
+ state = state,
+ isSending = sendState.isSending,
+ notifications = notifications,
+ ),
notifications = notifications,
showTapHelp = sendState.showTapHelp && notifications.isEmpty(),
),
@@ -323,11 +352,14 @@ internal class SendStateFactory(
)
}
- private fun isPrimaryButtonEnabled(state: SendUiState, notifications: ImmutableList): Boolean {
- val sendState = state.sendState ?: return false
+ private fun isPrimaryButtonEnabled(
+ state: SendUiState,
+ isSending: Boolean,
+ notifications: ImmutableList,
+ ): Boolean {
val feeState = state.getFeeState(stateRouterProvider().isEditState) ?: return false
val hasErrorNotifications = notifications.any { it is SendNotification.Error }
- return !hasErrorNotifications && !sendState.isSending && feeState.feeSelectorState is FeeSelectorState.Content
+ return !hasErrorNotifications && !isSending && feeState.feeSelectorState is FeeSelectorState.Content
}
//endregion
}
\ No newline at end of file
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt
index 23453c4b4d..c7aa7ddff0 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt
@@ -32,6 +32,7 @@ internal data class SendUiState(
val editRecipientState: SendStates.RecipientState? = null,
val editFeeState: SendStates.FeeState? = null,
val isBalanceHidden: Boolean,
+ val isSubtracted: Boolean,
val event: StateEvent,
) {
@@ -97,6 +98,7 @@ internal sealed class SendStates {
val walletBalance: TextReference,
val tokenIconState: TokenIconState,
val segmentedButtonConfig: PersistentList,
+ val selectedButton: Int,
val isSegmentedButtonsEnabled: Boolean,
val amountTextField: SendTextField.AmountField,
val appCurrencyCode: String,
@@ -139,6 +141,7 @@ internal sealed class SendStates {
val transactionDate: Long,
val txUrl: String,
val ignoreAmountReduce: Boolean,
+ val reduceAmountBy: BigDecimal?,
val isFromConfirmation: Boolean,
val showTapHelp: Boolean,
val notifications: ImmutableList,
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/StateRouter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/StateRouter.kt
index 5f2201052b..e09467fa9c 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/StateRouter.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/StateRouter.kt
@@ -34,7 +34,7 @@ internal class StateRouter(
when {
isSuccess -> popBackStack()
isEditingDisabled -> when (type) {
- SendUiStateType.Send -> showFee()
+ SendUiStateType.EditFee -> showSend()
else -> popBackStack()
}
else -> when (type) {
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 e91f30356f..6ff84cf35d 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
@@ -6,6 +6,7 @@ import com.tangem.features.send.impl.presentation.state.StateRouter
import com.tangem.features.send.impl.presentation.state.fields.SendAmountFieldChangeConverter
import com.tangem.features.send.impl.presentation.state.fields.SendAmountFieldMaxAmountConverter
import com.tangem.utils.Provider
+import java.math.BigDecimal
/**
* Factory to produce amount state for [SendUiState]
@@ -44,9 +45,18 @@ internal class AmountStateFactory(
currentStateProvider = currentStateProvider,
)
}
+ private val amountReducedConverter by lazy {
+ SendAmountReducedConverter(
+ stateRouterProvider = stateRouterProvider,
+ currentStateProvider = currentStateProvider,
+ cryptoCurrencyStatusProvider = cryptoCurrencyStatusProvider,
+ )
+ }
fun getOnAmountValueChange(value: String) = amountFieldChangeConverter.convert(value)
+ fun getOnAmountReducedState(reduceAmountBy: BigDecimal) = amountReducedConverter.convert(reduceAmountBy)
+
fun getOnMaxAmountClick(): SendUiState {
return amountFieldMaxAmountConverter.convert(Unit)
}
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/AmountUtils.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/AmountUtils.kt
new file mode 100644
index 0000000000..3921429828
--- /dev/null
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/AmountUtils.kt
@@ -0,0 +1,59 @@
+package com.tangem.features.send.impl.presentation.state.amount
+
+import androidx.compose.ui.text.input.ImeAction
+import com.tangem.common.extensions.isZero
+import com.tangem.core.ui.utils.parseBigDecimal
+import com.tangem.core.ui.utils.parseToBigDecimal
+import com.tangem.domain.tokens.model.CryptoCurrencyStatus
+import com.tangem.features.send.impl.presentation.state.fields.SendTextField
+import java.math.BigDecimal
+import java.math.RoundingMode
+
+internal fun String.getCryptoValue(fiatRate: BigDecimal?, isFiatValue: Boolean, decimals: Int): String {
+ return if (isFiatValue && fiatRate != null) {
+ parseToBigDecimal(decimals).divide(fiatRate, decimals, RoundingMode.DOWN)
+ .parseBigDecimal(decimals)
+ } else {
+ this
+ }
+}
+
+internal fun String.getFiatValue(
+ fiatRate: BigDecimal?,
+ isFiatValue: Boolean,
+ decimals: Int,
+): Pair {
+ return if (fiatRate != null) {
+ val fiatValue = if (!isFiatValue) {
+ parseToBigDecimal(decimals).multiply(fiatRate).parseBigDecimal(decimals)
+ } else {
+ this
+ }
+ val decimalFiatValue = fiatValue.parseToBigDecimal(decimals)
+ fiatValue to decimalFiatValue
+ } else {
+ "" to null
+ }
+}
+
+internal fun String.checkExceedBalance(
+ cryptoCurrencyStatus: CryptoCurrencyStatus,
+ amountTextField: SendTextField.AmountField,
+): Boolean {
+ val currencyCryptoAmount = cryptoCurrencyStatus.value.amount ?: BigDecimal.ZERO
+ val currencyFiatAmount = cryptoCurrencyStatus.value.fiatAmount ?: BigDecimal.ZERO
+ val fiatDecimal = parseToBigDecimal(amountTextField.fiatAmount.decimals)
+ val cryptoDecimal = parseToBigDecimal(amountTextField.cryptoAmount.decimals)
+ return if (amountTextField.isFiatValue) {
+ fiatDecimal > currencyFiatAmount
+ } else {
+ cryptoDecimal > currencyCryptoAmount
+ }
+}
+
+internal fun getKeyboardAction(isExceedBalance: Boolean, decimalCryptoValue: BigDecimal) =
+ if (!isExceedBalance && !decimalCryptoValue.isZero()) {
+ ImeAction.Done
+ } else {
+ ImeAction.None
+ }
\ 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 4817557ac6..fa31b63ea0 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
@@ -1,5 +1,8 @@
package com.tangem.features.send.impl.presentation.state.amount
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.KeyboardType
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.features.send.impl.presentation.state.SendUiState
import com.tangem.features.send.impl.presentation.state.StateRouter
@@ -20,6 +23,7 @@ internal class SendAmountCurrencyConverter(
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
val isValidFiatRate = cryptoCurrencyStatus.value.fiatRate.isNullOrZero()
+ val isDoneActionEnabled = amountState.isPrimaryButtonEnabled
return if (amountTextField.isFiatValue == value && !isValidFiatRate) {
state
} else {
@@ -29,7 +33,12 @@ internal class SendAmountCurrencyConverter(
amountTextField = amountTextField.copy(
isFiatValue = value,
isValuePasted = true,
+ keyboardOptions = KeyboardOptions(
+ imeAction = if (isDoneActionEnabled) ImeAction.Done else ImeAction.None,
+ keyboardType = KeyboardType.Number,
+ ),
),
+ selectedButton = amountState.segmentedButtonConfig.indexOfFirst { it.isFiat == value },
),
)
}
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/SendAmountReducedConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/SendAmountReducedConverter.kt
new file mode 100644
index 0000000000..d624608b14
--- /dev/null
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/SendAmountReducedConverter.kt
@@ -0,0 +1,62 @@
+package com.tangem.features.send.impl.presentation.state.amount
+
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.ui.text.input.KeyboardType
+import com.tangem.common.extensions.isZero
+import com.tangem.core.ui.utils.parseBigDecimal
+import com.tangem.domain.tokens.model.CryptoCurrencyStatus
+import com.tangem.features.send.impl.presentation.state.SendUiState
+import com.tangem.features.send.impl.presentation.state.StateRouter
+import com.tangem.utils.Provider
+import com.tangem.utils.converter.Converter
+import com.tangem.utils.isNullOrZero
+import java.math.BigDecimal
+
+internal class SendAmountReducedConverter(
+ private val stateRouterProvider: Provider,
+ private val currentStateProvider: Provider,
+ private val cryptoCurrencyStatusProvider: Provider,
+) : Converter {
+ override fun convert(value: BigDecimal): SendUiState {
+ val state = currentStateProvider()
+ val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
+ val isEditState = stateRouterProvider().isEditState
+ val amountState = state.getAmountState(isEditState) ?: return state
+ val amountTextField = amountState.amountTextField
+ val cryptoDecimals = amountTextField.cryptoAmount.decimals
+ val fiatDecimals = amountTextField.fiatAmount.decimals
+ val amountValue = amountState.amountTextField.cryptoAmount.value ?: return state
+
+ val decimalCryptoValue = amountValue.minus(value)
+ val cryptoValue = decimalCryptoValue.parseBigDecimal(cryptoDecimals)
+ val (fiatValue, decimalFiatValue) = cryptoValue.getFiatValue(
+ fiatRate = cryptoCurrencyStatus.value.fiatRate,
+ isFiatValue = false,
+ decimals = fiatDecimals,
+ )
+
+ val checkValue = if (amountTextField.isFiatValue) fiatValue else cryptoValue
+ val isExceedBalance = checkValue.checkExceedBalance(cryptoCurrencyStatus, amountTextField)
+ val isZero = if (amountTextField.isFiatValue) decimalFiatValue.isNullOrZero() else decimalCryptoValue.isZero()
+ return state.copyWrapped(
+ isEditState = isEditState,
+ sendState = state.sendState?.copy(
+ reduceAmountBy = value,
+ ),
+ amountState = amountState.copy(
+ isPrimaryButtonEnabled = !isExceedBalance && !isZero,
+ amountTextField = amountTextField.copy(
+ value = cryptoValue,
+ fiatValue = fiatValue,
+ isError = isExceedBalance,
+ cryptoAmount = amountTextField.cryptoAmount.copy(value = decimalCryptoValue),
+ fiatAmount = amountTextField.fiatAmount.copy(value = decimalFiatValue),
+ keyboardOptions = KeyboardOptions(
+ imeAction = getKeyboardAction(isExceedBalance, decimalCryptoValue),
+ keyboardType = KeyboardType.Number,
+ ),
+ ),
+ ),
+ )
+ }
+}
\ No newline at end of file
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/SendAmountStateConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/SendAmountStateConverter.kt
index 7e3199d1ff..6afdc1ada8 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/SendAmountStateConverter.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/SendAmountStateConverter.kt
@@ -57,6 +57,7 @@ internal class SendAmountStateConverter(
),
),
isSegmentedButtonsEnabled = !noFeeRate,
+ selectedButton = 0,
)
}
}
\ No newline at end of file
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendConfirmStateConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendConfirmStateConverter.kt
index 7935da04c8..254a979807 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendConfirmStateConverter.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendConfirmStateConverter.kt
@@ -16,6 +16,7 @@ internal class SendConfirmStateConverter(
transactionDate = 0L,
txUrl = "",
ignoreAmountReduce = false,
+ reduceAmountBy = null,
isFromConfirmation = true,
showTapHelp = isTapHelpPreviewEnabledProvider(),
notifications = persistentListOf(),
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt
index cd1e28de72..c98336636c 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt
@@ -20,7 +20,6 @@ import com.tangem.features.send.impl.presentation.analytics.SendAnalyticEvents
import com.tangem.features.send.impl.presentation.state.*
import com.tangem.features.send.impl.presentation.state.fee.*
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
-import com.tangem.lib.crypto.BlockchainUtils.isDogecoin
import com.tangem.lib.crypto.BlockchainUtils.isTezos
import com.tangem.utils.Provider
import kotlinx.collections.immutable.ImmutableList
@@ -74,7 +73,6 @@ internal class SendNotificationFactory(
addFeeUnreachableNotification(feeState.feeSelectorState)
addExceedBalanceNotification(feeValue, sendingAmount)
addExceedsBalanceNotification(feeState.fee)
- addMinimumAmountErrorNotification(feeValue, sendingAmount)
addDustWarningNotification(feeValue, sendingAmount)
addTransactionLimitErrorNotification(feeValue, sendingAmount)
// warnings
@@ -95,6 +93,7 @@ internal class SendNotificationFactory(
return state.copy(
sendState = sendState.copy(
ignoreAmountReduce = isIgnored,
+ reduceAmountBy = if (isIgnored) null else sendState.reduceAmountBy,
notifications = updatedNotifications.toImmutableList(),
),
)
@@ -227,8 +226,7 @@ internal class SendNotificationFactory(
SendNotification.Warning.HighFeeError(
amount = threshold.toPlainString(),
onConfirmClick = {
- val reduceTo = sendAmount.minus(threshold)
- clickIntents.onAmountReduceClick(reduceTo, SendNotification.Warning.HighFeeError::class.java)
+ clickIntents.onAmountReduceClick(threshold, SendNotification.Warning.HighFeeError::class.java)
},
onCloseClick = {
clickIntents.onNotificationCancel(SendNotification.Warning.HighFeeError::class.java)
@@ -238,21 +236,6 @@ internal class SendNotificationFactory(
}
}
- // todo remove in [REDACTED_TASK_KEY]
- private fun MutableList.addMinimumAmountErrorNotification(
- feeAmount: BigDecimal,
- receivedAmount: BigDecimal,
- ) {
- val coinCryptoCurrencyStatus = coinCryptoCurrencyStatusProvider()
- val minimum = BigDecimal(DOGECOIN_MINIMUM)
-
- val isDogecoin = isDogecoin(coinCryptoCurrencyStatus.currency.network.id.value)
- val isExceedDustLimit = checkDustLimits(feeAmount, receivedAmount, minimum)
- if (isDogecoin && isExceedDustLimit) {
- add(SendNotification.Error.MinimumAmountError(DOGECOIN_MINIMUM))
- }
- }
-
private suspend fun MutableList.addDustWarningNotification(
feeAmount: BigDecimal,
receivedAmount: BigDecimal,
@@ -380,8 +363,4 @@ internal class SendNotificationFactory(
val isChangeLowerThanDust = change < dustValue && change > BigDecimal.ZERO
return receivedAmount < dustValue || isChangeLowerThanDust
}
-
- companion object {
- private const val DOGECOIN_MINIMUM = "0.01"
- }
}
\ No newline at end of file
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeCalculation.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeCalculation.kt
index 43e7da9e42..b06d42a23d 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeCalculation.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeCalculation.kt
@@ -1,12 +1,10 @@
package com.tangem.features.send.impl.presentation.state.fee
-import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.transaction.TransactionFee
+import com.tangem.common.extensions.isZero
import com.tangem.core.ui.utils.parseBigDecimal
import com.tangem.core.ui.utils.parseToBigDecimal
-import com.tangem.domain.common.extensions.minimalAmount
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
-import com.tangem.lib.crypto.BlockchainUtils
import java.math.BigDecimal
import java.math.RoundingMode
@@ -18,6 +16,7 @@ internal fun checkAndCalculateSubtractedAmount(
cryptoCurrencyStatus: CryptoCurrencyStatus,
amountValue: BigDecimal,
feeValue: BigDecimal,
+ reduceAmountBy: BigDecimal?,
): BigDecimal {
val balance = cryptoCurrencyStatus.value.amount ?: return amountValue
val isFeeCoverage = checkFeeCoverage(
@@ -26,12 +25,17 @@ internal fun checkAndCalculateSubtractedAmount(
amountValue = amountValue,
feeValue = feeValue,
)
- return calculateSubtractedAmount(
+ val subtractedAmount = calculateSubtractedAmount(
isFeeCoverage = isFeeCoverage,
cryptoCurrencyStatus = cryptoCurrencyStatus,
amountValue = amountValue,
feeValue = feeValue,
)
+ return if (reduceAmountBy != null) {
+ subtractedAmount.minus(reduceAmountBy)
+ } else {
+ subtractedAmount
+ }
}
/**
@@ -44,7 +48,7 @@ internal fun checkFeeCoverage(
feeValue: BigDecimal,
): Boolean {
if (!isSubtractAvailable) return false
- return balance < amountValue + feeValue && balance > feeValue
+ return balance < amountValue + feeValue && balance > feeValue && balance >= amountValue
}
/**
@@ -58,12 +62,7 @@ internal fun calculateSubtractedAmount(
): BigDecimal {
val balance = cryptoCurrencyStatus.value.amount ?: return amountValue
return if (isFeeCoverage) {
- var subtractedValue = minOf(amountValue, balance.minus(feeValue))
- if (BlockchainUtils.isTezos(cryptoCurrencyStatus.currency.network.id.value)) {
- val threshold = Blockchain.Tezos.minimalAmount()
- subtractedValue = -threshold
- }
- subtractedValue
+ minOf(amountValue, balance.minus(feeValue))
} else {
amountValue
}
@@ -95,5 +94,12 @@ internal fun checkIfFeeTooHigh(feeSelectorState: FeeSelectorState.Content, onSho
return isShow
}
+/**
+ * Checks if fee exceeds fee paid currency balance
+ */
+fun checkExceedBalance(feeBalance: BigDecimal?, feeAmount: BigDecimal?): Boolean {
+ return feeAmount == null || feeBalance == null || feeAmount.isZero() || feeAmount > feeBalance
+}
+
private val FEE_MAX_DIFF = BigDecimal("5")
private const val ZERO_DECIMALS = 0
\ No newline at end of file
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeConverter.kt
index 1fa99ee291..5109aa17b9 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeConverter.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeConverter.kt
@@ -5,6 +5,7 @@ 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.send.impl.presentation.state.StateRouter
import com.tangem.features.send.impl.presentation.state.fee.custom.BitcoinCustomFeeConverter
import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCustomFeeConverter
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
@@ -13,6 +14,7 @@ import com.tangem.utils.converter.Converter
internal class FeeConverter(
private val clickIntents: SendClickIntents,
+ private val stateRouterProvider: Provider,
private val appCurrencyProvider: Provider,
private val feeCryptoCurrencyStatusProvider: Provider,
) : Converter {
@@ -20,6 +22,7 @@ internal class FeeConverter(
private val ethereumCustomFeeConverter by lazy(LazyThreadSafetyMode.NONE) {
EthereumCustomFeeConverter(
clickIntents = clickIntents,
+ stateRouterProvider = stateRouterProvider,
appCurrencyProvider = appCurrencyProvider,
feeCryptoCurrencyStatusProvider = feeCryptoCurrencyStatusProvider,
)
@@ -28,6 +31,7 @@ internal class FeeConverter(
private val bitcoinCustomFeeConverter by lazy(LazyThreadSafetyMode.NONE) {
BitcoinCustomFeeConverter(
clickIntents = clickIntents,
+ stateRouterProvider = stateRouterProvider,
appCurrencyProvider = appCurrencyProvider,
feeCryptoCurrencyStatusProvider = feeCryptoCurrencyStatusProvider,
)
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeStateFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeStateFactory.kt
index e5683fcdc7..e933b89477 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeStateFactory.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeStateFactory.kt
@@ -7,7 +7,10 @@ import com.tangem.core.ui.utils.parseToBigDecimal
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.transaction.usecase.IsFeeApproximateUseCase
-import com.tangem.features.send.impl.presentation.state.*
+import com.tangem.features.send.impl.presentation.state.SendNotification
+import com.tangem.features.send.impl.presentation.state.SendStates
+import com.tangem.features.send.impl.presentation.state.SendUiState
+import com.tangem.features.send.impl.presentation.state.StateRouter
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
import com.tangem.utils.Provider
import kotlinx.collections.immutable.ImmutableList
@@ -27,6 +30,7 @@ internal class FeeStateFactory(
private val customFeeFieldConverter by lazy(LazyThreadSafetyMode.NONE) {
SendFeeCustomFieldConverter(
clickIntents = clickIntents,
+ stateRouterProvider = stateRouterProvider,
appCurrencyProvider = appCurrencyProvider,
feeCryptoCurrencyStatusProvider = feeCryptoCurrencyStatusProvider,
)
@@ -35,6 +39,7 @@ internal class FeeStateFactory(
val feeConverter by lazy(LazyThreadSafetyMode.NONE) {
FeeConverter(
clickIntents = clickIntents,
+ stateRouterProvider = stateRouterProvider,
appCurrencyProvider = appCurrencyProvider,
feeCryptoCurrencyStatusProvider = feeCryptoCurrencyStatusProvider,
)
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeCustomFieldConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeCustomFieldConverter.kt
index c9534ea97f..5fd2a4060d 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeCustomFieldConverter.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeCustomFieldConverter.kt
@@ -3,6 +3,7 @@ package com.tangem.features.send.impl.presentation.state.fee
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
+import com.tangem.features.send.impl.presentation.state.StateRouter
import com.tangem.features.send.impl.presentation.state.fee.custom.BitcoinCustomFeeConverter
import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCustomFeeConverter
import com.tangem.features.send.impl.presentation.state.fields.SendTextField
@@ -14,6 +15,7 @@ import kotlinx.collections.immutable.persistentListOf
internal class SendFeeCustomFieldConverter(
private val clickIntents: SendClickIntents,
+ private val stateRouterProvider: Provider,
private val appCurrencyProvider: Provider,
private val feeCryptoCurrencyStatusProvider: Provider,
) : Converter> {
@@ -21,6 +23,7 @@ internal class SendFeeCustomFieldConverter(
private val ethereumCustomFeeConverter by lazy(LazyThreadSafetyMode.NONE) {
EthereumCustomFeeConverter(
clickIntents = clickIntents,
+ stateRouterProvider = stateRouterProvider,
appCurrencyProvider = appCurrencyProvider,
feeCryptoCurrencyStatusProvider = feeCryptoCurrencyStatusProvider,
)
@@ -29,6 +32,7 @@ internal class SendFeeCustomFieldConverter(
private val bitcoinCustomFeeConverter by lazy(LazyThreadSafetyMode.NONE) {
BitcoinCustomFeeConverter(
clickIntents = clickIntents,
+ stateRouterProvider = stateRouterProvider,
appCurrencyProvider = appCurrencyProvider,
feeCryptoCurrencyStatusProvider = feeCryptoCurrencyStatusProvider,
)
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/BitcoinCustomFeeConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/BitcoinCustomFeeConverter.kt
index 8226a67504..a2a13e987a 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/BitcoinCustomFeeConverter.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/BitcoinCustomFeeConverter.kt
@@ -5,17 +5,16 @@ import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import com.tangem.blockchain.common.transaction.Fee
-import com.tangem.common.extensions.isZero
-import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
-import com.tangem.core.ui.extensions.stringReference
-import com.tangem.core.ui.utils.BigDecimalFormatter
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.send.impl.R
+import com.tangem.features.send.impl.presentation.state.StateRouter
+import com.tangem.features.send.impl.presentation.state.fee.checkExceedBalance
import com.tangem.features.send.impl.presentation.state.fields.SendTextField
+import com.tangem.features.send.impl.presentation.utils.getFiatReference
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
import com.tangem.lib.crypto.BlockchainUtils.isBitcoin
import com.tangem.utils.Provider
@@ -27,12 +26,14 @@ import java.math.RoundingMode
internal class BitcoinCustomFeeConverter(
private val clickIntents: SendClickIntents,
+ private val stateRouterProvider: Provider,
private val appCurrencyProvider: Provider,
private val feeCryptoCurrencyStatusProvider: Provider,
) : CustomFeeConverter {
override fun convert(value: Fee.Bitcoin): ImmutableList {
val feeValue = value.amount.value
+ val feeCurrency = feeCryptoCurrencyStatusProvider()?.value
val network = feeCryptoCurrencyStatusProvider()?.currency?.network?.id?.value
return if (network != null && isBitcoin(network)) {
persistentListOf(
@@ -47,7 +48,11 @@ internal class BitcoinCustomFeeConverter(
),
title = resourceReference(R.string.send_max_fee),
footer = resourceReference(R.string.send_max_fee_footer),
- label = getFeeFormatted(feeValue),
+ label = getFiatReference(
+ rate = feeCurrency?.fiatRate,
+ value = feeValue,
+ appCurrency = appCurrencyProvider(),
+ ),
keyboardActions = KeyboardActions(),
isReadonly = true,
),
@@ -63,10 +68,20 @@ internal class BitcoinCustomFeeConverter(
footer = resourceReference(R.string.send_satoshi_per_byte_text),
onValueChange = { clickIntents.onCustomFeeValueChange(FEE_SATOSHI_INDEX, it) },
keyboardOptions = KeyboardOptions(
- imeAction = if (checkExceedBalance(feeValue)) ImeAction.None else ImeAction.Done,
+ imeAction = if (checkExceedBalance(
+ feeBalance = feeCurrency?.amount,
+ feeAmount = feeValue,
+ )
+ ) {
+ ImeAction.None
+ } else {
+ ImeAction.Done
+ },
keyboardType = KeyboardType.Number,
),
- keyboardActions = KeyboardActions(),
+ keyboardActions = KeyboardActions(
+ onDone = { clickIntents.onNextClick(stateRouterProvider().isEditState) },
+ ),
),
)
} else {
@@ -100,7 +115,11 @@ internal class BitcoinCustomFeeConverter(
FEE_AMOUNT_INDEX,
this[FEE_AMOUNT_INDEX].copy(
value = newFeeAmount.parseBigDecimal(this[FEE_AMOUNT_INDEX].decimals),
- label = getFeeFormatted(newFeeAmount),
+ label = getFiatReference(
+ rate = feeCryptoCurrencyStatusProvider()?.value?.fiatRate,
+ value = newFeeAmount,
+ appCurrency = appCurrencyProvider(),
+ ),
),
)
set(index, this[index].copy(value = value))
@@ -108,26 +127,6 @@ internal class BitcoinCustomFeeConverter(
}.toImmutableList()
}
- private fun getFeeFormatted(fee: BigDecimal?): TextReference {
- val appCurrency = appCurrencyProvider()
- val rate = feeCryptoCurrencyStatusProvider()?.value?.fiatRate
- val fiatFee = rate?.let { fee?.multiply(it) }
- return stringReference(
- BigDecimalFormatter.formatFiatAmount(
- fiatAmount = fiatFee,
- fiatCurrencyCode = appCurrency.code,
- fiatCurrencySymbol = appCurrency.symbol,
- ),
- )
- }
-
- private fun checkExceedBalance(feeAmount: BigDecimal?): Boolean {
- val cryptoCurrencyStatus = feeCryptoCurrencyStatusProvider()
- val currencyCryptoAmount = cryptoCurrencyStatus?.value?.amount ?: BigDecimal.ZERO
-
- return feeAmount == null || feeAmount.isZero() || feeAmount > currencyCryptoAmount
- }
-
private fun toSatoshiPerByte(amount: BigDecimal?, decimals: Int, txSize: BigDecimal): BigDecimal? {
val newFeeAmount = amount?.movePointRight(decimals)
return newFeeAmount?.divide(
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumCustomFeeConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumCustomFeeConverter.kt
index 4851533b49..6bed843250 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumCustomFeeConverter.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumCustomFeeConverter.kt
@@ -5,33 +5,33 @@ import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import com.tangem.blockchain.common.transaction.Fee
-import com.tangem.common.extensions.isZero
-import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
-import com.tangem.core.ui.extensions.stringReference
-import com.tangem.core.ui.utils.BigDecimalFormatter
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.send.impl.R
+import com.tangem.features.send.impl.presentation.state.StateRouter
+import com.tangem.features.send.impl.presentation.state.fee.checkExceedBalance
import com.tangem.features.send.impl.presentation.state.fields.SendTextField
+import com.tangem.features.send.impl.presentation.utils.getFiatReference
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
import com.tangem.utils.Provider
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
-import java.math.BigDecimal
import java.math.RoundingMode
internal class EthereumCustomFeeConverter(
private val clickIntents: SendClickIntents,
+ private val stateRouterProvider: Provider,
private val appCurrencyProvider: Provider,
private val feeCryptoCurrencyStatusProvider: Provider,
) : CustomFeeConverter {
override fun convert(value: Fee.Ethereum): ImmutableList {
val feeValue = value.amount.value
+ val feeCurrency = feeCryptoCurrencyStatusProvider()?.value
return persistentListOf(
SendTextField.CustomFee(
value = feeValue?.parseBigDecimal(value.amount.decimals).orEmpty(),
@@ -44,7 +44,11 @@ internal class EthereumCustomFeeConverter(
),
title = resourceReference(R.string.send_max_fee),
footer = resourceReference(R.string.send_max_fee_footer),
- label = getFeeFormatted(feeValue),
+ label = getFiatReference(
+ rate = feeCurrency?.fiatRate,
+ value = feeValue,
+ appCurrency = appCurrencyProvider(),
+ ),
keyboardActions = KeyboardActions(),
),
SendTextField.CustomFee(
@@ -68,10 +72,21 @@ internal class EthereumCustomFeeConverter(
footer = resourceReference(R.string.send_gas_limit_footer),
onValueChange = { clickIntents.onCustomFeeValueChange(GAS_LIMIT, it) },
keyboardOptions = KeyboardOptions(
- imeAction = if (checkExceedBalance(feeValue)) ImeAction.None else ImeAction.Done,
+ imeAction = if (
+ checkExceedBalance(
+ feeBalance = feeCurrency?.amount,
+ feeAmount = feeValue,
+ )
+ ) {
+ ImeAction.None
+ } else {
+ ImeAction.Done
+ },
keyboardType = KeyboardType.Number,
),
- keyboardActions = KeyboardActions(onDone = { clickIntents.onNextClick() }),
+ keyboardActions = KeyboardActions(
+ onDone = { clickIntents.onNextClick(stateRouterProvider().isEditState) },
+ ),
),
)
}
@@ -102,26 +117,6 @@ internal class EthereumCustomFeeConverter(
}.toImmutableList()
}
- private fun getFeeFormatted(fee: BigDecimal?): TextReference {
- val appCurrency = appCurrencyProvider()
- val rate = feeCryptoCurrencyStatusProvider()?.value?.fiatRate
- val fiatFee = rate?.let { fee?.multiply(it) }
- return stringReference(
- BigDecimalFormatter.formatFiatAmount(
- fiatAmount = fiatFee,
- fiatCurrencyCode = appCurrency.code,
- fiatCurrencySymbol = appCurrency.symbol,
- ),
- )
- }
-
- private fun checkExceedBalance(feeAmount: BigDecimal?): Boolean {
- val cryptoCurrencyStatus = feeCryptoCurrencyStatusProvider()
- val currencyCryptoAmount = cryptoCurrencyStatus?.value?.amount ?: BigDecimal.ZERO
-
- return feeAmount == null || feeAmount.isZero() || feeAmount > currencyCryptoAmount
- }
-
private fun MutableList.setEmpty(index: Int) {
set(index, this[index].copy(value = ""))
}
@@ -140,7 +135,11 @@ internal class EthereumCustomFeeConverter(
index,
this[index].copy(
value = value,
- label = getFeeFormatted(newFeeAmountDecimal),
+ label = getFiatReference(
+ rate = feeCryptoCurrencyStatusProvider()?.value?.fiatRate,
+ value = newFeeAmountDecimal,
+ appCurrency = appCurrencyProvider(),
+ ),
),
)
}
@@ -159,7 +158,11 @@ internal class EthereumCustomFeeConverter(
FEE_AMOUNT,
this[FEE_AMOUNT].copy(
value = newFeeAmount.parseBigDecimal(this[FEE_AMOUNT].decimals),
- label = getFeeFormatted(newFeeAmount),
+ label = getFiatReference(
+ rate = feeCryptoCurrencyStatusProvider()?.value?.fiatRate,
+ value = newFeeAmount,
+ appCurrency = appCurrencyProvider(),
+ ),
),
)
set(index, this[index].copy(value = value))
@@ -179,15 +182,23 @@ internal class EthereumCustomFeeConverter(
FEE_AMOUNT,
this[FEE_AMOUNT].copy(
value = newFeeAmount.parseBigDecimal(this[FEE_AMOUNT].decimals),
- label = getFeeFormatted(newFeeAmount),
+ label = getFiatReference(
+ rate = feeCryptoCurrencyStatusProvider()?.value?.fiatRate,
+ value = newFeeAmount,
+ appCurrency = appCurrencyProvider(),
+ ),
),
)
+ val isNotExceedBalance = checkExceedBalance(
+ feeBalance = feeCryptoCurrencyStatusProvider()?.value?.amount,
+ feeAmount = newFeeAmount,
+ )
set(
index,
this[index].copy(
value = value,
keyboardOptions = KeyboardOptions(
- imeAction = if (!checkExceedBalance(newFeeAmount)) ImeAction.None else ImeAction.Done,
+ imeAction = if (!isNotExceedBalance) ImeAction.None else ImeAction.Done,
keyboardType = KeyboardType.Number,
),
),
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldChangeConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldChangeConverter.kt
index 04c375714e..3958e3b64a 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldChangeConverter.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldChangeConverter.kt
@@ -1,18 +1,20 @@
package com.tangem.features.send.impl.presentation.state.fields
import androidx.compose.foundation.text.KeyboardOptions
-import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import com.tangem.common.extensions.isZero
-import com.tangem.core.ui.utils.parseBigDecimal
import com.tangem.core.ui.utils.parseToBigDecimal
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.features.send.impl.presentation.state.SendUiState
import com.tangem.features.send.impl.presentation.state.StateRouter
+import com.tangem.features.send.impl.presentation.state.amount.checkExceedBalance
+import com.tangem.features.send.impl.presentation.state.amount.getCryptoValue
+import com.tangem.features.send.impl.presentation.state.amount.getFiatValue
+import com.tangem.features.send.impl.presentation.state.amount.getKeyboardAction
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
+import com.tangem.utils.isNullOrZero
import java.math.BigDecimal
-import java.math.RoundingMode
internal class SendAmountFieldChangeConverter(
private val stateRouterProvider: Provider,
@@ -21,6 +23,7 @@ internal class SendAmountFieldChangeConverter(
) : Converter {
override fun convert(value: String): SendUiState {
val state = currentStateProvider()
+ val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
val isEditState = stateRouterProvider().isEditState
val amountState = state.getAmountState(isEditState) ?: return state
val amountTextField = amountState.amountTextField
@@ -30,14 +33,21 @@ internal class SendAmountFieldChangeConverter(
val fiatDecimals = amountTextField.fiatAmount.decimals
val trimmedValue = value.trim()
- val cryptoValue = trimmedValue.getCryptoValue(amountTextField.isFiatValue, cryptoDecimals)
- val fiatValue = trimmedValue.getFiatValue(amountTextField.isFiatValue, fiatDecimals)
+ val cryptoValue = trimmedValue.getCryptoValue(
+ fiatRate = cryptoCurrencyStatus.value.fiatRate,
+ isFiatValue = amountTextField.isFiatValue,
+ decimals = cryptoDecimals,
+ )
val decimalCryptoValue = cryptoValue.parseToBigDecimal(cryptoDecimals)
- val decimalFiatValue = fiatValue.parseToBigDecimal(fiatDecimals)
+ val (fiatValue, decimalFiatValue) = trimmedValue.getFiatValue(
+ fiatRate = cryptoCurrencyStatus.value.fiatRate,
+ isFiatValue = amountTextField.isFiatValue,
+ decimals = fiatDecimals,
+ )
val checkValue = if (amountTextField.isFiatValue) fiatValue else cryptoValue
- val isExceedBalance = checkValue.checkExceedBalance(amountTextField)
- val isZero = if (amountTextField.isFiatValue) decimalFiatValue.isZero() else decimalCryptoValue.isZero()
+ val isExceedBalance = checkValue.checkExceedBalance(cryptoCurrencyStatus, amountTextField)
+ val isZero = if (amountTextField.isFiatValue) decimalFiatValue.isNullOrZero() else decimalCryptoValue.isZero()
return state.copyWrapped(
isEditState = isEditState,
amountState = amountState.copy(
@@ -57,27 +67,6 @@ internal class SendAmountFieldChangeConverter(
)
}
- private fun String.getCryptoValue(isFiatValue: Boolean, decimals: Int): String {
- val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
- val fiatRate = cryptoCurrencyStatus.value.fiatRate
- return if (isFiatValue && fiatRate != null) {
- parseToBigDecimal(decimals).divide(fiatRate, decimals, RoundingMode.DOWN)
- .parseBigDecimal(decimals)
- } else {
- this
- }
- }
-
- private fun String.getFiatValue(isFiatValue: Boolean, decimals: Int): String {
- val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
- val fiatRate = cryptoCurrencyStatus.value.fiatRate
- return if (!isFiatValue && fiatRate != null) {
- parseToBigDecimal(decimals).multiply(fiatRate).parseBigDecimal(decimals)
- } else {
- this
- }
- }
-
private fun SendUiState.emptyState(): SendUiState {
val isEditState = stateRouterProvider().isEditState
val amountState = getAmountState(isEditState) ?: return this
@@ -96,24 +85,4 @@ internal class SendAmountFieldChangeConverter(
),
)
}
-
- private fun String.checkExceedBalance(amountTextField: SendTextField.AmountField): Boolean {
- val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
- val currencyCryptoAmount = cryptoCurrencyStatus.value.amount ?: BigDecimal.ZERO
- val currencyFiatAmount = cryptoCurrencyStatus.value.fiatAmount ?: BigDecimal.ZERO
- val fiatDecimal = parseToBigDecimal(amountTextField.fiatAmount.decimals)
- val cryptoDecimal = parseToBigDecimal(amountTextField.cryptoAmount.decimals)
- return if (amountTextField.isFiatValue) {
- fiatDecimal > currencyFiatAmount
- } else {
- cryptoDecimal > currencyCryptoAmount
- }
- }
-
- private fun getKeyboardAction(isExceedBalance: Boolean, decimalCryptoValue: BigDecimal) =
- if (!isExceedBalance && !decimalCryptoValue.isZero()) {
- ImeAction.Done
- } else {
- ImeAction.None
- }
}
\ 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 2070b8c633..8bf30c0b57 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
@@ -14,15 +14,18 @@ import com.tangem.domain.tokens.model.AmountType
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.convertToAmount
import com.tangem.features.send.impl.R
+import com.tangem.features.send.impl.presentation.state.StateRouter
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
+import com.tangem.utils.isNullOrZero
import java.math.BigDecimal
private const val FIAT_DECIMALS = 2
internal class SendAmountFieldConverter(
private val clickIntents: SendClickIntents,
+ private val stateRouterProvider: Provider,
private val cryptoCurrencyStatusProvider: Provider,
private val appCurrencyProvider: Provider,
) : Converter {
@@ -32,12 +35,14 @@ internal class SendAmountFieldConverter(
val cryptoDecimal = value.toBigDecimalOrDefault()
val cryptoAmount = cryptoDecimal.convertToAmount(cryptoCurrencyStatus.currency)
val fiatRate = cryptoCurrencyStatus.value.fiatRate
- val (fiatValue, fiatDecimal) = if (value.isEmpty()) {
- "" to BigDecimal.ZERO
- } else {
- val fiatDecimal = fiatRate?.multiply(cryptoDecimal) ?: BigDecimal.ZERO
- val fiatValue = fiatDecimal.parseBigDecimal(FIAT_DECIMALS)
- fiatValue to fiatDecimal
+ val (fiatValue, fiatDecimal) = when {
+ fiatRate.isNullOrZero() -> "" to null
+ value.isEmpty() -> "" to BigDecimal.ZERO
+ else -> {
+ val fiatDecimal = fiatRate?.multiply(cryptoDecimal)
+ val fiatValue = fiatDecimal?.parseBigDecimal(FIAT_DECIMALS).orEmpty()
+ fiatValue to fiatDecimal
+ }
}
val isDoneActionEnabled = !cryptoDecimal.isZero()
return SendTextField.AmountField(
@@ -48,7 +53,9 @@ internal class SendAmountFieldConverter(
imeAction = if (isDoneActionEnabled) ImeAction.Done else ImeAction.None,
keyboardType = KeyboardType.Number,
),
- keyboardActions = KeyboardActions(onDone = { clickIntents.onNextClick() }),
+ keyboardActions = KeyboardActions(
+ onDone = { clickIntents.onNextClick(stateRouterProvider().isEditState) },
+ ),
isFiatValue = false,
cryptoAmount = cryptoAmount,
fiatAmount = getAppCurrencyAmount(fiatDecimal, appCurrencyProvider()),
@@ -60,7 +67,7 @@ internal class SendAmountFieldConverter(
)
}
- private fun getAppCurrencyAmount(fiatValue: BigDecimal, appCurrency: AppCurrency) = Amount(
+ private fun getAppCurrencyAmount(fiatValue: BigDecimal?, appCurrency: AppCurrency) = Amount(
currencySymbol = appCurrency.symbol,
value = fiatValue,
decimals = FIAT_DECIMALS,
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 d39cd3df01..e1685ad0cf 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
@@ -49,6 +49,7 @@ internal object AmountStatePreviewData {
onValuePastedTriggerDismiss = {},
),
isSegmentedButtonsEnabled = true,
+ selectedButton = 0,
)
val fiatAmountState = amountState.copy(
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 0a113ea474..4f05dd6c30 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
@@ -14,6 +14,8 @@ internal object SendClickIntentsStub : SendClickIntents {
override fun onBackClick() {}
+ override fun onCloseClick() {}
+
override fun onNextClick(isFromEdit: Boolean) {}
override fun onPrevClick() {}
@@ -58,7 +60,7 @@ internal object SendClickIntentsStub : SendClickIntents {
override fun onShareClick() {}
- override fun onAmountReduceClick(reducedAmount: BigDecimal, clazz: Class) {}
+ override fun onAmountReduceClick(reduceAmountBy: BigDecimal, clazz: Class) {}
override fun onNotificationCancel(clazz: Class) {}
}
\ No newline at end of file
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt
index ace8e220f8..b0b37b764d 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt
@@ -165,7 +165,11 @@ private fun SendingText(
val fiatRate = feeState?.rate
val fiatAmount = amountState?.amountTextField?.fiatAmount
val feeFiat = fiatRate?.let { feeState.fee?.amount?.value?.multiply(it) }
- val sendingFiat = feeFiat?.let { fiatAmount?.value?.plus(it) }
+ val sendingFiat = if (uiState.isSubtracted) {
+ fiatAmount?.value
+ } else {
+ feeFiat?.let { fiatAmount?.value?.plus(it) }
+ }
if (feeFiat != null && sendingFiat != null) {
val sendingValue = BigDecimalFormatter.formatFiatAmount(
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendScreen.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendScreen.kt
index b289867885..5c7eba689d 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendScreen.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendScreen.kt
@@ -33,7 +33,7 @@ import kotlinx.coroutines.flow.withIndex
@Composable
internal fun SendScreen(uiState: SendUiState, currentState: SendUiCurrentScreen) {
val snackbarHostState = remember { SnackbarHostState() }
- BackHandler { uiState.clickIntents.onBackClick() }
+ BackHandler(onBack = uiState.clickIntents::onBackClick)
Column(
modifier = Modifier
.fillMaxSize()
@@ -88,17 +88,17 @@ private fun SendAppBar(uiState: SendUiState, currentState: SendUiCurrentScreen)
} else {
null
}
- val (backIcon, backClick) = when (currentState.type) {
+ val backIcon = when (currentState.type) {
SendUiStateType.EditAmount,
SendUiStateType.EditFee,
SendUiStateType.EditRecipient,
- -> R.drawable.ic_back_24 to uiState.clickIntents::onBackClick
- else -> R.drawable.ic_close_24 to uiState.clickIntents::popBackStack
+ -> R.drawable.ic_back_24
+ else -> R.drawable.ic_close_24
}
AppBarWithBackButtonAndIcon(
text = titleRes?.resolveReference(),
subtitle = subtitleRes,
- onBackClick = backClick,
+ onBackClick = uiState.clickIntents::onCloseClick,
onIconClick = uiState.clickIntents::onQrCodeScanClick,
backIconRes = backIcon,
iconRes = iconRes,
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/AmountButtons.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/AmountButtons.kt
index 340f8e20ad..1b6315e1ea 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/AmountButtons.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/AmountButtons.kt
@@ -29,6 +29,7 @@ internal fun LazyListScope.buttons(
segmentedButtonConfig: PersistentList,
clickIntents: SendClickIntents,
isSegmentedButtonsEnabled: Boolean,
+ selectedButton: Int,
) {
item(
key = AMOUNT_BUTTONS_KEY,
@@ -48,6 +49,7 @@ internal fun LazyListScope.buttons(
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
clickIntents.onCurrencyChangeClick(it.isFiat)
},
+ initialSelectedItem = segmentedButtonConfig.getOrNull(selectedButton),
isEnabled = isSegmentedButtonsEnabled,
) {
SendAmountCurrencyButton(
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/SendAmountContent.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/SendAmountContent.kt
index 44b5a0244d..01d23d4edb 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/SendAmountContent.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/SendAmountContent.kt
@@ -36,6 +36,7 @@ internal fun SendAmountContent(
segmentedButtonConfig = amountState.segmentedButtonConfig,
clickIntents = clickIntents,
isSegmentedButtonsEnabled = amountState.isSegmentedButtonsEnabled,
+ selectedButton = amountState.selectedButton,
)
}
}
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelectorItem.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelectorItem.kt
index 0a2a65c93e..c42e7e152d 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelectorItem.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelectorItem.kt
@@ -54,7 +54,7 @@ internal fun SendSpeedSelectorItem(
onSelect = onSelect,
modifier = modifier,
preDot = getCryptoReference(amount, state.isFeeApproximate),
- postDot = getFiatReference(amount, state.rate, state.appCurrency),
+ postDot = getFiatReference(amount?.value, state.rate, state.appCurrency),
ellipsizeOffset = amount?.currencySymbol?.length,
isSelected = content?.selectedFee == feeType,
showDivider = showDivider,
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/AmountBlock.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/AmountBlock.kt
index 85ff055ed6..ab68759908 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/AmountBlock.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/AmountBlock.kt
@@ -31,8 +31,8 @@ internal fun AmountBlock(
val amount = amountState.amountTextField
val cryptoAmount = BigDecimalFormatter.formatWithSymbol(amount.value, amount.cryptoAmount.currencySymbol)
- val fiatAmount = BigDecimalFormatter.formatFiatEditableAmount(
- fiatAmount = amount.fiatValue,
+ val fiatAmount = BigDecimalFormatter.formatFiatAmount(
+ fiatAmount = amount.fiatAmount.value,
fiatCurrencySymbol = amount.fiatAmount.currencySymbol,
fiatCurrencyCode = amountState.appCurrencyCode,
)
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/FeeBlock.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/FeeBlock.kt
index 11423e7c73..30814b802f 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/FeeBlock.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/FeeBlock.kt
@@ -60,7 +60,7 @@ internal fun FeeBlock(feeState: SendStates.FeeState, isSuccess: Boolean, onClick
titleRes = title,
iconRes = icon,
preDot = getCryptoReference(feeAmount, feeState.isFeeApproximate),
- postDot = feeAmount?.let { getFiatReference(it, feeState.rate, feeState.appCurrency) },
+ postDot = getFiatReference(feeAmount?.value, feeState.rate, feeState.appCurrency),
ellipsizeOffset = feeAmount?.currencySymbol?.length,
isSelected = true,
showDivider = false,
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/utils/FormatterUtils.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/utils/FormatterUtils.kt
index 022d0c5711..e21fe8c0c5 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/utils/FormatterUtils.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/utils/FormatterUtils.kt
@@ -22,11 +22,11 @@ internal fun getCryptoReference(amount: Amount?, isFeeApproximate: Boolean): Tex
)
}
-internal fun getFiatReference(amount: Amount?, rate: BigDecimal?, appCurrency: AppCurrency): TextReference? {
- if (amount == null) return null
+internal fun getFiatReference(value: BigDecimal?, rate: BigDecimal?, appCurrency: AppCurrency): TextReference? {
+ if (value == null || rate == null) return null
return stringReference(
BigDecimalFormatter.formatFiatAmount(
- fiatAmount = rate?.let { amount.value?.multiply(it) },
+ fiatAmount = value.multiply(rate),
fiatCurrencyCode = appCurrency.code,
fiatCurrencySymbol = appCurrency.symbol,
),
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 f0715cd50a..61c33cb023 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
@@ -14,6 +14,8 @@ internal interface SendClickIntents {
fun onBackClick()
+ fun onCloseClick()
+
fun onNextClick(isFromEdit: Boolean = false)
fun onPrevClick()
@@ -65,7 +67,7 @@ internal interface SendClickIntents {
fun onShareClick()
- fun onAmountReduceClick(reducedAmount: BigDecimal, clazz: Class)
+ fun onAmountReduceClick(reduceAmountBy: BigDecimal, clazz: Class)
fun onNotificationCancel(clazz: Class)
// endregion
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 1d678b777e..0273e12490 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
@@ -47,7 +47,7 @@ import com.tangem.features.send.impl.navigation.InnerSendRouter
import com.tangem.features.send.impl.presentation.analytics.EnterAddressSource
import com.tangem.features.send.impl.presentation.analytics.SendAnalyticEvents
import com.tangem.features.send.impl.presentation.analytics.SendScreenSource
-import com.tangem.features.send.impl.presentation.analytics.utils.SendOnNextScreenAnalyticSender
+import com.tangem.features.send.impl.presentation.analytics.utils.SendScreenAnalyticSender
import com.tangem.features.send.impl.presentation.domain.AvailableWallet
import com.tangem.features.send.impl.presentation.state.*
import com.tangem.features.send.impl.presentation.state.amount.AmountStateFactory
@@ -174,9 +174,10 @@ internal class SendViewModel @Inject constructor(
getBalanceNotEnoughForFeeWarningUseCase = getBalanceNotEnoughForFeeWarningUseCase,
)
- private val sendOnNextScreenAnalyticSender by lazy(LazyThreadSafetyMode.NONE) {
- SendOnNextScreenAnalyticSender(
+ private val sendScreenAnalyticSender by lazy(LazyThreadSafetyMode.NONE) {
+ SendScreenAnalyticSender(
stateRouterProvider = Provider { stateRouter },
+ currentStateProvider = Provider { uiState },
analyticsEventHandler = analyticsEventHandler,
)
}
@@ -464,7 +465,10 @@ internal class SendViewModel @Inject constructor(
SendUiStateType.Fee,
SendUiStateType.EditFee,
-> loadFee()
- SendUiStateType.Send -> sendIdleTimer = SystemClock.elapsedRealtime()
+ SendUiStateType.Send -> {
+ uiState = stateFactory.getIsAmountSubtractedState(isAmountSubtractAvailable)
+ sendIdleTimer = SystemClock.elapsedRealtime()
+ }
else -> Unit
}
}
@@ -498,10 +502,21 @@ internal class SendViewModel @Inject constructor(
stateRouter.onBackClick(isSuccess = uiState.sendState?.isSuccess == true)
}
+ override fun onCloseClick() {
+ sendScreenAnalyticSender.sendOnClose()
+ when (stateRouter.currentState.value.type) {
+ SendUiStateType.EditAmount,
+ SendUiStateType.EditFee,
+ SendUiStateType.EditRecipient,
+ -> onBackClick()
+ else -> popBackStack()
+ }
+ }
+
override fun onNextClick(isFromEdit: Boolean) {
val currentState = stateRouter.currentState.value
uiState = stateFactory.syncEditStates(isFromEdit = isFromEdit)
- sendOnNextScreenAnalyticSender.send(currentState.type, uiState)
+ sendScreenAnalyticSender.send(currentState.type, uiState)
when (currentState.type) {
SendUiStateType.Fee,
SendUiStateType.EditFee,
@@ -652,7 +667,7 @@ internal class SendViewModel @Inject constructor(
private fun autoNextFromRecipient(type: EnterAddressSource?, isValidAddress: Boolean) {
val isRecent = type == EnterAddressSource.RecentAddress
- if (isRecent && isValidAddress) onNextClick()
+ if (isRecent && isValidAddress) onNextClick(stateRouter.isEditState)
}
// endregion
@@ -687,6 +702,7 @@ internal class SendViewModel @Inject constructor(
val isShowStatus = uiState.feeState?.fee == null
if (isShowStatus) {
uiState = feeStateFactory.onFeeOnLoadingState()
+ updateNotifications()
}
val result = callFeeUseCase()?.fold(
ifRight = {
@@ -722,14 +738,12 @@ internal class SendViewModel @Inject constructor(
val recipientState = uiState.getRecipientState(isFromConfirmation) ?: return null
val amount = amountState.amountTextField.cryptoAmount.value ?: return null
- return feeCryptoCurrencyStatus?.let { feeCurrencyStatus ->
- getFeeUseCase.invoke(
- amount = amount,
- destination = recipientState.addressTextField.value,
- userWallet = userWallet,
- cryptoCurrency = feeCurrencyStatus.currency,
- )
- }
+ return getFeeUseCase.invoke(
+ amount = amount,
+ destination = recipientState.addressTextField.value,
+ userWallet = userWallet,
+ cryptoCurrency = cryptoCurrencyStatus.currency,
+ )
}
// endregion
@@ -783,8 +797,8 @@ internal class SendViewModel @Inject constructor(
analyticsEventHandler.send(SendAnalyticEvents.ShareButtonClicked)
}
- override fun onAmountReduceClick(reducedAmount: BigDecimal, clazz: Class) {
- uiState = amountStateFactory.getOnAmountValueChange(reducedAmount.parseBigDecimal(cryptoCurrency.decimals))
+ override fun onAmountReduceClick(reduceAmountBy: BigDecimal, clazz: Class) {
+ uiState = amountStateFactory.getOnAmountReducedState(reduceAmountBy)
uiState = sendNotificationFactory.dismissNotificationState(clazz)
feeReload()
}
@@ -806,6 +820,7 @@ internal class SendViewModel @Inject constructor(
cryptoCurrencyStatus = cryptoCurrencyStatus,
amountValue = amountValue,
feeValue = feeValue,
+ reduceAmountBy = uiState.sendState?.reduceAmountBy,
)
viewModelScope.launch(dispatchers.main) {