Updated on 2026-08-14
This commit is contained in:
commit
e55e6c11ce
628 changed files with 9744 additions and 6249 deletions
|
|
@ -6,10 +6,10 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.ui.UiDependencies
|
||||
import com.tangem.core.ui.components.SystemBarsEffect
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.screen.ComposeFragment
|
||||
import com.tangem.core.ui.theme.AppThemeModeHolder
|
||||
import com.tangem.features.send.api.navigation.SendRouter
|
||||
import com.tangem.features.send.impl.navigation.InnerSendRouter
|
||||
import com.tangem.features.send.impl.presentation.state.StateRouter
|
||||
|
|
@ -26,7 +26,7 @@ import javax.inject.Inject
|
|||
internal class SendFragment : ComposeFragment() {
|
||||
|
||||
@Inject
|
||||
override lateinit var appThemeModeHolder: AppThemeModeHolder
|
||||
override lateinit var uiDependencies: UiDependencies
|
||||
|
||||
@Inject
|
||||
lateinit var router: SendRouter
|
||||
|
|
|
|||
|
|
@ -162,4 +162,28 @@ internal sealed class SendNotification(val config: NotificationConfig) {
|
|||
),
|
||||
)
|
||||
}
|
||||
|
||||
sealed interface Cardano {
|
||||
|
||||
data class MinAdaValueCharged(val tokenName: String, val minAdaValue: String) : Warning(
|
||||
title = resourceReference(id = R.string.cardano_coin_will_be_send_with_token_title),
|
||||
subtitle = resourceReference(
|
||||
id = R.string.cardano_coin_will_be_send_with_token_description,
|
||||
formatArgs = wrappedList(minAdaValue, tokenName),
|
||||
),
|
||||
)
|
||||
|
||||
data object InsufficientBalanceToTransferCoin : Error(
|
||||
title = resourceReference(id = R.string.cardano_max_amount_has_token_title),
|
||||
subtitle = resourceReference(id = R.string.cardano_max_amount_has_token_description),
|
||||
)
|
||||
|
||||
data class InsufficientBalanceToTransferToken(val tokenName: String) : Error(
|
||||
title = resourceReference(id = R.string.cardano_insufficient_balance_to_send_token_title),
|
||||
subtitle = resourceReference(
|
||||
id = R.string.cardano_insufficient_balance_to_send_token_description,
|
||||
formatArgs = wrappedList(tokenName),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +1,24 @@
|
|||
package com.tangem.features.send.impl.presentation.state.confirm
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.BlockchainSdkError
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.blockchainsdk.utils.fromNetworkId
|
||||
import com.tangem.blockchainsdk.utils.minimalAmount
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.ui.extensions.networkIconResId
|
||||
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.common.extensions.fromNetworkId
|
||||
import com.tangem.domain.common.extensions.minimalAmount
|
||||
import com.tangem.domain.tokens.GetBalanceNotEnoughForFeeWarningUseCase
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning
|
||||
import com.tangem.domain.tokens.repository.CurrencyChecksRepository
|
||||
import com.tangem.domain.tokens.utils.convertToAmount
|
||||
import com.tangem.domain.transaction.usecase.ValidateTransactionUseCase
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.features.send.impl.R
|
||||
import com.tangem.features.send.impl.presentation.analytics.SendAnalyticEvents
|
||||
|
|
@ -23,6 +27,7 @@ import com.tangem.features.send.impl.presentation.state.fee.*
|
|||
import com.tangem.features.send.impl.presentation.state.fields.SendTextField
|
||||
import com.tangem.features.send.impl.presentation.utils.getFiatString
|
||||
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
|
||||
import com.tangem.lib.crypto.BlockchainUtils
|
||||
import com.tangem.lib.crypto.BlockchainUtils.isTezos
|
||||
import com.tangem.utils.Provider
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
|
@ -46,6 +51,7 @@ internal class SendNotificationFactory(
|
|||
private val clickIntents: SendClickIntents,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val getBalanceNotEnoughForFeeWarningUseCase: GetBalanceNotEnoughForFeeWarningUseCase,
|
||||
private val validateTransactionUseCase: ValidateTransactionUseCase,
|
||||
) {
|
||||
|
||||
fun create(): Flow<ImmutableList<SendNotification>> = stateRouterProvider().currentState
|
||||
|
|
@ -80,8 +86,9 @@ internal class SendNotificationFactory(
|
|||
addFeeUnreachableNotification(feeState.feeSelectorState)
|
||||
addExceedBalanceNotification(feeValue, sendingAmount)
|
||||
addExceedsBalanceNotification(feeState.fee)
|
||||
addDustWarningNotification(feeValue, sendingAmount)
|
||||
addDustWarningNotificationForSpecificBlockchains(feeValue, sendingAmount)
|
||||
addTransactionLimitErrorNotification(feeValue, sendingAmount)
|
||||
|
||||
// warnings
|
||||
addExistentialWarningNotification(feeValue, amountValue)
|
||||
addFeeCoverageNotification(
|
||||
|
|
@ -92,6 +99,9 @@ internal class SendNotificationFactory(
|
|||
addHighFeeWarningNotification(amountValue, sendState.ignoreAmountReduce)
|
||||
addTooHighNotification(feeState.feeSelectorState)
|
||||
addTooLowNotification(feeState)
|
||||
|
||||
// blockchain specific
|
||||
addCardanoNotifications(sendingAmount, feeState.fee, state)
|
||||
}.toImmutableList()
|
||||
}
|
||||
|
||||
|
|
@ -279,23 +289,35 @@ internal class SendNotificationFactory(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun MutableList<SendNotification>.addDustWarningNotification(
|
||||
feeAmount: BigDecimal,
|
||||
receivedAmount: BigDecimal,
|
||||
private suspend fun MutableList<SendNotification>.addDustWarningNotificationForSpecificBlockchains(
|
||||
feeValue: BigDecimal,
|
||||
sendingAmount: BigDecimal,
|
||||
) {
|
||||
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
|
||||
val dustValue = currencyChecksRepository.getDustValue(
|
||||
userWalletProvider().walletId,
|
||||
cryptoCurrencyStatus.currency.network,
|
||||
) ?: return
|
||||
val isCardano = BlockchainUtils.isCardano(cryptoCurrencyStatusProvider().currency.network.id.value)
|
||||
|
||||
if (checkDustLimits(feeAmount, receivedAmount, dustValue)) {
|
||||
add(
|
||||
SendNotification.Error.MinimumAmountError(dustValue.toPlainString()),
|
||||
)
|
||||
if (!isCardano) {
|
||||
addDustWarningNotification(feeValue, sendingAmount)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkDustLimits(feeAmount: BigDecimal, receivedAmount: BigDecimal, dustValue: BigDecimal): Boolean {
|
||||
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
|
||||
|
||||
val change = when (cryptoCurrencyStatus.currency) {
|
||||
is CryptoCurrency.Coin -> {
|
||||
val balance = cryptoCurrencyStatus.value.amount ?: BigDecimal.ZERO
|
||||
balance - (feeAmount + receivedAmount)
|
||||
}
|
||||
is CryptoCurrency.Token -> {
|
||||
val balance = coinCryptoCurrencyStatusProvider().value.amount ?: BigDecimal.ZERO
|
||||
balance - feeAmount
|
||||
}
|
||||
}
|
||||
|
||||
val isChangeLowerThanDust = change < dustValue && change > BigDecimal.ZERO
|
||||
return receivedAmount < dustValue || isChangeLowerThanDust
|
||||
}
|
||||
|
||||
private fun MutableList<SendNotification>.addTooLowNotification(feeState: SendStates.FeeState) {
|
||||
val feeSelectorState = feeState.feeSelectorState as? FeeSelectorState.Content ?: return
|
||||
val multipleFees = feeSelectorState.fees as? TransactionFee.Choosable ?: return
|
||||
|
|
@ -397,13 +419,90 @@ internal class SendNotificationFactory(
|
|||
return Blockchain.fromNetworkId(this.currency.network.backendId) == Blockchain.Arbitrum
|
||||
}
|
||||
|
||||
private fun checkDustLimits(feeAmount: BigDecimal, receivedAmount: BigDecimal, dustValue: BigDecimal): Boolean {
|
||||
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
|
||||
val balance = cryptoCurrencyStatus.value.amount ?: BigDecimal.ZERO
|
||||
private suspend fun MutableList<SendNotification>.addCardanoNotifications(
|
||||
sendingAmount: BigDecimal,
|
||||
fee: Fee?,
|
||||
state: SendUiState,
|
||||
) {
|
||||
val sendingCurrency = cryptoCurrencyStatusProvider().currency
|
||||
if (!BlockchainUtils.isCardano(sendingCurrency.network.id.value)) return
|
||||
|
||||
val totalAmount = feeAmount + receivedAmount
|
||||
val change = balance - totalAmount
|
||||
val isChangeLowerThanDust = change < dustValue && change > BigDecimal.ZERO
|
||||
return receivedAmount < dustValue || isChangeLowerThanDust
|
||||
validateTransactionUseCase(
|
||||
amount = sendingAmount.convertToAmount(sendingCurrency),
|
||||
fee = fee ?: return,
|
||||
memo = state.recipientState?.memoTextField?.value,
|
||||
destination = requireNotNull(state.recipientState?.addressTextField?.value),
|
||||
userWalletId = userWalletProvider().walletId,
|
||||
network = sendingCurrency.network,
|
||||
).fold(
|
||||
ifLeft = {
|
||||
addCardanoTransactionValidationError(
|
||||
error = it as? BlockchainSdkError.Cardano ?: return@fold,
|
||||
sendingCurrency = sendingCurrency,
|
||||
)
|
||||
},
|
||||
ifRight = {
|
||||
(fee as? Fee.CardanoToken)?.let {
|
||||
add(
|
||||
SendNotification.Cardano.MinAdaValueCharged(
|
||||
tokenName = sendingCurrency.name,
|
||||
minAdaValue = it.minAdaValue.parseBigDecimal(sendingCurrency.decimals),
|
||||
),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun MutableList<SendNotification>.addCardanoTransactionValidationError(
|
||||
error: BlockchainSdkError.Cardano,
|
||||
sendingCurrency: CryptoCurrency,
|
||||
) {
|
||||
when (error) {
|
||||
BlockchainSdkError.Cardano.InsufficientMinAdaBalanceToSendToken -> {
|
||||
add(SendNotification.Cardano.InsufficientBalanceToTransferToken(sendingCurrency.name))
|
||||
}
|
||||
BlockchainSdkError.Cardano.InsufficientRemainingBalanceToWithdrawTokens -> {
|
||||
when (sendingCurrency) {
|
||||
is CryptoCurrency.Coin -> SendNotification.Cardano.InsufficientBalanceToTransferCoin
|
||||
is CryptoCurrency.Token -> {
|
||||
SendNotification.Cardano.InsufficientBalanceToTransferToken(sendingCurrency.name)
|
||||
}
|
||||
}.let(::add)
|
||||
}
|
||||
BlockchainSdkError.Cardano.InsufficientRemainingBalance,
|
||||
BlockchainSdkError.Cardano.InsufficientSendingAdaAmount,
|
||||
-> {
|
||||
val dustValue = currencyChecksRepository.getDustValue(
|
||||
userWalletId = userWalletProvider().walletId,
|
||||
network = sendingCurrency.network,
|
||||
) ?: return
|
||||
|
||||
add(
|
||||
SendNotification.Error.MinimumAmountError(
|
||||
amount = dustValue.parseBigDecimal(sendingCurrency.decimals),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun MutableList<SendNotification>.addDustWarningNotification(
|
||||
feeValue: BigDecimal,
|
||||
sendingAmount: BigDecimal,
|
||||
) {
|
||||
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
|
||||
val dustValue = currencyChecksRepository.getDustValue(
|
||||
userWalletProvider().walletId,
|
||||
cryptoCurrencyStatus.currency.network,
|
||||
) ?: return
|
||||
|
||||
if (checkDustLimits(feeValue, sendingAmount, dustValue)) {
|
||||
add(
|
||||
SendNotification.Error.MinimumAmountError(
|
||||
amount = dustValue.parseBigDecimal(cryptoCurrencyStatus.currency.decimals),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -34,6 +34,7 @@ import com.tangem.core.ui.extensions.resourceReference
|
|||
import com.tangem.core.ui.extensions.shareText
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
import com.tangem.features.send.impl.presentation.state.SendUiCurrentScreen
|
||||
import com.tangem.features.send.impl.presentation.state.SendUiState
|
||||
import com.tangem.features.send.impl.presentation.state.SendUiStateType
|
||||
|
|
@ -179,10 +180,10 @@ private fun SendingText(
|
|||
}
|
||||
|
||||
if (feeFiat != null && sendingFiat != null) {
|
||||
val sendingValue = getFiatFormatted(
|
||||
value = sendingFiat,
|
||||
currencySymbol = feeState.appCurrency.symbol,
|
||||
currencyCode = feeState.appCurrency.code,
|
||||
val sendingValue = BigDecimalFormatter.formatFiatAmount(
|
||||
fiatAmount = sendingFiat,
|
||||
fiatCurrencySymbol = feeState.appCurrency.symbol,
|
||||
fiatCurrencyCode = feeState.appCurrency.code,
|
||||
)
|
||||
val feeValue = getFiatString(
|
||||
value = feeState.fee?.amount?.value,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.features.send.impl.presentation.ui.amount
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
|
|
@ -8,6 +9,7 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.send.impl.presentation.state.SendStates
|
||||
import com.tangem.features.send.impl.presentation.state.previewdata.AmountStatePreviewData
|
||||
|
|
@ -43,25 +45,12 @@ internal fun SendAmountContent(
|
|||
|
||||
// region Preview
|
||||
@Preview
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun AmountFieldPreview_Light(
|
||||
private fun AmountFieldPreview(
|
||||
@PreviewParameter(AmountFieldPreviewProvider::class) amountState: SendStates.AmountState,
|
||||
) {
|
||||
TangemTheme {
|
||||
SendAmountContent(
|
||||
amountState = amountState,
|
||||
isBalanceHiding = false,
|
||||
clickIntents = SendClickIntentsStub,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun AmountFieldPreview_Dark(
|
||||
@PreviewParameter(AmountFieldPreviewProvider::class) amountState: SendStates.AmountState,
|
||||
) {
|
||||
TangemTheme(isDark = true) {
|
||||
TangemThemePreview {
|
||||
SendAmountContent(
|
||||
amountState = amountState,
|
||||
isBalanceHiding = false,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.features.send.impl.presentation.ui.fee
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
|
|
@ -18,6 +19,7 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.send.impl.R
|
||||
import com.tangem.features.send.impl.presentation.state.SendStates
|
||||
import com.tangem.features.send.impl.presentation.state.fee.FeeType
|
||||
|
|
@ -107,21 +109,12 @@ private fun FooterText(onReadMoreClick: () -> Unit) {
|
|||
|
||||
// region Preview
|
||||
@Preview
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun SendSpeedSelectorPreview_Light(
|
||||
private fun SendSpeedSelectorPreview(
|
||||
@PreviewParameter(SendSpeedSelectorPreviewProvider::class) feeState: SendStates.FeeState,
|
||||
) {
|
||||
TangemTheme {
|
||||
SendSpeedSelector(state = feeState, clickIntents = SendClickIntentsStub)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun SendSpeedSelectorPreview_Dark(
|
||||
@PreviewParameter(SendSpeedSelectorPreviewProvider::class) feeState: SendStates.FeeState,
|
||||
) {
|
||||
TangemTheme(isDark = true) {
|
||||
TangemThemePreview {
|
||||
SendSpeedSelector(state = feeState, clickIntents = SendClickIntentsStub)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.features.send.impl.presentation.ui.recipient
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.fadeIn
|
||||
|
|
@ -27,6 +28,7 @@ import com.tangem.core.ui.components.atoms.text.EllipsisText
|
|||
import com.tangem.core.ui.components.atoms.text.TextEllipsis
|
||||
import com.tangem.core.ui.components.icons.identicon.IdentIcon
|
||||
import com.tangem.core.ui.extensions.rememberHapticFeedback
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.send.impl.R
|
||||
|
||||
|
|
@ -183,28 +185,12 @@ private fun ListItemLoading(modifier: Modifier = Modifier) {
|
|||
|
||||
// region preview
|
||||
@Preview
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun ListItemWithIconPreview_Light(
|
||||
private fun ListItemWithIconPreview(
|
||||
@PreviewParameter(ListItemWithIconPreviewProvider::class) config: ListItemWithIconPreviewConfig,
|
||||
) {
|
||||
TangemTheme {
|
||||
ListItemWithIcon(
|
||||
title = config.title,
|
||||
subtitle = config.subtitle,
|
||||
subtitleEndOffset = config.subtitleEndOffset,
|
||||
subtitleIconRes = config.iconRes,
|
||||
onClick = {},
|
||||
isLoading = config.isLoading,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun ListItemWithIconPreview_Dark(
|
||||
@PreviewParameter(ListItemWithIconPreviewProvider::class) config: ListItemWithIconPreviewConfig,
|
||||
) {
|
||||
TangemTheme(isDark = true) {
|
||||
TangemThemePreview {
|
||||
ListItemWithIcon(
|
||||
title = config.title,
|
||||
subtitle = config.subtitle,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.features.send.impl.presentation.ui.send
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
|
|
@ -16,6 +17,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
|
|||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import com.tangem.core.ui.components.ResizableText
|
||||
import com.tangem.core.ui.components.currency.tokenicon.TokenIcon
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
import com.tangem.features.send.impl.presentation.state.SendStates
|
||||
|
|
@ -84,11 +86,10 @@ internal fun AmountBlock(
|
|||
|
||||
// region Preview
|
||||
@Preview
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun AmountBlockPreview_Light(
|
||||
@PreviewParameter(AmountBlockPreviewProvider::class) value: SendStates.AmountState,
|
||||
) {
|
||||
TangemTheme {
|
||||
private fun AmountBlockPreview(@PreviewParameter(AmountBlockPreviewProvider::class) value: SendStates.AmountState) {
|
||||
TangemThemePreview {
|
||||
AmountBlock(
|
||||
amountState = value,
|
||||
isClickDisabled = false,
|
||||
|
|
@ -98,21 +99,6 @@ private fun AmountBlockPreview_Light(
|
|||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun AmountBlockPreview_Dark(
|
||||
@PreviewParameter(AmountBlockPreviewProvider::class) value: SendStates.AmountState,
|
||||
) {
|
||||
TangemTheme(isDark = true) {
|
||||
AmountBlock(
|
||||
amountState = value,
|
||||
isClickDisabled = true,
|
||||
isEditingDisabled = false,
|
||||
onClick = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class AmountBlockPreviewProvider : PreviewParameterProvider<SendStates.AmountState> {
|
||||
override val values: Sequence<SendStates.AmountState>
|
||||
get() = sequenceOf(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.features.send.impl.presentation.ui.send
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
|
|
@ -15,6 +16,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
|
|||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import com.tangem.core.ui.components.RectangleShimmer
|
||||
import com.tangem.core.ui.components.rows.SelectorRowItem
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
import com.tangem.features.send.impl.R
|
||||
|
|
@ -110,21 +112,10 @@ private fun BoxScope.FeeError(feeSelectorState: FeeSelectorState) {
|
|||
|
||||
// region Preview
|
||||
@Preview
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun FeeBlockPreview_Light(@PreviewParameter(FeeBlockPreviewProvider::class) value: SendStates.FeeState) {
|
||||
TangemTheme {
|
||||
FeeBlock(
|
||||
feeState = value,
|
||||
isClickDisabled = true,
|
||||
onClick = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun FeeBlockPreview_Dark(@PreviewParameter(FeeBlockPreviewProvider::class) value: SendStates.FeeState) {
|
||||
TangemTheme(isDark = true) {
|
||||
private fun FeeBlockPreview(@PreviewParameter(FeeBlockPreviewProvider::class) value: SendStates.FeeState) {
|
||||
TangemThemePreview {
|
||||
FeeBlock(
|
||||
feeState = value,
|
||||
isClickDisabled = true,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.features.send.impl.presentation.ui.send
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
|
|
@ -15,6 +16,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
|
|||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import com.tangem.core.ui.components.icons.identicon.IdentIcon
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.send.impl.presentation.state.SendStates
|
||||
import com.tangem.features.send.impl.presentation.state.fields.SendTextField
|
||||
|
|
@ -97,26 +99,12 @@ private fun MemoBlock(memo: SendTextField.RecipientMemo?) {
|
|||
|
||||
// region Preview
|
||||
@Preview
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun RecipientBlockPreview_Light(
|
||||
private fun RecipientBlockPreview(
|
||||
@PreviewParameter(RecipientBlockPreviewProvider::class) value: SendStates.RecipientState,
|
||||
) {
|
||||
TangemTheme {
|
||||
RecipientBlock(
|
||||
recipientState = value,
|
||||
isClickDisabled = true,
|
||||
isEditingDisabled = false,
|
||||
onClick = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun RecipientBlockPreview_Dark(
|
||||
@PreviewParameter(RecipientBlockPreviewProvider::class) value: SendStates.RecipientState,
|
||||
) {
|
||||
TangemTheme(isDark = true) {
|
||||
TangemThemePreview {
|
||||
RecipientBlock(
|
||||
recipientState = value,
|
||||
isClickDisabled = true,
|
||||
|
|
|
|||
|
|
@ -8,11 +8,8 @@ import com.tangem.core.ui.utils.BigDecimalFormatter
|
|||
import com.tangem.core.ui.utils.BigDecimalFormatter.EMPTY_BALANCE_SIGN
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
|
||||
private const val FIAT_DECIMALS = 2
|
||||
private const val CRYPTO_FEE_DECIMALS = 6
|
||||
private const val FEE_MINIMUM_VALUE = 0.01
|
||||
|
||||
internal fun getCryptoReference(amount: Amount?, isFeeApproximate: Boolean): TextReference? {
|
||||
if (amount == null) return null
|
||||
|
|
@ -37,27 +34,9 @@ internal fun getFiatReference(value: BigDecimal?, rate: BigDecimal?, appCurrency
|
|||
internal fun getFiatString(value: BigDecimal?, rate: BigDecimal?, appCurrency: AppCurrency): String {
|
||||
if (value == null || rate == null) return EMPTY_BALANCE_SIGN
|
||||
val feeValue = value.multiply(rate)
|
||||
return getFiatFormatted(feeValue, appCurrency.code, appCurrency.symbol)
|
||||
}
|
||||
|
||||
internal fun getFiatFormatted(value: BigDecimal?, currencyCode: String, currencySymbol: String): String {
|
||||
val scaled = value?.setScale(FIAT_DECIMALS, RoundingMode.UP) ?: BigDecimal.ZERO
|
||||
return if (scaled < BigDecimal(FEE_MINIMUM_VALUE)) {
|
||||
buildString {
|
||||
append(BigDecimalFormatter.CAN_BE_LOWER_SIGN)
|
||||
append(
|
||||
BigDecimalFormatter.formatFiatAmount(
|
||||
fiatAmount = BigDecimal(FEE_MINIMUM_VALUE),
|
||||
fiatCurrencyCode = currencyCode,
|
||||
fiatCurrencySymbol = currencySymbol,
|
||||
),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
BigDecimalFormatter.formatFiatAmount(
|
||||
fiatAmount = value,
|
||||
fiatCurrencyCode = currencyCode,
|
||||
fiatCurrencySymbol = currencySymbol,
|
||||
)
|
||||
}
|
||||
return BigDecimalFormatter.formatFiatAmount(
|
||||
fiatAmount = feeValue,
|
||||
fiatCurrencyCode = appCurrency.code,
|
||||
fiatCurrencySymbol = appCurrency.symbol,
|
||||
)
|
||||
}
|
||||
|
|
@ -30,10 +30,7 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
|||
import com.tangem.domain.tokens.repository.CurrencyChecksRepository
|
||||
import com.tangem.domain.tokens.utils.convertToAmount
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
import com.tangem.domain.transaction.usecase.CreateTransactionUseCase
|
||||
import com.tangem.domain.transaction.usecase.GetFeeUseCase
|
||||
import com.tangem.domain.transaction.usecase.IsFeeApproximateUseCase
|
||||
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
|
||||
import com.tangem.domain.transaction.usecase.*
|
||||
import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
|
||||
import com.tangem.domain.txhistory.usecase.GetFixedTxHistoryItemsUseCase
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
|
|
@ -100,6 +97,7 @@ internal class SendViewModel @Inject constructor(
|
|||
private val updateDelayedCurrencyStatusUseCase: UpdateDelayedNetworkStatusUseCase,
|
||||
private val fetchPendingTransactionsUseCase: FetchPendingTransactionsUseCase,
|
||||
@DelayedWork private val coroutineScope: CoroutineScope,
|
||||
validateTransactionUseCase: ValidateTransactionUseCase,
|
||||
currencyChecksRepository: CurrencyChecksRepository,
|
||||
isFeeApproximateUseCase: IsFeeApproximateUseCase,
|
||||
validateWalletMemoUseCase: ValidateWalletMemoUseCase,
|
||||
|
|
@ -178,6 +176,7 @@ internal class SendViewModel @Inject constructor(
|
|||
clickIntents = this,
|
||||
analyticsEventHandler = analyticsEventHandler,
|
||||
getBalanceNotEnoughForFeeWarningUseCase = getBalanceNotEnoughForFeeWarningUseCase,
|
||||
validateTransactionUseCase = validateTransactionUseCase,
|
||||
)
|
||||
|
||||
private val sendScreenAnalyticSender by lazy(LazyThreadSafetyMode.NONE) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue