Updated on 2026-08-14

This commit is contained in:
Tangem 2025-05-12 17:44:40 +04:00
parent 4e69a47c32
commit c470e8ef27
8 changed files with 429 additions and 98 deletions

View file

@ -14,44 +14,52 @@ android {
dependencies {
/** Project - Domain */
// region Project - Data
implementation(projects.data.common)
implementation(projects.data.networks)
// endregion
// region Project - Domain
implementation(projects.domain.core)
implementation(projects.domain.demo)
implementation(projects.domain.legacy)
implementation(projects.domain.models)
implementation(projects.domain.staking)
implementation(projects.domain.staking.models)
implementation(projects.domain.tokens)
implementation(projects.domain.tokens.models)
implementation(projects.domain.txhistory.models)
implementation(projects.domain.wallets.models)
implementation(projects.domain.staking.models)
implementation(projects.domain.staking)
// endregion
/** Project - Data */
// region Project - Utils
implementation(projects.core.datasource)
implementation(projects.data.common)
/** Project - Utils */
implementation(projects.core.utils)
implementation(projects.domain.legacy)
implementation(projects.libs.blockchainSdk)
// endregion
/** Tangem SDKs */
// region Tangem SDKs
implementation(tangemDeps.blockchain)
implementation(tangemDeps.card.core)
// endregion
/** AndroidX */
// region AndroidX
implementation(deps.androidx.datastore)
implementation(deps.androidx.paging.runtime)
// endregion
/** DI */
// region DI
implementation(deps.hilt.core)
kapt(deps.hilt.kapt)
// endregion
/** Other */
// region Other
implementation(deps.jodatime)
implementation(deps.kotlin.coroutines)
implementation(deps.moshi.kotlin)
implementation(deps.jodatime)
implementation(deps.timber)
implementation(deps.retrofit) // For HttpException
implementation(deps.androidx.paging.runtime)
implementation(deps.timber)
ksp(deps.moshi.kotlin.codegen)
kaptForObfuscatingVariants(deps.retrofit.response.type.keeper)
// endregion
}

View file

@ -7,7 +7,7 @@ import com.tangem.blockchainsdk.utils.fromNetworkId
import com.tangem.data.common.cache.CacheRegistry
import com.tangem.data.common.currency.CardCryptoCurrencyFactory
import com.tangem.data.common.currency.ResponseCryptoCurrenciesFactory
import com.tangem.data.tokens.utils.NetworkStatusFactory
import com.tangem.data.networks.utils.NetworkStatusFactory
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
import com.tangem.datasource.local.network.NetworksStatusesStore
import com.tangem.datasource.local.preferences.AppPreferencesStore
@ -43,7 +43,6 @@ internal class DefaultNetworksRepository(
) : NetworksRepository {
private val responseCurrenciesFactory = ResponseCryptoCurrenciesFactory(excludedBlockchains)
private val networkStatusFactory = NetworkStatusFactory()
override fun getNetworkStatusesUpdates(
userWalletId: UserWalletId,
@ -168,10 +167,10 @@ internal class DefaultNetworksRepository(
invalidateCacheKeyIfNeeded(userWalletId, network, result)
}
val networkStatus = networkStatusFactory.createNetworkStatus(
val networkStatus = NetworkStatusFactory.create(
network = network,
result = result,
currencies = networkCurrencies.toSet(),
updatingResult = result,
addedCurrencies = networkCurrencies.toSet(),
)
networksStatusesStore.store(userWalletId, networkStatus)
@ -191,10 +190,10 @@ internal class DefaultNetworksRepository(
invalidateCacheKeyIfNeeded(userWalletId, network, result)
}
val networkStatus = networkStatusFactory.createNetworkStatus(
val networkStatus = NetworkStatusFactory.create(
network = network,
result = result,
currencies = currencies.toSet(),
updatingResult = result,
addedCurrencies = currencies.toSet(),
)
networksStatusesStore.store(userWalletId, networkStatus)

View file

@ -1,134 +0,0 @@
package com.tangem.data.tokens.utils
import com.tangem.domain.models.StatusSource
import com.tangem.domain.tokens.model.*
import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.domain.walletmanager.model.Address
import com.tangem.domain.walletmanager.model.CryptoCurrencyAmount
import com.tangem.domain.walletmanager.model.CryptoCurrencyTransaction
import com.tangem.domain.walletmanager.model.UpdateWalletManagerResult
import timber.log.Timber
class NetworkStatusFactory {
fun createNetworkStatus(
network: Network,
result: UpdateWalletManagerResult,
currencies: Set<CryptoCurrency>,
): NetworkStatus {
return NetworkStatus(
network = network,
value = when (result) {
is UpdateWalletManagerResult.MissedDerivation -> NetworkStatus.MissedDerivation
is UpdateWalletManagerResult.Unreachable -> NetworkStatus.Unreachable(
address = getNetworkAddressOrNull(result.selectedAddress, result.addresses),
)
is UpdateWalletManagerResult.NoAccount -> NetworkStatus.NoAccount(
address = getNetworkAddress(result.selectedAddress, result.addresses),
amountToCreateAccount = result.amountToCreateAccount,
errorMessage = result.errorMessage,
source = StatusSource.ACTUAL,
)
is UpdateWalletManagerResult.Verified -> NetworkStatus.Verified(
address = getNetworkAddress(result.selectedAddress, result.addresses),
amounts = formatAmounts(result.currenciesAmounts, currencies),
pendingTransactions = formatTransactions(
transactions = result.currentTransactions,
currencies = currencies,
),
source = StatusSource.ACTUAL,
)
},
)
}
private fun formatAmounts(
amounts: Set<CryptoCurrencyAmount>,
currencies: Set<CryptoCurrency>,
): Map<CryptoCurrency.ID, CryptoCurrencyAmountStatus> {
return currencies.associate { currency ->
val amount = when (currency) {
is CryptoCurrency.Coin -> {
amounts.singleOrNull { it is CryptoCurrencyAmount.Coin }
}
is CryptoCurrency.Token -> {
amounts.firstOrNull { amount ->
amount is CryptoCurrencyAmount.Token &&
currency.id.rawCurrencyId == amount.tokenId &&
currency.contractAddress.equals(amount.tokenContractAddress, ignoreCase = true)
}
}
}
if (amount == null) {
Timber.w("Unable to find amount for cryptocurrency: $currency")
currency.id to CryptoCurrencyAmountStatus.NotFound
} else {
currency.id to CryptoCurrencyAmountStatus.Loaded(amount.value)
}
}
}
private fun formatTransactions(
transactions: Set<CryptoCurrencyTransaction>,
currencies: Set<CryptoCurrency>,
): Map<CryptoCurrency.ID, Set<TxHistoryItem>> {
if (transactions.isEmpty()) return emptyMap()
return currencies
.asSequence()
.map { currency ->
val currencyTransactions = when (currency) {
is CryptoCurrency.Coin -> transactions.filterTo(hashSetOf()) { transaction ->
transaction is CryptoCurrencyTransaction.Coin
}
is CryptoCurrency.Token -> transactions.filterTo(hashSetOf()) { transaction ->
transaction is CryptoCurrencyTransaction.Token &&
transaction.tokenContractAddress.equals(currency.contractAddress, ignoreCase = true)
}
}
currency.id to createCurrentTransactions(currencyTransactions)
}
.toMap()
}
private fun createCurrentTransactions(transactions: Set<CryptoCurrencyTransaction>): Set<TxHistoryItem> {
return transactions.mapTo(hashSetOf()) { it.txHistoryItem }
}
private fun getNetworkAddressOrNull(selectedAddress: String?, availableAddresses: Set<Address>?): NetworkAddress? {
if (selectedAddress == null || availableAddresses == null) {
return null
}
return getNetworkAddress(selectedAddress, availableAddresses)
}
private fun getNetworkAddress(selectedAddress: String, availableAddresses: Set<Address>): NetworkAddress {
val defaultAddress = availableAddresses
.firstOrNull { it.value == selectedAddress }
?.let(::mapToDomainAddress)
requireNotNull(defaultAddress) { "Selected address must not be null" }
return if (availableAddresses.size != 1) {
NetworkAddress.Selectable(defaultAddress, availableAddresses.mapTo(hashSetOf(), ::mapToDomainAddress))
} else {
NetworkAddress.Single(defaultAddress)
}
}
private fun mapToDomainAddress(address: Address): NetworkAddress.Address {
val type = when (address.type) {
Address.Type.Primary -> NetworkAddress.Address.Type.Primary
Address.Type.Secondary -> NetworkAddress.Address.Type.Secondary
}
if (address.value.isBlank()) {
Timber.w("Address value is blank")
}
return NetworkAddress.Address(address.value, type)
}
}