From b43e6bafb176d280dc36c24dfb620a9c0547dd52 Mon Sep 17 00:00:00 2001 From: James Brown Date: Sun, 8 Oct 2023 18:58:59 +1100 Subject: [PATCH] Optimise TS Loading and fix memory issue --- app/build.gradle | 2 - .../entity/tokenscript/TokenScriptFile.java | 7 +- .../app/service/AssetDefinitionService.java | 46 +++++++++++-- .../app/ui/AssetDisplayActivity.java | 10 +-- .../alphawallet/app/ui/FunctionActivity.java | 34 +++++++--- .../com/alphawallet/app/ui/HomeActivity.java | 5 +- .../app/ui/NFTAssetDetailActivity.java | 67 ++++++++++++------- .../app/viewmodel/TokenFunctionViewModel.java | 20 ++++-- .../alphawallet/app/web3/Web3TokenView.java | 37 ++++++++-- .../res/layout/activity_nft_asset_detail.xml | 7 -- .../token/tools/TokenDefinition.java | 5 ++ 11 files changed, 167 insertions(+), 73 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 3fd0de955d..21d84e889f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -259,8 +259,6 @@ dependencies { implementation 'com.journeyapps:zxing-android-embedded:4.3.0' implementation 'com.google.zxing:core:3.5.2' - implementation 'com.gu.android:toolargetool:0.3.0' - // Sugar implementation 'androidx.constraintlayout:constraintlayout:2.1.4' diff --git a/app/src/main/java/com/alphawallet/app/entity/tokenscript/TokenScriptFile.java b/app/src/main/java/com/alphawallet/app/entity/tokenscript/TokenScriptFile.java index a7a9689839..185151659e 100644 --- a/app/src/main/java/com/alphawallet/app/entity/tokenscript/TokenScriptFile.java +++ b/app/src/main/java/com/alphawallet/app/entity/tokenscript/TokenScriptFile.java @@ -95,13 +95,16 @@ public boolean isValidTokenScript() return active || resourceFile; } - public String calcMD5() + { + return calcMD5(getInputStream()); + } + + public static String calcMD5(InputStream fis) { StringBuilder sb = new StringBuilder(); try { - InputStream fis = getInputStream(); MessageDigest digest = MessageDigest.getInstance("MD5"); byte[] byteArray = new byte[1024]; diff --git a/app/src/main/java/com/alphawallet/app/service/AssetDefinitionService.java b/app/src/main/java/com/alphawallet/app/service/AssetDefinitionService.java index 3632cd0d7e..65a2e3e37b 100644 --- a/app/src/main/java/com/alphawallet/app/service/AssetDefinitionService.java +++ b/app/src/main/java/com/alphawallet/app/service/AssetDefinitionService.java @@ -81,6 +81,7 @@ import org.xml.sax.SAXException; import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -93,6 +94,7 @@ import java.math.BigInteger; import java.net.HttpURLConnection; import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; @@ -1304,6 +1306,11 @@ private File storeEntry(Token token, Pair> scriptD String tempFileKey = token.getTSKey(); + if (!checkFileDiff(tempFileKey, scriptData.second)) + { + return new File(UNCHANGED_SCRIPT); + } + File tempStoreFile = storeFile(tempFileKey, scriptData.second); TokenScriptFile tsf = new TokenScriptFile(context, tempStoreFile.getAbsolutePath()); @@ -2072,6 +2079,27 @@ private XMLDsigDescriptor IPFSSigDescriptor() return sig; } + private boolean checkFileDiff(String address, Pair result) + { + if (result.first == null || result.first.length() < 10) + { + return false; + } + + //calc MD5 of this new script + String newMD5Hash = TokenScriptFile.calcMD5(new ByteArrayInputStream(result.first.getBytes(StandardCharsets.UTF_8))); + TokenScriptFile tsf = new TokenScriptFile(context, defineDownloadTSFile(address).getAbsolutePath()); + + if (tsf.exists()) + { + return !tsf.calcMD5().equals(newMD5Hash); + } + else + { + return true; + } + } + /** * Use internal directory to store contracts fetched from the server * @@ -2082,13 +2110,12 @@ private XMLDsigDescriptor IPFSSigDescriptor() */ private File storeFile(String address, Pair result) throws IOException { - if (result.first == null || result.first.length() < 10) return new File(""); - - String fName = address + TS_EXTENSION; - - //Store received files in the internal storage area - no need to ask for permissions - File file = new File(context.getFilesDir(), fName); + if (result.first == null || result.first.length() < 10) + { + return new File(""); + } + File file = defineDownloadTSFile(address); FileOutputStream fos = new FileOutputStream(file); OutputStream os = new BufferedOutputStream(fos); os.write(result.first.getBytes()); @@ -2107,6 +2134,13 @@ private File storeFile(String address, Pair result) throws IOEx return file; } + private File defineDownloadTSFile(String address) + { + String fName = address + TS_EXTENSION; + //Store received files in the internal storage area - no need to ask for permissions + return new File(context.getFilesDir(), fName); + } + public boolean hasDefinition(Token token) { boolean hasDefinition = false; diff --git a/app/src/main/java/com/alphawallet/app/ui/AssetDisplayActivity.java b/app/src/main/java/com/alphawallet/app/ui/AssetDisplayActivity.java index 0c69e19c8d..6e693fc7d5 100644 --- a/app/src/main/java/com/alphawallet/app/ui/AssetDisplayActivity.java +++ b/app/src/main/java/com/alphawallet/app/ui/AssetDisplayActivity.java @@ -183,7 +183,7 @@ private void viewHeight(int fetchedViewHeight) { if (fetchedViewHeight < 100) { - initWebViewCheck(); + initWebViewCheck(viewModel.getAssetDefinitionService().getAssetDefinition(token)); handler.postDelayed(this, TOKEN_SIZING_DELAY); //wait 3 seconds until ending height check } else @@ -196,14 +196,14 @@ private void viewHeight(int fetchedViewHeight) private void onNewScript(TokenDefinition td) { //need to reload tokens, now we have an updated/new script - if (td != null) + if (td != null && td.isChanged()) { - initWebViewCheck(); + initWebViewCheck(td); handler.postDelayed(this, TOKEN_SIZING_DELAY); } } - private void initWebViewCheck() + private void initWebViewCheck(TokenDefinition td) { checkVal = 0; itemViewHeight = 0; @@ -212,7 +212,7 @@ private void initWebViewCheck() { BigInteger tokenId = token.getArrayBalance().get(0); TicketRange data = new TicketRange(tokenId, token.getAddress()); - testView.renderTokenScriptView(token, data, viewModel.getAssetDefinitionService(), ViewType.ITEM_VIEW); + testView.renderTokenScriptView(token, data, viewModel.getAssetDefinitionService(), ViewType.ITEM_VIEW, td); testView.setOnReadyCallback(this); } else diff --git a/app/src/main/java/com/alphawallet/app/ui/FunctionActivity.java b/app/src/main/java/com/alphawallet/app/ui/FunctionActivity.java index f50015e432..84fcc413db 100644 --- a/app/src/main/java/com/alphawallet/app/ui/FunctionActivity.java +++ b/app/src/main/java/com/alphawallet/app/ui/FunctionActivity.java @@ -84,7 +84,6 @@ import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; import timber.log.Timber; -import com.gu.toolargetool.TooLargeTool; /** * Created by James on 4/04/2019. @@ -111,16 +110,23 @@ public class FunctionActivity extends BaseActivity implements FunctionCallback, private TSAction action; private ActionSheet confirmationDialog; - private void initViews() { + private void initViews() + { actionMethod = getIntent().getStringExtra(C.EXTRA_STATE); String tokenIdStr = getIntent().getStringExtra(C.EXTRA_TOKEN_ID); - if (tokenIdStr == null || tokenIdStr.length() == 0) tokenIdStr = "0"; + if (tokenIdStr == null || tokenIdStr.length() == 0) + { + tokenIdStr = "0"; + } Wallet wallet = getIntent().getParcelableExtra(C.Key.WALLET); asset = getIntent().getParcelableExtra(C.EXTRA_NFTASSET); - if (wallet == null) { + if (wallet == null) + { viewModel.getCurrentWallet(); - } else { + } + else + { viewModel.loadWallet(wallet.address); } @@ -168,7 +174,7 @@ private void displayFunction(String tokenAttrs) TSAction action = functions.get(actionMethod); String magicValues = viewModel.getAssetDefinitionService().getMagicValuesForInjection(token.tokenInfo.chainId); - if (Objects.equals(action.view.getUrl(), "")) + if (TextUtils.isEmpty(Objects.requireNonNull(action).view.getUrl())) { String injectedView = tokenView.injectWeb3TokenInit(action.view.getTokenView(), tokenAttrs, tokenId); injectedView = tokenView.injectJSAtEnd(injectedView, magicValues); @@ -176,7 +182,9 @@ private void displayFunction(String tokenAttrs) String base64 = Base64.encodeToString(injectedView.getBytes(StandardCharsets.UTF_8), Base64.DEFAULT); tokenView.loadData(base64 + (!Objects.equals(action.view.getUrlFragment(), "") ? "#" + action.view.getUrlFragment() : ""), "text/html; charset=utf-8", "base64"); - } else { + } + else + { tokenView.loadUrl(action.view.getUrl()); } } @@ -282,14 +290,16 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_script_view); - setupViews(); - - TooLargeTool.startLogging(getApplication()); } private void setupViews() { initViewModel(); + resumeViews(); + } + + private void resumeViews() + { initViews(); toolbar(); setTitle(actionMethod); @@ -302,11 +312,12 @@ public void onResume() super.onResume(); if (viewModel == null) { - initViews(); + setupViews(); } if (parsePass == 0) { + resumeViews(); parsePass = 1; viewModel.getAssetDefinitionService().clearResultMap(); args.clear(); @@ -666,6 +677,7 @@ public void onPause() { super.onPause(); viewModel.resetSignDialog(); + tokenView.destroy(); } public void onSaveInstanceState(@NonNull Bundle savedInstanceState) diff --git a/app/src/main/java/com/alphawallet/app/ui/HomeActivity.java b/app/src/main/java/com/alphawallet/app/ui/HomeActivity.java index 69d654015a..74fae529ae 100644 --- a/app/src/main/java/com/alphawallet/app/ui/HomeActivity.java +++ b/app/src/main/java/com/alphawallet/app/ui/HomeActivity.java @@ -91,7 +91,6 @@ import com.journeyapps.barcodescanner.ScanContract; import com.journeyapps.barcodescanner.ScanOptions; import com.walletconnect.android.CoreClient; -import com.gu.toolargetool.TooLargeTool; import net.yslibrary.android.keyboardvisibilityevent.KeyboardVisibilityEvent; @@ -278,8 +277,6 @@ public void onPageScrollStateChanged(int state) viewModel.defaultWallet().observe(this, this::onDefaultWallet); viewModel.updateAvailable().observe(this, this::onUpdateAvailable); - TooLargeTool.startLogging(getApplication()); - if (CustomViewSettings.hideDappBrowser()) { removeDappBrowser(); @@ -612,7 +609,7 @@ protected void onPause() @Override public void onSaveInstanceState(@NonNull Bundle savedInstanceState) { - super.onSaveInstanceState(savedInstanceState); + super.onSaveInstanceState(new Bundle()); savedInstanceState.putInt(STORED_PAGE, viewPager.getCurrentItem()); if (getSelectedItem() != null) { diff --git a/app/src/main/java/com/alphawallet/app/ui/NFTAssetDetailActivity.java b/app/src/main/java/com/alphawallet/app/ui/NFTAssetDetailActivity.java index efb42bc64d..78284d3b1c 100644 --- a/app/src/main/java/com/alphawallet/app/ui/NFTAssetDetailActivity.java +++ b/app/src/main/java/com/alphawallet/app/ui/NFTAssetDetailActivity.java @@ -13,8 +13,10 @@ import android.view.Menu; import android.view.MenuItem; import android.view.View; +import android.view.ViewGroup; import android.view.animation.Animation; import android.view.animation.AnimationUtils; +import android.webkit.WebView; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; @@ -116,6 +118,7 @@ public class NFTAssetDetailActivity extends BaseActivity implements StandardFunc private ActivityResultLauncher getGasSettings; private boolean triggeredReload; private long chainId; + private Web3TokenView tokenScriptView; @Override protected void onCreate(@Nullable Bundle savedInstanceState) @@ -182,6 +185,13 @@ public void onPause() { super.onPause(); tokenImage.onPause(); + if (tokenScriptView != null && tokenScriptView.getVisibility() == View.VISIBLE) + { + LinearLayout webWrapper = findViewById(R.id.layout_webwrapper); + webWrapper.removeView(tokenScriptView); + tokenScriptView.destroy(); + tokenScriptView = null; + } } @Override @@ -244,14 +254,14 @@ private void getIntentData() tokenId = new BigInteger(getIntent().getStringExtra(C.EXTRA_TOKEN_ID)); asset = getIntent().getParcelableExtra(C.EXTRA_NFTASSET); sequenceId = getIntent().getStringExtra(C.EXTRA_STATE); + String walletAddress = getWalletFromIntent(); + viewModel.loadWallet(walletAddress); if (C.ACTION_TOKEN_SHORTCUT.equals(getIntent().getAction())) { - handleShortCut(); + handleShortCut(walletAddress); } else { - Wallet wallet = getIntent().getParcelableExtra(C.Key.WALLET); - viewModel.loadWallet(wallet.address); token = resolveAssetToken(); setup(); } @@ -259,6 +269,19 @@ private void getIntentData() viewModel.startGasPriceUpdate(chainId); } + private String getWalletFromIntent() + { + Wallet w = getIntent().getParcelableExtra(C.Key.WALLET); + if (w != null) + { + return w.address; + } + else + { + return getIntent().getStringExtra(C.Key.WALLET); + } + } + private Token resolveAssetToken() { if (asset != null && asset.isAttestation()) @@ -271,10 +294,8 @@ private Token resolveAssetToken() } } - private void handleShortCut() + private void handleShortCut(String walletAddress) { - String walletAddress = getIntent().getStringExtra(C.Key.WALLET); - viewModel.loadWallet(walletAddress); String tokenAddress = getIntent().getStringExtra(C.EXTRA_ADDRESS); token = viewModel.getTokensService().getToken(walletAddress, chainId, tokenAddress); if (token == null) @@ -319,13 +340,14 @@ private void initViewModel() viewModel.sig().observe(this, this::onSignature); viewModel.newScriptFound().observe(this, this::newScriptFound); viewModel.walletUpdate().observe(this, this::setupFunctionBar); + viewModel.attrFetchComplete().observe(this, this::displayTokenView); } private void newScriptFound(TokenDefinition td) { CertifiedToolbarView certificateToolbar = findViewById(R.id.certified_toolbar); //determinate signature - if (token != null && td != null) + if (token != null && td.isChanged()) { certificateToolbar.stopDownload(); certificateToolbar.setVisibility(View.VISIBLE); @@ -342,7 +364,7 @@ private void newScriptFound(TokenDefinition td) } else { - displayTokenView(td, tokenId); + displayTokenView(td); } } else @@ -614,7 +636,7 @@ else if (td != null) { attnAsset.setupScriptElements(td); attnAsset.setupScriptAttributes(td, token); - if (!displayTokenView(td, BigInteger.ONE)) + if (!displayTokenView(td)) { tokenImage.setupTokenImage(attnAsset); } @@ -831,30 +853,29 @@ public WalletType getWalletType() /*** * TokenScript view handling */ - private boolean displayTokenView(TokenDefinition td, BigInteger tokenId) + private boolean displayTokenView(final TokenDefinition td) { - if (!td.hasTokenView()) - { - return false; - } - + boolean couldDisplay = false; try { - //Attempt to display the token-view - Web3TokenView scriptView = findViewById(R.id.web3_tokenview); LinearLayout webWrapper = findViewById(R.id.layout_webwrapper); - webWrapper.setVisibility(View.VISIBLE); - scriptView.setChainId(token.tokenInfo.chainId); - scriptView.setWalletAddress(new Address(token.getWallet())); + tokenScriptView = new Web3TokenView(this); + tokenScriptView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - scriptView.renderTokenScriptView(token, new TicketRange(tokenId, token.getAddress()), viewModel.getAssetDefinitionService(), ViewType.VIEW); + if (tokenScriptView.renderTokenScriptView(token, new TicketRange(tokenId, token.getAddress()), viewModel.getAssetDefinitionService(), ViewType.VIEW, td)) + { + webWrapper.setVisibility(View.VISIBLE); + tokenScriptView.setChainId(token.tokenInfo.chainId); + tokenScriptView.setWalletAddress(new Address(token.getWallet())); + webWrapper.addView(tokenScriptView); + couldDisplay = true; + } } catch (Exception e) { //fillEmpty(); - return false; } - return true; + return couldDisplay; } } diff --git a/app/src/main/java/com/alphawallet/app/viewmodel/TokenFunctionViewModel.java b/app/src/main/java/com/alphawallet/app/viewmodel/TokenFunctionViewModel.java index adcec6fe57..208e05b78f 100644 --- a/app/src/main/java/com/alphawallet/app/viewmodel/TokenFunctionViewModel.java +++ b/app/src/main/java/com/alphawallet/app/viewmodel/TokenFunctionViewModel.java @@ -26,7 +26,6 @@ import com.alphawallet.app.entity.Wallet; import com.alphawallet.app.entity.WalletType; import com.alphawallet.app.entity.nftassets.NFTAsset; -import com.alphawallet.app.entity.opensea.AssetContract; import com.alphawallet.app.entity.opensea.OpenSeaAsset; import com.alphawallet.app.entity.tokens.Token; import com.alphawallet.app.interact.CreateTransactionInteract; @@ -66,13 +65,13 @@ import com.alphawallet.token.entity.TokenScriptResult; import com.alphawallet.token.entity.TokenscriptElement; import com.alphawallet.token.entity.XMLDsigDescriptor; -import org.web3j.utils.Numeric; import com.alphawallet.token.tools.TokenDefinition; import com.google.gson.Gson; import org.jetbrains.annotations.NotNull; import org.json.JSONException; import org.json.JSONObject; +import org.web3j.utils.Numeric; import java.math.BigDecimal; import java.math.BigInteger; @@ -112,13 +111,12 @@ public class TokenFunctionViewModel extends BaseViewModel implements Transaction private final MutableLiveData invalidAddress = new MutableLiveData<>(); private final MutableLiveData sig = new MutableLiveData<>(); private final MutableLiveData newScriptFound = new MutableLiveData<>(); + private final MutableLiveData attrFetchComplete = new MutableLiveData<>(); private final MutableLiveData walletUpdate = new MutableLiveData<>(); private final MutableLiveData transactionFinalised = new MutableLiveData<>(); private final MutableLiveData transactionError = new MutableLiveData<>(); private final MutableLiveData gasEstimateComplete = new MutableLiveData<>(); private final MutableLiveData> gasEstimateError = new MutableLiveData<>(); - private final MutableLiveData> traits = new MutableLiveData<>(); - private final MutableLiveData assetContract = new MutableLiveData<>(); private final MutableLiveData nftAsset = new MutableLiveData<>(); private final MutableLiveData scriptUpdateInProgress = new MutableLiveData<>(); private Wallet wallet; @@ -190,6 +188,11 @@ public LiveData newScriptFound() return newScriptFound; } + public LiveData attrFetchComplete() + { + return attrFetchComplete; + } + public LiveData scriptUpdateInProgress() { return scriptUpdateInProgress; @@ -601,7 +604,8 @@ private void handleDefinition(TokenDefinition td) switch (td.nameSpace) { case UNCHANGED_SCRIPT: - newScriptFound.postValue(null); + td.nameSpace = UNCHANGED_SCRIPT; + newScriptFound.postValue(td); break; case NO_SCRIPT: scriptUpdateInProgress.postValue(false); @@ -925,13 +929,17 @@ private void updateAllowedAttrs(Token token, Map> avail return; } TokenDefinition td = assetDefinitionService.getAssetDefinition(token); + if (td == null) + { + return; + } List localAttrList = assetDefinitionService.getLocalAttributes(td, availableActions); //now refresh all these attrs assetDefinitionService.refreshAttributes(token, td, availableActions.keySet().stream().findFirst().get(), localAttrList) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(v -> { }, this::onError) + .subscribe(v -> attrFetchComplete.postValue(td), this::onError) .isDisposed(); } diff --git a/app/src/main/java/com/alphawallet/app/web3/Web3TokenView.java b/app/src/main/java/com/alphawallet/app/web3/Web3TokenView.java index d9258c489f..62d0b5b966 100644 --- a/app/src/main/java/com/alphawallet/app/web3/Web3TokenView.java +++ b/app/src/main/java/com/alphawallet/app/web3/Web3TokenView.java @@ -434,7 +434,7 @@ private void renderTicketHolder(Token token, TokenDefinition td, TicketRange ran if (td != null && td.holdingToken != null) { //use webview - renderTokenScriptView(token, range, assetService, iconified); + renderTokenScriptView(token, range, assetService, iconified, td); } else { @@ -458,9 +458,13 @@ private void showLegacyView(Token token, TicketRange range) loadData(displayData, "text/html", "utf-8"); } - public void renderTokenScriptView(Token token, TicketRange range, AssetDefinitionService assetService, ViewType itemView) + public boolean renderTokenScriptView(Token token, TicketRange range, AssetDefinitionService assetService, ViewType itemView, final TokenDefinition td) { BigInteger tokenId = range.tokenIds.get(0); + if (!td.hasTokenView()) + { + return false; + } final StringBuilder attrs = assetService.getTokenAttrs(token, tokenId, range.tokenIds.size()); @@ -468,8 +472,10 @@ public void renderTokenScriptView(Token token, TicketRange range, AssetDefinitio .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(attr -> onAttr(attr, attrs), throwable -> onError(token, throwable, range), - () -> displayTicket(token, assetService, attrs, itemView, range)) + () -> displayTicket(token, assetService, attrs, itemView, range, td)) .isDisposed(); + + return true; } /** @@ -480,7 +486,7 @@ public void renderTokenScriptView(Token token, TicketRange range, AssetDefinitio * @param iconified * @param range */ - private void displayTicket(Token token, AssetDefinitionService assetService, StringBuilder attrs, ViewType iconified, TicketRange range) + private void displayTicket(Token token, AssetDefinitionService assetService, StringBuilder attrs, ViewType iconified, TicketRange range, final TokenDefinition td) { setVisibility(View.VISIBLE); String viewName; @@ -495,7 +501,7 @@ private void displayTicket(Token token, AssetDefinitionService assetService, Str break; } - TSTokenView tokenView = assetService.getTSTokenView(token, viewName); + TSTokenView tokenView = td.getTSTokenView(viewName); String view = tokenView.getTokenView(); if (TextUtils.isEmpty(view)) @@ -517,9 +523,10 @@ private void displayTicket(Token token, AssetDefinitionService assetService, Str realmAuxUpdates = RealmAuxData.getEventListener(realm, token, range.tokenIds.get(0), 1, lastUpdateTime); realmAuxUpdates.addChangeListener(realmAux -> { if (realmAux.size() == 0) return; - //reload token view, updated event will be fetched from DB - displayTicketHolder(token, range, assetService, iconified); + renderTicketHolder(token, td, range, assetService, iconified); }); + + invalidate(); } private long getLastUpdateTime(Realm realm, Token token, BigInteger tokenId) @@ -535,6 +542,22 @@ private long getLastUpdateTime(Realm realm, Token token, BigInteger tokenId) return lastResultTime + 1; } + @Override + public void onPause() + { + super.onPause(); + if (realmAuxUpdates != null) + { + realmAuxUpdates.removeAllChangeListeners(); + if (!realmAuxUpdates.getRealm().isClosed()) + { + realmAuxUpdates.getRealm().close(); + } + } + + loadData("", "text/html", "utf-8"); + } + @Override public void destroy() { diff --git a/app/src/main/res/layout/activity_nft_asset_detail.xml b/app/src/main/res/layout/activity_nft_asset_detail.xml index 5a814ea984..b68c1dae6a 100644 --- a/app/src/main/res/layout/activity_nft_asset_detail.xml +++ b/app/src/main/res/layout/activity_nft_asset_detail.xml @@ -56,13 +56,6 @@ android:visibility="gone" tools:visibility="visible"> - - - -