Updated on 2026-08-14

This commit is contained in:
Tangem 2025-03-28 09:36:24 +03:00
commit 4b78bf0d94
429 changed files with 10253 additions and 1865 deletions

View file

@ -4,7 +4,6 @@ import com.tangem.common.routing.AppRoute
import com.tangem.common.routing.AppRouter
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.navigation.url.UrlOpener
import com.tangem.domain.qrscanning.models.SourceType
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.wallets.models.UserWalletId
import javax.inject.Inject
@ -35,7 +34,7 @@ internal class DefaultSendRouter @Inject constructor(
override fun openQrCodeScanner(network: String) {
router.push(
AppRoute.QrScanning(
source = SourceType.SEND,
source = AppRoute.QrScanning.Source.SEND,
networkName = network,
),
)

View file

@ -36,8 +36,9 @@ import com.tangem.domain.tokens.*
import com.tangem.domain.tokens.error.CurrencyStatusError
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.transaction.error.AddressValidation
import com.tangem.domain.transaction.error.AddressValidationResult
import com.tangem.domain.transaction.error.GetFeeError
import com.tangem.domain.transaction.error.ValidateAddressError
import com.tangem.domain.transaction.usecase.*
import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
import com.tangem.domain.txhistory.usecase.GetFixedTxHistoryItemsUseCase
@ -116,7 +117,7 @@ internal class SendModel @Inject constructor(
private val txHistoryContentUpdateEmitter: TxHistoryContentUpdateEmitter,
@DelayedWork private val coroutineScope: CoroutineScope,
private val innerRouter: InnerSendRouter,
private val appRouter: AppRouter,
appRouter: AppRouter,
paramsContainer: ParamsContainer,
validateTransactionUseCase: ValidateTransactionUseCase,
getCurrencyCheckUseCase: GetCurrencyCheckUseCase,
@ -419,7 +420,10 @@ internal class SendModel @Inject constructor(
return filterNot { it.isLocked }
.mapNotNull { wallet ->
val addresses = if (!wallet.isMultiCurrency) {
getCryptoCurrencyUseCase(wallet.walletId).getOrNull()?.let {
getCryptoCurrencyUseCase(
userWallet = wallet,
cryptoCurrencyId = cryptoCurrency.id.value,
).getOrNull()?.let {
if (it.network.id == cryptoCurrency.network.id) {
getNetworkAddressesUseCase.invokeSync(wallet.walletId, it.network)
} else {
@ -690,7 +694,7 @@ internal class SendModel @Inject constructor(
}.saveIn(memoValidationJobHolder)
}
private suspend fun validateAddress(value: String): Either<ValidateAddressError, Unit> = runCatching {
private suspend fun validateAddress(value: String): AddressValidationResult = runCatching {
val maybeValidAddress = validateWalletAddressUseCase(
userWalletId = userWalletId,
network = cryptoCurrency.network,
@ -699,10 +703,10 @@ internal class SendModel @Inject constructor(
)
onEnteredValidAddress(maybeValidAddress.isLeft())
maybeValidAddress
}.getOrElse { ValidateAddressError.DataError(it).left() }
}.getOrElse { AddressValidation.Error.DataError(it).left() }
private fun validateMemo(value: String?): Boolean {
return value?.let { validateWalletMemoUseCase(cryptoCurrency.network, it).getOrElse { false } } ?: true
return value?.let { validateWalletMemoUseCase(cryptoCurrency.network, it).isRight() } != false
}
private suspend fun checkIfXrpAddressValue(value: String): Boolean {

View file

@ -19,7 +19,7 @@ internal class SendAmountPastedTriggerDismissConverter(
return state.copyWrapped(
isEditState = isEditState,
amountState = AmountPastedTriggerDismissTransformer().transform(amountState),
amountState = AmountPastedTriggerDismissTransformer.transform(amountState),
)
}
}

View file

@ -74,6 +74,7 @@ internal class SendNotificationFactory(
val sendState = state.sendState ?: return@map persistentListOf()
val feeState = state.getFeeState(isEditState) ?: return@map persistentListOf()
val amountState = state.getAmountState(isEditState) as? AmountState.Data ?: return@map persistentListOf()
val recipientState = state.getRecipientState(isEditState)
val amountValue = amountState.amountTextField.cryptoAmount.value.orZero()
val feeValue = feeState.fee?.amount?.value.orZero()
@ -118,6 +119,7 @@ internal class SendNotificationFactory(
)
addWarningNotifications(
amountState = amountState,
recipientState = recipientState,
feeState = feeState,
sendState = sendState,
sendingAmount = sendingAmount,
@ -233,6 +235,7 @@ internal class SendNotificationFactory(
private suspend fun MutableList<NotificationUM>.addWarningNotifications(
amountState: AmountState.Data,
recipientState: SendStates.RecipientState?,
feeState: SendStates.FeeState,
sendState: SendStates.SendState,
sendingAmount: BigDecimal,
@ -247,8 +250,8 @@ internal class SendNotificationFactory(
userWalletId = userWalletId,
amount = amountValue.convertToSdkAmount(cryptoCurrencyStatus.currency),
fee = feeState.fee,
memo = null,
destination = "",
memo = recipientState?.memoTextField?.value.orEmpty(),
destination = recipientState?.addressTextField?.value.orEmpty(),
network = cryptoCurrencyStatus.currency.network,
).leftOrNull()
}

View file

@ -1,20 +1,18 @@
package com.tangem.features.send.impl.presentation.state.recipient
import arrow.core.Either
import arrow.core.getOrElse
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.domain.transaction.error.ValidateAddressError
import com.tangem.domain.transaction.error.AddressValidation
import com.tangem.domain.transaction.error.AddressValidationResult
import com.tangem.domain.transaction.usecase.ValidateWalletMemoUseCase
import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.features.send.impl.R
import com.tangem.features.send.impl.presentation.domain.AvailableWallet
import com.tangem.features.send.impl.presentation.state.SendUiState
import com.tangem.features.send.impl.presentation.state.StateRouter
import com.tangem.utils.Provider
import kotlinx.collections.immutable.toPersistentList
import timber.log.Timber
internal class RecipientSendFactory(
private val stateRouterProvider: Provider<StateRouter>,
@ -66,10 +64,7 @@ internal class RecipientSendFactory(
)
}
fun getOnRecipientAddressValidState(
value: String,
maybeValidAddress: Either<ValidateAddressError, Unit>,
): SendUiState {
fun getOnRecipientAddressValidState(value: String, maybeValidAddress: AddressValidationResult): SendUiState {
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
val state = currentStateProvider()
val isEditState = stateRouterProvider().isEditState
@ -78,10 +73,7 @@ internal class RecipientSendFactory(
val isValidMemo = validateWalletMemoUseCase(
memo = recipientState.memoTextField?.value.orEmpty(),
network = cryptoCurrencyStatus.currency.network,
).getOrElse {
Timber.e("Failed to validateWalletMemoUseCase: $it")
false
}
).isRight()
return state.copyWrapped(
isEditState = isEditState,
@ -92,10 +84,10 @@ internal class RecipientSendFactory(
error = maybeValidAddress.fold(
ifLeft = {
when (it) {
ValidateAddressError.InvalidAddress -> resourceReference(
AddressValidation.Error.InvalidAddress -> resourceReference(
R.string.send_recipient_address_error,
)
ValidateAddressError.AddressInWallet -> resourceReference(
AddressValidation.Error.AddressInWallet -> resourceReference(
R.string.send_error_address_same_as_wallet,
)
else -> null
@ -143,10 +135,7 @@ internal class RecipientSendFactory(
val isValidMemo = validateWalletMemoUseCase(
memo = value,
network = cryptoCurrencyStatus.currency.network,
).getOrElse {
Timber.e("Failed to validateWalletMemoUseCase: $it")
false
}
).isRight()
return state.copyWrapped(
isEditState = isEditState,