diff --git a/app/build.gradle b/app/build.gradle index b1a6ec93fd..31aaf1a063 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -79,10 +79,9 @@ dependencies { implementation 'com.google.android.play:core-ktx:1.8.1' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' -// implementation 'com.tangem:blockchain:develop-67' - implementation 'com.tangem:blockchain:0.0.1' - implementation 'com.tangem.tangem-sdk-kotlin:core:0.0.1' - implementation 'com.tangem.tangem-sdk-kotlin:android:0.0.1' + implementation 'com.tangem:blockchain:develop-70' + implementation 'com.tangem.tangem-sdk-kotlin:core:develop-142' + implementation 'com.tangem.tangem-sdk-kotlin:android:develop-142' // WebView implementation "androidx.browser:browser:1.3.0" diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Blockchain.kt b/app/src/main/java/com/tangem/tap/common/extensions/Blockchain.kt index d4f5682508..a34f96c1b0 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Blockchain.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Blockchain.kt @@ -4,36 +4,16 @@ import androidx.annotation.DrawableRes import com.tangem.blockchain.common.Blockchain 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 fun Blockchain.getRoundIconRes(): Int { 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.BitcoinCash -> R.drawable.ic_bitcoin_cash_round Blockchain.Litecoin -> R.drawable.ic_litecoin_round Blockchain.Ethereum, Blockchain.EthereumTestnet, -> R.drawable.ic_eth_round Blockchain.RSK -> R.drawable.ic_rsk_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.XRP -> R.drawable.ic_xrp_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.Solana, Blockchain.SolanaTestnet -> R.drawable.ic_solana_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 } } @@ -56,7 +36,6 @@ fun Blockchain.getGreyedOutIconRes(): Int { Blockchain.Ethereum, Blockchain.EthereumTestnet, -> R.drawable.ic_eth_no_color Blockchain.RSK -> R.drawable.ic_rsk_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.XRP -> R.drawable.ic_xrp_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.Solana, Blockchain.SolanaTestnet -> R.drawable.ic_solana_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 } } diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Picasso.kt b/app/src/main/java/com/tangem/tap/common/extensions/Picasso.kt index 743d13d412..4799d802ad 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Picasso.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Picasso.kt @@ -1,7 +1,6 @@ package com.tangem.tap.common.extensions import android.graphics.* -import android.net.Uri import android.widget.TextView import androidx.constraintlayout.utils.widget.ImageFilterView 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.Token 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 fun Picasso.loadCurrenciesIcon( @@ -20,10 +21,11 @@ fun Picasso.loadCurrenciesIcon( blockchain: Blockchain, ) { - val url = if (token != null) { - token.getCustomIconUrl()?.let { Uri.parse(it) } ?: IconsUtil.getTokenIconUri(blockchain, token) + val url: String? = if (token != null) { + token.id?.let { getIconUrl(it) } ?: token.getCustomIconUrl() + ?: IconsUtil.getTokenIconUri(blockchain, token)?.toString() } else { - IconsUtil.getBlockchainIconUri(blockchain) + getIconUrl(blockchain.toNetworkId()) } imageView.setImageDrawable(null) @@ -85,7 +87,7 @@ private fun setBlockchainImage( textView: TextView, blockchain: Blockchain, ) { - imageView.setImageResource(blockchain.getIconRes()) + imageView.setImageResource(blockchain.getRoundIconRes()) imageView.colorFilter = null if (blockchain.isTestnet()) imageView.saturation = 0f textView.text = null diff --git a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt index a2ae6dc0c9..cd4dbc367f 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt @@ -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.GlobalAction 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.isTestCard import com.tangem.tap.domain.configurable.config.ConfigManager @@ -190,7 +191,7 @@ class TapWalletManager { primaryWalletManager: WalletManager? ) { 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 (primaryBlockchain != null && primaryWalletManager != null) { @@ -205,9 +206,10 @@ class TapWalletManager { ) } else { + val derivationStyle = scanResponse.card.derivationStyle val blockchainNetworks = listOf( - BlockchainNetwork(Blockchain.Bitcoin,null, emptyList()), - BlockchainNetwork(Blockchain.Ethereum,null, emptyList()) + BlockchainNetwork(Blockchain.Bitcoin, scanResponse.card), + BlockchainNetwork(Blockchain.Ethereum, scanResponse.card) ) val walletManagers = walletManagerFactory.makeWalletManagersForApp( diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt index cb33c418a3..753af42455 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt @@ -28,6 +28,7 @@ import com.tangem.operations.issuerAndUserData.ReadIssuerDataCommand import com.tangem.tap.domain.ProductType import com.tangem.tap.domain.TapSdkError 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.isExcluded import com.tangem.tap.domain.TapWorkarounds.isNotSupportedInThatRelease @@ -275,7 +276,7 @@ private class ScanWalletProcessor( private fun getBlockchainsToDerive(card: Card): List { 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 { mutableListOf( diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/CurrenciesRepository.kt b/app/src/main/java/com/tangem/tap/domain/tokens/CurrenciesRepository.kt index 0070a6e399..cd7fee1260 100644 --- a/app/src/main/java/com/tangem/tap/domain/tokens/CurrenciesRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/tokens/CurrenciesRepository.kt @@ -98,13 +98,19 @@ class CurrenciesRepository(val context: Application) { } } - fun loadSavedCurrencies(cardId: String): List { + fun loadSavedCurrencies( + cardId: String, + derivationStyle: DerivationStyle? = null + ): List { if (DemoHelper.isDemoCardId(cardId)) { return loadDemoCurrencies(cardId) } return try { val json = context.readFileText(getFileNameForBlockchains(cardId)) - blockchainNetworkAdapter.fromJson(json)?.distinct() ?: loadSavedCurrenciesOldWay(cardId) + blockchainNetworkAdapter.fromJson(json)?.distinct() ?: loadSavedCurrenciesOldWay( + cardId, + derivationStyle + ) } catch (exception: Exception) { emptyList() } @@ -120,16 +126,25 @@ class CurrenciesRepository(val context: Application) { } } - private fun loadSavedCurrenciesOldWay(cardId: String): List { + private fun loadSavedCurrenciesOldWay( + cardId: String, derivationStyle: DerivationStyle? + ): List { val blockchains = loadSavedBlockchains(cardId) val tokens = loadSavedTokens(cardId) + val currencies = getSupportedTokens() val blockchainNetworks = blockchains.map { blockchain -> BlockchainNetwork( blockchain = blockchain, - derivationPath = null, + derivationPath = blockchain.derivationPath(derivationStyle)?.rawPath, tokens = tokens .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 @@ -178,17 +193,6 @@ class CurrenciesRepository(val context: Application) { return obsoleteTokensAdapter.fromJson(tokenJson)!!.map { it.toTokenDao(blockchain) } } - private fun getSupportedTokens(): List { - return listOf( - Blockchain.Ethereum, - Blockchain.BSC, - Blockchain.Binance, - Blockchain.Polygon, - Blockchain.Avalanche, - Blockchain.Fantom, - ) - } - fun getBlockchains( cardFirmware: FirmwareVersion, isTestNet: Boolean = false diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/Currency.kt b/app/src/main/java/com/tangem/tap/domain/tokens/Currency.kt index 4c5589666a..be3d1b4229 100644 --- a/app/src/main/java/com/tangem/tap/domain/tokens/Currency.kt +++ b/app/src/main/java/com/tangem/tap/domain/tokens/Currency.kt @@ -26,7 +26,7 @@ data class CurrenciesFromJson( fun List.toContracts(): List { - return map { Contract.fromJsonObject(it) } + return mapNotNull { Contract.fromJsonObject(it) } } data class Currency( @@ -59,10 +59,11 @@ data class Contract( ) { companion object { - fun fromJsonObject(contract: ContractFromJson): Contract { + fun fromJsonObject(contract: ContractFromJson): Contract? { + val blockchain = Blockchain.fromNetworkId(contract.networkId) ?: return null return Contract( networkId = contract.networkId, - blockchain = Blockchain.fromNetworkId(contract.networkId), + blockchain = blockchain, address = contract.address, decimalCount = contract.decimalCount, 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) { "avalanche" -> Blockchain.Avalanche "binancecoin" -> Blockchain.Binance @@ -95,7 +96,7 @@ fun Blockchain.Companion.fromNetworkId(networkId: String): Blockchain { "stellar" -> Blockchain.Stellar "tezos" -> Blockchain.Tezos "ripple" -> Blockchain.XRP - else -> Blockchain.Unknown + else -> null } } @@ -103,7 +104,7 @@ fun Blockchain.toNetworkId(): String { return when (this) { Blockchain.Unknown -> "unknown" Blockchain.Avalanche -> "avalanche" - Blockchain.AvalancheTestnet -> "avalaunch" + Blockchain.AvalancheTestnet -> "avalaunche" Blockchain.Binance -> "binancecoin" Blockchain.BinanceTestnet -> "binancecoin" Blockchain.BSC -> "binance-smart-chain" diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt index 5ac3d790d9..362689ddc4 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt @@ -257,7 +257,7 @@ class WalletConnectMiddleware { blockchainToMake, card.derivationStyle?.let { DerivationParams.Default(it) } ) - if (currenciesRepository.loadSavedCurrencies(card.cardId) + if (currenciesRepository.loadSavedCurrencies(card.cardId, card.derivationStyle) .find { it.blockchain == blockchainToMake } != null ) { walletManager?.let { diff --git a/app/src/main/java/com/tangem/tap/features/feedback/FeedbackManager.kt b/app/src/main/java/com/tangem/tap/features/feedback/FeedbackManager.kt index e3d88e1b99..11680f7d46 100644 --- a/app/src/main/java/com/tangem/tap/features/feedback/FeedbackManager.kt +++ b/app/src/main/java/com/tangem/tap/features/feedback/FeedbackManager.kt @@ -106,6 +106,7 @@ class AdditionalEmailInfo { var address: String = "", var explorerLink: String = "", var host: String = "", + var derivationPath: String = "", ) var appVersion: String = "" @@ -159,7 +160,8 @@ class AdditionalEmailInfo { blockchain = manager.wallet.blockchain, address = getAddress(manager.wallet), explorerLink = getExploreUri(manager.wallet), - host = manager.currentHost + host = manager.currentHost, + derivationPath = manager.wallet.publicKey.derivationPath?.rawPath ?: "" ) ) if (manager.cardTokens.isNotEmpty()) { @@ -173,7 +175,8 @@ class AdditionalEmailInfo { blockchain = wallet.blockchain, address = getAddress(wallet), explorerLink = getExploreUri(wallet), - host = host + host = host, + derivationPath = wallet.publicKey.derivationPath?.rawPath ?: "" ) this.destinationAddress = destinationAddress @@ -325,6 +328,7 @@ class EmailDataBuilder( builder.appendKeyValue("Blockchain", it.blockchain.fullName) builder.appendKeyValue("Host", it.host) builder.appendKeyValue("Wallet address", it.address) + builder.appendKeyValue("Derivation path", it.derivationPath) builder.appendKeyValue("Explorer link", it.explorerLink) infoHolder.tokens[it.blockchain]?.let { tokens -> @@ -332,6 +336,7 @@ class EmailDataBuilder( appendLine() tokens.forEach { token -> builder.appendKeyValue("Name", token.name) + if (token.id != null) builder.appendKeyValue("Id", token.id ?: "") builder.appendKeyValue("Contract address", token.contractAddress) } } @@ -342,6 +347,7 @@ class EmailDataBuilder( fun appendTxFailedBlockchainInfo(error: String): EmailDataBuilder { val walletInfo = infoHolder.onSendErrorWalletInfo ?: AdditionalEmailInfo.EmailWalletInfo() builder.appendKeyValue("Blockchain", walletInfo.blockchain.fullName) + builder.appendKeyValue("Derivation path", walletInfo.derivationPath) builder.appendKeyValue("Host", walletInfo.host) builder.appendKeyValue("Token", infoHolder.token) builder.appendKeyValue("Error", error) diff --git a/app/src/main/java/com/tangem/tap/features/tokens/ui/AddTokensFragment.kt b/app/src/main/java/com/tangem/tap/features/tokens/ui/AddTokensFragment.kt index 9e41f681e3..fd1062e1dc 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/ui/AddTokensFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/ui/AddTokensFragment.kt @@ -14,8 +14,13 @@ import androidx.fragment.app.Fragment import androidx.transition.TransitionInflater import by.kirich1409.viewbindingdelegate.viewBinding 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.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.TokensState 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) toolbar.setNavigationOnClickListener { activity?.onBackPressed() } + val onSaveChanges = { tokens: List, blockchains: List -> + store.dispatch(TokensAction.SaveChanges(tokens, blockchains)) + } + val onNetworkItemClicked = { contractAddress: ContractAddress -> + context?.copyToClipboard(contractAddress) + store.dispatchNotification(R.string.contract_address_copied_message) + } + cvCurrencies.setContent { AppCompatTheme { CurrenciesScreen( tokensState = tokensState, - searchInput = searchInput - ) { tokens, blockchains -> - store.dispatch(TokensAction.SaveChanges(tokens, blockchains)) - } + searchInput = searchInput, + onSaveChanges = onSaveChanges, + onNetworkItemClicked = onNetworkItemClicked + ) } } } diff --git a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CollapsedCurrencyItem.kt b/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CollapsedCurrencyItem.kt index 50169d2c81..5d5de44aa4 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CollapsedCurrencyItem.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CollapsedCurrencyItem.kt @@ -36,11 +36,7 @@ fun CollapsedCurrencyItem( .clickable(onClick = { onCurrencyClick(currency.id) }) ) { val blockchain = Blockchain.fromNetworkId(currency.id) - val iconRes = if (blockchain == Blockchain.Unknown) { - currency.iconUrl - } else { - blockchain.getRoundIconRes() - } + val iconRes = currency.iconUrl SubcomposeAsyncImage( model = iconRes, @@ -66,32 +62,36 @@ fun CollapsedCurrencyItem( ) Spacer(modifier = Modifier.size(6.dp)) Row { - if (currency.contracts != null) { + if (!currency.contracts.isNullOrEmpty()) { currency.contracts.map { contract -> - val added = - addedTokens.map { it.token.contractAddress }.contains(contract.address) - val icon = if (added) { - contract.blockchain.getRoundIconRes() + if (contract.address == currency.symbol) { + BlockchainNetworkItem( + blockchain = Blockchain.fromNetworkId(contract.networkId), + addedBlockchains = addedBlockchains + ) } 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 { - val added = addedBlockchains.contains(blockchain) - val icon = - if (added) blockchain.getRoundIconRes() else blockchain.getGreyedOutIconRes() - Image( - painter = painterResource(id = icon), - contentDescription = null, - Modifier - .size(20.dp) + BlockchainNetworkItem( + blockchain = blockchain, + addedBlockchains = addedBlockchains ) } } @@ -105,4 +105,23 @@ fun CollapsedCurrencyItem( ) } +} + +@Composable +fun BlockchainNetworkItem( + blockchain: Blockchain?, + addedBlockchains: List +) { + 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)) + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrenciesScreen.kt b/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrenciesScreen.kt index 2fcdeee601..e9b9d3f3eb 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrenciesScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrenciesScreen.kt @@ -1,5 +1,6 @@ package com.tangem.tap.features.tokens.ui.compose +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.padding import androidx.compose.material.ExtendedFloatingActionButton 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.domain.tokens.Currency 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.TokensState import com.tangem.tap.store @@ -26,7 +28,8 @@ import com.tangem.wallet.R fun CurrenciesScreen( tokensState: MutableState = mutableStateOf(store.state.tokensState), searchInput: MutableState, - onSaveChanges: (List, List) -> Unit + onSaveChanges: (List, List) -> Unit, + onNetworkItemClicked: (ContractAddress) -> Unit ) { val addedTokensState = remember { mutableStateOf(tokensState.value.addedTokens) } @@ -49,7 +52,7 @@ fun CurrenciesScreen( if (mutableList.contains(blockchain)) { mutableList.remove(blockchain) } else { - mutableList.add(blockchain) + blockchain?.let { mutableList.add(blockchain) } } addedBlockchainsState.value = mutableList } @@ -65,16 +68,21 @@ fun CurrenciesScreen( floatingActionButtonPosition = FabPosition.Center, ) { - ListOfCurrencies( - currencies = tokensState.value.currencies, - nonRemovableTokens = tokensState.value.nonRemovableTokens, - nonRemovableBlockchains = tokensState.value.nonRemovableBlockchains, - addedTokens = addedTokensState.value, - addedBlockchains = addedBlockchainsState.value, - searchInput = searchInput.value, - allowToAdd = tokensState.value.allowToAdd, - onAddCurrencyToggled = onAddCurrencyToggleClick - ) + Column { + if (tokensState.value.allowToAdd) CurrenciesWarning() + ListOfCurrencies( + currencies = tokensState.value.currencies, + nonRemovableTokens = tokensState.value.nonRemovableTokens, + nonRemovableBlockchains = tokensState.value.nonRemovableBlockchains, + addedTokens = addedTokensState.value, + addedBlockchains = addedBlockchainsState.value, + searchInput = searchInput.value, + allowToAdd = tokensState.value.allowToAdd, + onAddCurrencyToggled = onAddCurrencyToggleClick, + onNetworkItemClicked = onNetworkItemClicked + ) + } + } } diff --git a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrenciesWarning.kt b/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrenciesWarning.kt new file mode 100644 index 0000000000..0e7a4341df --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrenciesWarning.kt @@ -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, + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrencyItem.kt b/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrencyItem.kt index 56d3f26277..9fd962bce7 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrencyItem.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrencyItem.kt @@ -16,7 +16,8 @@ fun CurrencyItem( allowToAdd: Boolean, expanded: Boolean, onCurrencyClick: (String) -> Unit, - onAddCurrencyToggled: (Currency, TokenWithBlockchain?) -> Unit + onAddCurrencyToggled: (Currency, TokenWithBlockchain?) -> Unit, + onNetworkItemClicked: (ContractAddress) -> Unit ) { if (expanded) { ExpandedCurrencyItem( @@ -26,7 +27,8 @@ fun CurrencyItem( addedTokens = addedTokens, addedBlockchains = addedBlockchains, allowToAdd = allowToAdd, - onCurrencyClick = onCurrencyClick, onAddCurrencyToggled = onAddCurrencyToggled + onCurrencyClick = onCurrencyClick, onAddCurrencyToggled = onAddCurrencyToggled, + onNetworkItemClicked = onNetworkItemClicked ) } else { CollapsedCurrencyItem( diff --git a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/ExpandedCurrencyItem.kt b/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/ExpandedCurrencyItem.kt index 825cb9fd8b..1756881f8f 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/ExpandedCurrencyItem.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/ExpandedCurrencyItem.kt @@ -18,7 +18,6 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import coil.compose.SubcomposeAsyncImage 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.fromNetworkId import com.tangem.tap.features.tokens.redux.ContractAddress @@ -34,14 +33,11 @@ fun ExpandedCurrencyItem( addedBlockchains: List, allowToAdd: Boolean, onCurrencyClick: (String) -> Unit, - onAddCurrencyToggled: (Currency, TokenWithBlockchain?) -> Unit + onAddCurrencyToggled: (Currency, TokenWithBlockchain?) -> Unit, + onNetworkItemClicked: (ContractAddress) -> Unit ) { val blockchain = Blockchain.fromNetworkId(currency.id) - val iconRes = if (blockchain == Blockchain.Unknown) { - currency.iconUrl - } else { - blockchain.getRoundIconRes() - } + val iconRes = currency.iconUrl Column { 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) ) @@ -99,11 +95,18 @@ fun ExpandedCurrencyItem( .fillMaxHeight() ) { if (blockchains.size > 1) { + val dividerHeight = if (blockchains.size == 2) { + 60 + } else if (blockchains.size == 3) { + 110 + } else { + 43 * blockchains.size + } Divider( color = Color(0xFFDEDEDE), modifier = Modifier - .height((43 * blockchains.size - 1).dp) - .padding(start = 37.dp, top = 16.dp) + .height(dividerHeight.dp) + .padding(start = 37.5.dp) .width(1.dp) ) } @@ -130,12 +133,12 @@ fun ExpandedCurrencyItem( ) { blockchains.map { 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) } else { addedBlockchains.contains(blockchain) } - val canBeRemoved = if (contract != null) { + val canBeRemoved = if (contract != null && contract.address != currency.symbol) { !nonRemovableTokens.contains(contract.address) } else { !nonRemovableBlockchains.contains(blockchain) @@ -146,7 +149,8 @@ fun ExpandedCurrencyItem( blockchain = blockchain, allowToAdd = allowToAdd, added = added, canBeRemoved = canBeRemoved, - onAddCurrencyToggled = onAddCurrencyToggled + onAddCurrencyToggled = onAddCurrencyToggled, + onNetworkItemClicked = onNetworkItemClicked, ) } } diff --git a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/ListOfCurrencies.kt b/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/ListOfCurrencies.kt index 3780b55a07..d435e6e785 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/ListOfCurrencies.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/ListOfCurrencies.kt @@ -22,7 +22,8 @@ fun ListOfCurrencies( addedBlockchains: List, searchInput: String, allowToAdd: Boolean, - onAddCurrencyToggled: (Currency, TokenWithBlockchain?) -> Unit + onAddCurrencyToggled: (Currency, TokenWithBlockchain?) -> Unit, + onNetworkItemClicked: (ContractAddress) -> Unit ) { val expandedCurrencies = remember { mutableStateOf(listOf("")) } @@ -59,7 +60,8 @@ fun ListOfCurrencies( allowToAdd = allowToAdd, expanded = expandedCurrencies.value.contains(currency.id), onCurrencyClick = onCurrencyClick, - onAddCurrencyToggled = onAddCurrencyToggled + onAddCurrencyToggled = onAddCurrencyToggled, + onNetworkItemClicked = onNetworkItemClicked ) } diff --git a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/NetworkItem.kt b/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/NetworkItem.kt index e094784ed7..0c32c40653 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/NetworkItem.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/NetworkItem.kt @@ -1,5 +1,7 @@ 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.shape.CircleShape 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.domain.tokens.Contract import com.tangem.tap.domain.tokens.Currency +import com.tangem.tap.features.tokens.redux.ContractAddress import com.tangem.tap.features.tokens.redux.TokenWithBlockchain +@OptIn(ExperimentalFoundationApi::class) @Composable fun NetworkItem( currency: Currency, contract: Contract?, blockchain: Blockchain, allowToAdd: 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( modifier = Modifier .fillMaxWidth() - + .combinedClickable { + if (contract != null) onNetworkItemClicked(contract.address) + } ) { SubcomposeAsyncImage( model = if (added) blockchain.getRoundIconRes() else blockchain.getGreyedOutIconRes(), @@ -46,10 +56,12 @@ fun NetworkItem( .size(20.dp) .align(Alignment.CenterVertically) ) - Row(modifier = Modifier - .fillMaxHeight() - .weight(1f) - .align(Alignment.CenterVertically)) { + Row( + modifier = Modifier + .fillMaxHeight() + .weight(1f) + .align(Alignment.CenterVertically) + ) { Text( text = blockchain.name.uppercase(), fontSize = 13.sp, @@ -58,30 +70,43 @@ fun NetworkItem( ) Spacer(modifier = Modifier.size(3.dp)) Text( - text = if (contract != null) blockchain.getNetworkName().uppercase() else "MAIN", + text = if (isBlockchain) "MAIN" else blockchain.getNetworkName().uppercase(), fontSize = 13.sp, 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) { - Token( - name = currency.name, symbol = currency.symbol, contractAddress = contract.address, - decimals = contract.decimalCount, + if (allowToAdd) { + val token = if (!isBlockchain) { + Token( + 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) - ) - ) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt index 5ecb015e9b..5495337abf 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt @@ -127,11 +127,7 @@ class MultiWalletMiddleware { val coinAmount = wallet.amounts[AmountType.Coin]?.value if (coinAmount != null && !coinAmount.isZero()) { scope.launch(Dispatchers.Main) { - val blockchainNetwork = BlockchainNetwork( - wallet.blockchain, - null, - walletManager.cardTokens.toList() - ) + val blockchainNetwork = BlockchainNetwork.fromWalletManager(walletManager) if (walletState?.getWalletData(blockchainNetwork) == null) { store.dispatch( WalletAction.MultiWallet.AddBlockchain( diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletAdapter.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletAdapter.kt index 968485c440..7218fd7758 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletAdapter.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletAdapter.kt @@ -11,6 +11,7 @@ import com.tangem.blockchain.common.Token import com.tangem.tap.common.extensions.getString import com.tangem.tap.common.extensions.loadCurrenciesIcon 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.WalletAction import com.tangem.tap.features.wallet.redux.WalletData @@ -26,7 +27,11 @@ class WalletAdapter return currentList[position].currencyData.currencySymbol?.hashCode()?.toLong() ?: 0 } - fun submitList(list: List, primaryBlockchain: Blockchain?, primaryToken: Token? = null) { + fun submitList( + list: List, + primaryBlockchain: Blockchain?, + primaryToken: Token? = null + ) { // We used this method to sort the list of currencies. Sorting is disabled for now. super.submitList(list) } @@ -44,21 +49,22 @@ class WalletAdapter object DiffUtilCallback : DiffUtil.ItemCallback() { override fun areContentsTheSame( - oldItem: WalletData, newItem: WalletData + oldItem: WalletData, newItem: WalletData ) = oldItem == newItem override fun areItemsTheSame( - oldItem: WalletData, newItem: WalletData + oldItem: WalletData, newItem: WalletData ) = oldItem == newItem } class WalletsViewHolder(val binding: ItemCurrencyWalletBinding) : - RecyclerView.ViewHolder(binding.root) { + RecyclerView.ViewHolder(binding.root) { fun bind(wallet: WalletData) = with(binding) { tvCurrency.text = wallet.currencyData.currency 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 tvExchangeRate.text = wallet.fiatRateString cardWallet.setOnClickListener { @@ -67,6 +73,11 @@ class WalletAdapter val blockchain = wallet.currency.blockchain 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( imageView = ivCurrency, textView = tvTokenLetter, diff --git a/app/src/main/res/layout/item_currency_wallet.xml b/app/src/main/res/layout/item_currency_wallet.xml index 35b4a700af..ec0f6d62ba 100644 --- a/app/src/main/res/layout/item_currency_wallet.xml +++ b/app/src/main/res/layout/item_currency_wallet.xml @@ -117,6 +117,21 @@ app:layout_constraintTop_toTopOf="@id/guideline" tools:text="USD 3 588" /> + + Not enough funds for fee on your %s wallet to send a transaction. Top up your %s wallet first. Available networks + Note that tokens on different networks have different addresses. Double check that your address matches the network when you transfer funds. + Contract address copied! + + Custom \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings_final.xml b/app/src/main/res/values-fr/strings_final.xml index 97fd745f11..9fc6dd2a11 100644 --- a/app/src/main/res/values-fr/strings_final.xml +++ b/app/src/main/res/values-fr/strings_final.xml @@ -38,4 +38,9 @@ Not enough funds for fee on your %s wallet to send a transaction. Top up your %s wallet first. Available networks + Note that tokens on different networks have different addresses. Double check that your address matches the network when you transfer funds. + Contract address copied! + + Custom + \ No newline at end of file diff --git a/app/src/main/res/values-it/strings_final.xml b/app/src/main/res/values-it/strings_final.xml index d1ad971590..9fc6dd2a11 100644 --- a/app/src/main/res/values-it/strings_final.xml +++ b/app/src/main/res/values-it/strings_final.xml @@ -38,5 +38,9 @@ Not enough funds for fee on your %s wallet to send a transaction. Top up your %s wallet first. Available networks + Note that tokens on different networks have different addresses. Double check that your address matches the network when you transfer funds. + Contract address copied! + + Custom \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings_final.xml b/app/src/main/res/values-ru/strings_final.xml index 0fc78cb747..19b4411fba 100644 --- a/app/src/main/res/values-ru/strings_final.xml +++ b/app/src/main/res/values-ru/strings_final.xml @@ -38,4 +38,9 @@ Недостаточно средств для комиссии на вашем %s кошельке для отправки транзакции. Сначала пополните свой %s кошелек. Доступные сети + Внимание! Валюты на разных сетях имеют разные адреса. Убедитесь, что адрес соответствует сети, в которой вы отправляете средства. + Адрес контракта скопирован! + + Пользовательский + \ No newline at end of file diff --git a/app/src/main/res/values/strings_final.xml b/app/src/main/res/values/strings_final.xml index 97fd745f11..9fc6dd2a11 100644 --- a/app/src/main/res/values/strings_final.xml +++ b/app/src/main/res/values/strings_final.xml @@ -38,4 +38,9 @@ Not enough funds for fee on your %s wallet to send a transaction. Top up your %s wallet first. Available networks + Note that tokens on different networks have different addresses. Double check that your address matches the network when you transfer funds. + Contract address copied! + + Custom + \ No newline at end of file diff --git a/dependencies.gradle b/dependencies.gradle index 8004a23445..5ceeadcc6e 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -1,4 +1,4 @@ ext.versions = [ kotlin : '1.6.10', - build_gradle: '7.0.4', + build_gradle: '7.1.3', ] diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8e5b6ad562..9ee3ffb21f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME 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