Updated on 2026-08-14
This commit is contained in:
parent
041ff02106
commit
307b311afd
8 changed files with 77 additions and 17 deletions
|
|
@ -2,6 +2,7 @@ package com.tangem.tap.di.domain
|
|||
|
||||
import com.tangem.domain.account.supplier.MultiAccountListSupplier
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.networks.repository.NetworksRepository
|
||||
import com.tangem.domain.qrscanning.repository.QrScanningEventsRepository
|
||||
import com.tangem.domain.qrscanning.usecases.EmitQrScannedEventUseCase
|
||||
import com.tangem.domain.qrscanning.usecases.ListenToQrScanningUseCase
|
||||
|
|
@ -41,11 +42,13 @@ internal object QrScanningDomainModule {
|
|||
multiAccountListSupplier: MultiAccountListSupplier,
|
||||
qrScanningEventsRepository: QrScanningEventsRepository,
|
||||
userWalletsListRepository: UserWalletsListRepository,
|
||||
networksRepository: NetworksRepository,
|
||||
): ResolveQrSendTargetsUseCase {
|
||||
return ResolveQrSendTargetsUseCase(
|
||||
multiAccountListSupplier = multiAccountListSupplier,
|
||||
qrScanningEventsRepository = qrScanningEventsRepository,
|
||||
userWalletsListRepository = userWalletsListRepository,
|
||||
networksRepository = networksRepository,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -57,7 +57,7 @@ internal class DefaultNetworksRepository(
|
|||
.map { currency ->
|
||||
CryptoCurrencyAddress(
|
||||
cryptoCurrency = currency,
|
||||
address = getDefaultAddress(userWalletId, network),
|
||||
address = getDefaultAddress(userWalletId, network).orEmpty(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -74,11 +74,17 @@ internal class DefaultNetworksRepository(
|
|||
.map { currency ->
|
||||
CryptoCurrencyAddress(
|
||||
cryptoCurrency = currency,
|
||||
address = getDefaultAddress(userWalletId, currency.network),
|
||||
address = getDefaultAddress(userWalletId, currency.network).orEmpty(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getDefaultAddress(userWalletId: UserWalletId, network: Network): String? {
|
||||
return withContext(dispatchers.io) {
|
||||
walletManagersFacade.getDefaultAddress(userWalletId = userWalletId, network = network)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun hasCachedStatuses(userWalletId: UserWalletId): Boolean {
|
||||
return networksStatusesStore.contains(userWalletId)
|
||||
}
|
||||
|
|
@ -100,10 +106,4 @@ internal class DefaultNetworksRepository(
|
|||
|
||||
networksStatusesStore.storeStatus(userWalletId = userWalletId, status = networkStatus)
|
||||
}
|
||||
|
||||
private suspend fun getDefaultAddress(userWalletId: UserWalletId, network: Network): String {
|
||||
return withContext(dispatchers.io) {
|
||||
walletManagersFacade.getDefaultAddress(userWalletId = userWalletId, network = network).orEmpty()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -30,6 +30,11 @@ interface NetworksRepository {
|
|||
*/
|
||||
suspend fun getNetworkAddresses(userWalletId: UserWalletId, network: Network.RawID): List<CryptoCurrencyAddress>
|
||||
|
||||
/**
|
||||
* Returns the default address for the given [network] in the selected [userWalletId]
|
||||
*/
|
||||
suspend fun getDefaultAddress(userWalletId: UserWalletId, network: Network): String?
|
||||
|
||||
/** Checks if there are cached statuses for given [userWalletId] */
|
||||
suspend fun hasCachedStatuses(userWalletId: UserWalletId): Boolean
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@ dependencies {
|
|||
api(projects.domain.models)
|
||||
implementation(projects.domain.account)
|
||||
implementation(projects.domain.common)
|
||||
implementation(projects.domain.networks)
|
||||
implementation(projects.domain.qrScanning.models)
|
||||
implementation(projects.domain.tokens.models)
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ sealed class QrSendTarget {
|
|||
)
|
||||
}
|
||||
|
||||
data object AddressSameAsWallet : QrSendTarget()
|
||||
|
||||
data class WalletConnect(val uri: String) : QrSendTarget()
|
||||
|
||||
data class Error(val error: ClassifiedQrContent.Error) : QrSendTarget()
|
||||
|
|
|
|||
|
|
@ -5,17 +5,23 @@ import com.tangem.domain.models.account.Account
|
|||
import com.tangem.domain.models.account.AccountId
|
||||
import com.tangem.domain.models.account.AccountName
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.networks.repository.NetworksRepository
|
||||
import com.tangem.domain.qrscanning.models.ClassifiedQrContent
|
||||
import com.tangem.domain.qrscanning.repository.QrScanningEventsRepository
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import java.math.BigDecimal
|
||||
import com.tangem.domain.qrscanning.models.QrSendTarget
|
||||
import kotlinx.coroutines.awaitAll
|
||||
|
||||
class ResolveQrSendTargetsUseCase(
|
||||
private val multiAccountListSupplier: MultiAccountListSupplier,
|
||||
private val qrScanningEventsRepository: QrScanningEventsRepository,
|
||||
private val userWalletsListRepository: UserWalletsListRepository,
|
||||
private val networksRepository: NetworksRepository,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(qrCode: String): QrSendTarget {
|
||||
|
|
@ -49,7 +55,7 @@ class ResolveQrSendTargetsUseCase(
|
|||
return resolve(classified, portfolioIndex)
|
||||
}
|
||||
|
||||
private fun resolve(classified: ClassifiedQrContent, portfolioIndex: PortfolioIndex): QrSendTarget {
|
||||
private suspend fun resolve(classified: ClassifiedQrContent, portfolioIndex: PortfolioIndex): QrSendTarget {
|
||||
return when (classified) {
|
||||
is ClassifiedQrContent.WalletConnect -> QrSendTarget.WalletConnect(classified.uri)
|
||||
is ClassifiedQrContent.Error -> QrSendTarget.Error(classified)
|
||||
|
|
@ -70,14 +76,19 @@ class ResolveQrSendTargetsUseCase(
|
|||
}
|
||||
}
|
||||
|
||||
private fun resolveAddressTarget(
|
||||
private suspend fun resolveAddressTarget(
|
||||
address: String,
|
||||
amount: BigDecimal?,
|
||||
memo: String?,
|
||||
matchingCurrencies: List<CryptoCurrency>,
|
||||
portfolioIndex: PortfolioIndex,
|
||||
): QrSendTarget {
|
||||
val walletGroups = buildWalletGroups(matchingCurrencies, portfolioIndex)
|
||||
val ownAddressNetworks = findOwnAddressNetworks(address, matchingCurrencies, portfolioIndex)
|
||||
val walletGroups = buildWalletGroups(matchingCurrencies, portfolioIndex, ownAddressNetworks)
|
||||
|
||||
if (walletGroups.isEmpty()) {
|
||||
return QrSendTarget.AddressSameAsWallet
|
||||
}
|
||||
|
||||
val singleGroup = walletGroups.singleOrNull()
|
||||
val singleCurrency = singleGroup?.accounts?.singleOrNull()?.currencies?.singleOrNull()
|
||||
|
|
@ -100,9 +111,33 @@ class ResolveQrSendTargetsUseCase(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun findOwnAddressNetworks(
|
||||
address: String,
|
||||
matchingCurrencies: List<CryptoCurrency>,
|
||||
portfolioIndex: PortfolioIndex,
|
||||
): Map<UserWalletId, List<Network.ID>> = coroutineScope {
|
||||
matchingCurrencies.distinctBy { it.id }
|
||||
.flatMap { currency ->
|
||||
portfolioIndex.currencyLocations[currency.id].orEmpty().map {
|
||||
it.accountId.userWalletId to currency.network
|
||||
}
|
||||
}
|
||||
.distinct()
|
||||
.map { (walletId, network) ->
|
||||
async {
|
||||
val ownAddress = networksRepository.getDefaultAddress(walletId, network)
|
||||
if (ownAddress == address) walletId to network else null
|
||||
}
|
||||
}
|
||||
.awaitAll()
|
||||
.filterNotNull()
|
||||
.groupBy(keySelector = { it.first }, valueTransform = { it.second.id })
|
||||
}
|
||||
|
||||
private fun buildWalletGroups(
|
||||
matchingCurrencies: List<CryptoCurrency>,
|
||||
portfolioIndex: PortfolioIndex,
|
||||
ownAddressNetworks: Map<UserWalletId, List<Network.ID>>,
|
||||
): List<QrSendTarget.Multiple.WalletGroup> {
|
||||
val walletMap = linkedMapOf<UserWalletId, WalletInfo>()
|
||||
val uniqueCurrencies = matchingCurrencies.distinctBy { it.id }
|
||||
|
|
@ -110,13 +145,18 @@ class ResolveQrSendTargetsUseCase(
|
|||
for (currency in uniqueCurrencies) {
|
||||
val locations = portfolioIndex.currencyLocations[currency.id].orEmpty()
|
||||
for (location in locations) {
|
||||
val walletInfo = walletMap.getOrPut(location.accountId.userWalletId) {
|
||||
WalletInfo(location.walletName, linkedMapOf())
|
||||
val walletId = location.accountId.userWalletId
|
||||
val isOwnAddress = ownAddressNetworks[walletId]?.contains(currency.network.id) == true
|
||||
|
||||
if (!isOwnAddress) {
|
||||
val walletInfo = walletMap.getOrPut(walletId) {
|
||||
WalletInfo(location.walletName, linkedMapOf())
|
||||
}
|
||||
val accountInfo = walletInfo.accounts.getOrPut(location.accountId) {
|
||||
AccountInfo(location.accountName, mutableListOf())
|
||||
}
|
||||
accountInfo.currencies.add(currency)
|
||||
}
|
||||
val accountInfo = walletInfo.accounts.getOrPut(location.accountId) {
|
||||
AccountInfo(location.accountName, mutableListOf())
|
||||
}
|
||||
accountInfo.currencies.add(currency)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -785,6 +785,9 @@ internal class WalletModel @Inject constructor(
|
|||
is QrSendTarget.Multiple -> {
|
||||
innerWalletRouter.openNetworkSelectionBottomSheet(target)
|
||||
}
|
||||
is QrSendTarget.AddressSameAsWallet -> {
|
||||
uiMessageSender.send(WalletAlertUM.qrCodeAddressSameAsWallet())
|
||||
}
|
||||
is QrSendTarget.Error -> handleQrError(target.error)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,6 +94,12 @@ internal object WalletAlertUM {
|
|||
)
|
||||
}
|
||||
|
||||
fun qrCodeAddressSameAsWallet(): DialogMessage {
|
||||
return DialogMessage(
|
||||
message = resourceReference(R.string.send_error_address_same_as_wallet),
|
||||
)
|
||||
}
|
||||
|
||||
fun confirmExpressStatusHide(onConfirmClick: () -> Unit): DialogMessage {
|
||||
return DialogMessage(
|
||||
title = resourceReference(R.string.express_status_hide_dialog_title),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue