Updated on 2026-08-14
This commit is contained in:
commit
7ab56fa251
9 changed files with 95 additions and 64 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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<Tag>(NfcAdapter.EXTRA_TAG)
|
||||
if (tag != null) {
|
||||
findNavController(R.id.nav_host_fragment).navigateSafely(R.id.main)
|
||||
onTagDiscovered(tag)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
16
app/src/main/java/com/tangem/util/NavigationExtensions.kt
Normal file
16
app/src/main/java/com/tangem/util/NavigationExtensions.kt
Normal file
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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"),
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -205,10 +205,12 @@
|
|||
<string name="confirm_transaction_error_incoming_transaction_unconfirmed">Please wait for confirmation of incoming transaction</string>
|
||||
<string name="confirm_transaction_error_not_enough_eth_for_fee">Not enough ETH funds for fee</string>
|
||||
<string name="confirm_transaction_error_not_enough_rbtc_for_fee">Not enough RBTC funds for fee</string>
|
||||
<string name="confirm_transaction_error_not_enough_xlm_for_create">Target account is not created! Send 1+ XLM to create it</string>
|
||||
<string name="confirm_transaction_error_pin_2_is_required">PIN2 is required to sign the payment</string>
|
||||
<string name="confirm_transaction_error_service_unavailable">Service unavailable</string>
|
||||
<string name="confirm_transaction_warning_risk_delaying">You have a risk of delaying transaction</string>
|
||||
|
||||
|
||||
<!-- EmptyWallet -->
|
||||
<string name="empty_wallet_not_created">Wallet hasn\'t been yet created</string>
|
||||
<string name="empty_wallet_btn_create">Create Wallet</string>
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue