Updated on 2026-08-14

This commit is contained in:
Tangem 2022-04-12 22:41:01 +04:00
parent 17b31dd192
commit 8fb493fef6
27 changed files with 322 additions and 157 deletions

View file

@ -79,10 +79,9 @@ dependencies {
implementation 'com.google.android.play:core-ktx:1.8.1' implementation 'com.google.android.play:core-ktx:1.8.1'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
// implementation 'com.tangem:blockchain:develop-67' implementation 'com.tangem:blockchain:develop-70'
implementation 'com.tangem:blockchain:0.0.1' implementation 'com.tangem.tangem-sdk-kotlin:core:develop-142'
implementation 'com.tangem.tangem-sdk-kotlin:core:0.0.1' implementation 'com.tangem.tangem-sdk-kotlin:android:develop-142'
implementation 'com.tangem.tangem-sdk-kotlin:android:0.0.1'
// WebView // WebView
implementation "androidx.browser:browser:1.3.0" implementation "androidx.browser:browser:1.3.0"

View file

@ -4,36 +4,16 @@ import androidx.annotation.DrawableRes
import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.Blockchain
import com.tangem.wallet.R import com.tangem.wallet.R
@DrawableRes
fun Blockchain.getIconRes(): Int {
return when (this) {
Blockchain.Unknown -> R.drawable.shape_circle
Blockchain.Ducatus -> R.drawable.ic_ducatus
Blockchain.Bitcoin, Blockchain.BitcoinTestnet,-> R.drawable.ic_btc
Blockchain.BitcoinCash -> R.drawable.ic_btc_cash
Blockchain.Litecoin -> R.drawable.ic_ltc
Blockchain.Ethereum, Blockchain.EthereumTestnet, -> R.drawable.ic_eth
Blockchain.RSK -> R.drawable.ic_rsk
Blockchain.Cardano, Blockchain.CardanoShelley -> R.drawable.ic_cardano
Blockchain.Binance, Blockchain.BinanceTestnet -> R.drawable.ic_binance
Blockchain.Tezos -> R.drawable.ic_tezos
Blockchain.XRP -> R.drawable.ic_xrp
Blockchain.Stellar -> R.drawable.ic_stellar
else -> R.drawable.shape_circle
}
}
@DrawableRes @DrawableRes
fun Blockchain.getRoundIconRes(): Int { fun Blockchain.getRoundIconRes(): Int {
return when (this) { return when (this) {
// Blockchain.Ducatus -> R.drawable.ic_ducatus Blockchain.Ducatus -> R.drawable.ic_ducatus
Blockchain.Bitcoin, Blockchain.BitcoinTestnet,-> R.drawable.ic_bitcoin_round Blockchain.Bitcoin, Blockchain.BitcoinTestnet,-> R.drawable.ic_bitcoin_round
Blockchain.BitcoinCash -> R.drawable.ic_bitcoin_cash_round Blockchain.BitcoinCash -> R.drawable.ic_bitcoin_cash_round
Blockchain.Litecoin -> R.drawable.ic_litecoin_round Blockchain.Litecoin -> R.drawable.ic_litecoin_round
Blockchain.Ethereum, Blockchain.EthereumTestnet, -> R.drawable.ic_eth_round Blockchain.Ethereum, Blockchain.EthereumTestnet, -> R.drawable.ic_eth_round
Blockchain.RSK -> R.drawable.ic_rsk_round Blockchain.RSK -> R.drawable.ic_rsk_round
Blockchain.Cardano, Blockchain.CardanoShelley -> R.drawable.ic_cardano_round Blockchain.Cardano, Blockchain.CardanoShelley -> R.drawable.ic_cardano_round
Blockchain.Binance, Blockchain.BinanceTestnet -> R.drawable.ic_binance_round
Blockchain.Tezos -> R.drawable.ic_tezos_round Blockchain.Tezos -> R.drawable.ic_tezos_round
Blockchain.XRP -> R.drawable.ic_xrp_round Blockchain.XRP -> R.drawable.ic_xrp_round
Blockchain.Stellar -> R.drawable.ic_stellar_round Blockchain.Stellar -> R.drawable.ic_stellar_round
@ -41,7 +21,7 @@ fun Blockchain.getRoundIconRes(): Int {
Blockchain.Polygon, Blockchain.PolygonTestnet -> R.drawable.ic_polygon_round Blockchain.Polygon, Blockchain.PolygonTestnet -> R.drawable.ic_polygon_round
Blockchain.Solana, Blockchain.SolanaTestnet -> R.drawable.ic_solana_round Blockchain.Solana, Blockchain.SolanaTestnet -> R.drawable.ic_solana_round
Blockchain.Fantom, Blockchain.FantomTestnet -> R.drawable.ic_fantom_round Blockchain.Fantom, Blockchain.FantomTestnet -> R.drawable.ic_fantom_round
Blockchain.BSC, Blockchain.BSCTestnet -> R.drawable.ic_bsc_round Blockchain.BSC, Blockchain.BSCTestnet, Blockchain.Binance, Blockchain.BinanceTestnet -> R.drawable.ic_bsc_round
else -> R.drawable.ic_tangem_logo else -> R.drawable.ic_tangem_logo
} }
} }
@ -56,7 +36,6 @@ fun Blockchain.getGreyedOutIconRes(): Int {
Blockchain.Ethereum, Blockchain.EthereumTestnet, -> R.drawable.ic_eth_no_color Blockchain.Ethereum, Blockchain.EthereumTestnet, -> R.drawable.ic_eth_no_color
Blockchain.RSK -> R.drawable.ic_rsk_no_color Blockchain.RSK -> R.drawable.ic_rsk_no_color
Blockchain.Cardano, Blockchain.CardanoShelley -> R.drawable.ic_cardano_no_color Blockchain.Cardano, Blockchain.CardanoShelley -> R.drawable.ic_cardano_no_color
Blockchain.Binance, Blockchain.BinanceTestnet -> R.drawable.ic_binance_no_color
Blockchain.Tezos -> R.drawable.ic_tezos_no_color Blockchain.Tezos -> R.drawable.ic_tezos_no_color
Blockchain.XRP -> R.drawable.ic_xrp_no_color Blockchain.XRP -> R.drawable.ic_xrp_no_color
Blockchain.Stellar -> R.drawable.ic_stellar_no_color Blockchain.Stellar -> R.drawable.ic_stellar_no_color
@ -64,7 +43,7 @@ fun Blockchain.getGreyedOutIconRes(): Int {
Blockchain.Polygon, Blockchain.PolygonTestnet -> R.drawable.ic_polygon_no_color Blockchain.Polygon, Blockchain.PolygonTestnet -> R.drawable.ic_polygon_no_color
Blockchain.Solana, Blockchain.SolanaTestnet -> R.drawable.ic_solana_no_color Blockchain.Solana, Blockchain.SolanaTestnet -> R.drawable.ic_solana_no_color
Blockchain.Fantom, Blockchain.FantomTestnet -> R.drawable.ic_fantom_no_color Blockchain.Fantom, Blockchain.FantomTestnet -> R.drawable.ic_fantom_no_color
Blockchain.BSC, Blockchain.BSCTestnet -> R.drawable.ic_bsc_no_color Blockchain.BSC, Blockchain.BSCTestnet, Blockchain.Binance, Blockchain.BinanceTestnet -> R.drawable.ic_bsc_no_color
else -> R.drawable.ic_tangem_logo else -> R.drawable.ic_tangem_logo
} }
} }

View file

@ -1,7 +1,6 @@
package com.tangem.tap.common.extensions package com.tangem.tap.common.extensions
import android.graphics.* import android.graphics.*
import android.net.Uri
import android.widget.TextView import android.widget.TextView
import androidx.constraintlayout.utils.widget.ImageFilterView import androidx.constraintlayout.utils.widget.ImageFilterView
import com.squareup.picasso.Callback import com.squareup.picasso.Callback
@ -11,6 +10,8 @@ import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.IconsUtil import com.tangem.blockchain.common.IconsUtil
import com.tangem.blockchain.common.Token import com.tangem.blockchain.common.Token
import com.tangem.tap.domain.extensions.getCustomIconUrl import com.tangem.tap.domain.extensions.getCustomIconUrl
import com.tangem.tap.domain.tokens.getIconUrl
import com.tangem.tap.domain.tokens.toNetworkId
import com.tangem.wallet.R import com.tangem.wallet.R
fun Picasso.loadCurrenciesIcon( fun Picasso.loadCurrenciesIcon(
@ -20,10 +21,11 @@ fun Picasso.loadCurrenciesIcon(
blockchain: Blockchain, blockchain: Blockchain,
) { ) {
val url = if (token != null) { val url: String? = if (token != null) {
token.getCustomIconUrl()?.let { Uri.parse(it) } ?: IconsUtil.getTokenIconUri(blockchain, token) token.id?.let { getIconUrl(it) } ?: token.getCustomIconUrl()
?: IconsUtil.getTokenIconUri(blockchain, token)?.toString()
} else { } else {
IconsUtil.getBlockchainIconUri(blockchain) getIconUrl(blockchain.toNetworkId())
} }
imageView.setImageDrawable(null) imageView.setImageDrawable(null)
@ -85,7 +87,7 @@ private fun setBlockchainImage(
textView: TextView, textView: TextView,
blockchain: Blockchain, blockchain: Blockchain,
) { ) {
imageView.setImageResource(blockchain.getIconRes()) imageView.setImageResource(blockchain.getRoundIconRes())
imageView.colorFilter = null imageView.colorFilter = null
if (blockchain.isTestnet()) imageView.saturation = 0f if (blockchain.isTestnet()) imageView.saturation = 0f
textView.text = null textView.text = null

View file

@ -11,6 +11,7 @@ import com.tangem.tap.common.extensions.withMainContext
import com.tangem.tap.common.redux.global.FiatCurrencyName import com.tangem.tap.common.redux.global.FiatCurrencyName
import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.currenciesRepository import com.tangem.tap.currenciesRepository
import com.tangem.tap.domain.TapWorkarounds.derivationStyle
import com.tangem.tap.domain.TapWorkarounds.isStart2Coin import com.tangem.tap.domain.TapWorkarounds.isStart2Coin
import com.tangem.tap.domain.TapWorkarounds.isTestCard import com.tangem.tap.domain.TapWorkarounds.isTestCard
import com.tangem.tap.domain.configurable.config.ConfigManager import com.tangem.tap.domain.configurable.config.ConfigManager
@ -190,7 +191,7 @@ class TapWalletManager {
primaryWalletManager: WalletManager? primaryWalletManager: WalletManager?
) { ) {
val primaryTokens = primaryWalletManager?.cardTokens?.toList() ?: emptyList() val primaryTokens = primaryWalletManager?.cardTokens?.toList() ?: emptyList()
val savedCurrencies = currenciesRepository.loadSavedCurrencies(scanResponse.card.cardId) val savedCurrencies = currenciesRepository.loadSavedCurrencies(scanResponse.card.cardId, scanResponse.card.derivationStyle)
if (savedCurrencies.isEmpty()) { if (savedCurrencies.isEmpty()) {
if (primaryBlockchain != null && primaryWalletManager != null) { if (primaryBlockchain != null && primaryWalletManager != null) {
@ -205,9 +206,10 @@ class TapWalletManager {
) )
} else { } else {
val derivationStyle = scanResponse.card.derivationStyle
val blockchainNetworks = listOf( val blockchainNetworks = listOf(
BlockchainNetwork(Blockchain.Bitcoin,null, emptyList()), BlockchainNetwork(Blockchain.Bitcoin, scanResponse.card),
BlockchainNetwork(Blockchain.Ethereum,null, emptyList()) BlockchainNetwork(Blockchain.Ethereum, scanResponse.card)
) )
val walletManagers = walletManagerFactory.makeWalletManagersForApp( val walletManagers = walletManagerFactory.makeWalletManagersForApp(

View file

@ -28,6 +28,7 @@ import com.tangem.operations.issuerAndUserData.ReadIssuerDataCommand
import com.tangem.tap.domain.ProductType import com.tangem.tap.domain.ProductType
import com.tangem.tap.domain.TapSdkError import com.tangem.tap.domain.TapSdkError
import com.tangem.tap.domain.TapWorkarounds import com.tangem.tap.domain.TapWorkarounds
import com.tangem.tap.domain.TapWorkarounds.derivationStyle
import com.tangem.tap.domain.TapWorkarounds.getTangemNoteBlockchain import com.tangem.tap.domain.TapWorkarounds.getTangemNoteBlockchain
import com.tangem.tap.domain.TapWorkarounds.isExcluded import com.tangem.tap.domain.TapWorkarounds.isExcluded
import com.tangem.tap.domain.TapWorkarounds.isNotSupportedInThatRelease import com.tangem.tap.domain.TapWorkarounds.isNotSupportedInThatRelease
@ -275,7 +276,7 @@ private class ScanWalletProcessor(
private fun getBlockchainsToDerive(card: Card): List<BlockchainNetwork> { private fun getBlockchainsToDerive(card: Card): List<BlockchainNetwork> {
val currenciesRepository = currenciesRepository ?: return emptyList() val currenciesRepository = currenciesRepository ?: return emptyList()
val cardCurrencies = currenciesRepository.loadSavedCurrencies(card.cardId).toMutableList() val cardCurrencies = currenciesRepository.loadSavedCurrencies(card.cardId, card.derivationStyle).toMutableList()
val blockchainsToDerive = cardCurrencies.ifEmpty { val blockchainsToDerive = cardCurrencies.ifEmpty {
mutableListOf( mutableListOf(

View file

@ -98,13 +98,19 @@ class CurrenciesRepository(val context: Application) {
} }
} }
fun loadSavedCurrencies(cardId: String): List<BlockchainNetwork> { fun loadSavedCurrencies(
cardId: String,
derivationStyle: DerivationStyle? = null
): List<BlockchainNetwork> {
if (DemoHelper.isDemoCardId(cardId)) { if (DemoHelper.isDemoCardId(cardId)) {
return loadDemoCurrencies(cardId) return loadDemoCurrencies(cardId)
} }
return try { return try {
val json = context.readFileText(getFileNameForBlockchains(cardId)) val json = context.readFileText(getFileNameForBlockchains(cardId))
blockchainNetworkAdapter.fromJson(json)?.distinct() ?: loadSavedCurrenciesOldWay(cardId) blockchainNetworkAdapter.fromJson(json)?.distinct() ?: loadSavedCurrenciesOldWay(
cardId,
derivationStyle
)
} catch (exception: Exception) { } catch (exception: Exception) {
emptyList() emptyList()
} }
@ -120,16 +126,25 @@ class CurrenciesRepository(val context: Application) {
} }
} }
private fun loadSavedCurrenciesOldWay(cardId: String): List<BlockchainNetwork> { private fun loadSavedCurrenciesOldWay(
cardId: String, derivationStyle: DerivationStyle?
): List<BlockchainNetwork> {
val blockchains = loadSavedBlockchains(cardId) val blockchains = loadSavedBlockchains(cardId)
val tokens = loadSavedTokens(cardId) val tokens = loadSavedTokens(cardId)
val currencies = getSupportedTokens()
val blockchainNetworks = blockchains.map { blockchain -> val blockchainNetworks = blockchains.map { blockchain ->
BlockchainNetwork( BlockchainNetwork(
blockchain = blockchain, blockchain = blockchain,
derivationPath = null, derivationPath = blockchain.derivationPath(derivationStyle)?.rawPath,
tokens = tokens tokens = tokens
.filter { it.blockchainDao.toBlockchain() == blockchain } .filter { it.blockchainDao.toBlockchain() == blockchain }
.map { it.toToken() } .map {
val token = it.toToken()
val id = currencies
.find { it.contracts?.find { it.address == token.contractAddress } != null }
?.id
token.copy(id = id)
}
) )
} }
saveCurrencies(cardId, blockchainNetworks) // migrate saved currencies saveCurrencies(cardId, blockchainNetworks) // migrate saved currencies
@ -178,17 +193,6 @@ class CurrenciesRepository(val context: Application) {
return obsoleteTokensAdapter.fromJson(tokenJson)!!.map { it.toTokenDao(blockchain) } return obsoleteTokensAdapter.fromJson(tokenJson)!!.map { it.toTokenDao(blockchain) }
} }
private fun getSupportedTokens(): List<Blockchain> {
return listOf(
Blockchain.Ethereum,
Blockchain.BSC,
Blockchain.Binance,
Blockchain.Polygon,
Blockchain.Avalanche,
Blockchain.Fantom,
)
}
fun getBlockchains( fun getBlockchains(
cardFirmware: FirmwareVersion, cardFirmware: FirmwareVersion,
isTestNet: Boolean = false isTestNet: Boolean = false

View file

@ -26,7 +26,7 @@ data class CurrenciesFromJson(
fun List<ContractFromJson>.toContracts(): List<Contract> { fun List<ContractFromJson>.toContracts(): List<Contract> {
return map { Contract.fromJsonObject(it) } return mapNotNull { Contract.fromJsonObject(it) }
} }
data class Currency( data class Currency(
@ -59,10 +59,11 @@ data class Contract(
) { ) {
companion object { companion object {
fun fromJsonObject(contract: ContractFromJson): Contract { fun fromJsonObject(contract: ContractFromJson): Contract? {
val blockchain = Blockchain.fromNetworkId(contract.networkId) ?: return null
return Contract( return Contract(
networkId = contract.networkId, networkId = contract.networkId,
blockchain = Blockchain.fromNetworkId(contract.networkId), blockchain = blockchain,
address = contract.address, address = contract.address,
decimalCount = contract.decimalCount, decimalCount = contract.decimalCount,
iconUrl = getIconUrl(contract.networkId) iconUrl = getIconUrl(contract.networkId)
@ -76,7 +77,7 @@ fun getIconUrl(id: String): String {
} }
fun Blockchain.Companion.fromNetworkId(networkId: String): Blockchain { fun Blockchain.Companion.fromNetworkId(networkId: String): Blockchain? {
return when (networkId) { return when (networkId) {
"avalanche" -> Blockchain.Avalanche "avalanche" -> Blockchain.Avalanche
"binancecoin" -> Blockchain.Binance "binancecoin" -> Blockchain.Binance
@ -95,7 +96,7 @@ fun Blockchain.Companion.fromNetworkId(networkId: String): Blockchain {
"stellar" -> Blockchain.Stellar "stellar" -> Blockchain.Stellar
"tezos" -> Blockchain.Tezos "tezos" -> Blockchain.Tezos
"ripple" -> Blockchain.XRP "ripple" -> Blockchain.XRP
else -> Blockchain.Unknown else -> null
} }
} }
@ -103,7 +104,7 @@ fun Blockchain.toNetworkId(): String {
return when (this) { return when (this) {
Blockchain.Unknown -> "unknown" Blockchain.Unknown -> "unknown"
Blockchain.Avalanche -> "avalanche" Blockchain.Avalanche -> "avalanche"
Blockchain.AvalancheTestnet -> "avalaunch" Blockchain.AvalancheTestnet -> "avalaunche"
Blockchain.Binance -> "binancecoin" Blockchain.Binance -> "binancecoin"
Blockchain.BinanceTestnet -> "binancecoin" Blockchain.BinanceTestnet -> "binancecoin"
Blockchain.BSC -> "binance-smart-chain" Blockchain.BSC -> "binance-smart-chain"

View file

@ -257,7 +257,7 @@ class WalletConnectMiddleware {
blockchainToMake, blockchainToMake,
card.derivationStyle?.let { DerivationParams.Default(it) } card.derivationStyle?.let { DerivationParams.Default(it) }
) )
if (currenciesRepository.loadSavedCurrencies(card.cardId) if (currenciesRepository.loadSavedCurrencies(card.cardId, card.derivationStyle)
.find { it.blockchain == blockchainToMake } != null .find { it.blockchain == blockchainToMake } != null
) { ) {
walletManager?.let { walletManager?.let {

View file

@ -106,6 +106,7 @@ class AdditionalEmailInfo {
var address: String = "", var address: String = "",
var explorerLink: String = "", var explorerLink: String = "",
var host: String = "", var host: String = "",
var derivationPath: String = "",
) )
var appVersion: String = "" var appVersion: String = ""
@ -159,7 +160,8 @@ class AdditionalEmailInfo {
blockchain = manager.wallet.blockchain, blockchain = manager.wallet.blockchain,
address = getAddress(manager.wallet), address = getAddress(manager.wallet),
explorerLink = getExploreUri(manager.wallet), explorerLink = getExploreUri(manager.wallet),
host = manager.currentHost host = manager.currentHost,
derivationPath = manager.wallet.publicKey.derivationPath?.rawPath ?: ""
) )
) )
if (manager.cardTokens.isNotEmpty()) { if (manager.cardTokens.isNotEmpty()) {
@ -173,7 +175,8 @@ class AdditionalEmailInfo {
blockchain = wallet.blockchain, blockchain = wallet.blockchain,
address = getAddress(wallet), address = getAddress(wallet),
explorerLink = getExploreUri(wallet), explorerLink = getExploreUri(wallet),
host = host host = host,
derivationPath = wallet.publicKey.derivationPath?.rawPath ?: ""
) )
this.destinationAddress = destinationAddress this.destinationAddress = destinationAddress
@ -325,6 +328,7 @@ class EmailDataBuilder(
builder.appendKeyValue("Blockchain", it.blockchain.fullName) builder.appendKeyValue("Blockchain", it.blockchain.fullName)
builder.appendKeyValue("Host", it.host) builder.appendKeyValue("Host", it.host)
builder.appendKeyValue("Wallet address", it.address) builder.appendKeyValue("Wallet address", it.address)
builder.appendKeyValue("Derivation path", it.derivationPath)
builder.appendKeyValue("Explorer link", it.explorerLink) builder.appendKeyValue("Explorer link", it.explorerLink)
infoHolder.tokens[it.blockchain]?.let { tokens -> infoHolder.tokens[it.blockchain]?.let { tokens ->
@ -332,6 +336,7 @@ class EmailDataBuilder(
appendLine() appendLine()
tokens.forEach { token -> tokens.forEach { token ->
builder.appendKeyValue("Name", token.name) builder.appendKeyValue("Name", token.name)
if (token.id != null) builder.appendKeyValue("Id", token.id ?: "")
builder.appendKeyValue("Contract address", token.contractAddress) builder.appendKeyValue("Contract address", token.contractAddress)
} }
} }
@ -342,6 +347,7 @@ class EmailDataBuilder(
fun appendTxFailedBlockchainInfo(error: String): EmailDataBuilder { fun appendTxFailedBlockchainInfo(error: String): EmailDataBuilder {
val walletInfo = infoHolder.onSendErrorWalletInfo ?: AdditionalEmailInfo.EmailWalletInfo() val walletInfo = infoHolder.onSendErrorWalletInfo ?: AdditionalEmailInfo.EmailWalletInfo()
builder.appendKeyValue("Blockchain", walletInfo.blockchain.fullName) builder.appendKeyValue("Blockchain", walletInfo.blockchain.fullName)
builder.appendKeyValue("Derivation path", walletInfo.derivationPath)
builder.appendKeyValue("Host", walletInfo.host) builder.appendKeyValue("Host", walletInfo.host)
builder.appendKeyValue("Token", infoHolder.token) builder.appendKeyValue("Token", infoHolder.token)
builder.appendKeyValue("Error", error) builder.appendKeyValue("Error", error)

View file

@ -14,8 +14,13 @@ import androidx.fragment.app.Fragment
import androidx.transition.TransitionInflater import androidx.transition.TransitionInflater
import by.kirich1409.viewbindingdelegate.viewBinding import by.kirich1409.viewbindingdelegate.viewBinding
import com.google.accompanist.appcompattheme.AppCompatTheme import com.google.accompanist.appcompattheme.AppCompatTheme
import com.tangem.blockchain.common.Blockchain
import com.tangem.tap.common.extensions.copyToClipboard
import com.tangem.tap.common.extensions.dispatchNotification
import com.tangem.tap.common.extensions.getString import com.tangem.tap.common.extensions.getString
import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.features.tokens.redux.ContractAddress
import com.tangem.tap.features.tokens.redux.TokenWithBlockchain
import com.tangem.tap.features.tokens.redux.TokensAction import com.tangem.tap.features.tokens.redux.TokensAction
import com.tangem.tap.features.tokens.redux.TokensState import com.tangem.tap.features.tokens.redux.TokensState
import com.tangem.tap.features.tokens.ui.compose.CurrenciesScreen import com.tangem.tap.features.tokens.ui.compose.CurrenciesScreen
@ -68,14 +73,22 @@ class AddTokensFragment : Fragment(R.layout.fragment_add_tokens),
(activity as? AppCompatActivity)?.setSupportActionBar(toolbar) (activity as? AppCompatActivity)?.setSupportActionBar(toolbar)
toolbar.setNavigationOnClickListener { activity?.onBackPressed() } toolbar.setNavigationOnClickListener { activity?.onBackPressed() }
val onSaveChanges = { tokens: List<TokenWithBlockchain>, blockchains: List<Blockchain> ->
store.dispatch(TokensAction.SaveChanges(tokens, blockchains))
}
val onNetworkItemClicked = { contractAddress: ContractAddress ->
context?.copyToClipboard(contractAddress)
store.dispatchNotification(R.string.contract_address_copied_message)
}
cvCurrencies.setContent { cvCurrencies.setContent {
AppCompatTheme { AppCompatTheme {
CurrenciesScreen( CurrenciesScreen(
tokensState = tokensState, tokensState = tokensState,
searchInput = searchInput searchInput = searchInput,
) { tokens, blockchains -> onSaveChanges = onSaveChanges,
store.dispatch(TokensAction.SaveChanges(tokens, blockchains)) onNetworkItemClicked = onNetworkItemClicked
} )
} }
} }
} }

View file

@ -36,11 +36,7 @@ fun CollapsedCurrencyItem(
.clickable(onClick = { onCurrencyClick(currency.id) }) .clickable(onClick = { onCurrencyClick(currency.id) })
) { ) {
val blockchain = Blockchain.fromNetworkId(currency.id) val blockchain = Blockchain.fromNetworkId(currency.id)
val iconRes = if (blockchain == Blockchain.Unknown) { val iconRes = currency.iconUrl
currency.iconUrl
} else {
blockchain.getRoundIconRes()
}
SubcomposeAsyncImage( SubcomposeAsyncImage(
model = iconRes, model = iconRes,
@ -66,32 +62,36 @@ fun CollapsedCurrencyItem(
) )
Spacer(modifier = Modifier.size(6.dp)) Spacer(modifier = Modifier.size(6.dp))
Row { Row {
if (currency.contracts != null) { if (!currency.contracts.isNullOrEmpty()) {
currency.contracts.map { contract -> currency.contracts.map { contract ->
val added = if (contract.address == currency.symbol) {
addedTokens.map { it.token.contractAddress }.contains(contract.address) BlockchainNetworkItem(
val icon = if (added) { blockchain = Blockchain.fromNetworkId(contract.networkId),
contract.blockchain.getRoundIconRes() addedBlockchains = addedBlockchains
)
} else { } else {
contract.blockchain.getGreyedOutIconRes() val added =
addedTokens.map { it.token.contractAddress }
.contains(contract.address)
val icon = if (added) {
contract.blockchain.getRoundIconRes()
} else {
contract.blockchain.getGreyedOutIconRes()
}
Image(
painter = painterResource(id = icon),
contentDescription = null,
Modifier
.size(20.dp)
)
Spacer(modifier = Modifier.size(5.dp))
} }
Image(
painter = painterResource(id = icon),
contentDescription = null,
Modifier
.size(20.dp)
)
Spacer(modifier = Modifier.size(5.dp))
} }
} else { } else {
val added = addedBlockchains.contains(blockchain) BlockchainNetworkItem(
val icon = blockchain = blockchain,
if (added) blockchain.getRoundIconRes() else blockchain.getGreyedOutIconRes() addedBlockchains = addedBlockchains
Image(
painter = painterResource(id = icon),
contentDescription = null,
Modifier
.size(20.dp)
) )
} }
} }
@ -105,4 +105,23 @@ fun CollapsedCurrencyItem(
) )
} }
}
@Composable
fun BlockchainNetworkItem(
blockchain: Blockchain?,
addedBlockchains: List<Blockchain>
) {
val added = addedBlockchains.contains(blockchain)
val icon =
if (added) blockchain?.getRoundIconRes() else blockchain?.getGreyedOutIconRes()
if (icon != null) {
Image(
painter = painterResource(id = icon),
contentDescription = null,
Modifier
.size(20.dp)
)
Spacer(modifier = Modifier.size(5.dp))
}
} }

View file

@ -1,5 +1,6 @@
package com.tangem.tap.features.tokens.ui.compose package com.tangem.tap.features.tokens.ui.compose
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material.ExtendedFloatingActionButton import androidx.compose.material.ExtendedFloatingActionButton
import androidx.compose.material.FabPosition import androidx.compose.material.FabPosition
@ -17,6 +18,7 @@ import com.tangem.tap.common.compose.keyboardAsState
import com.tangem.tap.common.extensions.pixelsToDp import com.tangem.tap.common.extensions.pixelsToDp
import com.tangem.tap.domain.tokens.Currency import com.tangem.tap.domain.tokens.Currency
import com.tangem.tap.domain.tokens.fromNetworkId import com.tangem.tap.domain.tokens.fromNetworkId
import com.tangem.tap.features.tokens.redux.ContractAddress
import com.tangem.tap.features.tokens.redux.TokenWithBlockchain import com.tangem.tap.features.tokens.redux.TokenWithBlockchain
import com.tangem.tap.features.tokens.redux.TokensState import com.tangem.tap.features.tokens.redux.TokensState
import com.tangem.tap.store import com.tangem.tap.store
@ -26,7 +28,8 @@ import com.tangem.wallet.R
fun CurrenciesScreen( fun CurrenciesScreen(
tokensState: MutableState<TokensState> = mutableStateOf(store.state.tokensState), tokensState: MutableState<TokensState> = mutableStateOf(store.state.tokensState),
searchInput: MutableState<String>, searchInput: MutableState<String>,
onSaveChanges: (List<TokenWithBlockchain>, List<Blockchain>) -> Unit onSaveChanges: (List<TokenWithBlockchain>, List<Blockchain>) -> Unit,
onNetworkItemClicked: (ContractAddress) -> Unit
) { ) {
val addedTokensState = remember { mutableStateOf(tokensState.value.addedTokens) } val addedTokensState = remember { mutableStateOf(tokensState.value.addedTokens) }
@ -49,7 +52,7 @@ fun CurrenciesScreen(
if (mutableList.contains(blockchain)) { if (mutableList.contains(blockchain)) {
mutableList.remove(blockchain) mutableList.remove(blockchain)
} else { } else {
mutableList.add(blockchain) blockchain?.let { mutableList.add(blockchain) }
} }
addedBlockchainsState.value = mutableList addedBlockchainsState.value = mutableList
} }
@ -65,16 +68,21 @@ fun CurrenciesScreen(
floatingActionButtonPosition = FabPosition.Center, floatingActionButtonPosition = FabPosition.Center,
) { ) {
ListOfCurrencies( Column {
currencies = tokensState.value.currencies, if (tokensState.value.allowToAdd) CurrenciesWarning()
nonRemovableTokens = tokensState.value.nonRemovableTokens, ListOfCurrencies(
nonRemovableBlockchains = tokensState.value.nonRemovableBlockchains, currencies = tokensState.value.currencies,
addedTokens = addedTokensState.value, nonRemovableTokens = tokensState.value.nonRemovableTokens,
addedBlockchains = addedBlockchainsState.value, nonRemovableBlockchains = tokensState.value.nonRemovableBlockchains,
searchInput = searchInput.value, addedTokens = addedTokensState.value,
allowToAdd = tokensState.value.allowToAdd, addedBlockchains = addedBlockchainsState.value,
onAddCurrencyToggled = onAddCurrencyToggleClick searchInput = searchInput.value,
) allowToAdd = tokensState.value.allowToAdd,
onAddCurrencyToggled = onAddCurrencyToggleClick,
onNetworkItemClicked = onNetworkItemClicked
)
}
} }
} }

View file

@ -0,0 +1,53 @@
package com.tangem.tap.features.tokens.ui.compose
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.tangem.wallet.R
@Composable
fun CurrenciesWarning() {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.padding(16.dp)
.background(Color(0xFFF2F2F2), shape = RoundedCornerShape(10.dp))
)
{
val warning = stringResource(id = R.string.alert_manage_tokens_addresses_message)
val end = warning.indexOf(" ")
val spanStyles = listOf(
AnnotatedString.Range(
SpanStyle(fontWeight = FontWeight.Bold),
start = 0,
end = end
)
)
Text(
text = AnnotatedString(text = warning, spanStyles = spanStyles),
textAlign = TextAlign.Center,
color = Color(0xFF848488),
modifier = Modifier.padding(
top = 8.dp,
bottom = 8.dp,
start = 16.dp,
end = 16.dp
),
fontSize = 13.sp,
fontWeight = FontWeight.Normal,
)
}
}

View file

@ -16,7 +16,8 @@ fun CurrencyItem(
allowToAdd: Boolean, allowToAdd: Boolean,
expanded: Boolean, expanded: Boolean,
onCurrencyClick: (String) -> Unit, onCurrencyClick: (String) -> Unit,
onAddCurrencyToggled: (Currency, TokenWithBlockchain?) -> Unit onAddCurrencyToggled: (Currency, TokenWithBlockchain?) -> Unit,
onNetworkItemClicked: (ContractAddress) -> Unit
) { ) {
if (expanded) { if (expanded) {
ExpandedCurrencyItem( ExpandedCurrencyItem(
@ -26,7 +27,8 @@ fun CurrencyItem(
addedTokens = addedTokens, addedTokens = addedTokens,
addedBlockchains = addedBlockchains, addedBlockchains = addedBlockchains,
allowToAdd = allowToAdd, allowToAdd = allowToAdd,
onCurrencyClick = onCurrencyClick, onAddCurrencyToggled = onAddCurrencyToggled onCurrencyClick = onCurrencyClick, onAddCurrencyToggled = onAddCurrencyToggled,
onNetworkItemClicked = onNetworkItemClicked
) )
} else { } else {
CollapsedCurrencyItem( CollapsedCurrencyItem(

View file

@ -18,7 +18,6 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import coil.compose.SubcomposeAsyncImage import coil.compose.SubcomposeAsyncImage
import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.Blockchain
import com.tangem.tap.common.extensions.getRoundIconRes
import com.tangem.tap.domain.tokens.Currency import com.tangem.tap.domain.tokens.Currency
import com.tangem.tap.domain.tokens.fromNetworkId import com.tangem.tap.domain.tokens.fromNetworkId
import com.tangem.tap.features.tokens.redux.ContractAddress import com.tangem.tap.features.tokens.redux.ContractAddress
@ -34,14 +33,11 @@ fun ExpandedCurrencyItem(
addedBlockchains: List<Blockchain>, addedBlockchains: List<Blockchain>,
allowToAdd: Boolean, allowToAdd: Boolean,
onCurrencyClick: (String) -> Unit, onCurrencyClick: (String) -> Unit,
onAddCurrencyToggled: (Currency, TokenWithBlockchain?) -> Unit onAddCurrencyToggled: (Currency, TokenWithBlockchain?) -> Unit,
onNetworkItemClicked: (ContractAddress) -> Unit
) { ) {
val blockchain = Blockchain.fromNetworkId(currency.id) val blockchain = Blockchain.fromNetworkId(currency.id)
val iconRes = if (blockchain == Blockchain.Unknown) { val iconRes = currency.iconUrl
currency.iconUrl
} else {
blockchain.getRoundIconRes()
}
Column { Column {
Row( Row(
@ -89,7 +85,7 @@ fun ExpandedCurrencyItem(
) )
} }
val blockchains = currency.contracts?.map { it.blockchain } ?: listOf( val blockchains = currency.contracts?.map { it.blockchain } ?: listOfNotNull(
Blockchain.fromNetworkId(currency.id) Blockchain.fromNetworkId(currency.id)
) )
@ -99,11 +95,18 @@ fun ExpandedCurrencyItem(
.fillMaxHeight() .fillMaxHeight()
) { ) {
if (blockchains.size > 1) { if (blockchains.size > 1) {
val dividerHeight = if (blockchains.size == 2) {
60
} else if (blockchains.size == 3) {
110
} else {
43 * blockchains.size
}
Divider( Divider(
color = Color(0xFFDEDEDE), color = Color(0xFFDEDEDE),
modifier = Modifier modifier = Modifier
.height((43 * blockchains.size - 1).dp) .height(dividerHeight.dp)
.padding(start = 37.dp, top = 16.dp) .padding(start = 37.5.dp)
.width(1.dp) .width(1.dp)
) )
} }
@ -130,12 +133,12 @@ fun ExpandedCurrencyItem(
) { ) {
blockchains.map { blockchain -> blockchains.map { blockchain ->
val contract = currency.contracts?.firstOrNull { it.blockchain == blockchain } val contract = currency.contracts?.firstOrNull { it.blockchain == blockchain }
val added = if (contract != null) { val added = if (contract != null && contract.address != currency.symbol) {
addedTokens.map { it.token.contractAddress }.contains(contract.address) addedTokens.map { it.token.contractAddress }.contains(contract.address)
} else { } else {
addedBlockchains.contains(blockchain) addedBlockchains.contains(blockchain)
} }
val canBeRemoved = if (contract != null) { val canBeRemoved = if (contract != null && contract.address != currency.symbol) {
!nonRemovableTokens.contains(contract.address) !nonRemovableTokens.contains(contract.address)
} else { } else {
!nonRemovableBlockchains.contains(blockchain) !nonRemovableBlockchains.contains(blockchain)
@ -146,7 +149,8 @@ fun ExpandedCurrencyItem(
blockchain = blockchain, allowToAdd = allowToAdd, blockchain = blockchain, allowToAdd = allowToAdd,
added = added, added = added,
canBeRemoved = canBeRemoved, canBeRemoved = canBeRemoved,
onAddCurrencyToggled = onAddCurrencyToggled onAddCurrencyToggled = onAddCurrencyToggled,
onNetworkItemClicked = onNetworkItemClicked,
) )
} }
} }

View file

@ -22,7 +22,8 @@ fun ListOfCurrencies(
addedBlockchains: List<Blockchain>, addedBlockchains: List<Blockchain>,
searchInput: String, searchInput: String,
allowToAdd: Boolean, allowToAdd: Boolean,
onAddCurrencyToggled: (Currency, TokenWithBlockchain?) -> Unit onAddCurrencyToggled: (Currency, TokenWithBlockchain?) -> Unit,
onNetworkItemClicked: (ContractAddress) -> Unit
) { ) {
val expandedCurrencies = remember { mutableStateOf(listOf("")) } val expandedCurrencies = remember { mutableStateOf(listOf("")) }
@ -59,7 +60,8 @@ fun ListOfCurrencies(
allowToAdd = allowToAdd, allowToAdd = allowToAdd,
expanded = expandedCurrencies.value.contains(currency.id), expanded = expandedCurrencies.value.contains(currency.id),
onCurrencyClick = onCurrencyClick, onCurrencyClick = onCurrencyClick,
onAddCurrencyToggled = onAddCurrencyToggled onAddCurrencyToggled = onAddCurrencyToggled,
onNetworkItemClicked = onNetworkItemClicked
) )
} }

View file

@ -1,5 +1,7 @@
package com.tangem.tap.features.tokens.ui.compose package com.tangem.tap.features.tokens.ui.compose
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.Switch import androidx.compose.material.Switch
@ -21,19 +23,27 @@ import com.tangem.tap.common.extensions.getNetworkName
import com.tangem.tap.common.extensions.getRoundIconRes import com.tangem.tap.common.extensions.getRoundIconRes
import com.tangem.tap.domain.tokens.Contract import com.tangem.tap.domain.tokens.Contract
import com.tangem.tap.domain.tokens.Currency import com.tangem.tap.domain.tokens.Currency
import com.tangem.tap.features.tokens.redux.ContractAddress
import com.tangem.tap.features.tokens.redux.TokenWithBlockchain import com.tangem.tap.features.tokens.redux.TokenWithBlockchain
@OptIn(ExperimentalFoundationApi::class)
@Composable @Composable
fun NetworkItem( fun NetworkItem(
currency: Currency, contract: Contract?, currency: Currency, contract: Contract?,
blockchain: Blockchain, allowToAdd: Boolean, blockchain: Blockchain, allowToAdd: Boolean,
added: Boolean, canBeRemoved: Boolean, added: Boolean, canBeRemoved: Boolean,
onAddCurrencyToggled: (Currency, TokenWithBlockchain?) -> Unit onAddCurrencyToggled: (Currency, TokenWithBlockchain?) -> Unit,
onNetworkItemClicked: (ContractAddress) -> Unit
) { ) {
val isBlockchain = contract == null || contract.address == currency.symbol
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.combinedClickable {
if (contract != null) onNetworkItemClicked(contract.address)
}
) { ) {
SubcomposeAsyncImage( SubcomposeAsyncImage(
model = if (added) blockchain.getRoundIconRes() else blockchain.getGreyedOutIconRes(), model = if (added) blockchain.getRoundIconRes() else blockchain.getGreyedOutIconRes(),
@ -46,10 +56,12 @@ fun NetworkItem(
.size(20.dp) .size(20.dp)
.align(Alignment.CenterVertically) .align(Alignment.CenterVertically)
) )
Row(modifier = Modifier Row(
.fillMaxHeight() modifier = Modifier
.weight(1f) .fillMaxHeight()
.align(Alignment.CenterVertically)) { .weight(1f)
.align(Alignment.CenterVertically)
) {
Text( Text(
text = blockchain.name.uppercase(), text = blockchain.name.uppercase(),
fontSize = 13.sp, fontSize = 13.sp,
@ -58,30 +70,43 @@ fun NetworkItem(
) )
Spacer(modifier = Modifier.size(3.dp)) Spacer(modifier = Modifier.size(3.dp))
Text( Text(
text = if (contract != null) blockchain.getNetworkName().uppercase() else "MAIN", text = if (isBlockchain) "MAIN" else blockchain.getNetworkName().uppercase(),
fontSize = 13.sp, fontSize = 13.sp,
fontWeight = FontWeight.Normal, fontWeight = FontWeight.Normal,
color = if (contract != null) Color(0xFF8E8E93) else Color(0xFF1ACE80), color = if (!isBlockchain) Color(0xFF8E8E93) else Color(0xFF1ACE80),
) )
} }
val token = if (contract != null) { if (allowToAdd) {
Token( val token = if (!isBlockchain) {
name = currency.name, symbol = currency.symbol, contractAddress = contract.address, Token(
decimals = contract.decimalCount, id = currency.id,
name = currency.name,
symbol = currency.symbol,
contractAddress = contract!!.address,
decimals = contract.decimalCount,
)
} else {
null
}
val tokenWithBlockchain =
token?.let { TokenWithBlockchain(token, contract!!.blockchain) }
val currencyToSave = if (isBlockchain && contract != null) {
currency.copy(id = contract.networkId)
} else {
currency
}
Switch(
checked = added,
enabled = canBeRemoved,
onCheckedChange = { onAddCurrencyToggled(currencyToSave, tokenWithBlockchain) },
modifier = Modifier.padding(start = 16.dp, end = 16.dp),
colors = SwitchDefaults.colors(
checkedThumbColor = Color(0xFF1ACE80)
)
) )
} else {
null
} }
val tokenWithBlockchain = token?.let { TokenWithBlockchain(token, contract!!.blockchain) }
if (allowToAdd) Switch(
checked = added,
enabled = canBeRemoved,
onCheckedChange = { onAddCurrencyToggled(currency, tokenWithBlockchain) },
modifier = Modifier.padding(start = 16.dp, end = 16.dp),
colors = SwitchDefaults.colors(
checkedThumbColor = Color(0xFF1ACE80)
)
)
} }
} }

View file

@ -127,11 +127,7 @@ class MultiWalletMiddleware {
val coinAmount = wallet.amounts[AmountType.Coin]?.value val coinAmount = wallet.amounts[AmountType.Coin]?.value
if (coinAmount != null && !coinAmount.isZero()) { if (coinAmount != null && !coinAmount.isZero()) {
scope.launch(Dispatchers.Main) { scope.launch(Dispatchers.Main) {
val blockchainNetwork = BlockchainNetwork( val blockchainNetwork = BlockchainNetwork.fromWalletManager(walletManager)
wallet.blockchain,
null,
walletManager.cardTokens.toList()
)
if (walletState?.getWalletData(blockchainNetwork) == null) { if (walletState?.getWalletData(blockchainNetwork) == null) {
store.dispatch( store.dispatch(
WalletAction.MultiWallet.AddBlockchain( WalletAction.MultiWallet.AddBlockchain(

View file

@ -11,6 +11,7 @@ import com.tangem.blockchain.common.Token
import com.tangem.tap.common.extensions.getString import com.tangem.tap.common.extensions.getString
import com.tangem.tap.common.extensions.loadCurrenciesIcon import com.tangem.tap.common.extensions.loadCurrenciesIcon
import com.tangem.tap.common.extensions.show import com.tangem.tap.common.extensions.show
import com.tangem.tap.domain.TapWorkarounds.derivationStyle
import com.tangem.tap.features.wallet.redux.Currency import com.tangem.tap.features.wallet.redux.Currency
import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.features.wallet.redux.WalletData import com.tangem.tap.features.wallet.redux.WalletData
@ -26,7 +27,11 @@ class WalletAdapter
return currentList[position].currencyData.currencySymbol?.hashCode()?.toLong() ?: 0 return currentList[position].currencyData.currencySymbol?.hashCode()?.toLong() ?: 0
} }
fun submitList(list: List<WalletData>, primaryBlockchain: Blockchain?, primaryToken: Token? = null) { fun submitList(
list: List<WalletData>,
primaryBlockchain: Blockchain?,
primaryToken: Token? = null
) {
// We used this method to sort the list of currencies. Sorting is disabled for now. // We used this method to sort the list of currencies. Sorting is disabled for now.
super.submitList(list) super.submitList(list)
} }
@ -44,21 +49,22 @@ class WalletAdapter
object DiffUtilCallback : DiffUtil.ItemCallback<WalletData>() { object DiffUtilCallback : DiffUtil.ItemCallback<WalletData>() {
override fun areContentsTheSame( override fun areContentsTheSame(
oldItem: WalletData, newItem: WalletData oldItem: WalletData, newItem: WalletData
) = oldItem == newItem ) = oldItem == newItem
override fun areItemsTheSame( override fun areItemsTheSame(
oldItem: WalletData, newItem: WalletData oldItem: WalletData, newItem: WalletData
) = oldItem == newItem ) = oldItem == newItem
} }
class WalletsViewHolder(val binding: ItemCurrencyWalletBinding) : class WalletsViewHolder(val binding: ItemCurrencyWalletBinding) :
RecyclerView.ViewHolder(binding.root) { RecyclerView.ViewHolder(binding.root) {
fun bind(wallet: WalletData) = with(binding) { fun bind(wallet: WalletData) = with(binding) {
tvCurrency.text = wallet.currencyData.currency tvCurrency.text = wallet.currencyData.currency
tvAmount.text = wallet.currencyData.amountFormatted?.takeWhile { !it.isWhitespace() } tvAmount.text = wallet.currencyData.amountFormatted?.takeWhile { !it.isWhitespace() }
tvCurrencySymbol.text = wallet.currencyData.amountFormatted?.takeLastWhile { !it.isWhitespace() } tvCurrencySymbol.text =
wallet.currencyData.amountFormatted?.takeLastWhile { !it.isWhitespace() }
tvAmountFiat.text = wallet.currencyData.fiatAmountFormatted tvAmountFiat.text = wallet.currencyData.fiatAmountFormatted
tvExchangeRate.text = wallet.fiatRateString tvExchangeRate.text = wallet.fiatRateString
cardWallet.setOnClickListener { cardWallet.setOnClickListener {
@ -67,6 +73,11 @@ class WalletAdapter
val blockchain = wallet.currency.blockchain val blockchain = wallet.currency.blockchain
val token = (wallet.currency as? Currency.Token)?.token val token = (wallet.currency as? Currency.Token)?.token
val isCustom =
wallet.currency.isCustomCurrency(store.state.globalState.scanResponse?.card?.derivationStyle)
tvExchangeRate.show(!isCustom)
tvCustomCurrency.show(isCustom)
Picasso.get().loadCurrenciesIcon( Picasso.get().loadCurrenciesIcon(
imageView = ivCurrency, imageView = ivCurrency,
textView = tvTokenLetter, textView = tvTokenLetter,

View file

@ -117,6 +117,21 @@
app:layout_constraintTop_toTopOf="@id/guideline" app:layout_constraintTop_toTopOf="@id/guideline"
tools:text="USD 3 588" /> tools:text="USD 3 588" />
<TextView
android:id="@+id/tv_custom_currency"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:paddingStart="4dp"
android:paddingEnd="4dp"
android:textColor="@color/darkGray2"
android:textSize="14sp"
android:background="@drawable/shape_rectangle_rounded_4"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/iv_currency"
app:layout_constraintTop_toTopOf="@id/guideline"
android:text="@string/common_custom" />
<TextView <TextView
android:id="@+id/tv_status_error_message" android:id="@+id/tv_status_error_message"
android:layout_width="0dp" android:layout_width="0dp"

View file

@ -38,5 +38,9 @@
<string name="token_details_send_blocked_fee_format">Not enough funds for fee on your %s wallet to send a transaction. Top up your %s wallet first.</string> <string name="token_details_send_blocked_fee_format">Not enough funds for fee on your %s wallet to send a transaction. Top up your %s wallet first.</string>
<string name="currency_subtitle_expanded">Available networks</string> <string name="currency_subtitle_expanded">Available networks</string>
<string name="alert_manage_tokens_addresses_message">Note that tokens on different networks have different addresses. Double check that your address matches the network when you transfer funds.</string>
<string name="contract_address_copied_message">Contract address copied!</string>
<string name="common_custom">Custom</string>
</resources> </resources>

View file

@ -38,4 +38,9 @@
<string name="token_details_send_blocked_fee_format">Not enough funds for fee on your %s wallet to send a transaction. Top up your %s wallet first.</string> <string name="token_details_send_blocked_fee_format">Not enough funds for fee on your %s wallet to send a transaction. Top up your %s wallet first.</string>
<string name="currency_subtitle_expanded">Available networks</string> <string name="currency_subtitle_expanded">Available networks</string>
<string name="alert_manage_tokens_addresses_message">Note that tokens on different networks have different addresses. Double check that your address matches the network when you transfer funds.</string>
<string name="contract_address_copied_message">Contract address copied!</string>
<string name="common_custom">Custom</string>
</resources> </resources>

View file

@ -38,5 +38,9 @@
<string name="token_details_send_blocked_fee_format">Not enough funds for fee on your %s wallet to send a transaction. Top up your %s wallet first.</string> <string name="token_details_send_blocked_fee_format">Not enough funds for fee on your %s wallet to send a transaction. Top up your %s wallet first.</string>
<string name="currency_subtitle_expanded">Available networks</string> <string name="currency_subtitle_expanded">Available networks</string>
<string name="alert_manage_tokens_addresses_message">Note that tokens on different networks have different addresses. Double check that your address matches the network when you transfer funds.</string>
<string name="contract_address_copied_message">Contract address copied!</string>
<string name="common_custom">Custom</string>
</resources> </resources>

View file

@ -38,4 +38,9 @@
<string name="token_details_send_blocked_fee_format">Недостаточно средств для комиссии на вашем %s кошельке для отправки транзакции. Сначала пополните свой %s кошелек.</string> <string name="token_details_send_blocked_fee_format">Недостаточно средств для комиссии на вашем %s кошельке для отправки транзакции. Сначала пополните свой %s кошелек.</string>
<string name="currency_subtitle_expanded">Доступные сети</string> <string name="currency_subtitle_expanded">Доступные сети</string>
<string name="alert_manage_tokens_addresses_message">Внимание! Валюты на разных сетях имеют разные адреса. Убедитесь, что адрес соответствует сети, в которой вы отправляете средства.</string>
<string name="contract_address_copied_message">Адрес контракта скопирован!</string>
<string name="common_custom">Пользовательский</string>
</resources> </resources>

View file

@ -38,4 +38,9 @@
<string name="token_details_send_blocked_fee_format">Not enough funds for fee on your %s wallet to send a transaction. Top up your %s wallet first.</string> <string name="token_details_send_blocked_fee_format">Not enough funds for fee on your %s wallet to send a transaction. Top up your %s wallet first.</string>
<string name="currency_subtitle_expanded">Available networks</string> <string name="currency_subtitle_expanded">Available networks</string>
<string name="alert_manage_tokens_addresses_message">Note that tokens on different networks have different addresses. Double check that your address matches the network when you transfer funds.</string>
<string name="contract_address_copied_message">Contract address copied!</string>
<string name="common_custom">Custom</string>
</resources> </resources>

View file

@ -1,4 +1,4 @@
ext.versions = [ ext.versions = [
kotlin : '1.6.10', kotlin : '1.6.10',
build_gradle: '7.0.4', build_gradle: '7.1.3',
] ]

View file

@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip