Updated on 2026-08-14

This commit is contained in:
Tangem 2022-04-22 18:31:28 +03:00
commit 85920292c9
19 changed files with 159 additions and 251 deletions

View file

@ -1,7 +1,7 @@
package com.tangem.tap.common.extensions
import com.tangem.common.extensions.isZero
import com.tangem.network.api.tangemTech.Coins
import com.tangem.network.api.tangemTech.CurrenciesResponse
import com.tangem.tap.common.redux.global.FiatCurrencyName
import java.math.BigDecimal
import java.math.RoundingMode
@ -52,7 +52,7 @@ fun BigDecimal.toFormattedFiatValue(fiatCurrencyName: FiatCurrencyName): String
return "≈ ${fiatCurrencyName} $this"
}
fun Coins.CurrenciesResponse.Currency.toFormattedString(): String = "${this.name} (${this.code}) - ${this.unit}"
fun CurrenciesResponse.Currency.toFormattedString(): String = "${this.name} (${this.code}) - ${this.unit}"
fun BigDecimal.stripZeroPlainString(): String = this.stripTrailingZeros().toPlainString()

View file

@ -87,22 +87,21 @@ class TapWalletManager {
return newResult
}
suspend fun loadFiatRate(fiatCurrency: FiatCurrencyName, wallet: Wallet) {
val currencies = wallet.getTokens()
suspend fun loadFiatRate(currencyId: FiatCurrencyName, wallet: Wallet) {
val coinsList = wallet.getTokens()
.map { Currency.Token(it, wallet.blockchain, wallet.publicKey.derivationPath?.rawPath) }
.plus(Currency.Blockchain(wallet.blockchain, wallet.publicKey.derivationPath?.rawPath))
loadFiatRate(fiatCurrency, currencies)
loadFiatRate(currencyId, coinsList)
}
suspend fun loadFiatRate(fiatCurrency: FiatCurrencyName, currencies: List<Currency>) {
suspend fun loadFiatRate(currencyId: FiatCurrencyName, coinsList: List<Currency>) {
suspend fun handleFiatRatesResult(rates: Map<Currency, Result<BigDecimal>?>) {
rates.forEach { (currency, priceResult) ->
when (priceResult) {
is Result.Success -> {
dispatchOnMain(
WalletAction.LoadFiatRate.Success(
currency to priceResult.data
))
dispatchOnMain(WalletAction.LoadFiatRate.Success(
currency to priceResult.data
))
}
is Result.Failure -> dispatchOnMain(WalletAction.LoadFiatRate.Failure)
null -> {}
@ -111,26 +110,26 @@ class TapWalletManager {
}
// get and submit previous result of equivalents.
val throttledResult = currencies.filter { fiatRatesThrottler.isStillThrottled(it) }.map {
val throttledResult = coinsList.filter { fiatRatesThrottler.isStillThrottled(it) }.map {
Pair(it, fiatRatesThrottler.geValue(it))
}
if (throttledResult.isNotEmpty()) {
handleFiatRatesResult(throttledResult.toMap())
}
val toUpdateCurrencies = currencies.filter { !fiatRatesThrottler.isStillThrottled(it) }
val toUpdateIds = toUpdateCurrencies.mapNotNull { it.coinId }.distinct()
if (toUpdateIds.isEmpty()) return
val currenciesToUpdate = coinsList.filter { !fiatRatesThrottler.isStillThrottled(it) }
val coinIds = currenciesToUpdate.mapNotNull { it.coinId }.distinct()
if (coinIds.isEmpty()) return
//TODO: refactoring: move fiatRatesThrottler to the TangemTechRepository
when (val result = tangemTechService.coins.prices(fiatCurrency, toUpdateIds)) {
when (val result = tangemTechService.rates(currencyId, coinIds)) {
is Result.Success -> {
val priceResultList: Map<String, Result<BigDecimal>> = result.data.prices.mapValues {
val ratesResultList: Map<String, Result<BigDecimal>> = result.data.rates.mapValues {
Result.Success(it.value.toBigDecimal())
}
val updatedCurrencies = mutableMapOf<Currency, Result<BigDecimal>?>()
toUpdateCurrencies.forEach { currency ->
priceResultList[currency.coinId]?.let {
currenciesToUpdate.forEach { currency ->
ratesResultList[currency.coinId]?.let {
updatedCurrencies[currency] = it
fiatRatesThrottler.updateThrottlingTo(currency)
fiatRatesThrottler.setValue(currency, it)

View file

@ -4,7 +4,7 @@ import com.tangem.blockchain.common.Wallet
import com.tangem.common.card.Card
import com.tangem.domain.common.ScanResponse
import com.tangem.domain.common.TwinCardNumber
import com.tangem.network.api.tangemTech.Coins
import com.tangem.network.api.tangemTech.CurrenciesResponse
import com.tangem.network.api.tangemTech.TangemTechService
import com.tangem.operations.pins.CheckUserCodesResponse
import com.tangem.tap.common.redux.NotificationAction
@ -48,7 +48,7 @@ sealed class DetailsAction : Action {
object CreateBackup : DetailsAction()
sealed class AppCurrencyAction : DetailsAction() {
data class SetCurrencies(val currencies: List<Coins.CurrenciesResponse.Currency>) : AppCurrencyAction()
data class SetCurrencies(val currencies: List<CurrenciesResponse.Currency>) : AppCurrencyAction()
object ChooseAppCurrency : AppCurrencyAction()
object Cancel : AppCurrencyAction()
data class SelectAppCurrency(val fiatCurrencyName: FiatCurrencyName) : AppCurrencyAction()

View file

@ -4,7 +4,6 @@ import com.tangem.common.CompletionResult
import com.tangem.common.card.FirmwareVersion
import com.tangem.common.core.TangemSdkError
import com.tangem.common.services.Result
import com.tangem.network.api.tangemTech.Coins
import com.tangem.operations.pins.CheckUserCodesResponse
import com.tangem.tap.*
import com.tangem.tap.common.analytics.Analytics
@ -77,14 +76,12 @@ class DetailsMiddleware {
scope.launch {
val tangemTechService = action.tangemTechService
when (val result = tangemTechService.coins.currencies()) {
when (val result = tangemTechService.currencies()) {
is Result.Success -> {
val fiatCurrencies = result.data.currencies.filter {
it.type == Coins.CurrenciesResponse.CurrencyType.Fiat.type
}
if (fiatCurrencies.isNotEmpty() && fiatCurrencies.toSet() != storedFiatCurrencies.toSet()) {
fiatCurrenciesPrefStorage.save(fiatCurrencies)
dispatchOnMain(DetailsAction.AppCurrencyAction.SetCurrencies(fiatCurrencies))
val currenciesList = result.data.currencies
if (currenciesList.isNotEmpty() && currenciesList.toSet() != storedFiatCurrencies.toSet()) {
fiatCurrenciesPrefStorage.save(currenciesList)
dispatchOnMain(DetailsAction.AppCurrencyAction.SetCurrencies(currenciesList))
}
}
is Result.Failure -> {}

View file

@ -3,7 +3,7 @@ package com.tangem.tap.features.details.redux
import android.net.Uri
import com.tangem.blockchain.common.Wallet
import com.tangem.domain.common.ScanResponse
import com.tangem.network.api.tangemTech.Coins
import com.tangem.network.api.tangemTech.CurrenciesResponse
import com.tangem.tap.common.entities.Button
import com.tangem.tap.common.entities.TapCurrency.Companion.DEFAULT_FIAT_CURRENCY
import com.tangem.tap.common.redux.global.FiatCurrencyName
@ -55,5 +55,5 @@ enum class SecurityOption { LongTap, PassCode, AccessCode }
data class AppCurrencyState(
val fiatCurrencyName: FiatCurrencyName = DEFAULT_FIAT_CURRENCY,
val showAppCurrencyDialog: Boolean = false,
val fiatCurrencies: List<Coins.CurrenciesResponse.Currency>? = null,
val fiatCurrencies: List<CurrenciesResponse.Currency>? = null,
)

View file

@ -2,7 +2,7 @@ package com.tangem.tap.features.details.ui
import android.content.Context
import androidx.appcompat.app.AlertDialog
import com.tangem.network.api.tangemTech.Coins
import com.tangem.network.api.tangemTech.CurrenciesResponse
import com.tangem.tap.common.extensions.toFormattedString
import com.tangem.tap.common.redux.global.FiatCurrencyName
import com.tangem.tap.features.details.redux.DetailsAction
@ -13,11 +13,11 @@ class CurrencySelectionDialog {
var dialog: AlertDialog? = null
fun show(currencies: List<Coins.CurrenciesResponse.Currency>, currentAppCurrency: FiatCurrencyName, context: Context) {
fun show(currenciesList: List<CurrenciesResponse.Currency>, currentAppCurrency: FiatCurrencyName, context: Context) {
if (dialog == null) {
val currenciesToShow = currencies.map { it.toFormattedString() }.toTypedArray()
var currentSelection = currencies.indexOfFirst { it.code == currentAppCurrency }
val currenciesToShow = currenciesList.map { it.toFormattedString() }.toTypedArray()
var currentSelection = currenciesList.indexOfFirst { it.code == currentAppCurrency }
dialog = AlertDialog.Builder(context)
.setTitle(context.getString(R.string.details_row_title_currency))
@ -25,7 +25,7 @@ class CurrencySelectionDialog {
store.dispatch(DetailsAction.AppCurrencyAction.Cancel)
}
.setPositiveButton(context.getString(R.string.common_done)) { _, _ ->
val selectedCurrency = currencies[currentSelection]
val selectedCurrency = currenciesList[currentSelection]
store.dispatch(DetailsAction.AppCurrencyAction.SelectAppCurrency(selectedCurrency.code))
}
.setOnDismissListener {

View file

@ -17,5 +17,5 @@ fun SelectTokenNetworkDialog(dialog: DomainDialog.SelectTokenDialog, onDismissRe
items = dialog.items,
onSelect = dialog.onSelect,
onDismissRequest = onDismissRequest
) { contract -> TitleSubtitle(dialog.networkIdConverter(contract.networkId), contract.address) }
) { network -> TitleSubtitle(dialog.networkIdConverter(network.networkId), network.address ?: "") }
}

View file

@ -12,14 +12,10 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.tangem.blockchain.common.Blockchain
import com.tangem.common.extensions.VoidCallback
import com.tangem.common.services.Result
import com.tangem.domain.common.form.Field
import com.tangem.domain.features.addCustomToken.AddCustomTokenService
import com.tangem.domain.features.addCustomToken.redux.AddCustomTokenAction
import com.tangem.domain.redux.domainStore
import com.tangem.network.api.tangemTech.TangemTechService
import com.tangem.wallet.BuildConfig
import timber.log.Timber
/**
[REDACTED_AUTHOR]
@ -40,7 +36,7 @@ fun TestAddCustomTokenActions() {
ActionRow("All in one") { AllInOne() }
// Any action
// ActionRow("CustomActions - find tokens active=false, decimals != null") { CustomActions() }
// ActionRow("CustomActions - find coins active=false, decimals != null") { CustomActions() }
}
}
@ -147,41 +143,6 @@ private fun UnknownContracts() {
@Composable
private fun CustomActions() {
CustomActionButton(
name = "Find tokens in several networks",
action = {
val manager = AddCustomTokenService(TangemTechService())
val currencies = manager.tokens()
val asdfsd = mutableMapOf<String, MutableList<Any>>()
val contractAddresses = currencies.mapNotNull { currency ->
currency.contracts?.map { it.address }
}.flatten()
contractAddresses.take(500).forEachIndexed() { index, address ->
when (val result = manager.checkAddress(address)) {
is Result.Success -> {
val contractList = mutableListOf<Any>()
result.data.forEach { token ->
token.contracts.forEach { contract ->
if (!contract.active && contract.decimalCount != null) {
contractList.add(contract)
}
}
}
if (contractList.isNotEmpty()) {
val list = asdfsd[address] ?: mutableListOf()
list.addAll(contractList)
asdfsd[address] = list
}
Timber.e("Success. handle $index item from size ${contractAddresses.size}. Result = ${asdfsd.size}")
}
is Result.Failure -> {}
}
}
val result = asdfsd.filter { it.value.size > 1 }
if (result.isEmpty()) return@CustomActionButton
}
)
}
@Composable

View file

@ -96,7 +96,7 @@ sealed class WalletAction : Action {
}
data class LoadFiatRate(
val wallet: Wallet? = null, val currencyList: List<Currency>? = null,
val wallet: Wallet? = null, val coinsList: List<Currency>? = null,
) : WalletAction() {
data class Success(val fiatRate: Pair<Currency, BigDecimal?>) : WalletAction()
object Failure : WalletAction()

View file

@ -55,19 +55,17 @@ class MultiWalletMiddleware {
blockchainNetwork = action.blockchain
)
}
store.dispatch(
WalletAction.LoadFiatRate(
currencyList = listOf(
Currency.Blockchain(
action.blockchain.blockchain,
action.blockchain.derivationPath
)
store.dispatch(WalletAction.LoadFiatRate(
coinsList = listOf(
Currency.Blockchain(
action.blockchain.blockchain,
action.blockchain.derivationPath
)
)
)
store.dispatch(
WalletAction.LoadWallet(action.blockchain, action.walletManager)
)
))
store.dispatch(WalletAction.LoadWallet(
action.blockchain, action.walletManager
))
}
is WalletAction.MultiWallet.SaveCurrencies -> {
globalState.scanResponse?.card?.cardId?.let {
@ -225,7 +223,7 @@ class MultiWalletMiddleware {
store.dispatch(WalletAction.MultiWallet.AddBlockchain(blockchainNetwork, it))
} ?: return
store.dispatch(WalletAction.LoadFiatRate(currencyList = tokens.map { token ->
store.dispatch(WalletAction.LoadFiatRate(coinsList = tokens.map { token ->
Currency.Token(
token, blockchainNetwork.blockchain, blockchainNetwork.derivationPath
)

View file

@ -101,27 +101,26 @@ class WalletMiddleware {
warningsMiddleware.tryToShowAppRatingWarning(action.wallet)
}
is WalletAction.LoadFiatRate -> {
val tapWalletManager = globalState.tapWalletManager
val fiatAppCurrency = globalState.appCurrency
val appCurrencyId = globalState.appCurrency
scope.launch {
when {
action.wallet != null -> {
globalState.tapWalletManager.loadFiatRate(
fiatCurrency = fiatAppCurrency,
currencyId = appCurrencyId,
wallet = action.wallet,
)
}
action.currencyList != null -> {
action.coinsList != null -> {
globalState.tapWalletManager.loadFiatRate(
fiatCurrency = fiatAppCurrency,
currencies = action.currencyList,
currencyId = appCurrencyId,
coinsList = action.coinsList,
)
}
else -> {
val currencyList = walletState.walletsData.map { it.currency }
val coinsList = walletState.walletsData.map { it.currency }
globalState.tapWalletManager.loadFiatRate(
fiatCurrency = fiatAppCurrency,
currencies = currencyList,
currencyId = appCurrencyId,
coinsList = coinsList,
)
}
}

View file

@ -3,7 +3,7 @@ package com.tangem.tap.persistence
import android.content.SharedPreferences
import androidx.core.content.edit
import com.tangem.common.json.MoshiJsonConverter
import com.tangem.network.api.tangemTech.Coins
import com.tangem.network.api.tangemTech.CurrenciesResponse
/**
[REDACTED_AUTHOR]
@ -21,14 +21,14 @@ class FiatCurrenciesPrefStorage(
}
}
fun save(currencies: List<Coins.CurrenciesResponse.Currency>) {
fun save(currencies: List<CurrenciesResponse.Currency>) {
val json: String = converter.toJson(currencies)
return preferences.edit().putString(FIAT_CURRENCIES_KEY, json).apply()
}
fun restore(): List<Coins.CurrenciesResponse.Currency> {
fun restore(): List<CurrenciesResponse.Currency> {
val json = preferences.getString(FIAT_CURRENCIES_KEY, "")
val type = converter.typedList(Coins.CurrenciesResponse.Currency::class.java)
val type = converter.typedList(CurrenciesResponse.Currency::class.java)
if (json.isNullOrBlank()) return emptyList()
return converter.fromJson(json, type) ?: emptyList()