diff --git a/app/src/main/java/com/tangem/data/network/ServerApiStellar.java b/app/src/main/java/com/tangem/data/network/ServerApiStellar.java index b63a42274e..9882a26902 100644 --- a/app/src/main/java/com/tangem/data/network/ServerApiStellar.java +++ b/app/src/main/java/com/tangem/data/network/ServerApiStellar.java @@ -117,9 +117,9 @@ public class ServerApiStellar { return Observable.just(stellarRequest1); } ) - .retryWhen(errors -> errors - .filter(throwable -> (throwable instanceof IOException) || (throwable instanceof ErrorResponse)) - .zipWith(Observable.range(1, 4), (n, i) -> i)) +// .retryWhen(errors -> errors +// .filter(throwable -> (throwable instanceof IOException) || (throwable instanceof ErrorResponse)) +// .zipWith(Observable.range(1, 4), (n, i) -> i)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); @@ -136,8 +136,8 @@ public class ServerApiStellar { LOG.e(TAG, "requestData " + stellarRequest.getClass().getSimpleName() + " onError " + e.getMessage()); LOG.e(TAG, String.format("%d requests left in processing", requestsCount)); - if (isRetry) { - stellarRequest.setError(ctx.getString(R.string.loaded_wallet_error_obtaining_blockchain_data)); + if (isRetry || stellarRequest.errorResponse.getCode() == 404) { + stellarRequest.setError(e.getMessage()); //setErrorOccurred(e.getMessage());//; listener.onFail(stellarRequest); } else { diff --git a/app/src/main/java/com/tangem/ui/activity/MainActivity.kt b/app/src/main/java/com/tangem/ui/activity/MainActivity.kt index f4e42ae6db..b68c82ab28 100644 --- a/app/src/main/java/com/tangem/ui/activity/MainActivity.kt +++ b/app/src/main/java/com/tangem/ui/activity/MainActivity.kt @@ -1,5 +1,3 @@ -@file:Suppress("ObsoleteExperimentalCoroutines") - package com.tangem.ui.activity import android.content.Context @@ -10,12 +8,14 @@ import android.nfc.Tag import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.ViewModelProviders +import androidx.navigation.findNavController import com.scottyab.rootbeer.RootBeer import com.tangem.App import com.tangem.di.ToastHelper import com.tangem.tangem_sdk.android.nfc.NfcLifecycleObserver import com.tangem.tangem_sdk.android.reader.NfcManager import com.tangem.ui.dialog.RootFoundDialog +import com.tangem.util.navigateSafely import com.tangem.wallet.BuildConfig import com.tangem.wallet.R import javax.inject.Inject @@ -39,6 +39,7 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback { if (intent != null && (NfcAdapter.ACTION_TECH_DISCOVERED == intent.action || NfcAdapter.ACTION_NDEF_DISCOVERED == intent.action)) { val tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG) if (tag != null) { + findNavController(R.id.nav_host_fragment).navigateSafely(R.id.main) onTagDiscovered(tag) } } diff --git a/app/src/main/java/com/tangem/ui/fragment/BaseFragment.kt b/app/src/main/java/com/tangem/ui/fragment/BaseFragment.kt index 776d159e6b..80bbf19131 100644 --- a/app/src/main/java/com/tangem/ui/fragment/BaseFragment.kt +++ b/app/src/main/java/com/tangem/ui/fragment/BaseFragment.kt @@ -11,6 +11,7 @@ import androidx.navigation.fragment.NavHostFragment.findNavController import com.tangem.ui.activity.MainActivity import com.tangem.ui.navigation.NavigationResult import com.tangem.ui.navigation.NavigationResultListener +import com.tangem.util.navigateSafely abstract class BaseFragment : Fragment() { @@ -74,13 +75,7 @@ abstract class BaseFragment : Fragment() { } protected fun navigateToDestination(@IdRes destination: Int, data: Bundle? = null) { - try { - findNavController(this).navigate(destination, data) - } catch (e: IllegalArgumentException) { - Log.w(this::class.java.simpleName, e.message) - } catch (e: IllegalStateException) { - Log.w(this::class.java.simpleName, e.message) - } + findNavController(this).navigateSafely(destination, data) } protected fun navigateBackWithResult(resultCode: Int, data: Bundle? = null, diff --git a/app/src/main/java/com/tangem/util/NavigationExtensions.kt b/app/src/main/java/com/tangem/util/NavigationExtensions.kt new file mode 100644 index 0000000000..ff4df71b13 --- /dev/null +++ b/app/src/main/java/com/tangem/util/NavigationExtensions.kt @@ -0,0 +1,16 @@ +package com.tangem.util + +import android.os.Bundle +import android.util.Log +import androidx.annotation.IdRes +import androidx.navigation.NavController + +fun NavController.navigateSafely(@IdRes destination: Int, data: Bundle? = null) { + try { + this.navigate(destination, data) + } catch (e: IllegalArgumentException) { + Log.w(this::class.java.simpleName, e.message) + } catch (e: IllegalStateException) { + Log.w(this::class.java.simpleName, e.message) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/wallet/bch/BitcoinCashNode.kt b/app/src/main/java/com/tangem/wallet/bch/BitcoinCashNode.kt index b31677c586..3355580efe 100644 --- a/app/src/main/java/com/tangem/wallet/bch/BitcoinCashNode.kt +++ b/app/src/main/java/com/tangem/wallet/bch/BitcoinCashNode.kt @@ -2,7 +2,6 @@ package com.tangem.wallet.bch enum class BitcoinCashNode(val host: String, val port: Int, val proto: String) { N_001("electrumx.hillsideinternet.com", 50002, "ssl"), - N_002("electron.coinucopia.io", 50002, "ssl"), - N_003("blackie.c3-soft.com", 50002, "ssl"), - N_004("electrum.imaginary.cash", 50002, "ssl"), + N_002("blackie.c3-soft.com", 50002, "ssl"), + N_003("electrum.imaginary.cash", 50002, "ssl"), } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/wallet/xlm/XlmData.java b/app/src/main/java/com/tangem/wallet/xlm/XlmData.java index b956759278..9eab0764f8 100644 --- a/app/src/main/java/com/tangem/wallet/xlm/XlmData.java +++ b/app/src/main/java/com/tangem/wallet/xlm/XlmData.java @@ -30,13 +30,14 @@ public class XlmData extends CoinData { private Long sequenceNumber = 0L; private CoinEngine.Amount baseReserve = new CoinEngine.Amount("0.5", "XLM"); private CoinEngine.Amount baseFee = new CoinEngine.Amount("0.00001", "XLM"); - private boolean error404 = false; + private boolean error404, targetAccountCreated = false; @Override public void clearInfo() { super.clearInfo(); balance = null; error404 = false; + targetAccountCreated = false; } CoinEngine.Amount getBalance() { @@ -86,6 +87,14 @@ public class XlmData extends CoinData { this.error404 = error404; } + public boolean isTargetAccountCreated() { + return targetAccountCreated; + } + + public void setTargetAccountCreated(boolean targetAccountCreated) { + this.targetAccountCreated = targetAccountCreated; + } + @Override public void loadFromBundle(Bundle B) { super.loadFromBundle(B); @@ -116,6 +125,9 @@ public class XlmData extends CoinData { if (B.containsKey("Error404")) error404 = B.getBoolean("Error404"); else error404 = false; + + if (B.containsKey("TargetAccountCreated")) targetAccountCreated = B.getBoolean("TargetAccountCreated"); + else targetAccountCreated = false; } @Override @@ -143,6 +155,8 @@ public class XlmData extends CoinData { if (error404) B.putBoolean("Error404", true); + if (targetAccountCreated) B.putBoolean("TargetAccountCreated", true); + } catch (Exception e) { Log.e("Can't save to bundle ", e.getMessage()); } diff --git a/app/src/main/java/com/tangem/wallet/xlm/XlmEngine.java b/app/src/main/java/com/tangem/wallet/xlm/XlmEngine.java index f22bdc5c2f..717d3d85bf 100644 --- a/app/src/main/java/com/tangem/wallet/xlm/XlmEngine.java +++ b/app/src/main/java/com/tangem/wallet/xlm/XlmEngine.java @@ -361,7 +361,7 @@ public class XlmEngine extends CoinEngine { } Operation operation; - if (isAccountCreated(targetAddress)) + if (coinData.isTargetAccountCreated()) operation = new PaymentOperation.Builder(KeyPair.fromAccountId(targetAddress), new AssetTypeNative(), amountValue.toValueString()).build(); else operation = new CreateAccountOperation.Builder(KeyPair.fromAccountId(targetAddress), amountValue.toValueString()).build(); @@ -414,24 +414,41 @@ public class XlmEngine extends CoinEngine { }; } - - // network call inside, don't use on main thread - private boolean isAccountCreated(String address) { + private void checkTargetAccountCreated(BlockchainRequestsCallbacks blockchainRequestsCallbacks, String targetAddress, Amount amount) { final ServerApiStellar serverApi = new ServerApiStellar(ctx.getBlockchain()); - StellarRequest.Balance request = new StellarRequest.Balance(address); + ServerApiStellar.Listener listener = new ServerApiStellar.Listener() { + @Override + public void onSuccess(StellarRequest.Base request) { + coinData.setTargetAccountCreated(true); + blockchainRequestsCallbacks.onComplete(true); + } - try { - serverApi.doStellarRequest(ctx, request); - } catch (IOException e) { - Log.e(TAG, e.getMessage()); - return true; // suppose account is created if anything goes wrong TODO:check - } - if (request.errorResponse != null && request.errorResponse.getCode() == 404) - return false; - else - return true; + @Override + public void onFail(StellarRequest.Base request) { + Log.i(TAG, "onFail: " + request.getClass().getSimpleName() + " " + request.getError()); + + if (request.errorResponse.getCode() == 404) { + coinData.setTargetAccountCreated(false); + + if (amount.compareTo(coinData.getReserve()) >= 0) { //TODO: take fee inclusion in account, now 1 XLM with fee included will fail after transaction is sent + blockchainRequestsCallbacks.onComplete(true); + } else { + ctx.setError(R.string.confirm_transaction_error_not_enough_xlm_for_create); + blockchainRequestsCallbacks.onComplete(false); + } + } else { // suppose account is created if anything goes wrong + coinData.setTargetAccountCreated(true); + blockchainRequestsCallbacks.onComplete(true); + } + } + }; + + serverApi.setListener(listener); + + serverApi.requestData(ctx, new StellarRequest.Balance(targetAddress)); + } @Override @@ -501,9 +518,8 @@ public class XlmEngine extends CoinEngine { @Override public void requestFee(BlockchainRequestsCallbacks blockchainRequestsCallbacks, String targetAddress, Amount amount) throws Exception { - // TODO: get fee stats? coinData.minFee = coinData.normalFee = coinData.maxFee = coinData.getBaseFee(); - blockchainRequestsCallbacks.onComplete(true); + checkTargetAccountCreated(blockchainRequestsCallbacks, targetAddress, amount); //TODO: move? } @Override diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 24812c1f37..53a6ee35ff 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -205,10 +205,12 @@ Please wait for confirmation of incoming transaction Not enough ETH funds for fee Not enough RBTC funds for fee + Target account is not created! Send 1+ XLM to create it PIN2 is required to sign the payment Service unavailable You have a risk of delaying transaction + Wallet hasn\'t been yet created Create Wallet diff --git a/app/src/tangemAccess/java/com/tangem/ui/PrepareTransactionFragment.kt b/app/src/tangemAccess/java/com/tangem/ui/PrepareTransactionFragment.kt index beeb4f1a33..e09a207c57 100644 --- a/app/src/tangemAccess/java/com/tangem/ui/PrepareTransactionFragment.kt +++ b/app/src/tangemAccess/java/com/tangem/ui/PrepareTransactionFragment.kt @@ -2,6 +2,7 @@ package com.tangem.ui import android.app.Activity import android.content.Context +import android.net.Uri import android.nfc.NfcAdapter import android.nfc.Tag import android.os.Build @@ -12,7 +13,6 @@ import android.view.inputmethod.EditorInfo import android.view.inputmethod.InputMethodManager import android.widget.Toast import com.tangem.Constant -import com.tangem.data.Blockchain import com.tangem.ui.activity.MainActivity import com.tangem.ui.fragment.BaseFragment import com.tangem.ui.fragment.qr.CameraPermissionManager @@ -23,6 +23,7 @@ import com.tangem.wallet.R import com.tangem.wallet.TangemContext import kotlinx.android.synthetic.tangemAccess.fragment_prepare_transaction.* import java.io.IOException +import java.util.* class PrepareTransactionFragment : BaseFragment(), NavigationResultListener, NfcAdapter.ReaderCallback { companion object { @@ -138,39 +139,26 @@ class PrepareTransactionFragment : BaseFragment(), NavigationResultListener, Nfc override fun onNavigationResult(requestCode: String, resultCode: Int, data: Bundle?) { if (requestCode == Constant.REQUEST_CODE_SCAN_QR && resultCode == Activity.RESULT_OK && data != null && data.containsKey("QRCode")) { - var code = data.getString("QRCode") - when (ctx.blockchain) { - Blockchain.Bitcoin -> { - if (code.contains("bitcoin:")) { - val tmp = code.split("bitcoin:".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() - code = tmp[1] - } - } - Blockchain.Ethereum, Blockchain.Token -> { - if (code.contains("ethereum:")) { - val tmp = code.split("ethereum:".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() - code = tmp[1] - } else if (code.contains("blockchain:")) { //TODO: is this needed? - val tmp = code.split("blockchain:".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() - code = tmp[1] - } - } - Blockchain.Litecoin -> { - if (code.contains("litecoin:")) { - val tmp = code.split("litecoin:".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() - code = tmp[1] - } - } - Blockchain.Ripple -> { - if (code.contains("ripple:")) { - val tmp = code.split("ripple:".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() - code = tmp[1] + val code = data.getString("QRCode") + val schemeSplit = code!!.split(":") + when (schemeSplit.size) { + 2 -> { + if (ctx.blockchain.officialName.toLowerCase(Locale.ROOT).replace("\\s","") == schemeSplit[0]) { + val uri = Uri.parse(schemeSplit[1]) + etWallet?.setText(uri.path) +// val amount = uri.getQueryParameter("amount") //TODO: enable after redesign +// if (amount != null) { +// etAmount?.setText(amount) +// rgIncFee.check(R.id.rbFeeOut) +// } + } else { + etWallet?.setText(code) } } else -> { + etWallet?.setText(code) } } - etWallet?.setText(code) } else if (requestCode == Constant.REQUEST_CODE_SEND_TRANSACTION__) { navigateBackWithResult(resultCode, data) }