From a9e43ac45bbe7029eec764851255956b48831d0f Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 5 Feb 2019 18:21:35 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../main/java/com/tangem/data/Blockchain.java | 1 + .../com/tangem/domain/wallet/CoinEngine.java | 4 + .../tangem/domain/wallet/CoinEngineFactory.kt | 4 + .../tangem/domain/wallet/TangemContext.java | 39 +- .../wallet/nftToken/NftTokenEngine.java | 359 ++++++++++++++++++ .../domain/wallet/rsk/RskTokenEngine.java | 21 +- .../domain/wallet/token/TokenEngine.java | 21 +- .../presentation/fragment/LoadedWallet.kt | 8 + .../main/res/drawable/card_default_nft.png | Bin 0 -> 24619 bytes .../tangemserver/android/data/LocalStorage.kt | 39 +- 10 files changed, 447 insertions(+), 49 deletions(-) create mode 100644 app/src/main/java/com/tangem/domain/wallet/nftToken/NftTokenEngine.java create mode 100644 tangemcard-android/src/main/res/drawable/card_default_nft.png diff --git a/app/src/main/java/com/tangem/data/Blockchain.java b/app/src/main/java/com/tangem/data/Blockchain.java index 11cb8eecf2..9e95661c57 100644 --- a/app/src/main/java/com/tangem/data/Blockchain.java +++ b/app/src/main/java/com/tangem/data/Blockchain.java @@ -12,6 +12,7 @@ public enum Blockchain { Ethereum("ETH", "ETH", 1.0, R.drawable.ic_logo_ethereum, "Ethereum"), EthereumTestNet("ETH/test", "ETH", 1.0, R.drawable.ic_logo_ethereum_testnet, "Ethereum Testnet"), Token("Token", "ETH", 1.0, R.drawable.ic_logo_bat_token, "Ethereum"), + NftToken("NftToken", "", 1.0, R.drawable.ic_logo_bat_token, "Ethereum"), BitcoinCash("BCH", "BCH", 100000000.0, R.drawable.ic_logo_bitcoin_cash, "Bitcoin Cash"), Litecoin("LTC", "LTC", 100000000.0, R.drawable.ic_logo_bitcoin, "Litecoin"), Rootstock("RSK", "RBTC", 1.0, R.drawable.ic_logo_bitcoin, "Rootstock"), diff --git a/app/src/main/java/com/tangem/domain/wallet/CoinEngine.java b/app/src/main/java/com/tangem/domain/wallet/CoinEngine.java index 1f53e9b4bd..9340405a2e 100644 --- a/app/src/main/java/com/tangem/domain/wallet/CoinEngine.java +++ b/app/src/main/java/com/tangem/domain/wallet/CoinEngine.java @@ -361,5 +361,9 @@ public abstract class CoinEngine { return true; } + public boolean isNftToken() { + return false; + } + } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/domain/wallet/CoinEngineFactory.kt b/app/src/main/java/com/tangem/domain/wallet/CoinEngineFactory.kt index adf693ade8..9d99f0121f 100644 --- a/app/src/main/java/com/tangem/domain/wallet/CoinEngineFactory.kt +++ b/app/src/main/java/com/tangem/domain/wallet/CoinEngineFactory.kt @@ -8,6 +8,7 @@ import com.tangem.domain.wallet.token.TokenEngine import com.tangem.domain.wallet.bch.BtcCashEngine import com.tangem.data.Blockchain import com.tangem.domain.wallet.ltc.LtcEngine +import com.tangem.domain.wallet.nftToken.NftTokenEngine import com.tangem.domain.wallet.rsk.RskEngine import com.tangem.domain.wallet.rsk.RskTokenEngine @@ -28,6 +29,7 @@ object CoinEngineFactory { Blockchain.BitcoinCash -> BtcCashEngine() Blockchain.Ethereum, Blockchain.EthereumTestNet -> EthEngine() Blockchain.Token -> TokenEngine() + Blockchain.NftToken -> NftTokenEngine() Blockchain.Litecoin -> LtcEngine() Blockchain.Rootstock -> RskEngine() Blockchain.RootstockToken -> RskTokenEngine() @@ -47,6 +49,8 @@ object CoinEngineFactory { EthEngine(context) else if (Blockchain.Token == context.blockchain) TokenEngine(context) + else if (Blockchain.NftToken == context.blockchain) + NftTokenEngine(context) else if (Blockchain.Litecoin == context.blockchain) LtcEngine(context) else if (Blockchain.Rootstock == context.blockchain) diff --git a/app/src/main/java/com/tangem/domain/wallet/TangemContext.java b/app/src/main/java/com/tangem/domain/wallet/TangemContext.java index 7e642c01b3..1537c56082 100644 --- a/app/src/main/java/com/tangem/domain/wallet/TangemContext.java +++ b/app/src/main/java/com/tangem/domain/wallet/TangemContext.java @@ -11,7 +11,7 @@ import com.tangem.tangemcard.data.TangemCardExtensionsKt; public class TangemContext { -// public static final String EXTRA_BLOCKCHAIN_DATA = "BLOCKCHAIN_DATA"; + // public static final String EXTRA_BLOCKCHAIN_DATA = "BLOCKCHAIN_DATA"; private Context context; private TangemCard card; private CoinData coinData; @@ -28,13 +28,15 @@ public class TangemContext { public Blockchain getBlockchain() { if (card == null) return Blockchain.Unknown; - Blockchain blockchain=Blockchain.fromId(card.getBlockchainID()); - if( (blockchain==Blockchain.Ethereum || blockchain==Blockchain.EthereumTestNet)&& card.isToken() ) - { - return Blockchain.Token; + Blockchain blockchain = Blockchain.fromId(card.getBlockchainID()); + if ((blockchain == Blockchain.Ethereum || blockchain == Blockchain.EthereumTestNet) && card.isToken()) { + if (card.getTokenSymbol().startsWith("NFT:")) { + return Blockchain.NftToken; + } else { + return Blockchain.Token; + } } - if( (blockchain==Blockchain.Rootstock)&& card.isToken() ) - { + if ((blockchain == Blockchain.Rootstock) && card.isToken()) { return Blockchain.RootstockToken; } return blockchain; @@ -48,13 +50,15 @@ public class TangemContext { // private String blockchainName = ""; public String getBlockchainName() { - Blockchain blockchain=getBlockchain(); - if( blockchain==Blockchain.Token || blockchain==Blockchain.RootstockToken ) { + Blockchain blockchain = getBlockchain(); + if (blockchain == Blockchain.Token || blockchain == Blockchain.RootstockToken) { String token = card.getTokenSymbol(); return token + "
" + getBlockchain().getOfficialName() + " smart contract token"; - }else { - return blockchain.getOfficialName(); } + if (blockchain == Blockchain.NftToken) { + return card.getTokenSymbol().substring(4) + "
" + getBlockchain().getOfficialName() + " smart contract token"; + } + return blockchain.getOfficialName(); } public Context getContext() { @@ -84,6 +88,7 @@ public class TangemContext { public void setError(String error) { this.error = error; } + public void setError(int valueId) { this.error = getString(valueId); } @@ -93,7 +98,7 @@ public class TangemContext { } public boolean hasError() { - return error!=null && !error.isEmpty(); + return error != null && !error.isEmpty(); } public void setMessage(String value) { @@ -154,13 +159,13 @@ public class TangemContext { public void setDenomination(byte[] denomination) { try { - CoinEngine engine= CoinEngineFactory.INSTANCE.create(getBlockchain()); - CoinEngine.InternalAmount internalAmount=engine.convertToInternalAmount(denomination); - CoinEngine.Amount amount=engine.convertToAmount(internalAmount); - card.setDenomination(denomination,amount.toString()); + CoinEngine engine = CoinEngineFactory.INSTANCE.create(getBlockchain()); + CoinEngine.InternalAmount internalAmount = engine.convertToInternalAmount(denomination); + CoinEngine.Amount amount = engine.convertToAmount(internalAmount); + card.setDenomination(denomination, amount.toString()); } catch (Exception e) { e.printStackTrace(); - card.setDenomination(denomination,"N/A"); + card.setDenomination(denomination, "N/A"); } } diff --git a/app/src/main/java/com/tangem/domain/wallet/nftToken/NftTokenEngine.java b/app/src/main/java/com/tangem/domain/wallet/nftToken/NftTokenEngine.java new file mode 100644 index 0000000000..2e9e73e016 --- /dev/null +++ b/app/src/main/java/com/tangem/domain/wallet/nftToken/NftTokenEngine.java @@ -0,0 +1,359 @@ +package com.tangem.domain.wallet.nftToken; + +import android.net.Uri; +import android.os.Bundle; +import android.text.InputFilter; +import android.util.Log; + +import com.tangem.data.Blockchain; +import com.tangem.data.network.ServerApiInfura; +import com.tangem.data.network.model.InfuraResponse; +import com.tangem.domain.wallet.BTCUtils; +import com.tangem.domain.wallet.BalanceValidator; +import com.tangem.domain.wallet.CoinData; +import com.tangem.domain.wallet.CoinEngine; +import com.tangem.domain.wallet.Keccak256; +import com.tangem.domain.wallet.TangemContext; +import com.tangem.domain.wallet.eth.EthData; +import com.tangem.domain.wallet.token.TokenData; +import com.tangem.tangemcard.data.TangemCard; +import com.tangem.tangemcard.tasks.SignTask; +import com.tangem.wallet.R; + +import java.math.BigInteger; + + +public class NftTokenEngine extends CoinEngine { + + private static final String TAG = NftTokenEngine.class.getSimpleName(); + public TokenData coinData = null; + + public NftTokenEngine(TangemContext ctx) throws Exception { + super(ctx); + if (ctx.getCoinData() == null) { + coinData = new TokenData(); + ctx.setCoinData(coinData); + } else if (ctx.getCoinData() instanceof TokenData) { + coinData = (TokenData) ctx.getCoinData(); + } else if (ctx.getCoinData() instanceof EthData) { + // special case with receive card data substitution from server at the moment + Bundle B = new Bundle(); + ctx.getCoinData().saveToBundle(B); + coinData = new TokenData(); + coinData.loadFromBundle(B); + ctx.setCoinData(coinData); + } else { + throw new Exception("Invalid type of Blockchain data for " + this.getClass().getSimpleName()); + } + } + + public NftTokenEngine() { + super(); + } + + public Blockchain getBlockchain() { + return Blockchain.NftToken; + } + + @Override + public boolean awaitingConfirmation() { + return false; + } + + + @Override + public String getBalanceHTML() { + if (hasBalanceInfo()) { + if (isBalanceNotZero()) { + return "AUTHENTIC";// + getBalanceCurrency(); + } else { + return "NOT FOUND"; + } + } else { + return ""; + } + } + + @Override + public String getBalanceCurrency() { + return ctx.getCard().getTokenSymbol().substring(4); + } + + @Override + public InputFilter[] getAmountInputFilters() { + return new InputFilter[0]; + } + + @Override + public String getOfflineBalanceHTML() { + return ctx.getString(R.string.not_implemented); + } + + protected String getContractAddress(TangemCard card) { + return card.getContractAddress(); + } + + public boolean isNeedCheckNode() { + return false; + } + + @Override + public String getBalanceEquivalent() { + return null; + } + + @Override + public boolean validateAddress(String address) { + if (address == null || address.isEmpty()) { + return false; + } + + if (!address.startsWith("0x") && !address.startsWith("0X")) { + return false; + } + + if (address.length() != 42) { + return false; + } + + return true; + } + + @Override + public boolean isBalanceNotZero() { + if (coinData == null) return false; + if (coinData.getBalanceInInternalUnits() == null) return false; + return coinData.getBalanceInInternalUnits().notZero(); + } + + @Override + public String calculateAddress(byte[] pkUncompressed) { + Keccak256 kec = new Keccak256(); + int lenPk = pkUncompressed.length; + if (lenPk < 2) { + throw new IllegalArgumentException("Uncompress public key length is invalid"); + } + byte[] cleanKey = new byte[lenPk - 1]; + for (int i = 0; i < cleanKey.length; ++i) { + cleanKey[i] = pkUncompressed[i + 1]; + } + byte[] r = kec.digest(cleanKey); + + byte[] address = new byte[20]; + for (int i = 0; i < 20; ++i) { + address[i] = r[i + 12]; + } + + return String.format("0x%s", BTCUtils.toHex(address)); + } + + @Override + public Amount convertToAmount(InternalAmount internalAmount) throws Exception { + throw new Exception("Not implemented"); + } + + @Override + public Amount convertToAmount(String strAmount, String currency) { + return null; + } + + @Override + public InternalAmount convertToInternalAmount(Amount amount) throws Exception { + throw new Exception("Not implemented"); + } + + @Override + public InternalAmount convertToInternalAmount(byte[] bytes) throws Exception { + throw new Exception("Not implemented"); + } + + @Override + public byte[] convertToByteArray(InternalAmount amount) throws Exception { + throw new Exception("Not implemented"); + } + + @Override + public CoinData createCoinData() { + return new TokenData(); + } + + @Override + public String getUnspentInputsDescription() { + return ""; + } + + @Override + public boolean hasBalanceInfo() { + return coinData != null && coinData.getBalanceInInternalUnits() != null; + } + + + @Override + public Uri getWalletExplorerUri() { + return Uri.parse("https://etherscan.io/token/" + getContractAddress(ctx.getCard()) + "?a=" + ctx.getCoinData().getWallet()); + } + + @Override + public Uri getShareWalletUri() { + return Uri.parse("ethereum:" + ctx.getCoinData().getWallet()); + } + + @Override + public boolean isExtractPossible() { + return false; + } + + @Override + public boolean checkNewTransactionAmount(Amount amount) { + return false; + } + + @Override + public boolean checkNewTransactionAmountAndFee(Amount amount, Amount fee, Boolean isFeeIncluded) { + return false; + } + + @Override + public boolean validateBalance(BalanceValidator balanceValidator) { + if (coinData.getBalanceInInternalUnits() == null) { + balanceValidator.setScore(0); + balanceValidator.setFirstLine("No connection"); + balanceValidator.setSecondLine("Authenticity cannot be verified. Swipe down to refresh."); + return false; + } + + if (coinData.isBalanceReceived()) { + if (isBalanceNotZero()) { + balanceValidator.setScore(100); + balanceValidator.setFirstLine("Verified in blockchain"); + balanceValidator.setSecondLine(""); + } else { + balanceValidator.setScore(0); + balanceValidator.setFirstLine("Authenticity was not verified"); + balanceValidator.setSecondLine(""); + } + } + + return true; + } + + @Override + public Amount getBalance() { + return null; + } + + + @Override + public String evaluateFeeEquivalent(String fee) { + return null; + } + + @Override + public String getFeeCurrency() { + return null; + } + + @Override + public SignTask.TransactionToSign constructTransaction(Amount amountValue, Amount feeValue, boolean IncFee, String targetAddress) throws Exception { + throw new Exception("Not implemented"); + } + + @Override + public void requestBalanceAndUnspentTransactions(BlockchainRequestsCallbacks blockchainRequestsCallbacks) { + final ServerApiInfura serverApiInfura = new ServerApiInfura(); + // request requestData listener + ServerApiInfura.ResponseListener responseListener = new ServerApiInfura.ResponseListener() { + @Override + public void onSuccess(String method, InfuraResponse infuraResponse) { + try { + if (validateAddress(getContractAddress(ctx.getCard()))) { + String balanceCap = infuraResponse.getResult(); + balanceCap = balanceCap.substring(2); + BigInteger l = new BigInteger(balanceCap, 16); + coinData.setBalanceInInternalUnits(new InternalAmount(l, ctx.getCard().tokenSymbol)); + coinData.setBalanceReceived(true); +// Log.i("$TAG eth_call", balanceCap) + } else { + ctx.setError("Smart contract address not defined"); + } + } catch (Exception e) { + e.printStackTrace(); + } + blockchainRequestsCallbacks.onComplete(!ctx.hasError()); + } + + @Override + public void onFail(String method, String message) { + if (!serverApiInfura.isRequestsSequenceCompleted()) { + ctx.setError(message); + blockchainRequestsCallbacks.onComplete(false); + } + } + }; + serverApiInfura.setResponseListener(responseListener); + + serverApiInfura.requestData(ServerApiInfura.INFURA_ETH_CALL, 67, coinData.getWallet(), getContractAddress(ctx.getCard()), ""); + } + + @Override + public void requestFee(BlockchainRequestsCallbacks blockchainRequestsCallbacks, String targetAddress, Amount amount) { + ServerApiInfura serverApiInfura = new ServerApiInfura(); + // request requestData eth gasPrice listener + ServerApiInfura.ResponseListener responseListener = new ServerApiInfura.ResponseListener() { + @Override + public void onSuccess(String method, InfuraResponse infuraResponse) { + String gasPrice = infuraResponse.getResult(); + gasPrice = gasPrice.substring(2); + + // rounding gas price to integer gwei + BigInteger l = new BigInteger(gasPrice, 16); + + Log.i(TAG, "Infura gas price: " + gasPrice + " (" + l.toString() + ")"); + BigInteger m; + if (!amount.getCurrency().equals(Blockchain.Ethereum.getCurrency())) + m = BigInteger.valueOf(60000); + else m = BigInteger.valueOf(21000); + + Log.i(TAG, "fee multiplier: " + m.toString()); + + InternalAmount weiMinFee = new InternalAmount(l.multiply(m), "wei"); + InternalAmount weiNormalFee = new InternalAmount(l.multiply(BigInteger.valueOf(12)).divide(BigInteger.valueOf(10)).multiply(m), "wei"); + InternalAmount weiMaxFee = new InternalAmount(l.multiply(BigInteger.valueOf(15)).divide(BigInteger.valueOf(10)).multiply(m), "wei"); + Log.i(TAG, "min fee : " + weiMinFee.toValueString() + " wei"); + Log.i(TAG, "normal fee: " + weiNormalFee.toValueString() + " wei"); + Log.i(TAG, "max fee : " + weiMaxFee.toValueString() + " wei"); + + try { + coinData.minFee = convertToAmount(weiMinFee); + coinData.normalFee = convertToAmount(weiNormalFee); + coinData.maxFee = convertToAmount(weiMaxFee); + Log.i(TAG, "min fee : " + coinData.minFee.toString()); + Log.i(TAG, "normal fee: " + coinData.normalFee.toString()); + Log.i(TAG, "max fee : " + coinData.maxFee.toString()); + } catch (Exception e) { + e.printStackTrace(); + } + blockchainRequestsCallbacks.onComplete(true); + } + + @Override + public void onFail(String method, String message) { + ctx.setError(message); + blockchainRequestsCallbacks.onComplete(false); + } + }; + serverApiInfura.setResponseListener(responseListener); + + serverApiInfura.requestData(ServerApiInfura.INFURA_ETH_GAS_PRICE, 67, coinData.getWallet(), "", ""); + } + + @Override + public void requestSendTransaction(BlockchainRequestsCallbacks blockchainRequestsCallbacks, byte[] txForSend) { + } + + public boolean isNftToken() { + return true; + } + + +} diff --git a/app/src/main/java/com/tangem/domain/wallet/rsk/RskTokenEngine.java b/app/src/main/java/com/tangem/domain/wallet/rsk/RskTokenEngine.java index af34eef559..c33b7902ac 100644 --- a/app/src/main/java/com/tangem/domain/wallet/rsk/RskTokenEngine.java +++ b/app/src/main/java/com/tangem/domain/wallet/rsk/RskTokenEngine.java @@ -39,7 +39,7 @@ public class RskTokenEngine extends TokenEngine { @Override public Uri getWalletExplorerUri() { - return Uri.parse("https://explorer.rsk.co/address/" + ctx.getCoinData().getWallet()); + return Uri.parse("https://explorer.rsk.co/address/" + ctx.getCoinData().getWallet() + "?__tab=tokens"); } // Only RSK explorer for now @Override @@ -105,15 +105,11 @@ public class RskTokenEngine extends TokenEngine { // case ServerApiRootstock.ROOTSTOCK_ETH_CALL: { try { - if (validateAddress(getContractAddress(ctx.getCard()))) { - String balanceCap = rootstockResponse.getResult(); - balanceCap = balanceCap.substring(2); - BigInteger l = new BigInteger(balanceCap, 16); - coinData.setBalanceInInternalUnits(new CoinEngine.InternalAmount(l, ctx.getCard().tokenSymbol)); + String balanceCap = rootstockResponse.getResult(); + balanceCap = balanceCap.substring(2); + BigInteger l = new BigInteger(balanceCap, 16); + coinData.setBalanceInInternalUnits(new CoinEngine.InternalAmount(l, ctx.getCard().tokenSymbol)); // Log.i("$TAG eth_call", balanceCap) - } else { - ctx.setError("Smart contract address not defined"); - } if (blockchainRequestsCallbacks.allowAdvance()) { serverApiRootstock.requestData(ServerApiRootstock.ROOTSTOCK_ETH_GET_BALANCE, 67, coinData.getWallet(), "", ""); @@ -147,7 +143,12 @@ public class RskTokenEngine extends TokenEngine { }; serverApiRootstock.setResponseListener(responseListener); - serverApiRootstock.requestData(ServerApiRootstock.ROOTSTOCK_ETH_CALL, 67, coinData.getWallet(), getContractAddress(ctx.getCard()), ""); + if (validateAddress(getContractAddress(ctx.getCard()))) { + serverApiRootstock.requestData(ServerApiRootstock.ROOTSTOCK_ETH_CALL, 67, coinData.getWallet(), getContractAddress(ctx.getCard()), ""); + } else { + ctx.setError("Smart contract address not defined"); + blockchainRequestsCallbacks.onComplete(false); + } } @Override diff --git a/app/src/main/java/com/tangem/domain/wallet/token/TokenEngine.java b/app/src/main/java/com/tangem/domain/wallet/token/TokenEngine.java index cf1fe4ba00..45fd76eba1 100644 --- a/app/src/main/java/com/tangem/domain/wallet/token/TokenEngine.java +++ b/app/src/main/java/com/tangem/domain/wallet/token/TokenEngine.java @@ -679,15 +679,13 @@ public class TokenEngine extends CoinEngine { // case ServerApiInfura.INFURA_ETH_CALL: { try { - if (validateAddress(getContractAddress(ctx.getCard()))) { - String balanceCap = infuraResponse.getResult(); - balanceCap = balanceCap.substring(2); - BigInteger l = new BigInteger(balanceCap, 16); - coinData.setBalanceInInternalUnits(new CoinEngine.InternalAmount(l, ctx.getCard().tokenSymbol)); + + String balanceCap = infuraResponse.getResult(); + balanceCap = balanceCap.substring(2); + BigInteger l = new BigInteger(balanceCap, 16); + coinData.setBalanceInInternalUnits(new CoinEngine.InternalAmount(l, ctx.getCard().tokenSymbol)); // Log.i("$TAG eth_call", balanceCap) - } else { - ctx.setError("Smart contract address not defined"); - } + if (blockchainRequestsCallbacks.allowAdvance()) { serverApiInfura.requestData(ServerApiInfura.INFURA_ETH_GET_BALANCE, 67, coinData.getWallet(), "", ""); @@ -721,7 +719,12 @@ public class TokenEngine extends CoinEngine { }; serverApiInfura.setResponseListener(responseListener); - serverApiInfura.requestData(ServerApiInfura.INFURA_ETH_CALL, 67, coinData.getWallet(), getContractAddress(ctx.getCard()), ""); + if (validateAddress(getContractAddress(ctx.getCard()))) { + serverApiInfura.requestData(ServerApiInfura.INFURA_ETH_CALL, 67, coinData.getWallet(), getContractAddress(ctx.getCard()), ""); + } else { + ctx.setError("Smart contract address not defined"); + blockchainRequestsCallbacks.onComplete(false); + } } @Override diff --git a/app/src/main/java/com/tangem/presentation/fragment/LoadedWallet.kt b/app/src/main/java/com/tangem/presentation/fragment/LoadedWallet.kt index c1d0a3eafc..1ce7f91a5b 100644 --- a/app/src/main/java/com/tangem/presentation/fragment/LoadedWallet.kt +++ b/app/src/main/java/com/tangem/presentation/fragment/LoadedWallet.kt @@ -620,6 +620,13 @@ class LoadedWallet : androidx.fragment.app.Fragment(), NfcAdapter.ReaderCallback btnExtract.backgroundTintList = inactiveColor } + if (engine.isNftToken) { + btnLoad.isEnabled = false + btnLoad.backgroundTintList = inactiveColor + btnExtract.isEnabled = false + btnExtract.backgroundTintList = inactiveColor + } + // //TODO why ??? // ctx.error = null // ctx.message = null @@ -714,6 +721,7 @@ class LoadedWallet : androidx.fragment.app.Fragment(), NfcAdapter.ReaderCallback Blockchain.Ethereum -> "ethereum" Blockchain.EthereumTestNet -> "ethereum" Blockchain.Token -> "ethereum" + Blockchain.NftToken -> "ethereum" Blockchain.BitcoinCash -> "bitcoin-cash" Blockchain.Litecoin -> "litecoin" Blockchain.Rootstock -> "bitcoin" diff --git a/tangemcard-android/src/main/res/drawable/card_default_nft.png b/tangemcard-android/src/main/res/drawable/card_default_nft.png new file mode 100644 index 0000000000000000000000000000000000000000..8f7598bc99d0df6fae16575052a31a6eec6d3654 GIT binary patch literal 24619 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 literal 0 HcmV?d00001 diff --git a/tangemserver-android/src/main/java/com/tangem/tangemserver/android/data/LocalStorage.kt b/tangemserver-android/src/main/java/com/tangem/tangemserver/android/data/LocalStorage.kt index c437f13f27..707e189b87 100644 --- a/tangemserver-android/src/main/java/com/tangem/tangemserver/android/data/LocalStorage.kt +++ b/tangemserver-android/src/main/java/com/tangem/tangemserver/android/data/LocalStorage.kt @@ -50,7 +50,9 @@ class LocalStorage } if (artworks.count() == 0) { +// forceSave=true only on the last one putResourceArtworkToCatalog(R.drawable.card_default, false) + putResourceArtworkToCatalog(R.drawable.card_default_nft, false) putResourceArtworkToCatalog(R.drawable.card_ru006, false) putResourceArtworkToCatalog(R.drawable.card_ru007, false) putResourceArtworkToCatalog(R.drawable.card_ru011, false) @@ -62,12 +64,12 @@ class LocalStorage putResourceArtworkToCatalog(R.drawable.card_ru020, false) putResourceArtworkToCatalog(R.drawable.card_ru021, false) putResourceArtworkToCatalog(R.drawable.card_ru022, false) - putResourceArtworkToCatalog(R.drawable.card_ru023, true) - putResourceArtworkToCatalog(R.drawable.card_ru024, true) - putResourceArtworkToCatalog(R.drawable.card_ru028, true) - putResourceArtworkToCatalog(R.drawable.card_ru029, true) - putResourceArtworkToCatalog(R.drawable.card_ru030, true) - putResourceArtworkToCatalog(R.drawable.card_ru031, true) + putResourceArtworkToCatalog(R.drawable.card_ru023, false) + putResourceArtworkToCatalog(R.drawable.card_ru024, false) + putResourceArtworkToCatalog(R.drawable.card_ru028, false) + putResourceArtworkToCatalog(R.drawable.card_ru029, false) + putResourceArtworkToCatalog(R.drawable.card_ru030, false) + putResourceArtworkToCatalog(R.drawable.card_ru031, false) putResourceArtworkToCatalog(R.drawable.card_ru032, true) } if (batchesFile.exists()) { @@ -175,14 +177,25 @@ class LocalStorage } } - private fun getDefaultArtworkBitmap(): Bitmap { - val defaultArtworkId = context.resources.getResourceEntryName(R.drawable.card_default) + private fun getDefaultArtworkBitmap(card: TangemCard): Bitmap { + val defaultArtworkId: String + if (card.tokenSymbol.startsWith("NFT:")) { + defaultArtworkId = context.resources.getResourceEntryName(R.drawable.card_default_nft) + } else { + defaultArtworkId = context.resources.getResourceEntryName(R.drawable.card_default) + } val info = artworks[defaultArtworkId] var bitmap: Bitmap? = null if (info != null && !info.isResource) { bitmap = loadArtworkBitmapFromFile(defaultArtworkId) } - if (bitmap == null) return BitmapFactory.decodeResource(context.resources, R.drawable.card_default) + if (bitmap == null) { + if (card.tokenSymbol.startsWith("NFT:")) { + return BitmapFactory.decodeResource(context.resources, R.drawable.card_default_nft) + } else { + return BitmapFactory.decodeResource(context.resources, R.drawable.card_default) + } + } return bitmap } @@ -236,11 +249,11 @@ class LocalStorage if (artworkResourceId != null) { val artworkId = context.resources.getResourceEntryName(artworkResourceId) - return getArtworkBitmap(artworkId) ?: return getDefaultArtworkBitmap() + return getArtworkBitmap(artworkId) ?: return getDefaultArtworkBitmap(card) } - val batchInfo = batches[card.batch] ?: return getDefaultArtworkBitmap() - val artworkId = batchInfo.artworkId ?: return getDefaultArtworkBitmap() - return getArtworkBitmap(artworkId) ?: return getDefaultArtworkBitmap() + val batchInfo = batches[card.batch] ?: return getDefaultArtworkBitmap(card) + val artworkId = batchInfo.artworkId ?: return getDefaultArtworkBitmap(card) + return getArtworkBitmap(artworkId) ?: return getDefaultArtworkBitmap(card) } override fun applySubstitution(card: TangemCard) {