diff --git a/app/src/main/java/com/tangem/tap/di/domain/TransactionDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/TransactionDomainModule.kt index 456bf93702..5fc760156f 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/TransactionDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/TransactionDomainModule.kt @@ -2,9 +2,11 @@ package com.tangem.tap.di.domain import com.tangem.domain.card.repository.CardSdkConfigRepository import com.tangem.domain.demo.IsDemoCardUseCase +import com.tangem.domain.transaction.FeeRepository import com.tangem.domain.transaction.TransactionRepository 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.walletmanager.WalletManagersFacade import dagger.Module @@ -42,4 +44,10 @@ internal object TransactionDomainModule { fun provideCreateTransactionUseCase(transactionRepository: TransactionRepository): CreateTransactionUseCase { return CreateTransactionUseCase(transactionRepository) } + + @Provides + @ViewModelScoped + fun provideIsFeeApproximateUseCase(feeRepository: FeeRepository): IsFeeApproximateUseCase { + return IsFeeApproximateUseCase(feeRepository) + } } \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/utils/BigDecimalFormatter.kt b/core/ui/src/main/java/com/tangem/core/ui/utils/BigDecimalFormatter.kt index e2d0c8dc42..c5fc3d7442 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/utils/BigDecimalFormatter.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/utils/BigDecimalFormatter.kt @@ -10,6 +10,7 @@ import java.util.Locale object BigDecimalFormatter { const val EMPTY_BALANCE_SIGN = "—" + const val CAN_BE_LOWER_SIGN = "<" private const val TEMP_CURRENCY_CODE = "USD" diff --git a/data/transaction/src/main/java/com/tangem/data/transaction/DefaultFeeRepository.kt b/data/transaction/src/main/java/com/tangem/data/transaction/DefaultFeeRepository.kt new file mode 100644 index 0000000000..25ee54c0b0 --- /dev/null +++ b/data/transaction/src/main/java/com/tangem/data/transaction/DefaultFeeRepository.kt @@ -0,0 +1,13 @@ +package com.tangem.data.transaction + +import com.tangem.blockchain.common.AmountType +import com.tangem.blockchain.common.Blockchain +import com.tangem.domain.tokens.model.Network +import com.tangem.domain.transaction.FeeRepository + +internal class DefaultFeeRepository : FeeRepository { + override fun isFeeApproximate(networkId: Network.ID, amountType: AmountType): Boolean { + val blockchain = Blockchain.fromId(networkId.value) + return blockchain.isFeeApproximate(amountType) + } +} \ No newline at end of file diff --git a/data/transaction/src/main/java/com/tangem/data/transaction/di/TransactionDataModule.kt b/data/transaction/src/main/java/com/tangem/data/transaction/di/TransactionDataModule.kt index de935654bb..c8949d39c0 100644 --- a/data/transaction/src/main/java/com/tangem/data/transaction/di/TransactionDataModule.kt +++ b/data/transaction/src/main/java/com/tangem/data/transaction/di/TransactionDataModule.kt @@ -1,6 +1,8 @@ package com.tangem.data.transaction.di +import com.tangem.data.transaction.DefaultFeeRepository import com.tangem.data.transaction.DefaultTransactionRepository +import com.tangem.domain.transaction.FeeRepository import com.tangem.domain.transaction.TransactionRepository import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.utils.coroutines.CoroutineDispatcherProvider @@ -25,4 +27,10 @@ internal object TransactionDataModule { coroutineDispatcherProvider = coroutineDispatcherProvider, ) } + + @Provides + @Singleton + fun providesFeeRepository(): FeeRepository { + return DefaultFeeRepository() + } } \ No newline at end of file diff --git a/domain/transaction/src/main/java/com/tangem/domain/transaction/FeeRepository.kt b/domain/transaction/src/main/java/com/tangem/domain/transaction/FeeRepository.kt new file mode 100644 index 0000000000..9434d8cf80 --- /dev/null +++ b/domain/transaction/src/main/java/com/tangem/domain/transaction/FeeRepository.kt @@ -0,0 +1,10 @@ +package com.tangem.domain.transaction + +import com.tangem.blockchain.common.AmountType +import com.tangem.domain.tokens.model.Network + +interface FeeRepository { + + /** Returns if fee is approximate for current [networkId] */ + fun isFeeApproximate(networkId: Network.ID, amountType: AmountType): Boolean +} \ No newline at end of file diff --git a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/IsFeeApproximateUseCase.kt b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/IsFeeApproximateUseCase.kt new file mode 100644 index 0000000000..688716716f --- /dev/null +++ b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/IsFeeApproximateUseCase.kt @@ -0,0 +1,19 @@ +package com.tangem.domain.transaction.usecase + +import com.tangem.blockchain.common.AmountType +import com.tangem.domain.tokens.model.Network +import com.tangem.domain.transaction.FeeRepository + +/** + * Use case to check if fee is approximate + * + * @param feeRepository [FeeRepository] + */ +class IsFeeApproximateUseCase( + private val feeRepository: FeeRepository, +) { + + operator fun invoke(networkId: Network.ID, amountType: AmountType): Boolean { + return feeRepository.isFeeApproximate(networkId, amountType) + } +} \ 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 14b9295f17..0e13e65c4f 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 @@ -77,6 +77,7 @@ internal sealed class SendStates { val receivedAmount: String, val rate: BigDecimal?, val appCurrency: AppCurrency, + val isFeeApproximate: Boolean, val notifications: ImmutableList, ) : SendStates() 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 dd003ef56f..c03cfaef65 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 @@ -5,6 +5,7 @@ import com.tangem.blockchain.common.transaction.TransactionFee import com.tangem.core.ui.utils.BigDecimalFormatter 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.SendStates import com.tangem.features.send.impl.presentation.state.SendUiState import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents @@ -24,6 +25,7 @@ internal class FeeStateFactory( private val coinCryptoCurrencyStatusProvider: Provider, private val cryptoCurrencyStatusProvider: Provider, private val appCurrencyProvider: Provider, + private val isFeeApproximateUseCase: IsFeeApproximateUseCase, ) { private val customFeeFieldConverter by lazy { SendFeeCustomFieldConverter( @@ -66,6 +68,7 @@ internal class FeeStateFactory( receivedAmountValue = receivedAmount, receivedAmount = getFormattedValue(receivedAmount), isSubtract = isSubtractAvailable && checkAutoSubtract(state, fee, balance), + isFeeApproximate = isFeeApproximate(fee), ), ) } @@ -206,6 +209,14 @@ internal class FeeStateFactory( } } + private fun isFeeApproximate(fee: Fee): Boolean { + val cryptoCurrencyStatus = cryptoCurrencyStatusProvider() + return isFeeApproximateUseCase( + networkId = cryptoCurrencyStatus.currency.network.id, + amountType = fee.amount.type, + ) + } + private fun getFormattedValue(value: BigDecimal): String { val cryptoCurrency = cryptoCurrencyStatusProvider().currency return BigDecimalFormatter.formatCryptoAmount( diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeStateConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeStateConverter.kt index 2231fab584..1dbee6b3fd 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeStateConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeStateConverter.kt @@ -26,6 +26,7 @@ internal class SendFeeStateConverter( notifications = persistentListOf(), rate = cryptoCurrencyStatus.value.fiatRate, appCurrency = appCurrencyProvider(), + isFeeApproximate = false, ) } } \ No newline at end of file diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelector.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelector.kt index 59e6fd4cc2..db73ae5c7e 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelector.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelector.kt @@ -28,10 +28,12 @@ import com.tangem.core.ui.components.SpacerWMax import com.tangem.core.ui.components.atoms.text.EllipsisText import com.tangem.core.ui.components.atoms.text.TextEllipsis import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.combinedReference import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.utils.BigDecimalFormatter +import com.tangem.core.ui.utils.BigDecimalFormatter.CAN_BE_LOWER_SIGN import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.features.send.impl.R import com.tangem.features.send.impl.presentation.state.SendStates @@ -79,7 +81,7 @@ internal fun SendSpeedSelector( SendSpeedSelectorItem( titleRes = R.string.common_fee_selector_option_slow, iconRes = R.drawable.ic_tortoise_24, - amount = getCryptoReference(minimumAmount), + amount = getCryptoReference(minimumAmount, state.isFeeApproximate), fiatAmount = getFiatReference(minimumAmount, state.rate, state.appCurrency), symbolLength = minimumAmount.currencySymbol.length, isSelected = isSelected == FeeType.SLOW, @@ -89,7 +91,7 @@ internal fun SendSpeedSelector( SendSpeedSelectorItem( titleRes = R.string.common_fee_selector_option_market, iconRes = R.drawable.ic_bird_24, - amount = getCryptoReference(normalAmount), + amount = getCryptoReference(normalAmount, state.isFeeApproximate), fiatAmount = getFiatReference(normalAmount, state.rate, state.appCurrency), symbolLength = normalAmount.currencySymbol.length, isSelected = isSelected == FeeType.MARKET, @@ -99,7 +101,7 @@ internal fun SendSpeedSelector( SendSpeedSelectorItem( titleRes = R.string.common_fee_selector_option_fast, iconRes = R.drawable.ic_hare_24, - amount = getCryptoReference(priorityAmount), + amount = getCryptoReference(priorityAmount, state.isFeeApproximate), fiatAmount = getFiatReference(priorityAmount, state.rate, state.appCurrency), symbolLength = priorityAmount.currencySymbol.length, isSelected = isSelected == FeeType.FAST, @@ -125,7 +127,7 @@ internal fun SendSpeedSelector( titleRes = R.string.common_fee_selector_option_market, iconRes = R.drawable.ic_bird_24, isSelected = true, - amount = getCryptoReference(normalAmount), + amount = getCryptoReference(normalAmount, state.isFeeApproximate), fiatAmount = getFiatReference(normalAmount, state.rate, state.appCurrency), symbolLength = normalAmount.currencySymbol.length, onSelect = { clickIntents.onFeeSelectorClick(FeeType.MARKET) }, @@ -140,11 +142,14 @@ internal fun SendSpeedSelector( } // todo remove after refactoring [REDACTED_JIRA] -private fun getCryptoReference(amount: Amount) = stringReference( - BigDecimalFormatter.formatCryptoAmount( - cryptoAmount = amount.value, - cryptoCurrency = amount.currencySymbol, - decimals = amount.decimals, +private fun getCryptoReference(amount: Amount, isFeeApproximate: Boolean) = combinedReference( + if (isFeeApproximate) stringReference("$CAN_BE_LOWER_SIGN ") else TextReference.EMPTY, + stringReference( + BigDecimalFormatter.formatCryptoAmount( + cryptoAmount = amount.value, + cryptoCurrency = amount.currencySymbol, + decimals = amount.decimals, + ), ), ) 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 32629e642a..80f5e20cac 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 @@ -24,6 +24,7 @@ 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.txhistory.models.TxHistoryItem import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase @@ -70,6 +71,7 @@ internal class SendViewModel @Inject constructor( private val walletManagersFacade: WalletManagersFacade, private val reduxStateHolder: ReduxStateHolder, private val isAmountSubtractAvailableUseCase: IsAmountSubtractAvailableUseCase, + private val isFeeApproximateUseCase: IsFeeApproximateUseCase, getExplorerTransactionUrlUseCase: GetExplorerTransactionUrlUseCase, validateWalletMemoUseCase: ValidateWalletMemoUseCase, getBalanceNotEnoughForFeeWarningUseCase: GetBalanceNotEnoughForFeeWarningUseCase, @@ -104,6 +106,7 @@ internal class SendViewModel @Inject constructor( coinCryptoCurrencyStatusProvider = Provider { coinCryptoCurrencyStatus }, cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus }, appCurrencyProvider = Provider(selectedAppCurrencyFlow::value), + isFeeApproximateUseCase = isFeeApproximateUseCase, ) private val eventStateFactory = SendEventStateFactory(