diff --git a/app/build.gradle b/app/build.gradle index c2bb0b4..8e4a678 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -7,8 +7,8 @@ android { applicationId "com.m2049r.xmrwallet" minSdkVersion 21 targetSdkVersion 29 - versionCode 702 - versionName "1.17.2 'Druk'" + versionCode 705 + versionName "1.17.5.1 'Druk'" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" externalNativeBuild { cmake { diff --git a/app/src/main/java/com/m2049r/xmrwallet/BaseActivity.java b/app/src/main/java/com/m2049r/xmrwallet/BaseActivity.java index 43185b2..d30f297 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/BaseActivity.java +++ b/app/src/main/java/com/m2049r/xmrwallet/BaseActivity.java @@ -213,7 +213,7 @@ public class BaseActivity extends SecureActivity implements GenerateReviewFragme if (uri == null) { Toast.makeText(this, getString(R.string.nfc_tag_read_undef), Toast.LENGTH_LONG).show(); } else { - BarcodeData bc = BarcodeData.fromQrCode(uri.toString()); + BarcodeData bc = BarcodeData.fromString(uri.toString()); if (bc == null) Toast.makeText(this, getString(R.string.nfc_tag_read_undef), Toast.LENGTH_LONG).show(); else diff --git a/app/src/main/java/com/m2049r/xmrwallet/ReceiveFragment.java b/app/src/main/java/com/m2049r/xmrwallet/ReceiveFragment.java index ffc0c5b..2c0276a 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/ReceiveFragment.java +++ b/app/src/main/java/com/m2049r/xmrwallet/ReceiveFragment.java @@ -58,6 +58,7 @@ import com.google.zxing.qrcode.QRCodeWriter; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; import com.m2049r.xmrwallet.BuildConfig; import com.m2049r.xmrwallet.data.BarcodeData; +import com.m2049r.xmrwallet.data.Crypto; import com.m2049r.xmrwallet.ledger.LedgerProgressDialog; import com.m2049r.xmrwallet.model.Wallet; import com.m2049r.xmrwallet.model.WalletManager; @@ -469,7 +470,7 @@ public class ReceiveFragment extends Fragment { Timber.d("CLEARQR"); return; } - bcData = new BarcodeData(BarcodeData.Asset.XMR, address, notes, xmrAmount); + bcData = new BarcodeData(Crypto.XMR, address, notes, xmrAmount); int size = Math.max(ivQrCode.getWidth(), ivQrCode.getHeight()); Bitmap qr = generate(bcData.getUriString(), size, size); if (qr != null) { diff --git a/app/src/main/java/com/m2049r/xmrwallet/ScannerFragment.java b/app/src/main/java/com/m2049r/xmrwallet/ScannerFragment.java index 4f08cdd..32512fd 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/ScannerFragment.java +++ b/app/src/main/java/com/m2049r/xmrwallet/ScannerFragment.java @@ -73,14 +73,7 @@ public class ScannerFragment extends Fragment implements ZXingScannerView.Result // * On older devices continuously stopping and resuming camera preview can result in freezing the app. // * I don't know why this is the case but I don't have the time to figure out. Handler handler = new Handler(); - handler.postDelayed(new - - Runnable() { - @Override - public void run() { - mScannerView.resumeCameraPreview(ScannerFragment.this); - } - }, 2000); + handler.postDelayed(() -> mScannerView.resumeCameraPreview(ScannerFragment.this), 2000); } @Override diff --git a/app/src/main/java/com/m2049r/xmrwallet/TxFragment.java b/app/src/main/java/com/m2049r/xmrwallet/TxFragment.java index ccf72c4..22e199b 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/TxFragment.java +++ b/app/src/main/java/com/m2049r/xmrwallet/TxFragment.java @@ -300,7 +300,7 @@ public class TxFragment extends Fragment { } tvTxXmrToKey.setText(key); tvDestinationBtc.setText(userNotes.xmrtoDestination); - tvTxAmountBtc.setText(userNotes.xmrtoAmount + " BTC"); + tvTxAmountBtc.setText(userNotes.xmrtoAmount + " "+ userNotes.xmrtoCurrency); switch (userNotes.xmrtoTag) { case "xmrto": tvXmrToSupport.setVisibility(View.GONE); diff --git a/app/src/main/java/com/m2049r/xmrwallet/WalletActivity.java b/app/src/main/java/com/m2049r/xmrwallet/WalletActivity.java index 87de0d8..10d6c1d 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/WalletActivity.java +++ b/app/src/main/java/com/m2049r/xmrwallet/WalletActivity.java @@ -921,7 +921,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste @Override public boolean onScanned(String qrCode) { // #gurke - BarcodeData bcData = BarcodeData.fromQrCode(qrCode); + BarcodeData bcData = BarcodeData.fromString(qrCode); if (bcData != null) { popFragmentStack(null); Timber.d("AAA"); diff --git a/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java b/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java index f441ac5..1a1ac10 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java +++ b/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java @@ -49,6 +49,7 @@ import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi; import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback; import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate; import com.m2049r.xmrwallet.util.Helper; +import com.m2049r.xmrwallet.util.ServiceHelper; import com.m2049r.xmrwallet.widget.Toolbar; import java.text.NumberFormat; @@ -242,7 +243,7 @@ public class WalletFragment extends Fragment String balanceCurrency = Helper.BASE_CRYPTO; double balanceRate = 1.0; - private final ExchangeApi exchangeApi = Helper.getExchangeApi(); + private final ExchangeApi exchangeApi = ServiceHelper.getExchangeApi(); void refreshBalance() { double unconfirmedXmr = Helper.getDecimalAmount(balance - unlockedBalance).doubleValue(); diff --git a/app/src/main/java/com/m2049r/xmrwallet/data/BarcodeData.java b/app/src/main/java/com/m2049r/xmrwallet/data/BarcodeData.java index 8d2b60f..eb155f1 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/data/BarcodeData.java +++ b/app/src/main/java/com/m2049r/xmrwallet/data/BarcodeData.java @@ -18,69 +18,57 @@ package com.m2049r.xmrwallet.data; import android.net.Uri; -import com.m2049r.xmrwallet.model.Wallet; -import com.m2049r.xmrwallet.util.BitcoinAddressValidator; import com.m2049r.xmrwallet.util.OpenAliasHelper; import java.net.URI; import java.net.URISyntaxException; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; +import lombok.ToString; import timber.log.Timber; +@ToString public class BarcodeData { - - public static final String XMR_SCHEME = "monero:"; - public static final String XMR_PAYMENTID = "tx_payment_id"; - public static final String XMR_AMOUNT = "tx_amount"; - public static final String XMR_DESCRIPTION = "tx_description"; - - public static final String OA_XMR_ASSET = "xmr"; - public static final String OA_BTC_ASSET = "btc"; - - static final String BTC_SCHEME = "bitcoin"; - static final String BTC_DESCRIPTION = "message"; - static final String BTC_AMOUNT = "amount"; - - public enum Asset { - XMR, BTC - } - public enum Security { NORMAL, OA_NO_DNSSEC, OA_DNSSEC } - final public Asset asset; + final public Crypto asset; + final public List ambiguousAssets; final public String address; final public String addressName; final public String amount; final public String description; final public Security security; - public BarcodeData(Asset asset, String address) { - this(asset, address, null, null, null, Security.NORMAL); + public BarcodeData(List assets, String address) { + if (assets.isEmpty()) + throw new IllegalArgumentException("no assets specified"); + this.addressName = null; + this.description = null; + this.amount = null; + this.security = Security.NORMAL; + this.address = address; + if (assets.size() == 1) { + this.asset = assets.get(0); + this.ambiguousAssets = null; + } else { + this.asset = null; + this.ambiguousAssets = assets; + } } - public BarcodeData(Asset asset, String address, String amount) { - this(asset, address, null, null, amount, Security.NORMAL); - } - - public BarcodeData(Asset asset, String address, String amount, String description, Security security) { - this(asset, address, null, description, amount, security); - } - - public BarcodeData(Asset asset, String address, String paymentId, String description, String amount) { + public BarcodeData(Crypto asset, String address, String description, String amount) { this(asset, address, null, description, amount, Security.NORMAL); } - public BarcodeData(Asset asset, String address, String description, String amount) { - this(asset, address, null, description, amount, Security.NORMAL); - } - - public BarcodeData(Asset asset, String address, String addressName, String description, String amount, Security security) { + public BarcodeData(Crypto asset, String address, String addressName, String description, String amount, Security security) { + this.ambiguousAssets = null; this.asset = asset; this.address = address; this.addressName = addressName; @@ -94,133 +82,54 @@ public class BarcodeData { } public String getUriString() { - if (asset != Asset.XMR) throw new IllegalStateException("We can only do XMR stuff!"); + if (asset != Crypto.XMR) throw new IllegalStateException("We can only do XMR stuff!"); StringBuilder sb = new StringBuilder(); - sb.append(BarcodeData.XMR_SCHEME).append(address); + sb.append(Crypto.XMR.getUriScheme()).append(address); boolean first = true; if ((description != null) && !description.isEmpty()) { sb.append(first ? "?" : "&"); first = false; - sb.append(BarcodeData.XMR_DESCRIPTION).append('=').append(Uri.encode(description)); + sb.append(Crypto.XMR.getUriMessage()).append('=').append(Uri.encode(description)); } if ((amount != null) && !amount.isEmpty()) { sb.append(first ? "?" : "&"); - sb.append(BarcodeData.XMR_AMOUNT).append('=').append(amount); + sb.append(Crypto.XMR.getUriAmount()).append('=').append(amount); } return sb.toString(); } - static public BarcodeData fromQrCode(String qrCode) { - // check for monero uri - BarcodeData bcData = parseMoneroUri(qrCode); - // check for naked monero address / integrated address - if (bcData == null) { - bcData = parseMoneroNaked(qrCode); - } - // check for btc uri - if (bcData == null) { - bcData = parseBitcoinUri(qrCode); - } - // check for naked btc address - if (bcData == null) { - bcData = parseBitcoinNaked(qrCode); - } - // check for OpenAlias - if (bcData == null) { - bcData = parseOpenAlias(qrCode, false); - } - return bcData; - } - - /** - * Parse and decode a monero scheme string. It is here because it needs to validate the data. - * - * @param uri String containing a monero URL - * @return BarcodeData object or null if uri not valid - */ - - static public BarcodeData parseMoneroUri(String uri) { - Timber.d("parseMoneroUri=%s", uri); - - if (uri == null) return null; - - if (!uri.startsWith(XMR_SCHEME)) return null; - - String noScheme = uri.substring(XMR_SCHEME.length()); - Uri monero = Uri.parse(noScheme); - Map parms = new HashMap<>(); - String query = monero.getEncodedQuery(); - if (query != null) { - String[] args = query.split("&"); - for (String arg : args) { - String[] namevalue = arg.split("="); - if (namevalue.length == 0) { - continue; - } - parms.put(Uri.decode(namevalue[0]).toLowerCase(), - namevalue.length > 1 ? Uri.decode(namevalue[1]) : ""); + static private BarcodeData parseNaked(String address) { + List possibleAssets = new ArrayList<>(); + for (Crypto crypto : Crypto.values()) { + if (crypto.validate(address)) { + possibleAssets.add(crypto); } } - String address = monero.getPath(); - - String paymentId = parms.get(XMR_PAYMENTID); - // no support for payment ids! - if (paymentId != null) { - Timber.e("no support for payment ids!"); + if (possibleAssets.isEmpty()) return null; - } - - String description = parms.get(XMR_DESCRIPTION); - String amount = parms.get(XMR_AMOUNT); - if (amount != null) { - try { - Double.parseDouble(amount); - } catch (NumberFormatException ex) { - Timber.d(ex.getLocalizedMessage()); - return null; // we have an amount but its not a number! - } - } - - if ((address == null) || !Wallet.isAddressValid(address)) { - Timber.d("address invalid"); - return null; - } - return new BarcodeData(Asset.XMR, address, description, amount); + return new BarcodeData(possibleAssets, address); } - static public BarcodeData parseMoneroNaked(String address) { - Timber.d("parseMoneroNaked=%s", address); + static public BarcodeData parseUri(String uriString) { + Timber.d("parseBitUri=%s", uriString); - if (address == null) return null; - - if (!Wallet.isAddressValid(address)) { - Timber.d("address invalid"); - return null; - } - - return new BarcodeData(Asset.XMR, address); - } - - // bitcoin:mpQ84J43EURZHkCnXbyQ4PpNDLLBqdsMW2?amount=0.01 - // bitcoin:?r=https://bitpay.com/i/xxx - static public BarcodeData parseBitcoinUri(String uriString) { - Timber.d("parseBitcoinUri=%s", uriString); - - if (uriString == null) return null; URI uri; try { uri = new URI(uriString); } catch (URISyntaxException ex) { return null; } - if (!uri.isOpaque() || - !uri.getScheme().equals(BTC_SCHEME)) return null; + if (!uri.isOpaque()) return null; + final String scheme = uri.getScheme(); + Crypto crypto = Crypto.withScheme(scheme); + if (crypto == null) return null; String[] parts = uri.getRawSchemeSpecificPart().split("[?]"); if ((parts.length <= 0) || (parts.length > 2)) { Timber.d("invalid number of parts %d", parts.length); return null; } + Map parms = new HashMap<>(); if (parts.length == 2) { String[] args = parts[1].split("&"); @@ -233,17 +142,19 @@ public class BarcodeData { namevalue.length > 1 ? Uri.decode(namevalue[1]) : ""); } } - String description = parms.get(BTC_DESCRIPTION); - String address = parts[0]; // no need to decode as there can bo no special characters + + String addressName = parms.get(crypto.getUriLabel()); + String description = parms.get(crypto.getUriMessage()); + String address = parts[0]; // no need to decode as there can be no special characters if (address.isEmpty()) { Timber.d("no address"); return null; } - if (!BitcoinAddressValidator.validate(address)) { - Timber.d("BTC address (%s) invalid", address); + if (!crypto.validate(address)) { + Timber.d("%s address (%s) invalid", crypto, address); return null; } - String amount = parms.get(BTC_AMOUNT); + String amount = parms.get(crypto.getUriAmount()); if ((amount != null) && (!amount.isEmpty())) { try { Double.parseDouble(amount); @@ -252,20 +163,21 @@ public class BarcodeData { return null; // we have an amount but its not a number! } } - return new BarcodeData(BarcodeData.Asset.BTC, address, description, amount); + return new BarcodeData(crypto, address, addressName, description, amount, Security.NORMAL); } - static public BarcodeData parseBitcoinNaked(String address) { - Timber.d("parseBitcoinNaked=%s", address); - if (address == null) return null; - - if (!BitcoinAddressValidator.validate(address)) { - Timber.d("address invalid"); - return null; + static public BarcodeData fromString(String qrCode) { + BarcodeData bcData = parseUri(qrCode); + if (bcData == null) { + // maybe it's naked? + bcData = parseNaked(qrCode); } - - return new BarcodeData(BarcodeData.Asset.BTC, address); + if (bcData == null) { + // check for OpenAlias + bcData = parseOpenAlias(qrCode, false); + } + return bcData; } static public BarcodeData parseOpenAlias(String oaString, boolean dnssec) { @@ -281,29 +193,16 @@ public class BarcodeData { String address = oaAttrs.get(OpenAliasHelper.OA1_ADDRESS); if (address == null) return null; - Asset asset; - if (OA_XMR_ASSET.equals(oaAsset)) { - if (!Wallet.isAddressValid(address)) { - Timber.d("XMR address invalid"); - return null; - } - asset = Asset.XMR; - } else if (OA_BTC_ASSET.equals(oaAsset)) { - if (!BitcoinAddressValidator.validate(address)) { - Timber.d("BTC address invalid"); - return null; - } - asset = Asset.BTC; - } else { + Crypto crypto = Crypto.withSymbol(oaAsset); + if (crypto == null) { Timber.i("Unsupported OpenAlias asset %s", oaAsset); return null; } - - String paymentId = oaAttrs.get(OpenAliasHelper.OA1_PAYMENTID); - if (paymentId != null) { - Timber.e("paymentId not supported"); + if (!crypto.validate(address)) { + Timber.d("%s address invalid", crypto); return null; } + String description = oaAttrs.get(OpenAliasHelper.OA1_DESCRIPTION); if (description == null) { description = oaAttrs.get(OpenAliasHelper.OA1_NAME); @@ -322,6 +221,10 @@ public class BarcodeData { Security sec = dnssec ? BarcodeData.Security.OA_DNSSEC : BarcodeData.Security.OA_NO_DNSSEC; - return new BarcodeData(asset, address, addressName, description, amount, sec); + return new BarcodeData(crypto, address, addressName, description, amount, sec); + } + + public boolean isAmbiguous() { + return ambiguousAssets != null; } } \ No newline at end of file diff --git a/app/src/main/java/com/m2049r/xmrwallet/data/Crypto.java b/app/src/main/java/com/m2049r/xmrwallet/data/Crypto.java new file mode 100644 index 0000000..e9e66f1 --- /dev/null +++ b/app/src/main/java/com/m2049r/xmrwallet/data/Crypto.java @@ -0,0 +1,89 @@ +package com.m2049r.xmrwallet.data; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.m2049r.xmrwallet.R; +import com.m2049r.xmrwallet.model.Wallet; +import com.m2049r.xmrwallet.util.validator.BitcoinAddressType; +import com.m2049r.xmrwallet.util.validator.BitcoinAddressValidator; +import com.m2049r.xmrwallet.util.validator.EthAddressValidator; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public enum Crypto { + XMR("XMR", true, "monero:tx_amount:recipient_name:tx_description", R.id.ibXMR, R.drawable.ic_monero, R.drawable.ic_monero_bw, Wallet::isAddressValid), + BTC("BTC", true, "bitcoin:amount:label:message", R.id.ibBTC, R.drawable.ic_xmrto_btc, R.drawable.ic_xmrto_btc_off, address -> { + return BitcoinAddressValidator.validate(address, BitcoinAddressType.BTC); + }), + DASH("DASH", true, "dash:amount:label:message", R.id.ibDASH, R.drawable.ic_xmrto_dash, R.drawable.ic_xmrto_dash_off, address -> { + return BitcoinAddressValidator.validate(address, BitcoinAddressType.DASH); + }), + DOGE("DOGE", true, "dogecoin:amount:label:message", R.id.ibDOGE, R.drawable.ic_xmrto_doge, R.drawable.ic_xmrto_doge_off, address -> { + return BitcoinAddressValidator.validate(address, BitcoinAddressType.DOGE); + }), + ETH("ETH", false, "ethereum:amount:label:message", R.id.ibETH, R.drawable.ic_xmrto_eth, R.drawable.ic_xmrto_eth_off, EthAddressValidator::validate), + LTC("LTC", true, "litecoin:amount:label:message", R.id.ibLTC, R.drawable.ic_xmrto_ltc, R.drawable.ic_xmrto_ltc_off, address -> { + return BitcoinAddressValidator.validate(address, BitcoinAddressType.LTC); + }); + + @Getter + @NonNull + private final String symbol; + @Getter + private final boolean casefull; + @NonNull + private final String uriSpec; + @Getter + private final int buttonId; + @Getter + private final int iconEnabledId; + @Getter + private final int iconDisabledId; + @NonNull + private final Validator validator; + + @Nullable + public static Crypto withScheme(@NonNull String scheme) { + for (Crypto crypto : values()) { + if (crypto.getUriScheme().equals(scheme)) return crypto; + } + return null; + } + + @Nullable + public static Crypto withSymbol(@NonNull String symbol) { + final String upperSymbol = symbol.toUpperCase(); + for (Crypto crypto : values()) { + if (crypto.symbol.equals(upperSymbol)) return crypto; + } + return null; + } + + interface Validator { + boolean validate(String address); + } + + // TODO maybe cache these segments + String getUriScheme() { + return uriSpec.split(":")[0]; + } + + String getUriAmount() { + return uriSpec.split(":")[1]; + } + + String getUriLabel() { + return uriSpec.split(":")[2]; + } + + String getUriMessage() { + return uriSpec.split(":")[3]; + } + + boolean validate(String address) { + return validator.validate(address); + } +} diff --git a/app/src/main/java/com/m2049r/xmrwallet/data/TxDataBtc.java b/app/src/main/java/com/m2049r/xmrwallet/data/TxDataBtc.java index d95dbd2..55ec71a 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/data/TxDataBtc.java +++ b/app/src/main/java/com/m2049r/xmrwallet/data/TxDataBtc.java @@ -24,6 +24,9 @@ import lombok.Getter; import lombok.Setter; public class TxDataBtc extends TxData { + @Getter + @Setter + private String btcSymbol; // the actual non-XMR thing we're sending @Getter @Setter private String xmrtoOrderId; // shown in success screen @@ -45,6 +48,7 @@ public class TxDataBtc extends TxData { @Override public void writeToParcel(Parcel out, int flags) { super.writeToParcel(out, flags); + out.writeString(btcSymbol); out.writeString(xmrtoOrderId); out.writeString(btcAddress); out.writeDouble(btcAmount); @@ -63,6 +67,7 @@ public class TxDataBtc extends TxData { protected TxDataBtc(Parcel in) { super(in); + btcSymbol = in.readString(); xmrtoOrderId = in.readString(); btcAddress = in.readString(); btcAmount = in.readDouble(); @@ -74,10 +79,23 @@ public class TxDataBtc extends TxData { StringBuilder sb = new StringBuilder(); sb.append("xmrtoOrderId:"); sb.append(xmrtoOrderId); + sb.append(",btcSymbol:"); + sb.append(btcSymbol); sb.append(",btcAddress:"); sb.append(btcAddress); sb.append(",btcAmount:"); sb.append(btcAmount); return sb.toString(); } + + public boolean validateAddress(@NonNull String address) { + if ((btcSymbol == null) || (btcAddress == null)) return false; + final Crypto crypto = Crypto.withSymbol(btcSymbol); + if (crypto == null) return false; + if (crypto.isCasefull()) { // compare as-is + return address.equals(btcAddress); + } else { // normalize & compare (e.g. ETH with and without checksum capitals + return address.toLowerCase().equals(btcAddress.toLowerCase()); + } + } } diff --git a/app/src/main/java/com/m2049r/xmrwallet/data/UserNotes.java b/app/src/main/java/com/m2049r/xmrwallet/data/UserNotes.java index 0e83105..f5eb14b 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/data/UserNotes.java +++ b/app/src/main/java/com/m2049r/xmrwallet/data/UserNotes.java @@ -28,6 +28,7 @@ public class UserNotes { public String xmrtoTag = null; public String xmrtoKey = null; public String xmrtoAmount = null; // could be a double - but we are not doing any calculations + public String xmrtoCurrency = null; public String xmrtoDestination = null; public UserNotes(final String txNotes) { @@ -35,14 +36,15 @@ public class UserNotes { return; } this.txNotes = txNotes; - Pattern p = Pattern.compile("^\\{([a-z]+)-(\\w{6,}),([0-9.]*)BTC,(\\w*)\\} ?(.*)"); + Pattern p = Pattern.compile("^\\{([a-z]+)-(\\w{6,}),([0-9.]*)([A-Z]+),(\\w*)\\} ?(.*)"); Matcher m = p.matcher(txNotes); if (m.find()) { xmrtoTag = m.group(1); xmrtoKey = m.group(2); xmrtoAmount = m.group(3); - xmrtoDestination = m.group(4); - note = m.group(5); + xmrtoCurrency = m.group(4); + xmrtoDestination = m.group(5); + note = m.group(6); } else { note = txNotes; } @@ -62,6 +64,7 @@ public class UserNotes { xmrtoTag = order.TAG; xmrtoKey = order.getOrderId(); xmrtoAmount = Helper.getDisplayAmount(order.getBtcAmount()); + xmrtoCurrency = order.getBtcCurrency(); xmrtoDestination = order.getBtcAddress(); } else { xmrtoTag = null; @@ -83,7 +86,8 @@ public class UserNotes { sb.append(xmrtoKey); sb.append(","); sb.append(xmrtoAmount); - sb.append("BTC,"); + sb.append(xmrtoCurrency); + sb.append(","); sb.append(xmrtoDestination); sb.append("}"); if ((note != null) && (!note.isEmpty())) diff --git a/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendAddressWizardFragment.java b/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendAddressWizardFragment.java index 2ad428e..5114b41 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendAddressWizardFragment.java +++ b/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendAddressWizardFragment.java @@ -39,16 +39,23 @@ import androidx.annotation.NonNull; import com.google.android.material.textfield.TextInputLayout; import com.m2049r.xmrwallet.R; import com.m2049r.xmrwallet.data.BarcodeData; +import com.m2049r.xmrwallet.data.Crypto; import com.m2049r.xmrwallet.data.TxData; import com.m2049r.xmrwallet.data.TxDataBtc; import com.m2049r.xmrwallet.data.UserNotes; import com.m2049r.xmrwallet.model.PendingTransaction; import com.m2049r.xmrwallet.model.Wallet; -import com.m2049r.xmrwallet.util.BitcoinAddressValidator; import com.m2049r.xmrwallet.util.Helper; import com.m2049r.xmrwallet.util.OpenAliasHelper; +import com.m2049r.xmrwallet.util.ServiceHelper; +import com.m2049r.xmrwallet.util.validator.BitcoinAddressType; +import com.m2049r.xmrwallet.util.validator.BitcoinAddressValidator; +import com.m2049r.xmrwallet.util.validator.EthAddressValidator; +import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import timber.log.Timber; @@ -64,9 +71,8 @@ public class SendAddressWizardFragment extends SendWizardFragment { Listener sendListener; - public SendAddressWizardFragment setSendListener(Listener listener) { + public void setSendListener(Listener listener) { this.sendListener = listener; - return this; } public interface Listener { @@ -84,11 +90,10 @@ public class SendAddressWizardFragment extends SendWizardFragment { private EditText etDummy; private TextInputLayout etAddress; private TextInputLayout etNotes; - private View cvScan; - private View tvPaymentIdIntegrated; private TextView tvXmrTo; - private View llXmrTo; - private ImageButton bPasteAddress; + private Map ibCrypto; + final private Set possibleCryptos = new HashSet<>(); + private Crypto selectedCrypto = null; private boolean resolvingOA = false; @@ -98,6 +103,13 @@ public class SendAddressWizardFragment extends SendWizardFragment { void onScan(); } + private Crypto getCryptoForButton(ImageButton button) { + for (Map.Entry entry : ibCrypto.entrySet()) { + if (entry.getValue() == button) return entry.getKey(); + } + return null; + } + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -105,10 +117,31 @@ public class SendAddressWizardFragment extends SendWizardFragment { View view = inflater.inflate(R.layout.fragment_send_address, container, false); - tvPaymentIdIntegrated = view.findViewById(R.id.tvPaymentIdIntegrated); - llXmrTo = view.findViewById(R.id.llXmrTo); tvXmrTo = view.findViewById(R.id.tvXmrTo); - tvXmrTo.setText(Html.fromHtml(getString(R.string.info_xmrto))); + + ibCrypto = new HashMap<>(); + for (Crypto crypto : Crypto.values()) { + final ImageButton button = view.findViewById(crypto.getButtonId()); + ibCrypto.put(crypto, button); + button.setOnClickListener(v -> { + if (possibleCryptos.contains(crypto)) { + selectedCrypto = crypto; + updateCryptoButtons(false); + } else { + // show help what to do: + if (button.getId() != R.id.ibXMR) { + final String name = getResources().getStringArray(R.array.cryptos)[crypto.ordinal()]; + final String symbol = getCryptoForButton(button).getSymbol(); + tvXmrTo.setText(Html.fromHtml(getString(R.string.info_xmrto_help, name, symbol))); + tvXmrTo.setVisibility(View.VISIBLE); + } else { + tvXmrTo.setText(Html.fromHtml(getString(R.string.info_xmrto_help_xmr))); + tvXmrTo.setVisibility(View.VISIBLE); + } + } + }); + } + updateCryptoButtons(true); etAddress = view.findViewById(R.id.etAddress); etAddress.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); @@ -118,16 +151,13 @@ public class SendAddressWizardFragment extends SendWizardFragment { return ((event != null) && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)); } }); - etAddress.getEditText().setOnFocusChangeListener(new View.OnFocusChangeListener() { - @Override - public void onFocusChange(View v, boolean hasFocus) { - if (!hasFocus) { - String enteredAddress = etAddress.getEditText().getText().toString().trim(); - String dnsOA = dnsFromOpenAlias(enteredAddress); - Timber.d("OpenAlias is %s", dnsOA); - if (dnsOA != null) { - processOpenAlias(dnsOA); - } + etAddress.getEditText().setOnFocusChangeListener((v, hasFocus) -> { + if (!hasFocus) { + String enteredAddress = etAddress.getEditText().getText().toString().trim(); + String dnsOA = dnsFromOpenAlias(enteredAddress); + Timber.d("OpenAlias is %s", dnsOA); + if (dnsOA != null) { + processOpenAlias(dnsOA); } } }); @@ -136,21 +166,47 @@ public class SendAddressWizardFragment extends SendWizardFragment { public void afterTextChanged(Editable editable) { Timber.d("AFTER: %s", editable.toString()); etAddress.setError(null); - if (isIntegratedAddress()) { + possibleCryptos.clear(); + selectedCrypto = null; + final String address = etAddress.getEditText().getText().toString(); + if (isIntegratedAddress(address)) { Timber.d("isIntegratedAddress"); + possibleCryptos.add(Crypto.XMR); + selectedCrypto = Crypto.XMR; etAddress.setError(getString(R.string.info_paymentid_integrated)); - tvPaymentIdIntegrated.setVisibility(View.VISIBLE); - llXmrTo.setVisibility(View.INVISIBLE); sendListener.setMode(SendFragment.Mode.XMR); - } else if (isBitcoinAddress()) { - Timber.d("isBitcoinAddress"); - setBtcMode(); - } else { - Timber.d("isStandardAddress or other"); - tvPaymentIdIntegrated.setVisibility(View.INVISIBLE); - llXmrTo.setVisibility(View.INVISIBLE); + } else if (isStandardAddress(address)) { + Timber.d("isStandardAddress"); + possibleCryptos.add(Crypto.XMR); + selectedCrypto = Crypto.XMR; sendListener.setMode(SendFragment.Mode.XMR); } + if ((selectedCrypto == null) && isEthAddress(address)) { + Timber.d("isEthAddress"); + possibleCryptos.add(Crypto.ETH); + selectedCrypto = Crypto.ETH; + tvXmrTo.setVisibility(View.VISIBLE); + sendListener.setMode(SendFragment.Mode.BTC); + } + if (possibleCryptos.isEmpty()) { + Timber.d("isBitcoinAddress"); + for (BitcoinAddressType type : BitcoinAddressType.values()) { + if (BitcoinAddressValidator.validate(address, type)) { + possibleCryptos.add(Crypto.valueOf(type.name())); + } + } + if (!possibleCryptos.isEmpty()) // found something in need of shifting! + sendListener.setMode(SendFragment.Mode.BTC); + if (possibleCryptos.size() == 1) { + selectedCrypto = (Crypto) possibleCryptos.toArray()[0]; + } + } + if (possibleCryptos.isEmpty()) { + Timber.d("other"); + tvXmrTo.setVisibility(View.INVISIBLE); + sendListener.setMode(SendFragment.Mode.XMR); + } + updateCryptoButtons(address.isEmpty()); } @Override @@ -162,45 +218,38 @@ public class SendAddressWizardFragment extends SendWizardFragment { } }); - bPasteAddress = view.findViewById(R.id.bPasteAddress); - bPasteAddress.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - final String clip = Helper.getClipBoardText(getActivity()); - if (clip == null) return; - // clean it up - final String address = clip.replaceAll("[^0-9A-Z-a-z]", ""); - if (Wallet.isAddressValid(address) || BitcoinAddressValidator.validate(address)) { - final EditText et = etAddress.getEditText(); - et.setText(address); - et.setSelection(et.getText().length()); - etAddress.requestFocus(); - } else { - Toast.makeText(getActivity(), getString(R.string.send_address_invalid), Toast.LENGTH_SHORT).show(); - } + final ImageButton bPasteAddress = view.findViewById(R.id.bPasteAddress); + bPasteAddress.setOnClickListener(v -> { + final String clip = Helper.getClipBoardText(getActivity()); + if (clip == null) return; + // clean it up + final String address = clip.replaceAll("( +)|(\\r?\\n?)", ""); + BarcodeData bc = BarcodeData.fromString(address); + if (bc != null) { + processScannedData(bc); + final EditText et = etAddress.getEditText(); + et.setSelection(et.getText().length()); + etAddress.requestFocus(); + } else { + Toast.makeText(getActivity(), getString(R.string.send_address_invalid), Toast.LENGTH_SHORT).show(); } }); etNotes = view.findViewById(R.id.etNotes); etNotes.getEditText().setRawInputType(InputType.TYPE_CLASS_TEXT); - etNotes.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() { - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN)) - || (actionId == EditorInfo.IME_ACTION_DONE)) { - etDummy.requestFocus(); - return true; - } - return false; - } - }); + etNotes.getEditText(). - cvScan = view.findViewById(R.id.bScan); - cvScan.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - onScanListener.onScan(); - } - }); + setOnEditorActionListener((v, actionId, event) -> { + if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN)) + || (actionId == EditorInfo.IME_ACTION_DONE)) { + etDummy.requestFocus(); + return true; + } + return false; + }); + + final View cvScan = view.findViewById(R.id.bScan); + cvScan.setOnClickListener(v -> onScanListener.onScan()); etDummy = view.findViewById(R.id.etDummy); etDummy.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); @@ -214,11 +263,49 @@ public class SendAddressWizardFragment extends SendWizardFragment { return view; } - private void setBtcMode() { - Timber.d("setBtcMode"); - tvPaymentIdIntegrated.setVisibility(View.INVISIBLE); - llXmrTo.setVisibility(View.VISIBLE); - sendListener.setMode(SendFragment.Mode.BTC); + private void selectedCrypto(Crypto crypto) { + final ImageButton button = ibCrypto.get(crypto); + button.setImageResource(crypto.getIconEnabledId()); + button.setImageAlpha(255); + button.setEnabled(true); + } + + private void possibleCrypto(Crypto crypto) { + final ImageButton button = ibCrypto.get(crypto); + button.setImageResource(crypto.getIconDisabledId()); + button.setImageAlpha(255); + button.setEnabled(true); + } + + private void impossibleCrypto(Crypto crypto) { + final ImageButton button = ibCrypto.get(crypto); + button.setImageResource(crypto.getIconDisabledId()); + button.setImageAlpha(128); + button.setEnabled(true); + } + + private void updateCryptoButtons(boolean noAddress) { + for (Crypto crypto : Crypto.values()) { + if (crypto == selectedCrypto) { + selectedCrypto(crypto); + } else if (possibleCryptos.contains(crypto)) { + possibleCrypto(crypto); + } else { + impossibleCrypto(crypto); + } + } + if ((selectedCrypto != null) && (selectedCrypto != Crypto.XMR)) { + tvXmrTo.setText(Html.fromHtml(getString(R.string.info_xmrto, selectedCrypto.getSymbol()))); + tvXmrTo.setVisibility(View.VISIBLE); + } else if ((selectedCrypto == null) && (possibleCryptos.size() > 1)) { + tvXmrTo.setText(Html.fromHtml(getString(R.string.info_xmrto_ambiguous))); + tvXmrTo.setVisibility(View.VISIBLE); + } else { + tvXmrTo.setVisibility(View.INVISIBLE); + } + if (noAddress) { + selectedCrypto(Crypto.XMR); + } } private void processOpenAlias(String dnsOA) { @@ -229,10 +316,10 @@ public class SendAddressWizardFragment extends SendWizardFragment { etAddress.setError(getString(R.string.send_address_resolve_openalias)); OpenAliasHelper.resolve(dnsOA, new OpenAliasHelper.OnResolvedListener() { @Override - public void onResolved(Map dataMap) { + public void onResolved(Map dataMap) { resolvingOA = false; - BarcodeData barcodeData = dataMap.get(BarcodeData.Asset.XMR); - if (barcodeData == null) barcodeData = dataMap.get(BarcodeData.Asset.BTC); + BarcodeData barcodeData = dataMap.get(Crypto.XMR); + if (barcodeData == null) barcodeData = dataMap.get(Crypto.BTC); if (barcodeData != null) { Timber.d("Security=%s, %s", barcodeData.security.toString(), barcodeData.address); processScannedData(barcodeData); @@ -253,9 +340,7 @@ public class SendAddressWizardFragment extends SendWizardFragment { } private boolean checkAddressNoError() { - String address = etAddress.getEditText().getText().toString(); - return Wallet.isAddressValid(address) - || BitcoinAddressValidator.validate(address); + return selectedCrypto != null; } private boolean checkAddress() { @@ -268,19 +353,37 @@ public class SendAddressWizardFragment extends SendWizardFragment { return ok; } - private boolean isIntegratedAddress() { - String address = etAddress.getEditText().getText().toString(); + private boolean isStandardAddress(String address) { + return Wallet.isAddressValid(address); + } + + private boolean isIntegratedAddress(String address) { return (address.length() == INTEGRATED_ADDRESS_LENGTH) && Wallet.isAddressValid(address); } - private boolean isBitcoinAddress() { - final String address = etAddress.getEditText().getText().toString(); - return BitcoinAddressValidator.validate(address); + private boolean isBitcoinishAddress(String address) { + return BitcoinAddressValidator.validate(address, BitcoinAddressType.BTC) + || + BitcoinAddressValidator.validate(address, BitcoinAddressType.LTC) + || + BitcoinAddressValidator.validate(address, BitcoinAddressType.DASH); + } + + private boolean isEthAddress(String address) { + return EthAddressValidator.validate(address); } private void shakeAddress() { - etAddress.startAnimation(Helper.getShakeAnimation(getContext())); + if (possibleCryptos.size() > 1) { // address ambiguous + for (Crypto crypto : Crypto.values()) { + if (possibleCryptos.contains(crypto)) { + ibCrypto.get(crypto).startAnimation(Helper.getShakeAnimation(getContext())); + } + } + } else { + etAddress.startAnimation(Helper.getShakeAnimation(getContext())); + } } @Override @@ -300,9 +403,12 @@ public class SendAddressWizardFragment extends SendWizardFragment { TxData txData = sendListener.getTxData(); if (txData instanceof TxDataBtc) { ((TxDataBtc) txData).setBtcAddress(etAddress.getEditText().getText().toString()); + ((TxDataBtc) txData).setBtcSymbol(selectedCrypto.getSymbol()); txData.setDestinationAddress(null); + ServiceHelper.ASSET = selectedCrypto.getSymbol().toLowerCase(); } else { txData.setDestinationAddress(etAddress.getEditText().getText().toString()); + ServiceHelper.ASSET = null; } txData.setUserNotes(new UserNotes(etNotes.getEditText().getText().toString())); txData.setPriority(PendingTransaction.Priority.Priority_Default); @@ -344,6 +450,15 @@ public class SendAddressWizardFragment extends SendWizardFragment { if (barcodeData.address != null) { etAddress.getEditText().setText(barcodeData.address); + possibleCryptos.clear(); + selectedCrypto = null; + if (barcodeData.isAmbiguous()) { + possibleCryptos.addAll(barcodeData.ambiguousAssets); + } else { + possibleCryptos.add(barcodeData.asset); + selectedCrypto = barcodeData.asset; + } + updateCryptoButtons(false); if (checkAddress()) { if (barcodeData.security == BarcodeData.Security.OA_NO_DNSSEC) etAddress.setError(getString(R.string.send_address_no_dnssec)); @@ -355,7 +470,12 @@ public class SendAddressWizardFragment extends SendWizardFragment { etAddress.setError(null); } - String scannedNotes = barcodeData.description; + String scannedNotes = barcodeData.addressName; + if (scannedNotes == null) { + scannedNotes = barcodeData.description; + } else if (barcodeData.description != null) { + scannedNotes = scannedNotes + ": " + barcodeData.description; + } if (scannedNotes != null) { etNotes.getEditText().setText(scannedNotes); } else { diff --git a/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendAmountWizardFragment.java b/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendAmountWizardFragment.java index a061df4..3e66a87 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendAmountWizardFragment.java +++ b/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendAmountWizardFragment.java @@ -42,9 +42,8 @@ public class SendAmountWizardFragment extends SendWizardFragment { Listener sendListener; - public SendAmountWizardFragment setSendListener(Listener listener) { + public void setSendListener(Listener listener) { this.sendListener = listener; - return this; } interface Listener { diff --git a/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendBtcAmountWizardFragment.java b/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendBtcAmountWizardFragment.java index b819d5c..f4b4ae0 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendBtcAmountWizardFragment.java +++ b/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendBtcAmountWizardFragment.java @@ -28,16 +28,16 @@ import com.m2049r.xmrwallet.R; import com.m2049r.xmrwallet.data.BarcodeData; import com.m2049r.xmrwallet.data.TxDataBtc; import com.m2049r.xmrwallet.model.Wallet; -import com.m2049r.xmrwallet.util.Helper; -import com.m2049r.xmrwallet.util.OkHttpHelper; -import com.m2049r.xmrwallet.widget.ExchangeOtherEditText; -import com.m2049r.xmrwallet.widget.SendProgressView; +import com.m2049r.xmrwallet.service.shift.ShiftCallback; import com.m2049r.xmrwallet.service.shift.ShiftError; import com.m2049r.xmrwallet.service.shift.ShiftException; import com.m2049r.xmrwallet.service.shift.sideshift.api.QueryOrderParameters; import com.m2049r.xmrwallet.service.shift.sideshift.api.SideShiftApi; -import com.m2049r.xmrwallet.service.shift.ShiftCallback; import com.m2049r.xmrwallet.service.shift.sideshift.network.SideShiftApiImpl; +import com.m2049r.xmrwallet.util.OkHttpHelper; +import com.m2049r.xmrwallet.util.ServiceHelper; +import com.m2049r.xmrwallet.widget.ExchangeOtherEditText; +import com.m2049r.xmrwallet.widget.SendProgressView; import java.text.NumberFormat; import java.util.Locale; @@ -85,6 +85,7 @@ public class SendBtcAmountWizardFragment extends SendWizardFragment { etAmount = view.findViewById(R.id.etAmount); etAmount.requestFocus(); + return view; } @@ -130,20 +131,26 @@ public class SendBtcAmountWizardFragment extends SendWizardFragment { public void onResumeFragment() { super.onResumeFragment(); Timber.d("onResumeFragment()"); + final String btcSymbol = ((TxDataBtc) sendListener.getTxData()).getBtcSymbol(); + if (!btcSymbol.toLowerCase().equals(ServiceHelper.ASSET)) + throw new IllegalStateException("Asset Symbol is wrong!"); final long funds = getTotalFunds(); if (!sendListener.getActivityCallback().isStreetMode()) { tvFunds.setText(getString(R.string.send_available, Wallet.getDisplayAmount(funds))); + //TODO } else { tvFunds.setText(getString(R.string.send_available, getString(R.string.unknown_amount))); } + etAmount.setAmount(""); final BarcodeData data = sendListener.popBarcodeData(); if (data != null) { if (data.amount != null) { etAmount.setAmount(data.amount); } } + etAmount.setBaseCurrency(btcSymbol); callXmrTo(); } @@ -166,7 +173,9 @@ public class SendBtcAmountWizardFragment extends SendWizardFragment { String min = df.format(minBtc); String max = df.format(maxBtc); String rate = df.format(price); - Spanned xmrParmText = Html.fromHtml(getString(R.string.info_send_xmrto_parms, min, max, rate)); + final TxDataBtc txDataBtc = (TxDataBtc) sendListener.getTxData(); + Spanned xmrParmText = Html.fromHtml(getString(R.string.info_send_xmrto_parms, + min, max, rate, txDataBtc.getBtcSymbol())); tvXmrToParms.setText(xmrParmText); final long funds = getTotalFunds(); @@ -183,7 +192,8 @@ public class SendBtcAmountWizardFragment extends SendWizardFragment { } tvFunds.setText(getString(R.string.send_available_btc, availXmrString, - availBtcString)); + availBtcString, + ((TxDataBtc) sendListener.getTxData()).getBtcSymbol())); llXmrToParms.setVisibility(View.VISIBLE); evParams.hideProgress(); }); @@ -246,7 +256,7 @@ public class SendBtcAmountWizardFragment extends SendWizardFragment { synchronized (this) { if (xmrToApi == null) { xmrToApi = new SideShiftApiImpl(OkHttpHelper.getOkHttpClient(), - Helper.getXmrToBaseUrl()); + ServiceHelper.getXmrToBaseUrl()); } } } diff --git a/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendBtcConfirmWizardFragment.java b/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendBtcConfirmWizardFragment.java index 27ff90d..a37ece8 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendBtcConfirmWizardFragment.java +++ b/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendBtcConfirmWizardFragment.java @@ -29,16 +29,17 @@ import com.m2049r.xmrwallet.data.TxData; import com.m2049r.xmrwallet.data.TxDataBtc; import com.m2049r.xmrwallet.model.PendingTransaction; import com.m2049r.xmrwallet.model.Wallet; -import com.m2049r.xmrwallet.util.Helper; -import com.m2049r.xmrwallet.util.OkHttpHelper; -import com.m2049r.xmrwallet.widget.SendProgressView; +import com.m2049r.xmrwallet.service.shift.ShiftCallback; import com.m2049r.xmrwallet.service.shift.ShiftError; import com.m2049r.xmrwallet.service.shift.ShiftException; import com.m2049r.xmrwallet.service.shift.sideshift.api.CreateOrder; import com.m2049r.xmrwallet.service.shift.sideshift.api.RequestQuote; import com.m2049r.xmrwallet.service.shift.sideshift.api.SideShiftApi; -import com.m2049r.xmrwallet.service.shift.ShiftCallback; import com.m2049r.xmrwallet.service.shift.sideshift.network.SideShiftApiImpl; +import com.m2049r.xmrwallet.util.Helper; +import com.m2049r.xmrwallet.util.OkHttpHelper; +import com.m2049r.xmrwallet.util.ServiceHelper; +import com.m2049r.xmrwallet.widget.SendProgressView; import java.text.NumberFormat; import java.util.Locale; @@ -67,6 +68,7 @@ public class SendBtcConfirmWizardFragment extends SendWizardFragment implements private TextView tvTxBtcAmount; private TextView tvTxBtcRate; private TextView tvTxBtcAddress; + private TextView tvTxBtcAddressLabel; private TextView tvTxXmrToKey; private TextView tvTxFee; private TextView tvTxTotal; @@ -84,6 +86,7 @@ public class SendBtcConfirmWizardFragment extends SendWizardFragment implements R.layout.fragment_send_btc_confirm, container, false); tvTxBtcAddress = view.findViewById(R.id.tvTxBtcAddress); + tvTxBtcAddressLabel = view.findViewById(R.id.tvTxBtcAddressLabel); tvTxBtcAmount = view.findViewById(R.id.tvTxBtcAmount); tvTxBtcRate = view.findViewById(R.id.tvTxBtcRate); tvTxXmrToKey = view.findViewById(R.id.tvTxXmrToKey); @@ -259,6 +262,8 @@ public class SendBtcConfirmWizardFragment extends SendWizardFragment implements if (sendListener.getMode() != SendFragment.Mode.BTC) { throw new IllegalStateException("Mode is not BTC!"); } + if (!((TxDataBtc) sendListener.getTxData()).getBtcSymbol().toLowerCase().equals(ServiceHelper.ASSET)) + throw new IllegalStateException("Asset Symbol is wrong!"); Helper.hideKeyboard(getActivity()); llStageA.setVisibility(View.INVISIBLE); evStageA.hideProgress(); @@ -392,9 +397,10 @@ public class SendBtcConfirmWizardFragment extends SendWizardFragment implements df.setMaximumFractionDigits(12); final String btcAmount = df.format(xmrtoQuote.getBtcAmount()); final String xmrAmountTotal = df.format(xmrtoQuote.getXmrAmount()); - tvTxBtcAmount.setText(getString(R.string.text_send_btc_amount, btcAmount, xmrAmountTotal)); + tvTxBtcAmount.setText(getString(R.string.text_send_btc_amount, + btcAmount, xmrAmountTotal, txDataBtc.getBtcSymbol())); final String xmrPriceBtc = df.format(xmrtoQuote.getPrice()); - tvTxBtcRate.setText(getString(R.string.text_send_btc_rate, xmrPriceBtc)); + tvTxBtcRate.setText(getString(R.string.text_send_btc_rate, xmrPriceBtc, txDataBtc.getBtcSymbol())); hideProgress(); }); stageB(requestQuote.getId()); @@ -477,13 +483,14 @@ public class SendBtcConfirmWizardFragment extends SendWizardFragment implements TxDataBtc txDataBtc = (TxDataBtc) sendListener.getTxData(); // verify amount & destination if ((order.getBtcAmount() != txDataBtc.getBtcAmount()) - || (!order.getBtcAddress().equals(txDataBtc.getBtcAddress()))) { + || (!txDataBtc.validateAddress(order.getBtcAddress()))) { throw new IllegalStateException("Order does not fulfill quote!"); // something is terribly wrong - die } xmrtoOrder = order; getView().post(() -> { tvTxXmrToKey.setText(order.getOrderId()); tvTxBtcAddress.setText(order.getBtcAddress()); + tvTxBtcAddressLabel.setText(getString(R.string.label_send_btc_address, txDataBtc.getBtcSymbol())); hideProgress(); Timber.d("Expires @ %s", order.getExpiresAt().toString()); final int timeout = (int) (order.getExpiresAt().getTime() - order.getCreatedAt().getTime()) / 1000 - 60; // -1 minute buffer @@ -561,7 +568,7 @@ public class SendBtcConfirmWizardFragment extends SendWizardFragment implements synchronized (this) { if (xmrToApi == null) { xmrToApi = new SideShiftApiImpl(OkHttpHelper.getOkHttpClient(), - Helper.getXmrToBaseUrl()); + ServiceHelper.getXmrToBaseUrl()); } } } diff --git a/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendBtcSuccessWizardFragment.java b/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendBtcSuccessWizardFragment.java index d2a6462..4156ee5 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendBtcSuccessWizardFragment.java +++ b/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendBtcSuccessWizardFragment.java @@ -30,6 +30,7 @@ import android.widget.TextView; import android.widget.Toast; import com.m2049r.xmrwallet.R; +import com.m2049r.xmrwallet.data.Crypto; import com.m2049r.xmrwallet.data.PendingTx; import com.m2049r.xmrwallet.data.TxDataBtc; import com.m2049r.xmrwallet.service.shift.ShiftCallback; @@ -39,6 +40,7 @@ import com.m2049r.xmrwallet.service.shift.sideshift.api.SideShiftApi; import com.m2049r.xmrwallet.service.shift.sideshift.network.SideShiftApiImpl; import com.m2049r.xmrwallet.util.Helper; import com.m2049r.xmrwallet.util.OkHttpHelper; +import com.m2049r.xmrwallet.util.ServiceHelper; import java.text.NumberFormat; import java.util.Locale; @@ -62,10 +64,10 @@ public class SendBtcSuccessWizardFragment extends SendWizardFragment { ImageButton bCopyTxId; private TextView tvTxId; private TextView tvTxAddress; - private TextView tvTxPaymentId; private TextView tvTxAmount; private TextView tvTxFee; private TextView tvXmrToAmount; + private ImageView ivXmrToIcon; private TextView tvXmrToStatus; private ImageView ivXmrToStatus; private ImageView ivXmrToStatusBig; @@ -90,13 +92,13 @@ public class SendBtcSuccessWizardFragment extends SendWizardFragment { }); tvXmrToAmount = view.findViewById(R.id.tvXmrToAmount); + ivXmrToIcon = view.findViewById(R.id.ivXmrToIcon); tvXmrToStatus = view.findViewById(R.id.tvXmrToStatus); ivXmrToStatus = view.findViewById(R.id.ivXmrToStatus); ivXmrToStatusBig = view.findViewById(R.id.ivXmrToStatusBig); tvTxId = view.findViewById(R.id.tvTxId); tvTxAddress = view.findViewById(R.id.tvTxAddress); - tvTxPaymentId = view.findViewById(R.id.tvTxPaymentId); tvTxAmount = view.findViewById(R.id.tvTxAmount); tvTxFee = view.findViewById(R.id.tvTxFee); @@ -150,9 +152,11 @@ public class SendBtcSuccessWizardFragment extends SendWizardFragment { NumberFormat df = NumberFormat.getInstance(Locale.US); df.setMaximumFractionDigits(12); String btcAmount = df.format(btcData.getBtcAmount()); - tvXmrToAmount.setText(getString(R.string.info_send_xmrto_success_btc, btcAmount)); + tvXmrToAmount.setText(getString(R.string.info_send_xmrto_success_btc, btcAmount, btcData.getBtcSymbol())); //TODO btcData.getBtcAddress(); tvTxXmrToKey.setText(btcData.getXmrtoOrderId()); + final Crypto crypto = Crypto.withSymbol(btcData.getBtcSymbol()); + ivXmrToIcon.setImageResource(crypto.getIconEnabledId()); tvXmrToSupport.setOnClickListener(v -> { Uri orderUri = getXmrToApi().getQueryOrderUri(btcData.getXmrtoOrderId()); Intent intent = new Intent(Intent.ACTION_VIEW, orderUri); @@ -211,7 +215,7 @@ public class SendBtcSuccessWizardFragment extends SendWizardFragment { statusResource = R.drawable.ic_error_red_24dp; pbXmrto.getIndeterminateDrawable().setColorFilter(0xff8b0000, android.graphics.PorterDuff.Mode.MULTIPLY); } else if (status.isSent() || status.isPaid()) { - tvXmrToStatus.setText(getString(R.string.info_send_xmrto_sent)); + tvXmrToStatus.setText(getString(R.string.info_send_xmrto_sent, btcData.getBtcSymbol())); statusResource = R.drawable.ic_success_green_24dp; pbXmrto.getIndeterminateDrawable().setColorFilter(0xFF417505, android.graphics.PorterDuff.Mode.MULTIPLY); } else if (status.isWaiting()) { @@ -228,6 +232,7 @@ public class SendBtcSuccessWizardFragment extends SendWizardFragment { ivXmrToStatus.setImageResource(statusResource); if (status.isTerminal()) { pbXmrto.setVisibility(View.INVISIBLE); + ivXmrToIcon.setVisibility(View.GONE); ivXmrToStatus.setVisibility(View.GONE); ivXmrToStatusBig.setImageResource(statusResource); ivXmrToStatusBig.setVisibility(View.VISIBLE); @@ -241,7 +246,7 @@ public class SendBtcSuccessWizardFragment extends SendWizardFragment { synchronized (this) { if (xmrToApi == null) { xmrToApi = new SideShiftApiImpl(OkHttpHelper.getOkHttpClient(), - Helper.getXmrToBaseUrl()); + ServiceHelper.getXmrToBaseUrl()); } } } diff --git a/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendFragment.java b/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendFragment.java index 2e0faf5..903aff0 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendFragment.java +++ b/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendFragment.java @@ -29,6 +29,7 @@ import android.view.ViewGroup; import android.widget.Button; import android.widget.EditText; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; @@ -92,8 +93,6 @@ public class SendFragment extends Fragment void setOnUriScannedListener(OnUriScannedListener onUriScannedListener); } - private EditText etDummy; - private View llNavBar; private DotBar dotBar; private Button bPrev; @@ -101,7 +100,7 @@ public class SendFragment extends Fragment private Button bDone; - static private int MAX_FALLBACK = Integer.MAX_VALUE; + static private final int MAX_FALLBACK = Integer.MAX_VALUE; public static SendFragment newInstance(String uri) { SendFragment f = new SendFragment(); @@ -166,28 +165,18 @@ public class SendFragment extends Fragment } }); - bPrev.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - spendViewPager.previous(); - } - }); + bPrev.setOnClickListener(v -> spendViewPager.previous()); - bNext.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - spendViewPager.next(); - } - }); + bNext.setOnClickListener(v -> spendViewPager.next()); - bDone.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - Timber.d("bDone.onClick"); - activityCallback.onFragmentDone(); - } + bDone.setOnClickListener(v -> { + Timber.d("bDone.onClick"); + activityCallback.onFragmentDone(); }); updatePosition(0); - etDummy = view.findViewById(R.id.etDummy); + final EditText etDummy = view.findViewById(R.id.etDummy); etDummy.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); etDummy.requestFocus(); Helper.hideKeyboard(getActivity()); @@ -197,7 +186,7 @@ public class SendFragment extends Fragment String uri = args.getString(WalletActivity.REQUEST_URI); Timber.d("URI: %s", uri); if (uri != null) { - barcodeData = BarcodeData.fromQrCode(uri); + barcodeData = BarcodeData.fromString(uri); Timber.d("barcodeData: %s", barcodeData != null ? barcodeData.toString() : "null"); } } @@ -236,7 +225,7 @@ public class SendFragment extends Fragment } @Override - public void onAttach(Context context) { + public void onAttach(@NonNull Context context) { Timber.d("onAttach %s", context); super.onAttach(context); if (context instanceof Listener) { @@ -300,12 +289,7 @@ public class SendFragment extends Fragment default: throw new IllegalArgumentException("Mode " + String.valueOf(aMode) + " unknown!"); } - getView().post(new Runnable() { - @Override - public void run() { - pagerAdapter.notifyDataSetChanged(); - } - }); + getView().post(() -> pagerAdapter.notifyDataSetChanged()); Timber.d("New Mode = %s", mode.toString()); } } @@ -338,8 +322,9 @@ public class SendFragment extends Fragment return numPages; } + @NonNull @Override - public Object instantiateItem(ViewGroup container, int position) { + public Object instantiateItem(@NonNull ViewGroup container, int position) { Timber.d("instantiateItem %d", position); SendWizardFragment fragment = (SendWizardFragment) super.instantiateItem(container, position); myFragments.put(position, new WeakReference<>(fragment)); @@ -347,20 +332,21 @@ public class SendFragment extends Fragment } @Override - public void destroyItem(ViewGroup container, int position, Object object) { + public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { Timber.d("destroyItem %d", position); myFragments.remove(position); super.destroyItem(container, position, object); } public SendWizardFragment getFragment(int position) { - WeakReference ref = myFragments.get(position); + WeakReference ref = myFragments.get(position); if (ref != null) return myFragments.get(position).get(); else return null; } + @NonNull @Override public SendWizardFragment getItem(int position) { Timber.d("getItem(%d) CREATE", position); @@ -415,7 +401,7 @@ public class SendFragment extends Fragment } @Override - public int getItemPosition(Object object) { + public int getItemPosition(@NonNull Object object) { Timber.d("getItemPosition %s", String.valueOf(object)); if (object instanceof SendAddressWizardFragment) { // keep these pages diff --git a/app/src/main/java/com/m2049r/xmrwallet/layout/TransactionInfoAdapter.java b/app/src/main/java/com/m2049r/xmrwallet/layout/TransactionInfoAdapter.java index d90bb63..9d2d8ba 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/layout/TransactionInfoAdapter.java +++ b/app/src/main/java/com/m2049r/xmrwallet/layout/TransactionInfoAdapter.java @@ -17,18 +17,20 @@ package com.m2049r.xmrwallet.layout; import android.content.Context; -import androidx.core.content.ContextCompat; -import androidx.recyclerview.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.RecyclerView; + import com.m2049r.xmrwallet.R; +import com.m2049r.xmrwallet.data.Crypto; +import com.m2049r.xmrwallet.data.UserNotes; import com.m2049r.xmrwallet.model.TransactionInfo; import com.m2049r.xmrwallet.util.Helper; -import com.m2049r.xmrwallet.data.UserNotes; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -141,7 +143,13 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter callback) { - api.call("pairs/xmr/" + SideShiftApi.ASSET, new NetworkCallback() { + api.call("pairs/xmr/" + ServiceHelper.ASSET, new NetworkCallback() { @Override public void onSuccess(JSONObject jsonObject) { try { diff --git a/app/src/main/java/com/m2049r/xmrwallet/service/shift/sideshift/network/RequestQuoteImpl.java b/app/src/main/java/com/m2049r/xmrwallet/service/shift/sideshift/network/RequestQuoteImpl.java index 91addc5..6a1b802 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/service/shift/sideshift/network/RequestQuoteImpl.java +++ b/app/src/main/java/com/m2049r/xmrwallet/service/shift/sideshift/network/RequestQuoteImpl.java @@ -24,6 +24,7 @@ import com.m2049r.xmrwallet.util.DateHelper; import com.m2049r.xmrwallet.service.shift.sideshift.api.RequestQuote; import com.m2049r.xmrwallet.service.shift.sideshift.api.SideShiftApi; import com.m2049r.xmrwallet.service.shift.ShiftCallback; +import com.m2049r.xmrwallet.util.ServiceHelper; import org.json.JSONException; import org.json.JSONObject; @@ -55,7 +56,7 @@ class RequestQuoteImpl implements RequestQuote { // sanity checks final String depositMethod = jsonObject.getString("depositMethod"); final String settleMethod = jsonObject.getString("settleMethod"); - if (!"xmr".equals(depositMethod) || !SideShiftApi.ASSET.equals(settleMethod)) + if (!"xmr".equals(depositMethod) || !ServiceHelper.ASSET.equals(settleMethod)) throw new IllegalStateException(); btcAmount = jsonObject.getDouble("settleAmount"); @@ -106,7 +107,7 @@ class RequestQuoteImpl implements RequestQuote { static JSONObject createRequest(final double xmrAmount) throws JSONException { final JSONObject jsonObject = new JSONObject(); jsonObject.put("depositMethod", "xmr"); - jsonObject.put("settleMethod", SideShiftApi.ASSET); + jsonObject.put("settleMethod", ServiceHelper.ASSET); // #sideshift is silly and likes numbers as strings String amount = AmountFormatter.format(xmrAmount); jsonObject.put("depositAmount", amount); diff --git a/app/src/main/java/com/m2049r/xmrwallet/util/Helper.java b/app/src/main/java/com/m2049r/xmrwallet/util/Helper.java index 326da62..66a3704 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/util/Helper.java +++ b/app/src/main/java/com/m2049r/xmrwallet/util/Helper.java @@ -323,15 +323,6 @@ public class Helper { return ShakeAnimation; } - static public HttpUrl getXmrToBaseUrl() { - if ((WalletManager.getInstance() == null) - || (WalletManager.getInstance().getNetworkType() != NetworkType.NetworkType_Mainnet)) { - throw new IllegalStateException("Only mainnet not supported"); - } else { - return HttpUrl.parse("https://sideshift.ai/api/v1/"); - } - } - private final static char[] HexArray = "0123456789ABCDEF".toCharArray(); public static String bytesToHex(byte[] data) { @@ -639,10 +630,6 @@ public class Helper { } } - static public ExchangeApi getExchangeApi() { - return new com.m2049r.xmrwallet.service.exchange.krakenEcb.ExchangeApiImpl(OkHttpHelper.getOkHttpClient()); - } - public interface Action { boolean run(); } diff --git a/app/src/main/java/com/m2049r/xmrwallet/util/OpenAliasHelper.java b/app/src/main/java/com/m2049r/xmrwallet/util/OpenAliasHelper.java index 4b9c784..b710fbc 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/util/OpenAliasHelper.java +++ b/app/src/main/java/com/m2049r/xmrwallet/util/OpenAliasHelper.java @@ -21,6 +21,7 @@ package com.m2049r.xmrwallet.util; import android.os.AsyncTask; import com.m2049r.xmrwallet.data.BarcodeData; +import com.m2049r.xmrwallet.data.Crypto; import org.jitsi.dnssec.validator.ValidatingResolver; import org.xbill.DNS.DClass; @@ -52,7 +53,6 @@ public class OpenAliasHelper { public static final String OA1_NAME = "recipient_name"; public static final String OA1_DESCRIPTION = "tx_description"; public static final String OA1_AMOUNT = "tx_amount"; - public static final String OA1_PAYMENTID = "tx_payment_id"; public static final int DNS_LOOKUP_TIMEOUT = 2500; // ms @@ -65,7 +65,7 @@ public class OpenAliasHelper { } public interface OnResolvedListener { - void onResolved(Map dataMap); + void onResolved(Map dataMap); void onFailure(); } @@ -138,7 +138,7 @@ public class OpenAliasHelper { public void onPostExecute(Boolean success) { if (resolvedListener != null) if (success) { - Map dataMap = new HashMap<>(); + Map dataMap = new HashMap<>(); for (String txt : txts) { BarcodeData bc = BarcodeData.parseOpenAlias(txt, dnssec); if (bc != null) { diff --git a/app/src/main/java/com/m2049r/xmrwallet/util/ServiceHelper.java b/app/src/main/java/com/m2049r/xmrwallet/util/ServiceHelper.java new file mode 100644 index 0000000..6221682 --- /dev/null +++ b/app/src/main/java/com/m2049r/xmrwallet/util/ServiceHelper.java @@ -0,0 +1,24 @@ +package com.m2049r.xmrwallet.util; + +import com.m2049r.xmrwallet.model.NetworkType; +import com.m2049r.xmrwallet.model.WalletManager; +import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi; + +import okhttp3.HttpUrl; + +public class ServiceHelper { + public static String ASSET = null; + + static public HttpUrl getXmrToBaseUrl() { + if ((WalletManager.getInstance() == null) + || (WalletManager.getInstance().getNetworkType() != NetworkType.NetworkType_Mainnet)) { + throw new IllegalStateException("Only mainnet not supported"); + } else { + return HttpUrl.parse("https://sideshift.ai/api/v1/"); + } + } + + static public ExchangeApi getExchangeApi() { + return new com.m2049r.xmrwallet.service.exchange.krakenEcb.ExchangeApiImpl(OkHttpHelper.getOkHttpClient()); + } +} diff --git a/app/src/main/java/com/m2049r/xmrwallet/util/validator/BitcoinAddressType.java b/app/src/main/java/com/m2049r/xmrwallet/util/validator/BitcoinAddressType.java new file mode 100644 index 0000000..a1415b1 --- /dev/null +++ b/app/src/main/java/com/m2049r/xmrwallet/util/validator/BitcoinAddressType.java @@ -0,0 +1,51 @@ +package com.m2049r.xmrwallet.util.validator; + +import lombok.Getter; + +public enum BitcoinAddressType { + BTC(Type.BTC, Type.BTC_BECH32_PREFIX), + LTC(Type.LTC, Type.LTC_BECH32_PREFIX), + DASH(Type.DASH, null), + DOGE(Type.DOGE, null); + + @Getter + private final byte[] production; + @Getter + private final byte[] testnet; + + @Getter + private final String productionBech32Prefix; + @Getter + private final String testnetBech32Prefix; + + public boolean hasBech32() { + return productionBech32Prefix != null; + } + + public String getBech32Prefix(boolean testnet) { + return testnet ? testnetBech32Prefix : productionBech32Prefix; + } + + BitcoinAddressType(byte[][] types, String[] bech32Prefix) { + production = types[0]; + testnet = types[1]; + if (bech32Prefix != null) { + productionBech32Prefix = bech32Prefix[0]; + testnetBech32Prefix = bech32Prefix[1]; + } else { + productionBech32Prefix = null; + testnetBech32Prefix = null; + } + } + + // Java is silly and doesn't allow array initializers in the construction + private static class Type { + private static final byte[][] BTC = {{0x00, 0x05}, {0x6f, (byte) 0xc4}}; + private static final String[] BTC_BECH32_PREFIX = {"bc", "tb"}; + private static final byte[][] LTC = {{0x30, 0x05, 0x32}, {0x6f, (byte) 0xc4, 0x3a}}; + private static final String[] LTC_BECH32_PREFIX = {"ltc", "tltc"}; + private static final byte[][] DASH = {{0x4c, 0x10}, {(byte) 0x8c, 0x13}}; + private static final byte[][] DOGE = {{0x1e, 0x16}, {0x71, (byte) 0xc4}}; + } + +} diff --git a/app/src/main/java/com/m2049r/xmrwallet/util/BitcoinAddressValidator.java b/app/src/main/java/com/m2049r/xmrwallet/util/validator/BitcoinAddressValidator.java similarity index 74% rename from app/src/main/java/com/m2049r/xmrwallet/util/BitcoinAddressValidator.java rename to app/src/main/java/com/m2049r/xmrwallet/util/validator/BitcoinAddressValidator.java index 76fa897..ce5cec0 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/util/BitcoinAddressValidator.java +++ b/app/src/main/java/com/m2049r/xmrwallet/util/validator/BitcoinAddressValidator.java @@ -14,10 +14,11 @@ * limitations under the License. */ -package com.m2049r.xmrwallet.util; +package com.m2049r.xmrwallet.util.validator; // mostly based on https://rosettacode.org/wiki/Bitcoin/address_validation#Java +import com.m2049r.xmrwallet.data.Crypto; import com.m2049r.xmrwallet.model.NetworkType; import com.m2049r.xmrwallet.model.WalletManager; @@ -28,28 +29,47 @@ import java.security.NoSuchAlgorithmException; import java.util.Arrays; public class BitcoinAddressValidator { - private static final String ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; - public static boolean validate(String addrress) { - boolean testnet = WalletManager.getInstance().getNetworkType() != NetworkType.NetworkType_Mainnet; - if (validate(addrress, testnet)) return true; - return validateBech32Segwit(addrress, testnet); + public static Crypto validate(String address) { + for (BitcoinAddressType type : BitcoinAddressType.values()) { + if (validate(address, type)) + return Crypto.valueOf(type.name()); + } + return null; } - public static boolean validate(String addrress, boolean testnet) { + // just for tests + public static boolean validateBTC(String addrress, boolean testnet) { + return validate(addrress, BitcoinAddressType.BTC, testnet); + } + + public static boolean validate(String addrress, BitcoinAddressType type, boolean testnet) { + if (validate(addrress, testnet ? type.getTestnet() : type.getProduction())) + return true; + if (type.hasBech32()) + return validateBech32Segwit(addrress, type, testnet); + else + return false; + } + + public static boolean validate(String addrress, BitcoinAddressType type) { + final boolean testnet = WalletManager.getInstance().getNetworkType() != NetworkType.NetworkType_Mainnet; + return validate(addrress, type, testnet); + } + + public static boolean validate(String addrress, byte[] addressTypes) { if (addrress.length() < 26 || addrress.length() > 35) return false; byte[] decoded = decodeBase58To25Bytes(addrress); if (decoded == null) return false; - int v = decoded[0] & 0xFF; - if (!testnet) { - if ((v != 0x00) && (v != 0x05)) return false; - } else { - if ((v != 0x6f) && (v != 0xc4)) return false; + boolean nok = true; + for (byte b : addressTypes) { + nok = nok && (v != (b & 0xFF)); } + if (nok) return false; byte[] hash1 = sha256(Arrays.copyOfRange(decoded, 0, 21)); byte[] hash2 = sha256(hash1); @@ -95,18 +115,20 @@ public class BitcoinAddressValidator { private static final String DATA_CHARS = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; - public static boolean validateBech32Segwit(String bech32, boolean testnet) { + public static boolean validateBech32Segwit(String bech32, BitcoinAddressType type, boolean testnet) { if (!bech32.equals(bech32.toLowerCase()) && !bech32.equals(bech32.toUpperCase())) { return false; // mixing upper and lower case not allowed } bech32 = bech32.toLowerCase(); - if (testnet && !bech32.startsWith("tb1")) return false; - if (!testnet && !bech32.startsWith("bc1")) return false; + if (!bech32.startsWith(type.getBech32Prefix(testnet))) return false; - if ((bech32.length() < 14) || (bech32.length() > 74)) return false; - int mod = bech32.length() % 8; - if ((mod == 0) || (mod == 3) || (mod == 5)) return false; + final int hrpLength = type.getBech32Prefix(testnet).length(); + + if ((bech32.length() < (12 + hrpLength)) || (bech32.length() > (72 + hrpLength))) + return false; + int mod = (bech32.length() - hrpLength) % 8; + if ((mod == 6) || (mod == 1) || (mod == 3)) return false; int sep = -1; final byte[] bytes = bech32.getBytes(StandardCharsets.US_ASCII); @@ -117,7 +139,7 @@ public class BitcoinAddressValidator { if (bytes[i] == 49) sep = i; // 49 := '1' in ASCII } - if (sep != 2) return false; // bech32 always has len(hrp)==2 + if (sep != hrpLength) return false; if (sep > bytes.length - 7) { return false; // min 6 bytes data } @@ -158,12 +180,12 @@ public class BitcoinAddressValidator { private static byte[] hrpExpand(byte[] hrp) { final byte[] expanded = new byte[(2 * hrp.length) + 1]; int i = 0; - for (int j = 0; j < hrp.length; j++) { - expanded[i++] = (byte) (hrp[j] >> 5); + for (byte b : hrp) { + expanded[i++] = (byte) (b >> 5); } expanded[i++] = 0; - for (int j = 0; j < hrp.length; j++) { - expanded[i++] = (byte) (hrp[j] & 0x1f); + for (byte b : hrp) { + expanded[i++] = (byte) (b & 0x1f); } return expanded; } @@ -195,4 +217,4 @@ public class BitcoinAddressValidator { return true; } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/m2049r/xmrwallet/util/validator/EthAddressValidator.java b/app/src/main/java/com/m2049r/xmrwallet/util/validator/EthAddressValidator.java new file mode 100644 index 0000000..3e4c476 --- /dev/null +++ b/app/src/main/java/com/m2049r/xmrwallet/util/validator/EthAddressValidator.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2017 m2049r er al. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.m2049r.xmrwallet.util.validator; + +// mostly based on https://github.com/ognus/wallet-address-validator/blob/master/src/ethereum_validator.js + +import com.theromus.sha.Keccak; +import com.theromus.sha.Parameters; + +import java.nio.charset.StandardCharsets; +import java.util.regex.Pattern; + +public class EthAddressValidator { + static private final Pattern ETH_ADDRESS = Pattern.compile("^0x[0-9a-fA-F]{40}$"); + static private final Pattern ETH_ALLLOWER = Pattern.compile("^0x[0-9a-f]{40}$"); + static private final Pattern ETH_ALLUPPER = Pattern.compile("^0x[0-9A-F]{40}$"); + + public static boolean validate(String address) { + // Check if it has the basic requirements of an address + if (!ETH_ADDRESS.matcher(address).matches()) + return false; + + // If it's all small caps or all all caps, return true + if (ETH_ALLLOWER.matcher(address).matches() || ETH_ALLUPPER.matcher(address).matches()) { + return true; + } + + // Otherwise check each case + return validateChecksum(address); + } + + private static boolean validateChecksum(String address) { + // Check each case + address = address.substring(2); // strip 0x + + Keccak keccak = new Keccak(); + final byte[] addressHash = keccak.getHash( + address.toLowerCase().getBytes(StandardCharsets.US_ASCII), + Parameters.KECCAK_256); + for (int i = 0; i < 40; i++) { + boolean upper = (addressHash[i / 2] & ((i % 2) == 0 ? 128 : 8)) != 0; + char c = address.charAt(i); + if (Character.isAlphabetic(c)) { + if (Character.isUpperCase(c) && !upper) return false; + if (Character.isLowerCase(c) && upper) return false; + } + } + return true; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/m2049r/xmrwallet/widget/ExchangeEditText.java b/app/src/main/java/com/m2049r/xmrwallet/widget/ExchangeEditText.java index a85900f..6602cb7 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/widget/ExchangeEditText.java +++ b/app/src/main/java/com/m2049r/xmrwallet/widget/ExchangeEditText.java @@ -40,6 +40,7 @@ import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi; import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback; import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate; import com.m2049r.xmrwallet.util.Helper; +import com.m2049r.xmrwallet.util.ServiceHelper; import java.util.ArrayList; import java.util.Arrays; @@ -184,6 +185,12 @@ public class ExchangeEditText extends LinearLayout { private boolean isInitialized = false; + void postInitialize() { + setInitialSpinnerSelections(sCurrencyA, sCurrencyB); + isInitialized = true; + startExchange(); + } + @Override protected void onFinishInflate() { super.onFinishInflate(); @@ -212,14 +219,7 @@ public class ExchangeEditText extends LinearLayout { setCurrencyAdapter(sCurrencyA); setCurrencyAdapter(sCurrencyB); - post(new Runnable() { - @Override - public void run() { - setInitialSpinnerSelections(sCurrencyA, sCurrencyB); - isInitialized = true; - startExchange(); - } - }); + post(this::postInitialize); // make progress circle gray pbExchange.getIndeterminateDrawable(). @@ -296,7 +296,7 @@ public class ExchangeEditText extends LinearLayout { } } - private final ExchangeApi exchangeApi = Helper.getExchangeApi(); + private final ExchangeApi exchangeApi = ServiceHelper.getExchangeApi(); // starts exchange through exchange api void startExchange() { diff --git a/app/src/main/java/com/m2049r/xmrwallet/widget/ExchangeOtherEditText.java b/app/src/main/java/com/m2049r/xmrwallet/widget/ExchangeOtherEditText.java index 3b57d07..3dd344e 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/widget/ExchangeOtherEditText.java +++ b/app/src/main/java/com/m2049r/xmrwallet/widget/ExchangeOtherEditText.java @@ -25,6 +25,8 @@ import android.os.Looper; import android.util.AttributeSet; import android.widget.Spinner; +import androidx.annotation.NonNull; + import com.m2049r.xmrwallet.R; import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback; import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate; @@ -46,12 +48,15 @@ public class ExchangeOtherEditText extends ExchangeEditText { public void setExchangeRate(double rate) { exchangeRate = rate; - post(new Runnable() { - @Override - public void run() { - startExchange(); - } - }); + post(this::startExchange); + } + + public void setBaseCurrency(@NonNull String symbol) { + if (symbol.equals(baseCurrency)) return; + baseCurrency = symbol; + setCurrencyAdapter(sCurrencyA); + setCurrencyAdapter(sCurrencyB); + post(this::postInitialize); } private void setBaseCurrency(Context context, AttributeSet attrs) { @@ -184,12 +189,7 @@ public class ExchangeOtherEditText extends ExchangeEditText { @Override public void onError(final Exception e) { Timber.e(e.getLocalizedMessage()); - new Handler(Looper.getMainLooper()).post(new Runnable() { - @Override - public void run() { - exchangeFailed(); - } - }); + new Handler(Looper.getMainLooper()).post(() -> exchangeFailed()); } }); } diff --git a/app/src/main/java/com/m2049r/xmrwallet/widget/ExchangeView.java b/app/src/main/java/com/m2049r/xmrwallet/widget/ExchangeView.java index dceb376..b35a0b6 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/widget/ExchangeView.java +++ b/app/src/main/java/com/m2049r/xmrwallet/widget/ExchangeView.java @@ -44,6 +44,7 @@ import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback; import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate; import com.m2049r.xmrwallet.util.ColorHelper; import com.m2049r.xmrwallet.util.Helper; +import com.m2049r.xmrwallet.util.ServiceHelper; import java.util.ArrayList; import java.util.Arrays; @@ -311,7 +312,7 @@ public class ExchangeView extends LinearLayout { } } - private final ExchangeApi exchangeApi = Helper.getExchangeApi(); + private final ExchangeApi exchangeApi = ServiceHelper.getExchangeApi(); void startExchange() { showProgress(); diff --git a/app/src/main/res/drawable/ic_monero.xml b/app/src/main/res/drawable/ic_monero.xml new file mode 100644 index 0000000..b50ba67 --- /dev/null +++ b/app/src/main/res/drawable/ic_monero.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_monero_bw.xml b/app/src/main/res/drawable/ic_monero_bw.xml new file mode 100644 index 0000000..1b4cef1 --- /dev/null +++ b/app/src/main/res/drawable/ic_monero_bw.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_sideshift_circle.xml b/app/src/main/res/drawable/ic_sideshift_circle.xml new file mode 100644 index 0000000..366f959 --- /dev/null +++ b/app/src/main/res/drawable/ic_sideshift_circle.xml @@ -0,0 +1,12 @@ + + > + + diff --git a/app/src/main/res/drawable/ic_sideshift_white.xml b/app/src/main/res/drawable/ic_sideshift_white.xml index 7d8a328..76d8891 100644 --- a/app/src/main/res/drawable/ic_sideshift_white.xml +++ b/app/src/main/res/drawable/ic_sideshift_white.xml @@ -3,46 +3,46 @@ android:height="80dp" android:viewportWidth="648" android:viewportHeight="80"> - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_xmrto_32dp.png b/app/src/main/res/drawable/ic_xmrto_32dp.png deleted file mode 100644 index b9cec90..0000000 Binary files a/app/src/main/res/drawable/ic_xmrto_32dp.png and /dev/null differ diff --git a/app/src/main/res/drawable/ic_xmrto_btc.xml b/app/src/main/res/drawable/ic_xmrto_btc.xml new file mode 100644 index 0000000..60efbe2 --- /dev/null +++ b/app/src/main/res/drawable/ic_xmrto_btc.xml @@ -0,0 +1,14 @@ + + + + diff --git a/app/src/main/res/drawable/ic_xmrto_btc_off.xml b/app/src/main/res/drawable/ic_xmrto_btc_off.xml new file mode 100644 index 0000000..5a49d3d --- /dev/null +++ b/app/src/main/res/drawable/ic_xmrto_btc_off.xml @@ -0,0 +1,14 @@ + + + + diff --git a/app/src/main/res/drawable/ic_xmrto_dash.xml b/app/src/main/res/drawable/ic_xmrto_dash.xml new file mode 100644 index 0000000..a3ace15 --- /dev/null +++ b/app/src/main/res/drawable/ic_xmrto_dash.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_xmrto_dash_off.xml b/app/src/main/res/drawable/ic_xmrto_dash_off.xml new file mode 100644 index 0000000..28a712f --- /dev/null +++ b/app/src/main/res/drawable/ic_xmrto_dash_off.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_xmrto_doge.xml b/app/src/main/res/drawable/ic_xmrto_doge.xml new file mode 100644 index 0000000..c8bfcd7 --- /dev/null +++ b/app/src/main/res/drawable/ic_xmrto_doge.xml @@ -0,0 +1,14 @@ + + + + diff --git a/app/src/main/res/drawable/ic_xmrto_doge_off.xml b/app/src/main/res/drawable/ic_xmrto_doge_off.xml new file mode 100644 index 0000000..51f0639 --- /dev/null +++ b/app/src/main/res/drawable/ic_xmrto_doge_off.xml @@ -0,0 +1,14 @@ + + + + diff --git a/app/src/main/res/drawable/ic_xmrto_eth.xml b/app/src/main/res/drawable/ic_xmrto_eth.xml new file mode 100644 index 0000000..9569125 --- /dev/null +++ b/app/src/main/res/drawable/ic_xmrto_eth.xml @@ -0,0 +1,38 @@ + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_xmrto_eth_off.xml b/app/src/main/res/drawable/ic_xmrto_eth_off.xml new file mode 100644 index 0000000..04da5f0 --- /dev/null +++ b/app/src/main/res/drawable/ic_xmrto_eth_off.xml @@ -0,0 +1,38 @@ + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_xmrto_ltc.xml b/app/src/main/res/drawable/ic_xmrto_ltc.xml new file mode 100644 index 0000000..5bb3470 --- /dev/null +++ b/app/src/main/res/drawable/ic_xmrto_ltc.xml @@ -0,0 +1,14 @@ + + + + diff --git a/app/src/main/res/drawable/ic_xmrto_ltc_off.xml b/app/src/main/res/drawable/ic_xmrto_ltc_off.xml new file mode 100644 index 0000000..663c247 --- /dev/null +++ b/app/src/main/res/drawable/ic_xmrto_ltc_off.xml @@ -0,0 +1,14 @@ + + + + diff --git a/app/src/main/res/drawable/ic_xmrto_whitestroke_24px.png b/app/src/main/res/drawable/ic_xmrto_whitestroke_24px.png deleted file mode 100644 index a1650c3..0000000 Binary files a/app/src/main/res/drawable/ic_xmrto_whitestroke_24px.png and /dev/null differ diff --git a/app/src/main/res/layout/fragment_send_address.xml b/app/src/main/res/layout/fragment_send_address.xml index ded4ab8..29dcfcb 100644 --- a/app/src/main/res/layout/fragment_send_address.xml +++ b/app/src/main/res/layout/fragment_send_address.xml @@ -29,14 +29,12 @@ android:orientation="horizontal"> - - - - + android:layout_height="wrap_content" + android:orientation="vertical"> + android:weightSum="6"> - + android:layout_weight="1" + android:background="@null" + android:padding="8dp" + android:src="@drawable/ic_monero" /> - + android:layout_weight="1" + android:background="@null" + android:padding="8dp" + android:src="@drawable/ic_xmrto_btc_off" /> + + + + + + + + - + + + diff --git a/app/src/main/res/layout/fragment_send_btc_amount.xml b/app/src/main/res/layout/fragment_send_btc_amount.xml index 00e5a7d..fd1b9f8 100644 --- a/app/src/main/res/layout/fragment_send_btc_amount.xml +++ b/app/src/main/res/layout/fragment_send_btc_amount.xml @@ -12,7 +12,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" - android:gravity="center" + android:layout_marginStart="56dp" tools:text="@string/send_available_btc" /> + android:src="@drawable/ic_sideshift_circle" /> + android:visibility="visible"> + card_view:drawableStartCompat="@drawable/ic_sideshift_circle" /> + android:src="@drawable/ic_monero" /> @@ -128,6 +128,13 @@ android:layout_height="wrap_content" android:layout_centerInParent="true"> + + @@ -151,15 +158,6 @@ android:layout_height="72dp" android:layout_gravity="center" android:visibility="invisible" /> - - - @@ -20,10 +19,10 @@ + android:src="@drawable/ic_monero" /> + android:text="@string/tx_amount" /> + android:text="@string/tx_destination" /> Ledger habilitat, premi aquí per més informació. Heu introduït una adreça de Bitcoin.
- Està a punt d\'enviar XMR i el destinatari rebrà BTC a través del servei SideShift.ai service. + Heu introduït una adreça %1$s.
+ Està a punt d\'enviar XMR i el destinatari rebrà %1$s a través del servei SideShift.ai service. ]]>
Ordre SideShift.ai - %1$s BTC + %1$s %2$s Confirmació Pendent Pagament Pendent Error de SideShift.ai (%1$s) - BTC Enviats! + %1$s Enviats! Consultant … You can send %1$s — %2$s BTC.
- SideShift.ai està oferint una tasa de canvi de %3$s BTC en aquest moment. - ]]>
- Quantitats fins a %1$s BTC seran enviats a l\'instant! + You can send %1$s — %2$s %4$s.
+ SideShift.ai està oferint una tasa de canvi de %3$s %4$s/XMR en aquest moment. ]]>
- Balanç: %2$s BTC (%1$s XMR) + Balanç: %2$s %3$s (%1$s XMR) ✔ ID de pagment integrat Preparant la seva transacció @@ -75,13 +72,13 @@ Vatua l\'olla! Sembla ser que estem encallats! Ups, sembla que SideShift.ai no està disponible ara mateix! - %1$s BTC = %2$s XMR - (Canvi: %1$s BTC/XMR) + %1$s %3$s = %2$s XMR + (Canvi: %1$s %2$s/XMR) Visita SideShift.ai per suport i seguiment Clau secreta\nSideShift.ai Clau secreta SideShift.ai - Adreça BTC de destí + Adreça %1$s de destí Quantitat ID de transacció @@ -251,11 +248,9 @@ ID de transacció Clau de transacció Destí - Destí\n(BTC) ID de pagament Bloc Quantitat - Quantitat\n(BTC) Comissió Transferències Notes @@ -354,11 +349,6 @@ Receptor - SideShift.ai fora de línia - intenti-ho més tard - Quantitat de BTC fora dels límits - URL de pagament no vàlida o obsoleta - Massa peticions - TOT! Convertir la llavor del Ledger @@ -381,8 +371,8 @@ This app allows you to create and use Monero wallets. You can store your sweet moneroj in them. Keep your seed safe The seed grants full access to whoever has it. If you lose it, we cannot help you recover it and you lose your beloved moneroj. - Send Bitcoin - Monerujo has SideShift.ai support built-in. Just paste or scan a Bitcoin address and you\'ll be sending BTC by spending XMR. + Send Crypto + Monerujo has SideShift.ai support built-in. Just paste or scan a BTC, LTC, ETH, DASH or DOGE address and you\'ll be sending these cryptos by spending XMR. Nodes, your way Nodes connect you to the Monero network. Choose between public nodes or go full cypherpunk using your own. Send with fingerprint @@ -406,4 +396,18 @@ Cannot get quote Check amount and try again + + Ambiguous address.
+ Please select the type above. + ]]>
+ + Please enter or scan a %1$s address.
+ You'll send XMR and the receiver will get %2$s using the SideShift.ai service. + ]]>
+ + Please enter or scan a Monero address. + ]]> diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index b73a845..94d5ee5 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -35,30 +35,26 @@ Ledger aktiviert – Tippe für mehr Infos. Du hast eine BTC-Adresse eingegeben.
- Du wirst XMR versenden und der Empfänger durch den SideShift.ai Service BTC erhalten. + Du hast eine %1$s-Adresse eingegeben.
+ Du wirst XMR versenden und der Empfänger durch den SideShift.ai Service %1$s erhalten. ]]>
SideShift.ai-Auftrag - %1$s BTC - + %1$s %2$s Bestätigung ausstehend Bezahlung ausstehend SideShift.ai-Fehler (%1$s) - BTC gesendet! + %1$s gesendet! Frage ab … Du kannst %1$s — %2$s BTC senden.
- SideShift.ai gibt dir aktuell einen Wechselkurs von %3$s BTC. - ]]>
- Beträge bis zu %1$s BTC werden sofort versendet! + Du kannst %1$s — %2$s %4$s senden.
+ SideShift.ai gibt dir aktuell einen Wechselkurs von %3$s %4$s/XMR. ]]>
- Guthaben: %2$s BTC (%1$s XMR) + Guthaben: %2$s %3$s (%1$s XMR) ✔ Zahlungs-ID integriert Bereite deine Transaktion vor @@ -76,13 +72,13 @@ Jetzt hängen wir hier fest! Oh oh – SideShift.ai scheint im Moment nicht verfügbar zu sein! - %1$s BTC = %2$s XMR - (Kurs: %1$s BTC/XMR) + %1$s %3$s = %2$s XMR + (Kurs: %1$s %2$s/XMR) Besuche SideShift.ai für Support & Nachverfolgung Geheimer Schlüssel\nSideShift.ai SideShift.ai – Geheimer Schlüssel - BTC-Zieladresse + %1$s-Zieladresse Betrag Transaktions-ID @@ -246,11 +242,9 @@ Transaktions-ID Transaktionsschlüssel Ziel - Ziel\n(BTC) Zahlungs-ID Block Betrag - Betrag\n(BTC) Gebühr Transfers Notizen @@ -357,11 +351,6 @@ Empfänger - SideShift.ai nicht erreichbar – versuche es später nochmal - BTC-Betrag außerhalb des gültigen Bereiches - Ungültige oder veraltete Zahlungs-URL - Zu viele Anfragen - ALLES! Konvertiere Ledger-Seed @@ -384,8 +373,8 @@ This app allows you to create and use Monero wallets. You can store your sweet moneroj in them. Keep your seed safe The seed grants full access to whoever has it. If you lose it, we cannot help you recover it and you lose your beloved moneroj. - Send Bitcoin - Monerujo has SideShift.ai support built-in. Just paste or scan a Bitcoin address and you\'ll be sending BTC by spending XMR. + Send Crypto + Monerujo has SideShift.ai support built-in. Just paste or scan a BTC, LTC, ETH, DASH or DOGE address and you\'ll be sending these cryptos by spending XMR. Nodes, your way Nodes connect you to the Monero network. Choose between public nodes or go full cypherpunk using your own. Send with fingerprint @@ -409,4 +398,18 @@ Cannot get quote Check amount and try again + + Ambiguous address.
+ Please select the type above. + ]]>
+ + Please enter or scan a %1$s address.
+ You'll send XMR and the receiver will get %2$s using the SideShift.ai service. + ]]>
+ + Please enter or scan a Monero address. + ]]> diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 675f841..f2c4815 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -34,29 +34,26 @@ Ledger ενεργοποιήθηκε, πάτα για περισσότερες πληροφορείες. Έβαλες μια διεύθυνση bitcoin.
- Θα στείλεις XMR και ο παραλήπτης θα πάρει BTC μέσο της υπηρεσίας SideShift.ai. + Έβαλες μια διεύθυνση %1$s.
+ Θα στείλεις XMR και ο παραλήπτης θα πάρει %1$s μέσο της υπηρεσίας SideShift.ai. ]]>
Εντολή SideShift.ai - %1$s BTC + %1$s %2$s Επιβεβαίωση Εκκρεμεί Πληρωμή σε εκκρεμότητα SideShift.ai Σφάλμα (%1$s) - BTC Αποστάλθηκαν! + %1$s Αποστάλθηκαν! Αίτηση … Μπορείς να στείλεις %1$s — %2$s BTC.
- Το SideShift.ai σου δίνει ισοτιμία ανταλλαγής %3$s BTC αυτή τη στιγμή. - ]]>
- Ποσά μέχρι %1$s BTC θα σταλούν άμεσα! + Μπορείς να στείλεις %1$s — %2$s %4$s.
+ Το SideShift.ai σου δίνει ισοτιμία ανταλλαγής %3$s %4$s/XMR αυτή τη στιγμή. ]]>
- Σύνολο: %2$s BTC (%1$s XMR) + Σύνολο: %2$s %3$s (%1$s XMR) ✔ ID πληρωμής ενσωματωμένο Προετοιμασία της συναλλαγής σου @@ -74,13 +71,13 @@ Τώρα έχουμε κολλήσει εδώ! Ωχ,το SideShift.ai φαίνεται να μην ειναι προσωρινά διαθέσιμο! - %1$s BTC = %2$s XMR - (Rate: %1$s BTC/XMR) + %1$s %3$s = %2$s XMR + (Rate: %1$s %2$s/XMR) Επίσκεψη στο SideShift.ai για υποστήριξη & με εντοπισμό συναλλαγής Μυστικό Κλειδί\nSideShift.ai SideShift.ai Μυστικό Κλειδί - BTC Διεύθυνση Παραλήπτη + %1$s Διεύθυνση Παραλήπτη Ποσό ID Συναλλαγής @@ -220,11 +217,9 @@ ID Συναλλαγής(TX ID) Κλειδί συναλλαγής(TX Key) Προορισμός - Προορισμός\n(BTC) ID Πληρωμής(Payment ID) Μπλοκ Ποσό - Ποσό\n(BTC) Κόμιστρο Συναλλαγές Σημειώσεις @@ -356,11 +351,6 @@ Receiver - SideShift.ai offline - try again later - BTC amount out of bounds - Invalid or outdated Payment URL - Too many requests - EVERYTHING! Convert Ledger Seed @@ -383,8 +373,8 @@ This app allows you to create and use Monero wallets. You can store your sweet moneroj in them. Keep your seed safe The seed grants full access to whoever has it. If you lose it, we cannot help you recover it and you lose your beloved moneroj. - Send Bitcoin - Monerujo has SideShift.ai support built-in. Just paste or scan a Bitcoin address and you\'ll be sending BTC by spending XMR. + Send Crypto + Monerujo has SideShift.ai support built-in. Just paste or scan a BTC, LTC, ETH, DASH or DOGE address and you\'ll be sending these cryptos by spending XMR. Nodes, your way Nodes connect you to the Monero network. Choose between public nodes or go full cypherpunk using your own. Send with fingerprint @@ -408,4 +398,18 @@ Cannot get quote Check amount and try again + + Ambiguous address.
+ Please select the type above. + ]]>
+ + Please enter or scan a %1$s address.
+ You'll send XMR and the receiver will get %2$s using the SideShift.ai service. + ]]>
+ + Please enter or scan a Monero address. + ]]> diff --git a/app/src/main/res/values-eo/strings.xml b/app/src/main/res/values-eo/strings.xml index 6bafaf0..a112287 100644 --- a/app/src/main/res/values-eo/strings.xml +++ b/app/src/main/res/values-eo/strings.xml @@ -35,29 +35,26 @@ Ledger permesita, frapetu por detaloj. Vi entajpis Bitmono-adreson.
- Vi sendos XMR-on, kaj per laSideShift.ai-servo, la ricevanto havos BTC-on. + Vi entajpis %1$s-adreson.
+ Vi sendos XMR-on, kaj per laSideShift.ai-servo, la ricevanto havos %1$s-on. ]]>
mendo al SideShift.ai - %1$s BTC + %1$s %2$s Konfirmo okazonta Pago okazonta SideShift.ai eraro (%1$s) - BTC sendiĝis! + %1$s sendiĝis! Informpetante … Vi povas sendi %1$s — %2$s BTC.
- SideShift.ai proponas al vi tiun kurzon: %3$s BTC nun. - ]]>
- Kvantoj ĝis %1$s BTC sendiĝos senatende! + Vi povas sendi %1$s — %2$s %4$s.
+ SideShift.ai proponas al vi tiun kurzon: %3$s %4$s/XMR nun. ]]>
- Saldo: %2$s BTC (%1$s XMR) + Saldo: %2$s %3$s (%1$s XMR) ✔ Paga-ID integriĝis Preparante vian transakcion @@ -75,13 +72,13 @@ Ni blokiĝis ĉi tie! Uh-oh, ŝajne SideShift.ai ne disponas momente! - %1$s BTC = %2$s XMR - (kurzo: %1$s BTC/XMR) + %1$s %3$s = %2$s XMR + (kurzo: %1$s %2$s/XMR) Vizitu SideShift.ai por helpo kaj sekvado Sekreta ŝlosilo\nSideShift.ai SideShift.ai sekreta ŝlosilo - Ricevanta BTC-adreso + Ricevanta %1$s-adreso Kvanto Transakcia ID @@ -251,11 +248,9 @@ TX ID TX Ŝlosilo Destino - Destino\n(BTC) Paga-ID Bloko Kvanto - Kvanto\n(BTC) Kosto Transigoj Notoj @@ -356,11 +351,6 @@ Ricevanto - SideShift.ai ne enretas - provu pli poste - BTC-kvanto tro grandas - La paga URL malvalidas aŭ ne ĝisdatiĝis - Tro da mendoj - ĈIO! Convert Ledger Seed @@ -383,8 +373,8 @@ This app allows you to create and use Monero wallets. You can store your sweet moneroj in them. Keep your seed safe The seed grants full access to whoever has it. If you lose it, we cannot help you recover it and you lose your beloved moneroj. - Send Bitcoin - Monerujo has SideShift.ai support built-in. Just paste or scan a Bitcoin address and you\'ll be sending BTC by spending XMR. + Send Crypto + Monerujo has SideShift.ai support built-in. Just paste or scan a BTC, LTC, ETH, DASH or DOGE address and you\'ll be sending these cryptos by spending XMR. Nodes, your way Nodes connect you to the Monero network. Choose between public nodes or go full cypherpunk using your own. Send with fingerprint @@ -408,4 +398,18 @@ Cannot get quote Check amount and try again + + Ambiguous address.
+ Please select the type above. + ]]>
+ + Please enter or scan a %1$s address.
+ You'll send XMR and the receiver will get %2$s using the SideShift.ai service. + ]]>
+ + Please enter or scan a Monero address. + ]]> diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 2b84f3d..99974d0 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -218,23 +218,20 @@ Restaurar monedero con claves privadas Restaurar monedero con semilla de 25 palabras Ingresaste una dirección Bitcoin
- Vas a enviar XMR y el destinatario recibirá BTC usando el servicio SideShift.ai. + Ingresaste una dirección %1$s
+ Vas a enviar XMR y el destinatario recibirá %1$s usando el servicio SideShift.ai. ]]>
- %1$s BTC + %1$s %2$s Confirmación pendiente Pago pendiente Error de SideShift.ai (%1$s) - BTC Enviados! + %1$s Enviados! Consultando … Puedes enviar %1$s — %2$s BTC.
- SideShift.ai está ofreciendo una tasa de cambio de %3$s BTC en este momento. + Puedes enviar %1$s — %2$s %4$s.
+ SideShift.ai está ofreciendo una tasa de cambio de %3$s %4$s/XMR en este momento. ]]>
- Montos hasta %1$s BTC serán enviados en el momento! - ]]> - Saldo: %2$s BTC (%1$s XMR) + Saldo: %2$s %3$s (%1$s XMR) Creando orden SideShift.ai Consultando orden SideShift.ai Preparando transacción Monero @@ -244,12 +241,12 @@ Toca para reintentar Parece que estamos atascados! Oh-oh, parece que SideShift.ai no está disponible ahora! - %1$s BTC = %2$s XMR - (Cambio: %1$s BTC/XMR) + %1$s %3$s = %2$s XMR + (Cambio: %1$s %2$s/XMR) Visita https://sideshift.ai para soporte y rastreo Clave secreta\nSideShift.ai Clave secreta SideShift.ai - Dirección BTC destino + Dirección %1$s destino Monto Oye, esperaste demasiado! Clave @@ -261,8 +258,6 @@ Total (XMR) %1$s XMR +%1$s Comisión - Destino\n(BTC) - Monto\n(BTC) Soy monerujo Orden SideShift.ai @@ -347,11 +342,6 @@ Receptor - SideShift.ai offline - try again later - BTC amount out of bounds - Invalid or outdated Payment URL - Too many requests - EVERYTHING! Convert Ledger Seed @@ -374,8 +364,8 @@ This app allows you to create and use Monero wallets. You can store your sweet moneroj in them. Keep your seed safe The seed grants full access to whoever has it. If you lose it, we cannot help you recover it and you lose your beloved moneroj. - Send Bitcoin - Monerujo has SideShift.ai support built-in. Just paste or scan a Bitcoin address and you\'ll be sending BTC by spending XMR. + Send Crypto + Monerujo has SideShift.ai support built-in. Just paste or scan a BTC, LTC, ETH, DASH or DOGE address and you\'ll be sending these cryptos by spending XMR. Nodes, your way Nodes connect you to the Monero network. Choose between public nodes or go full cypherpunk using your own. Send with fingerprint @@ -399,4 +389,18 @@ Cannot get quote Check amount and try again + + Ambiguous address.
+ Please select the type above. + ]]>
+ + Please enter or scan a %1$s address.
+ You'll send XMR and the receiver will get %2$s using the SideShift.ai service. + ]]>
+ + Please enter or scan a Monero address. + ]]> diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml index 8b10e14..ad8e6cc 100644 --- a/app/src/main/res/values-et/strings.xml +++ b/app/src/main/res/values-et/strings.xml @@ -35,29 +35,26 @@ Ledger\'i tugi sisse lülitatud, puuduta lisainfo saamiseks. Sa sisestasid Bitcoini aadressi.
- See tähendab, et sa saadad Monerosid ning kohale jõuavad Bitcoinid kasutades SideShift.ai teenust. + Sa sisestasid %1$s aadressi.
+ See tähendab, et sa saadad Monerosid ning kohale jõuavad %1$s kasutades SideShift.ai teenust. ]]>
SideShift.ai tellimus - %1$s BTC + %1$s %2$s Ootan kinnitust Ootan makset SideShift.ai viga (%1$s) - BTC saadetud! + %1$s saadetud! Küsin … Sa saad saata %1$s — %2$s BTC.
- SideShift.ai annab hetkel vahetuskursiks %3$s BTC. - ]]>
- Kuni %1$s BTC saadetakse viivitamatult! + Sa saad saata %1$s — %2$s %4$s.
+ SideShift.ai annab hetkel vahetuskursiks %3$s %4$s/XMR. ]]>
- Kontojääk: %2$s BTC (%1$s XMR) + Kontojääk: %2$s %3$s (%1$s XMR) ✔ Makse ID integreeritud Valmistan ülekannet ette @@ -75,13 +72,13 @@ Nüüd jõudsime küll tupikusse! Oh ei, SideShift.ai ei ole hetkel saadaval! - %1$s BTC = %2$s XMR - (Kurss: %1$s BTC/XMR) + %1$s %3$s = %2$s XMR + (Kurss: %1$s %2$s/XMR) Külasta SideShift.ai lisainfo saamiseks & jälgin Privaatvõti\nSideShift.ai SideShift.ai privaatvõti - Sihtkoha Bitcoini aadress + Sihtkoha %1$s aadress Kogus Ülekande ID @@ -246,11 +243,9 @@ Ülekande ID Ülekande võti Sihtkoht - Sihtkoht\n(BTC) Makse ID Plokk Kogus - Kogus\n(BTC) Teenustasu Ülekanded Kommentaarid @@ -354,11 +349,6 @@ Saaja - SideShift.ai offline - try again later - BTC amount out of bounds - Invalid or outdated Payment URL - Too many requests - EVERYTHING! Convert Ledger Seed @@ -381,8 +371,8 @@ This app allows you to create and use Monero wallets. You can store your sweet moneroj in them. Keep your seed safe The seed grants full access to whoever has it. If you lose it, we cannot help you recover it and you lose your beloved moneroj. - Send Bitcoin - Monerujo has SideShift.ai support built-in. Just paste or scan a Bitcoin address and you\'ll be sending BTC by spending XMR. + Send Crypto + Monerujo has SideShift.ai support built-in. Just paste or scan a BTC, LTC, ETH, DASH or DOGE address and you\'ll be sending these cryptos by spending XMR. Nodes, your way Nodes connect you to the Monero network. Choose between public nodes or go full cypherpunk using your own. Send with fingerprint @@ -406,4 +396,18 @@ Cannot get quote Check amount and try again + + Ambiguous address.
+ Please select the type above. + ]]>
+ + Please enter or scan a %1$s address.
+ You'll send XMR and the receiver will get %2$s using the SideShift.ai service. + ]]>
+ + Please enter or scan a Monero address. + ]]> diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 41f2998..563431a 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -35,30 +35,27 @@ Ledger activé, tapez pour plus d\'infos. Vous avez entré une adresse Bitcoin.
- Vous envoyez des XMR et le destinataire recevra des BTC via le service SideShift.ai. + Vous avez entré une adresse %1$s.
+ Vous envoyez des XMR et le destinataire recevra des %1$s via le service SideShift.ai. ]]>
Ordres SideShift.ai - %1$s BTC + %1$s %2$s En Attente de Confirmation En Attente de Paiement Erreur SideShift.ai (%1$s) - BTC Envoyé ! + %1$s Envoyé ! Interrogation … Vous pouvez envoyer %1$s — %2$s BTC.
- SideShift.ai vous donne un taux de change de %3$s BTC actuellement. - ]]>
- Les montant n\'excédant pas %1$s BTC seront envoyés immédiatement! + Vous pouvez envoyer %1$s — %2$s %4$s.
+ SideShift.ai vous donne un taux de change de %3$s %4$s/XMR actuellement. ]]>
- Solde : %2$s BTC (%1$s XMR) + Solde : %2$s %3$s (%1$s XMR) ✔ ID de Paiement intégré Préparation de votre transaction @@ -76,13 +73,13 @@ Maintenant on est coincé ici ! Oh-oh, SideShift.ai n\'a pas l\'air disponible pour le moment ! - %1$s BTC = %2$s XMR - (Taux : %1$s BTC/XMR) + %1$s %3$s = %2$s XMR + (Taux : %1$s %2$s/XMR) Visitez SideShift.ai pour l\'assistance & le suivi Clef Secrète\nSideShift.ai Clef Secrète SideShift.ai - Adresse BTC Destination + Adresse %1$s Destination Montant ID de Transaction @@ -248,11 +245,9 @@ ID TX Clef TX Destination - Destination\n(BTC) ID de Paiement Bloc Montant - Montant\n(BTC) Frais Transferts Notes @@ -360,11 +355,6 @@ Destinataire - SideShift.ai hors ligne - réessayer ultérieurement - Montant BTC hors limites - URL de Paiement invalide ou périmée - Trop de requêtes - TOTALITÉ! Convertir mnémonique Ledger @@ -387,8 +377,8 @@ This app allows you to create and use Monero wallets. You can store your sweet moneroj in them. Keep your seed safe The seed grants full access to whoever has it. If you lose it, we cannot help you recover it and you lose your beloved moneroj. - Send Bitcoin - Monerujo has SideShift.ai support built-in. Just paste or scan a Bitcoin address and you\'ll be sending BTC by spending XMR. + Send Crypto + Monerujo has SideShift.ai support built-in. Just paste or scan a BTC, LTC, ETH, DASH or DOGE address and you\'ll be sending these cryptos by spending XMR. Nodes, your way Nodes connect you to the Monero network. Choose between public nodes or go full cypherpunk using your own. Send with fingerprint @@ -412,4 +402,18 @@ Cannot get quote Check amount and try again + + Ambiguous address.
+ Please select the type above. + ]]>
+ + Please enter or scan a %1$s address.
+ You'll send XMR and the receiver will get %2$s using the SideShift.ai service. + ]]>
+ + Please enter or scan a Monero address. + ]]> diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 5892dde..429404b 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -35,29 +35,26 @@ Ledger engedélyezve, koppints ide a részletekért Bitcoin-címet adtál meg.
- XMR-t fogsz küldeni, a fogadó pedig BTC-t fog kapni az SideShift.ai szolgáltatásán keresztül. + %1$s-címet adtál meg.
+ XMR-t fogsz küldeni, a fogadó pedig %1$s-t fog kapni az SideShift.ai szolgáltatásán keresztül. ]]>
SideShift.ai megrendelés - %1$s BTC + %1$s %2$s Megerősítés folyamatban Kifizetés folyamatban SideShift.ai-hiba (%1$s) - BTC elküldve! + %1$s elküldve! Lekérdezés… Elküldhetsz: %1$s — %2$s BTC.
- Az SideShift.ai aktuális árfolyama: %3$s BTC. - ]]>
- A legfeljebb %1$s BTC nagyságú összegek azonnal elküldésre kerülnek! + Elküldhetsz: %1$s — %2$s %4$s.
+ Az SideShift.ai aktuális árfolyama: %3$s %4$s/XMR. ]]>
- Egyenleg: %2$s BTC (%1$s XMR) + Egyenleg: %2$s %3$s (%1$s XMR) ✔ Fizetési azonosító integrálva Tranzakció előkészítése @@ -75,13 +72,13 @@ Itt most elakadtunk! Ajjaj! Úgy néz ki, az SideShift.ai most nem elérhető! - %1$s BTC = %2$s XMR - (Arány: %1$s BTC/XMR) + %1$s %3$s = %2$s XMR + (Arány: %1$s %2$s/XMR) Segítségért és nyomonkövetésért látogass el az SideShift.ai weboldalra Titkos kulcs\nSideShift.ai SideShift.ai titkos kulcs - Kedvezményezett BTC-címe + Kedvezményezett %1$s-címe Mennyiség Tranzakcióazonosító @@ -245,11 +242,9 @@ Tranzakcióazonosító Tranzkaciós kulcs Cél - Cél\n(BTC) Fizetési azonosító Blokk Mennyiség - Mennyiség\n(BTC) Díj Transzferek Közlemény @@ -358,11 +353,6 @@ Receiver - SideShift.ai offline - try again later - BTC amount out of bounds - Invalid or outdated Payment URL - Too many requests - EVERYTHING! Convert Ledger Seed @@ -385,8 +375,8 @@ This app allows you to create and use Monero wallets. You can store your sweet moneroj in them. Keep your seed safe The seed grants full access to whoever has it. If you lose it, we cannot help you recover it and you lose your beloved moneroj. - Send Bitcoin - Monerujo has SideShift.ai support built-in. Just paste or scan a Bitcoin address and you\'ll be sending BTC by spending XMR. + Send Crypto + Monerujo has SideShift.ai support built-in. Just paste or scan a BTC, LTC, ETH, DASH or DOGE address and you\'ll be sending these cryptos by spending XMR. Nodes, your way Nodes connect you to the Monero network. Choose between public nodes or go full cypherpunk using your own. Send with fingerprint @@ -410,4 +400,18 @@ Cannot get quote Check amount and try again + + Ambiguous address.
+ Please select the type above. + ]]>
+ + Please enter or scan a %1$s address.
+ You'll send XMR and the receiver will get %2$s using the SideShift.ai service. + ]]>
+ + Please enter or scan a Monero address. + ]]> diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index b79b500..92d9060 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -35,30 +35,27 @@ Ledger abilitato, tocca per maggiori informazioni. Hai inserito un indirizzo Bitcoin.
- Invierai XMR e il destinatario riceverà BTC tramite il servizio SideShift.ai. + Hai inserito un indirizzo %1$s.
+ Invierai XMR e il destinatario riceverà %1$s tramite il servizio SideShift.ai. ]]>
Ordine SideShift.ai - %1$s BTC + %1$s %2$s In attesa di conferma In attesa del pagamento Errore SideShift.ai (%1$s) - BTC Inviati! + %1$s Inviati! Richiedendo … Puoi inviare %1$s — %2$s BTC.
- SideShift.ai ti sta attualmente concedendo un tasso di cambio di %3$s BTC. - ]]>
- Ammontare fino a %1$s BTC inviati istantaneamente! + Puoi inviare %1$s — %2$s %4$s.
+ SideShift.ai ti sta attualmente concedendo un tasso di cambio di %3$s %4$s/XMR. ]]>
- Saldo: %2$s BTC (%1$s XMR) + Saldo: %2$s %3$s (%1$s XMR) ✔ ID pagamento integrato Preparando la tua transazione @@ -76,13 +73,13 @@ Ora siamo bloccati qui!! Oh Oh, SideShift.ai sembra non essere disponibile in questo momento! - %1$s BTC = %2$s XMR - (Tasso: %1$s BTC/XMR) + %1$s %3$s = %2$s XMR + (Tasso: %1$s %2$s/XMR) Visita SideShift.ai per supporto e tracciamento Chiave segreta\nSideShift.ai Chiave segreta SideShift.ai - Indirizzo BTC di destinazione + Indirizzo %1$s di destinazione Ammontare ID Transazione @@ -247,11 +244,9 @@ ID TX Chiave TX Destinazione - Destinazione\n(BTC) ID Pagamento Blocco Ammontare - Ammontare\n(BTC) Commissione Trasferimenti Note @@ -359,11 +354,6 @@ Ricevente - SideShift.ai è offline - prova più tardi - Ammontare in BTC fuori dai limiti - URL di pagamento obsoleto o invalido - Troppe richieste - TUTTO! Converti seed Ledger @@ -386,8 +376,8 @@ This app allows you to create and use Monero wallets. You can store your sweet moneroj in them. Keep your seed safe The seed grants full access to whoever has it. If you lose it, we cannot help you recover it and you lose your beloved moneroj. - Send Bitcoin - Monerujo has SideShift.ai support built-in. Just paste or scan a Bitcoin address and you\'ll be sending BTC by spending XMR. + Send Crypto + Monerujo has SideShift.ai support built-in. Just paste or scan a BTC, LTC, ETH, DASH or DOGE address and you\'ll be sending these cryptos by spending XMR. Nodes, your way Nodes connect you to the Monero network. Choose between public nodes or go full cypherpunk using your own. Send with fingerprint @@ -411,4 +401,18 @@ Cannot get quote Check amount and try again + + Ambiguous address.
+ Please select the type above. + ]]>
+ + Please enter or scan a %1$s address.
+ You'll send XMR and the receiver will get %2$s using the SideShift.ai service. + ]]>
+ + Please enter or scan a Monero address. + ]]> diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index c40f150..fec82ef 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -35,29 +35,26 @@ レッジャーは有効化されています。詳細はタップしてください。 あなたが入力したのはビットコインのアドレスです。
- あなたはXMRを送金し、受け手は SideShift.ai のサービスを利用してBTCを受取ります。 + あなたが入力したのは%1$sのアドレスです。
+ あなたはXMRを送金し、受け手は SideShift.ai のサービスを利用して%1$sを受取ります。 ]]>
SideShift.ai の注文 - %1$s BTC + %1$s %2$s 承認を待っています 支払いを待っています SideShift.ai のエラー (%1$s) - BTCが送金されました! + %1$sが送金されました! 問い合わせ中 … %1$s から %2$s BTC を送金することができます。
- SideShift.ai での交換レートは現在%3$s BTCです。 - ]]>
- %1$s BTC までの数量は 即時に送金可能です! + %1$s から %2$s %4$s を送金することができます。
+ SideShift.ai での交換レートは現在%3$s %4$s/XMRです。 ]]>
- 残高: %2$s BTC (%1$s XMR) + 残高: %2$s %3$s (%1$s XMR) ✔ ペイメントID組み込み済み 取引を準備しています @@ -75,13 +72,13 @@ 私達はここで立ち往生のようです! あーあ、 SideShift.ai は現在利用不能のようです! - %1$s BTC = %2$s XMR - (レート: %1$s BTC/XMR) + %1$s %3$s = %2$s XMR + (レート: %1$s %2$s/XMR) サポートと追跡については SideShift.ai をご覧ください シークレットキー\nSideShift.ai SideShift.ai のシークレットキー - 支払先の BTC アドレス + 支払先の %1$s アドレス 数量 取引ID @@ -251,11 +248,9 @@ 取引ID 取引キー 送金先 - 送金先\n(BTC) ペイメントID ブロック 数量 - 数量\n(BTC) 手数料 送金 メモ @@ -359,11 +354,6 @@ 受け取り手 - SideShift.aiはオフラインです。もう一度お試しください - BTCの金額は範囲外 - ペイメントURLは不正古いです - リクエストは多すぎます - 残高合計! Ledgerシードを転換 @@ -386,8 +376,8 @@ This app allows you to create and use Monero wallets. You can store your sweet moneroj in them. Keep your seed safe The seed grants full access to whoever has it. If you lose it, we cannot help you recover it and you lose your beloved moneroj. - Send Bitcoin - Monerujo has SideShift.ai support built-in. Just paste or scan a Bitcoin address and you\'ll be sending BTC by spending XMR. + Send Crypto + Monerujo has SideShift.ai support built-in. Just paste or scan a BTC, LTC, ETH, DASH or DOGE address and you\'ll be sending these cryptos by spending XMR. Nodes, your way Nodes connect you to the Monero network. Choose between public nodes or go full cypherpunk using your own. Send with fingerprint @@ -411,4 +401,18 @@ Cannot get quote Check amount and try again + + Ambiguous address.
+ Please select the type above. + ]]>
+ + Please enter or scan a %1$s address.
+ You'll send XMR and the receiver will get %2$s using the SideShift.ai service. + ]]>
+ + Please enter or scan a Monero address. + ]]> diff --git a/app/src/main/res/values-nb/strings.xml b/app/src/main/res/values-nb/strings.xml index 73deac1..bc9ba41 100644 --- a/app/src/main/res/values-nb/strings.xml +++ b/app/src/main/res/values-nb/strings.xml @@ -35,28 +35,25 @@ Ledger tilgjengelig, trykk for mer info. Du skrev inn en Bitcoin addresse.
- Du vil sende XMR og mottakeren vil få BTC gjennom SideShift.ai tjenesten. + Du skrev inn en %1$s addresse.
+ Du vil sende XMR og mottakeren vil få %1$s gjennom SideShift.ai tjenesten. ]]>
SideShift.ai Ordre - %1$s BTC + %1$s %2$s Bekreftelse venter Betaling venter SideShift.ai error (%1$s) - BTC sendt! + %1$s sendt! Spør … Du kan sende %1$s — %2$s BTC.
- SideShift.ai gir deg en vekslingskurs på %3$s BTC akkurat nå. - ]]>
- Mengder opp til %1$s BTC vil bli sendt umiddelbart! + Du kan sende %1$s — %2$s %4$s.
+ SideShift.ai gir deg en vekslingskurs på %3$s %4$s/XMR akkurat nå. ]]>
- Saldo: %2$s BTC (%1$s XMR) + Saldo: %2$s %3$s (%1$s XMR) ✔ Betalings ID integrert Forbereder din transaksjon @@ -74,13 +71,13 @@ Nå sitter vi fast her! Ops, det ser ikke ut til at SideShift.ai er tilgjengelig for øyeblikket! - %1$s BTC = %2$s XMR - (Rate: %1$s BTC/XMR) + %1$s %3$s = %2$s XMR + (Rate: %1$s %2$s/XMR) Besøk SideShift.ai for støtte og sporing Hemmelig nøkkel\nSideShift.ai SideShift.ai Hemmelig nøkkel - BTC destinasjonsadresse + %1$s destinasjonsadresse Mengde Transaksjons-ID @@ -245,11 +242,9 @@ TX ID TX-nøkkel Destinasjon - Destinasjon\n(BTC) Betalings-ID Blokk Mengde - Mengde\n(BTC) Avgift Overføringer Notater @@ -356,11 +351,6 @@ Receiver - SideShift.ai offline - try again later - BTC amount out of bounds - Invalid or outdated Payment URL - Too many requests - EVERYTHING! Convert Ledger Seed @@ -383,8 +373,8 @@ This app allows you to create and use Monero wallets. You can store your sweet moneroj in them. Keep your seed safe The seed grants full access to whoever has it. If you lose it, we cannot help you recover it and you lose your beloved moneroj. - Send Bitcoin - Monerujo has SideShift.ai support built-in. Just paste or scan a Bitcoin address and you\'ll be sending BTC by spending XMR. + Send Crypto + Monerujo has SideShift.ai support built-in. Just paste or scan a BTC, LTC, ETH, DASH or DOGE address and you\'ll be sending these cryptos by spending XMR. Nodes, your way Nodes connect you to the Monero network. Choose between public nodes or go full cypherpunk using your own. Send with fingerprint @@ -408,4 +398,18 @@ Cannot get quote Check amount and try again + + Ambiguous address.
+ Please select the type above. + ]]>
+ + Please enter or scan a %1$s address.
+ You'll send XMR and the receiver will get %2$s using the SideShift.ai service. + ]]>
+ + Please enter or scan a Monero address. + ]]> diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index b44da6c..b903a59 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -35,29 +35,26 @@ Ledger ingeschakeld. Tik voor meer info. Je hebt een Bitcoin-adres ingevoerd.
- Je verzendt XMR en de ontvanger krijgt BTC via SideShift.ai. + Je hebt een %1$s-adres ingevoerd.
+ Je verzendt XMR en de ontvanger krijgt %1$s via SideShift.ai. ]]>
SideShift.ai-opdracht - %1$s BTC + %1$s %2$s Wacht op bevestiging Wacht op betaling Fout bij SideShift.ai (%1$s) - BTC verzonden! + %1$s verzonden! Aanvragen… Je kunt %1$s — %2$s BTC verzenden.
- SideShift.ai biedt nu een wisselkoers van %3$s BTC aan. - ]]>
- Bedragen tot %1$s BTC worden meteen verzonden! + Je kunt %1$s — %2$s %4$s verzenden.
+ SideShift.ai biedt nu een wisselkoers van %3$s %4$s/XMR aan. ]]>
- Saldo: %2$s BTC (%1$s XMR) + Saldo: %2$s %3$s (%1$s XMR) ✔ Betalings-ID geïntegreerd Transactie wordt voorbereid @@ -75,13 +72,13 @@ Nu zitten we vast… Oeps, SideShift.ai is op dit moment niet beschikbaar. - %1$s BTC = %2$s XMR - (Koers: %1$s BTC/XMR) + %1$s %3$s = %2$s XMR + (Koers: %1$s %2$s/XMR) Ga naar SideShift.ai voor hulp en traceren Geheime sleutel\nSideShift.ai Geheime sleutel SideShift.ai - BTC-doeladres + %1$s-doeladres Bedrag Transactie-ID @@ -242,11 +239,9 @@ Transactie-ID Transactiesleutel Bestemming - Bestemming\nBTC Betalings-ID Blok Bedrag - Bedrag\nBTC Vergoeding Betalingen Opmerkingen @@ -356,11 +351,6 @@ Ontvanger - SideShift.ai offline - try again later - BTC amount out of bounds - Invalid or outdated Payment URL - Too many requests - EVERYTHING! Convert Ledger Seed @@ -383,8 +373,8 @@ This app allows you to create and use Monero wallets. You can store your sweet moneroj in them. Keep your seed safe The seed grants full access to whoever has it. If you lose it, we cannot help you recover it and you lose your beloved moneroj. - Send Bitcoin - Monerujo has SideShift.ai support built-in. Just paste or scan a Bitcoin address and you\'ll be sending BTC by spending XMR. + Send Crypto + Monerujo has SideShift.ai support built-in. Just paste or scan a BTC, LTC, ETH, DASH or DOGE address and you\'ll be sending these cryptos by spending XMR. Nodes, your way Nodes connect you to the Monero network. Choose between public nodes or go full cypherpunk using your own. Send with fingerprint @@ -408,4 +398,18 @@ Cannot get quote Check amount and try again + + Ambiguous address.
+ Please select the type above. + ]]>
+ + Please enter or scan a %1$s address.
+ You'll send XMR and the receiver will get %2$s using the SideShift.ai service. + ]]>
+ + Please enter or scan a Monero address. + ]]> diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index cd7f720..7e42d76 100755 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -35,29 +35,26 @@ Ledger ativada, toque para mais informações. Você colocou um endereço Bitcoin.
- Você enviará XMR e o destinatário receberá BTC via o serviço SideShift.ai + Você colocou um endereço %1$s.
+ Você enviará XMR e o destinatário receberá %1$s via o serviço SideShift.ai ]]>
Ordem no SideShift.ai - %1$s BTC + %1$s %2$s Confirmação Pendente Pagamento Pendente Erro SideShift.ai (%1$s) - BTC Enviado! + %1$s Enviado! Consultando … Você pode enviar %1$s — %2$s BTC.
- SideShift.ai enviou a cotação de %3$s BTC neste momento. - ]]>
- Quantias até %1$s BTC serão enviadas instantaneamente! + Você pode enviar %1$s — %2$s %4$s.
+ SideShift.ai enviou a cotação de %3$s %4$s/XMR neste momento. ]]>
- Saldo: %2$s BTC (%1$s XMR) + Saldo: %2$s %3$s (%1$s XMR) ✔ ID do pagamento integrado Preparando sua transação @@ -75,13 +72,13 @@ Opa, estamos travados aqui! Hm, parece que o SideShift.ai não está disponível no momento - %1$s BTC = %2$s XMR - (Cotação: %1$s BTC/XMR) + %1$s %3$s = %2$s XMR + (Cotação: %1$s %2$s/XMR) Visite o SideShift.ai para suporte & rastreio da ordem Chave secreta\nSideShift.ai Chave secreta SideShift.ai - Endereço BTC de destino + Endereço %1$s de destino Valor ID da Transação @@ -244,11 +241,9 @@ ID TX Chave TX Destino - Destino\n(BTC) ID do Pagamento Bloco Valor - Valor\n(BTC) Taxa Transferências Notas @@ -348,11 +343,6 @@ Destinatário - SideShift.ai offline - tente novamente mais tarde - Valor BTC fora dos limites - URL de pagamento inválido - Solicitações em excesso - TUDO! Converter semente da Ledger @@ -375,8 +365,8 @@ Esse aplicativo permite que você crie e use carteiras Monero. Você poderá guardar seus queridos moneroj aqui. Mantenha sua semente em segurança A semente dá acesso total a qualquer pessoa que a tenha. Se você perdê-la, nós não conseguiremos lhe ajudar a recuperá-la e você perderá seus amados moneroj. - Enviar Bitcoin - A Monerujo possui o SideShift.ai integrado. Basta colar ou escaner um endereço Bitcoin e você estará enviando BTC, mas gastando em XMR. + Enviar Crypto + A Monerujo possui o SideShift.ai integrado. Basta colar ou escaner um endereço BTC, LTC, ETH, DASH ou DOGE e você estará enviando cripto, mas gastando em XMR. "Nós", do seu jeito Os nós conectam você à rede Monero. Escolha entre nós públicos ou seja completamente "cypherpunk" e utilize seu próprio nó. Enviar usando a digital @@ -400,4 +390,18 @@ Cannot get quote Check amount and try again + + Ambiguous address.
+ Please select the type above. + ]]>
+ + Please enter or scan a %1$s address.
+ You'll send XMR and the receiver will get %2$s using the SideShift.ai service. + ]]>
+ + Please enter or scan a Monero address. + ]]> diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 9b6fea9..b6cc1d4 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -35,29 +35,26 @@ Ledger activa, toca para mais informação. Introduziu um endereço Bitcoin.
- Vai enviar em XMR e o destinatário vai receber BTC através do serviço SideShift.ai + Introduziu um endereço %1$s.
+ Vai enviar em XMR e o destinatário vai receber %1$s através do serviço SideShift.ai ]]>
SideShift.ai Order - %1$s BTC + %1$s %2$s Confirmação Pendente Pagamento Pendente Erro SideShift.ai (%1$s) - BTC Enviadas! + %1$s Enviadas! A comunicar … Pode enviar %1$s — %2$s BTC.
- SideShift.ai está com uma taxa de conversão de %3$s BTC neste momento. - ]]>
- Quantidades até %1$s BTC serão enviadas instantaneament! + Pode enviar %1$s — %2$s %4$s.
+ SideShift.ai está com uma taxa de conversão de %3$s %4$s/XMR neste momento. ]]>
- Saldo: %2$s BTC (%1$s XMR) + Saldo: %2$s %3$s (%1$s XMR) ✔ ID do pagamento integrado A preparar a transacção @@ -75,13 +72,13 @@ Agora estamos emperrados aqui! Ups, SideShift.ai não parece estar disponível neste momento! - %1$s BTC = %2$s XMR - (Rácio: %1$s BTC/XMR) + %1$s %3$s = %2$s XMR + (Rácio: %1$s %2$s/XMR) Vai a SideShift.ai para suporte & seguimento Chave secreta\nSideShift.ai SideShift.ai Chave secreta - Endereço BTC de destino + Endereço %1$s de destino Quantidade ID da Transacção @@ -244,11 +241,9 @@ ID TX Chave TX Destino - Destino\n(BTC) ID Pagamento Bloco Quantidade - Quantidade\n(BTC) Taxa Transferências Notas @@ -360,11 +355,6 @@ Receptor - SideShift.ai offline - tenta mais tarde - Montante de BTC fora dos limites - URL de pagamento invalido ou fora de prazo - Demasiadas solicitações - A TOTALIDADE! Converter semente do Ledger @@ -387,8 +377,8 @@ This app allows you to create and use Monero wallets. You can store your sweet moneroj in them. Keep your seed safe The seed grants full access to whoever has it. If you lose it, we cannot help you recover it and you lose your beloved moneroj. - Send Bitcoin - Monerujo has SideShift.ai support built-in. Just paste or scan a Bitcoin address and you\'ll be sending BTC by spending XMR. + Send Crypto + Monerujo has SideShift.ai support built-in. Just paste or scan a BTC, LTC, ETH, DASH or DOGE address and you\'ll be sending these cryptos by spending XMR. Nodes, your way Nodes connect you to the Monero network. Choose between public nodes or go full cypherpunk using your own. Send with fingerprint @@ -412,4 +402,18 @@ Cannot get quote Check amount and try again + + Ambiguous address.
+ Please select the type above. + ]]>
+ + Please enter or scan a %1$s address.
+ You'll send XMR and the receiver will get %2$s using the SideShift.ai service. + ]]>
+ + Please enter or scan a Monero address. + ]]> diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index 6a37db6..5d2861c 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -34,29 +34,26 @@ Ledger activată, apasă pentru mai multe informații. Ai introdus o adresă de Bitcoin.
- Vei trimite XMR și destinatarul va primi BTC folosind serviciul SideShift.ai. + Ai introdus o adresă de %1$s.
+ Vei trimite XMR și destinatarul va primi %1$s folosind serviciul SideShift.ai. ]]>
Ordin SideShift.ai - %1$s BTC + %1$s %2$s Confirmare în așteptare Plată în așteptare Eroare SideShift.ai (%1$s) - BTC trimis! + %1$s trimis! Interogare … Poți trimite %1$s — %2$s BTC.
- SideShift.ai îți oferă un curs de %3$s BTC în acest moment. - ]]>
- Sume până la %1$s BTC vor fi trimise instantaneu! + Poți trimite %1$s — %2$s %4$s.
+ SideShift.ai îți oferă un curs de %3$s %4$s/XMR în acest moment. ]]>
- Balanță: %2$s BTC (%1$s XMR) + Balanță: %2$s %3$s (%1$s XMR) ✔ Payment ID integrat Se pregătește tranzacția @@ -74,13 +71,13 @@ Pff.. ne-am blocat cum! Oh, serviciul SideShift.ai este momentan indisponibil! - %1$s BTC = %2$s XMR - (Rată: %1$s BTC/XMR) + %1$s %3$s = %2$s XMR + (Rată: %1$s %2$s/XMR) Vizitează SideShift.ai pentru suport & interogare Cheia secretă \nSideShift.ai Cheia secretă SideShift.ai - Destinație adresă BTC + Destinație adresă %1$s Sumă ID Tranzacție @@ -220,11 +217,9 @@ ID Tranzacție Cheie tranzacție Destinație - Destinație\n(BTC) Payment ID Monobloc Sumă - Sumă\n(BTC) Comision Transferuri Notițe @@ -356,11 +351,6 @@ Receiver - SideShift.ai offline - try again later - BTC amount out of bounds - Invalid or outdated Payment URL - Too many requests - EVERYTHING! Convert Ledger Seed @@ -383,8 +373,8 @@ This app allows you to create and use Monero wallets. You can store your sweet moneroj in them. Keep your seed safe The seed grants full access to whoever has it. If you lose it, we cannot help you recover it and you lose your beloved moneroj. - Send Bitcoin - Monerujo has SideShift.ai support built-in. Just paste or scan a Bitcoin address and you\'ll be sending BTC by spending XMR. + Send Crypto + Monerujo has SideShift.ai support built-in. Just paste or scan a BTC, LTC, ETH, DASH or DOGE address and you\'ll be sending these cryptos by spending XMR. Nodes, your way Nodes connect you to the Monero network. Choose between public nodes or go full cypherpunk using your own. Send with fingerprint @@ -408,4 +398,18 @@ Cannot get quote Check amount and try again + + Ambiguous address.
+ Please select the type above. + ]]>
+ + Please enter or scan a %1$s address.
+ You'll send XMR and the receiver will get %2$s using the SideShift.ai service. + ]]>
+ + Please enter or scan a Monero address. + ]]> diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index a04c215..0d97e89 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -35,30 +35,27 @@ Доступен Ledger, нажмите для доп. информации Вы ввели Bitcoin адрес.
- Отправляйте XMR, получатель получит BTC, используя сервис SideShift.ai + Вы ввели %1$s адрес.
+ Отправляйте XMR, получатель получит %1$s, используя сервис SideShift.ai ]]>
Заказ SideShift.ai - %1$s BTC + %1$s %2$s Ожидание подтверждения Ожидание платежа Ошибка SideShift.ai (%1$s) - BTC успешно отправлены! + %1$s успешно отправлены! Запрос … Вы можете отправить %1$s — %2$s BTC.
- SideShift.ai устанавливает курс обмена %3$s BTC в данный момент. - ]]>
- Сумма до %1$s BTC будет отправлена немедленно! + Вы можете отправить %1$s — %2$s %4$s.
+ SideShift.ai устанавливает курс обмена %3$s %4$s/XMR в данный момент. ]]>
- Баланс: %2$s BTC (%1$s XMR) + Баланс: %2$s %3$s (%1$s XMR) ✔ Интегрированный ID платежа Подготовка транзакции @@ -76,13 +73,13 @@ Теперь мы застряли здесь! Ой-ой! Кажется SideShift.ai недоступен в данный момент! - %1$s BTC = %2$s XMR - (Курс: %1$s BTC/XMR) + %1$s %3$s = %2$s XMR + (Курс: %1$s %2$s/XMR) Посетите SideShift.ai для получения помощи & Секретный ключ\nSideShift.ai SideShift.ai секретный ключ - Адрес получателя BTC + Адрес получателя %1$s Сумма ID транзакции @@ -246,11 +243,9 @@ TX ID Ключ TX Адресат - Адресат\n(BTC) ID платежа Блок Сумма - Сумма\n(BTC) Комиссия Переводы Заметки @@ -360,11 +355,6 @@ Получатель - SideShift.ai недоступен - повторите попытку позже - Сумма BTC выходит за доступные пределы - Неверный или устаревший платежный URL - Превышен лимит запросов - ВСЕ! Преобразовать фразу Ledger @@ -387,8 +377,8 @@ This app allows you to create and use Monero wallets. You can store your sweet moneroj in them. Keep your seed safe The seed grants full access to whoever has it. If you lose it, we cannot help you recover it and you lose your beloved moneroj. - Send Bitcoin - Monerujo has SideShift.ai support built-in. Just paste or scan a Bitcoin address and you\'ll be sending BTC by spending XMR. + Send Crypto + Monerujo has SideShift.ai support built-in. Just paste or scan a BTC, LTC, ETH, DASH or DOGE address and you\'ll be sending these cryptos by spending XMR. Nodes, your way Nodes connect you to the Monero network. Choose between public nodes or go full cypherpunk using your own. Send with fingerprint @@ -412,4 +402,18 @@ Cannot get quote Check amount and try again + + Ambiguous address.
+ Please select the type above. + ]]>
+ + Please enter or scan a %1$s address.
+ You'll send XMR and the receiver will get %2$s using the SideShift.ai service. + ]]>
+ + Please enter or scan a Monero address. + ]]> diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index 1384e29..86e720c 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -35,30 +35,27 @@ Ledger aktivovaný, klepni pre viac info. Vložil si Bitcoin adresu.
- Pošleš XMR a adresát dostane BTC cez službu SideShift.ai. + Vložil si %1$s adresu.
+ Pošleš XMR a adresát dostane %1$s cez službu SideShift.ai. ]]>
SideShift.ai Objednávka - %1$s BTC + %1$s %2$s Čaká na Potvrdenie Čakajúca Platba SideShift.ai Chyba (%1$s) - BTC Odoslané! + %1$s Odoslané! Zisťujem … Môžeš poslať %1$s — %2$s BTC.
- SideShift.ai ti dáva výmenný kurz of %3$s BTC práve teraz. - ]]>
- čiastka do %1$s BTC bude odoslaná okamžite! + Môžeš poslať %1$s — %2$s %4$s.
+ SideShift.ai ti dáva výmenný kurz of %3$s %4$s/XMR práve teraz. ]]>
- Zostatok: %2$s BTC (%1$s XMR) + Zostatok: %2$s %3$s (%1$s XMR) ✔ Payment ID integrované Pripravujem transakciu @@ -76,13 +73,13 @@ Uviazli sme tu! Myslím, že služba SideShift.ai nie je momentálne dostupná! - %1$s BTC = %2$s XMR - (Kurz: %1$s BTC/XMR) + %1$s %3$s = %2$s XMR + (Kurz: %1$s %2$s/XMR) Navštív SideShift.ai pre podporu & tracking Tajný kľúč\nSideShift.ai SideShift.ai Tajný kľúč - Cieľová BTC Adresa + Cieľová %1$s Adresa Čiastka ID Transakcie @@ -243,11 +240,9 @@ TX ID Kľúč Transakcie Cieľ - Cieľová (BTC) ID Platby Blok Suma - Čiastka\n(BTC) poplatok Poslaných Poznámky @@ -357,11 +352,6 @@ Príjemca - SideShift.ai je offline - skús neskôr - Množstvo BTC je mimo rámca - Neplatná alebo stará URL platby - Príliš veľa požiadaviek - VŠETKO! Konvertuj Ledger Seed @@ -384,8 +374,8 @@ This app allows you to create and use Monero wallets. You can store your sweet moneroj in them. Keep your seed safe The seed grants full access to whoever has it. If you lose it, we cannot help you recover it and you lose your beloved moneroj. - Send Bitcoin - Monerujo has SideShift.ai support built-in. Just paste or scan a Bitcoin address and you\'ll be sending BTC by spending XMR. + Send Crypto + Monerujo has SideShift.ai support built-in. Just paste or scan a BTC, LTC, ETH, DASH or DOGE address and you\'ll be sending these cryptos by spending XMR. Nodes, your way Nodes connect you to the Monero network. Choose between public nodes or go full cypherpunk using your own. Send with fingerprint @@ -409,4 +399,18 @@ Cannot get quote Check amount and try again + + Ambiguous address.
+ Please select the type above. + ]]>
+ + Please enter or scan a %1$s address.
+ You'll send XMR and the receiver will get %2$s using the SideShift.ai service. + ]]>
+ + Please enter or scan a Monero address. + ]]> diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 3a44afd..ad42e37 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -35,29 +35,26 @@ Knjiga računa omogućena, tapni za više info. Ubacio/la si Bitkoin adresu.
- You'će poslati XMR a primalac će dobiti BTC koristeći SideShift.ai servis. + Ubacio/la si %1$s adresu.
+ You'će poslati XMR a primalac će dobiti %1$s koristeći SideShift.ai servis. ]]>
SideShift.ai Nalog - %1$s BTC + %1$s %2$s Potvrda u toku Plaćanje u toku SideShift.ai Greška (%1$s) - BTC Poslato! + %1$s Poslato! Ispitivanje … Možeš poslati %1$s — %2$s BTC.
- SideShift.ai daje ti devizni kurs od %3$s BTC trenutno. - ]]>
- Sume do %1$s BTC biće poslate instantly! + Možeš poslati %1$s — %2$s %4$s.
+ SideShift.ai daje ti devizni kurs od %3$s %4$s/XMR trenutno. ]]>
- Stanje: %2$s BTC (%1$s XMR) + Stanje: %2$s %3$s (%1$s XMR) ✔ ID plaćanja integrisan Priprema tvoje transakcije @@ -75,13 +72,13 @@ Sada se zaglavismo! Uh, SideShift.ai izgleda da sad nije dostupan! - %1$s BTC = %2$s XMR - (Rate: %1$s BTC/XMR) + %1$s %3$s = %2$s XMR + (Rate: %1$s %2$s/XMR) Poseti SideShift.ai za bekap & praćenje Tajna šifra\nSideShift.ai SideShift.ai Tajna šifra - Odredište BTC adrese + Odredište %1$s adrese Suma ID transakcije @@ -252,11 +249,9 @@ TX ID TX šifra Odredište - Odredište\n(BTC) ID plaćanja Blok Suma - Suma\n(BTC) Naknada Transferi Čvorovi @@ -355,11 +350,6 @@ Primalac - SideShift.ai van mreže - pokušajte kasnije ponovo - BTC iznos izvan granica - Nevalidan ili neažuriran URL plaćanja - Previše zahteva - SVE! Pretvori seme iz knjige računa @@ -382,8 +372,8 @@ This app allows you to create and use Monero wallets. You can store your sweet moneroj in them. Keep your seed safe The seed grants full access to whoever has it. If you lose it, we cannot help you recover it and you lose your beloved moneroj. - Send Bitcoin - Monerujo has SideShift.ai support built-in. Just paste or scan a Bitcoin address and you\'ll be sending BTC by spending XMR. + Send Crypto + Monerujo has SideShift.ai support built-in. Just paste or scan a BTC, LTC, ETH, DASH or DOGE address and you\'ll be sending these cryptos by spending XMR. Nodes, your way Nodes connect you to the Monero network. Choose between public nodes or go full cypherpunk using your own. Send with fingerprint @@ -407,4 +397,18 @@ Cannot get quote Check amount and try again + + Ambiguous address.
+ Please select the type above. + ]]>
+ + Please enter or scan a %1$s address.
+ You'll send XMR and the receiver will get %2$s using the SideShift.ai service. + ]]>
+ + Please enter or scan a Monero address. + ]]> diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index c4680bc..d11cfcb 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -34,22 +34,27 @@ BTC-betalning aktiverad, tryck för mer info. Ledger aktiverat, tryck för mer info. - Du har angivit en Bitcoin-adress.
Du kommer att skicka XMR och mottagaren får BTC via tjänsten SideShift.ai.]]>
+ Du har angivit en %1$s-adress.
+ Du kommer att skicka XMR och mottagaren får %1$s via tjänsten SideShift.ai. + ]]>
SideShift.ai-beställning - %1$s BTC + %1$s %2$s Väntar på bekräftelse Väntar på betalning SideShift.ai-fel (%1$s) - BTC skickades! + %1$s skickades! Frågar … - Du kan skicka %1$s — %2$s BTC.
SideShift.ai ger dig just nu en växelkurs på %3$s BTC.]]>
- Belopp upp till %1$s BTC skickas omedelbart!]]> + Du kan skicka %1$s — %2$s %4$s.
+ SideShift.ai ger dig just nu en växelkurs på %3$s %4$s/XMR. + ]]>
- Saldo: %2$s BTC (%1$s XMR) + Saldo: %2$s %3$s (%1$s XMR) ✔ Betalnings-ID integrerat Förbereder din transaktion @@ -67,13 +72,13 @@ Nu har vi kört fast! Åh nej, SideShift.ai verkar inte vara tillgänglig just nu! - %1$s BTC = %2$s XMR - (Kurs: %1$s BTC/XMR) + %1$s %3$s = %2$s XMR + (Kurs: %1$s %2$s/XMR) Besök SideShift.ai för support & spårning Hemlig nyckel\nSideShift.ai SideShift.ai hemlig nyckel - Måladress för BTC + Måladress för %1$s Belopp Transaktions-ID @@ -225,11 +230,9 @@ TX-ID TX-nyckel Mål - Mål\n(BTC) Betalnings-ID Block Belopp - Belopp\n(BTC) Avgift Överföringar Anteckningar @@ -340,11 +343,6 @@ Mottagaren - SideShift.ai offline - try again later - BTC amount out of bounds - Invalid or outdated Payment URL - Too many requests - EVERYTHING! Convert Ledger Seed @@ -367,8 +365,8 @@ This app allows you to create and use Monero wallets. You can store your sweet moneroj in them. Keep your seed safe The seed grants full access to whoever has it. If you lose it, we cannot help you recover it and you lose your beloved moneroj. - Send Bitcoin - Monerujo has SideShift.ai support built-in. Just paste or scan a Bitcoin address and you\'ll be sending BTC by spending XMR. + Send Crypto + Monerujo has SideShift.ai support built-in. Just paste or scan a BTC, LTC, ETH, DASH or DOGE address and you\'ll be sending these cryptos by spending XMR. Nodes, your way Nodes connect you to the Monero network. Choose between public nodes or go full cypherpunk using your own. Send with fingerprint @@ -392,4 +390,18 @@ Cannot get quote Check amount and try again + + Ambiguous address.
+ Please select the type above. + ]]>
+ + Please enter or scan a %1$s address.
+ You'll send XMR and the receiver will get %2$s using the SideShift.ai service. + ]]>
+ + Please enter or scan a Monero address. + ]]> diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 2489199..bf66f77 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -35,30 +35,27 @@ Доступний Ledger, натисніть для доп. інформації Ви ввели Bitcoin адресу.
- Надсилайте XMR, одержувач отримає BTC, використовуючи сервіс SideShift.ai + Ви ввели %1$s адресу.
+ Надсилайте XMR, одержувач отримає %1$s, використовуючи сервіс SideShift.ai ]]>
Заявка SideShift.ai - %1$s BTC + %1$s %2$s Очікування підтвердження Очікування платежу Помилка SideShift.ai (%1$s) - BTC успішно відправлені! + %1$s успішно відправлені! Запит … Ви можете відправити %1$s — %2$s BTC.
- SideShift.ai встановлює курс обміну %3$s BTC в даний момент. - ]]>
- Сума до %1$s BTC буде відправлена негайно! + Ви можете відправити %1$s — %2$s %4$s.
+ SideShift.ai встановлює курс обміну %3$s %4$s/XMR в даний момент. ]]>
- Баланс: %2$s BTC (%1$s XMR) + Баланс: %2$s %3$s (%1$s XMR) ✔ Інтегрований ID платежу Підготовка транзакції @@ -76,13 +73,13 @@ Тепер ми застрягли тут! Ой ой! Здається SideShift.ai недоступний в даний момент! - %1$s BTC = %2$s XMR - (Курс: %1$s BTC/XMR) + %1$s %3$s = %2$s XMR + (Курс: %1$s %2$s/XMR) Відвідайте SideShift.ai для отримання допомоги & Секретний ключ\nSideShift.ai SideShift.ai секретний ключ - Адреса отримувача BTC + Адреса отримувача %1$s Сума ID транзакції @@ -246,11 +243,9 @@ TX ID Ключ TX Адресат - Адресат\n(BTC) ID платежу Блок Сума - Сума\n(BTC) Комісія Перекази Замітки @@ -360,11 +355,6 @@ Отримувач - SideShift.ai недоступний - спробуйте пізніше - Сума BTC виходить за допустимі ліміти - Невірний або застарілий платіжний URL - Перевищено кількість запитів - ВСЕ! Конвертувати фразу Ledger @@ -387,8 +377,8 @@ This app allows you to create and use Monero wallets. You can store your sweet moneroj in them. Keep your seed safe The seed grants full access to whoever has it. If you lose it, we cannot help you recover it and you lose your beloved moneroj. - Send Bitcoin - Monerujo has SideShift.ai support built-in. Just paste or scan a Bitcoin address and you\'ll be sending BTC by spending XMR. + Send Crypto + Monerujo has SideShift.ai support built-in. Just paste or scan a BTC, LTC, ETH, DASH or DOGE address and you\'ll be sending these cryptos by spending XMR. Nodes, your way Nodes connect you to the Monero network. Choose between public nodes or go full cypherpunk using your own. Send with fingerprint @@ -412,4 +402,18 @@ Cannot get quote Check amount and try again + + Ambiguous address.
+ Please select the type above. + ]]>
+ + Please enter or scan a %1$s address.
+ You'll send XMR and the receiver will get %2$s using the SideShift.ai service. + ]]>
+ + Please enter or scan a Monero address. + ]]> diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 6021d30..622c2a9 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -27,24 +27,21 @@ 已支持比特币支付,点此了解更多 已支持Ledger硬件钱包,点此了解更多 您输入了一个比特币地址
-您发送的门罗币将通过SideShift.ai服务,转换为比特币发送给对方。 -]]>
+ 您输入了一个%1$s地址
+ 您发送的门罗币将通过SideShift.ai服务,转换为%1$s发送给对方。 + ]]> SideShift.ai订单 - %1$s BTC + %1$s %2$s 等待确认中 等待支付中 SideShift.ai错误(%1$s) - 成功发送比特币! + 成功发送%1$s! 查询中… 您可以发送%1$s — %2$s BTC.
-此刻SideShift.ai的汇率是%3$s BTC . -]]>
- 至多%1$s BTC将会即刻发送! -]]> - 余额: %2$s BTC (%1$s XMR) + 您可以发送%1$s — %2$s %4$s.
+ 此刻SideShift.ai的汇率是%3$s %4$s/XMR . + ]]> + 余额: %2$s %3$s (%1$s XMR) ✔ 支付ID已集成 正在为您的交易做准备工作 创建SideShift.ai订单 @@ -56,12 +53,12 @@ 再次尝试 我们遇到了困难! 抱歉, SideShift.ai服务现在似乎不可用 - %1$s BTC = %2$s XMR - (Rate: %1$s BTC/XMR) + %1$s %3$s = %2$s XMR + (Rate: %1$s %2$s/XMR) 访问SideShift.ai以获得更多支持 密钥\nSideShift.ai SideShift.ai密钥 - 比特币收款地址 + %1$s收款地址 金额 交易ID 收款地址 @@ -196,11 +193,9 @@ 交易ID 交易密钥 目标地址 - 目标地址\n(BTC) 支付ID 区块 金额 - 金额\n(BTC) 手续费 转账 备注 @@ -281,10 +276,6 @@ 已自动将最佳%1$d节点加入书签 测试 收款人 - SideShift.ai离线-请稍后重试 - 比特币金额超出限制 - 无效或过期的支付URL - 当前请求数过多 全部资产! 转换Ledger种子密语 Ledger种子密语 @@ -306,8 +297,8 @@ This app allows you to create and use Monero wallets. You can store your sweet moneroj in them. Keep your seed safe The seed grants full access to whoever has it. If you lose it, we cannot help you recover it and you lose your beloved moneroj. - Send Bitcoin - Monerujo has SideShift.ai support built-in. Just paste or scan a Bitcoin address and you\'ll be sending BTC by spending XMR. + Send Crypto + Monerujo has SideShift.ai support built-in. Just paste or scan a BTC, LTC, ETH, DASH or DOGE address and you\'ll be sending these cryptos by spending XMR. Nodes, your way Nodes connect you to the Monero network. Choose between public nodes or go full cypherpunk using your own. Send with fingerprint @@ -331,4 +322,18 @@ Cannot get quote Check amount and try again + + Ambiguous address.
+ Please select the type above. + ]]>
+ + Please enter or scan a %1$s address.
+ You'll send XMR and the receiver will get %2$s using the SideShift.ai service. + ]]>
+ + Please enter or scan a Monero address. + ]]> diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 98ea248..12d518a 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -35,30 +35,27 @@ Ledger 已啟用,點選了解更多 你輸入了 Bitcoin 地址
- 你將會發送 XMR 而收款方將會收到 BTC (由 SideShift.ai 提供轉換) + 你輸入了 %1$s 地址
+ 你將會發送 XMR 而收款方將會收到 %1$s (由 SideShift.ai 提供轉換) ]]>
SideShift.ai 訂單 - %1$s BTC + %1$s %2$s 等待確認中 等待付款中 SideShift.ai 發生錯誤 (%1$s) - BTC 已發送! + %1$s 已發送! 查詢中 … 你可發送 %1$s — %2$s BTC.
- SideShift.ai 提供的即時匯率為 %3$s BTC. - ]]>
- 金額少於 %1$s BTC ,將會馬上發送! + 你可發送 %1$s — %2$s %4$s.
+ SideShift.ai 提供的即時匯率為 %3$s %4$s/XMR. ]]>
- 餘額:%2$s BTC (%1$s XMR) + 餘額:%2$s %3$s (%1$s XMR) ✔ 已加入付款 ID 正在準備你的交易 @@ -76,13 +73,13 @@ 我們卡住了! 不好,SideShift.ai 現在似乎無法提供服務! - %1$s BTC = %2$s XMR - (匯率:%1$s BTC/XMR) + %1$s %3$s = %2$s XMR + (匯率:%1$s %2$s/XMR) 參訪 SideShift.ai 以獲得支援及追蹤交易 私鑰\nSideShift.ai SideShift.ai 私鑰 - 目的地 BTC 地址 + 目的地 %1$s 地址 金額 交易 ID @@ -244,11 +241,9 @@ 交易 ID (TXID) 交易金鑰 (TX Key) 收款地址 - 收款地址\n(BTC) 付款 ID 區塊 金額 - 金額\n(BTC) 手續費 轉帳 附註 @@ -355,11 +350,6 @@ 收款者 - SideShift.ai 無法使用 - 請稍候再試 - BTC 金額超出限制 - 無效或過期的付款網址 - 請求過於頻繁 - 全部! 轉換 Ledger 種子碼 @@ -382,8 +372,8 @@ This app allows you to create and use Monero wallets. You can store your sweet moneroj in them. Keep your seed safe The seed grants full access to whoever has it. If you lose it, we cannot help you recover it and you lose your beloved moneroj. - Send Bitcoin - Monerujo has SideShift.ai support built-in. Just paste or scan a Bitcoin address and you\'ll be sending BTC by spending XMR. + Send Crypto + Monerujo has SideShift.ai support built-in. Just paste or scan a BTC, LTC, ETH, DASH or DOGE address and you\'ll be sending these cryptos by spending XMR. Nodes, your way Nodes connect you to the Monero network. Choose between public nodes or go full cypherpunk using your own. Send with fingerprint @@ -407,4 +397,18 @@ Cannot get quote Check amount and try again + + Ambiguous address.
+ Please select the type above. + ]]>
+ + Please enter or scan a %1$s address.
+ You'll send XMR and the receiver will get %2$s using the SideShift.ai service. + ]]>
+ + Please enter or scan a Monero address. + ]]> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 219f14d..6157b4b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -32,33 +32,30 @@ Touch for QR Code - BTC payment enabled, tap for more info. + Non-XMR payments enabled, tap for more info. Ledger enabled, tap for more info. You entered a Bitcoin address.
- You'll send XMR and the receiver will get BTC using the SideShift.ai service. + You entered a %1$s address.
+ You'll send XMR and the receiver will get %1$s using the SideShift.ai service. ]]>
SideShift.ai Order - %1$s BTC + %1$s %2$s Confirmation Pending Payment Pending SideShift.ai Error (%1$s) - BTC Sent! + %1$s Sent! Querying … You can send %1$s — %2$s BTC.
- SideShift.ai is giving you an exchange rate of %3$s BTC right now. - ]]>
- Amounts up to %1$s BTC will be sent instantly! + You can send %1$s — %2$s %4$s.
+ SideShift.ai is giving you an exchange rate of %3$s %4$s/XMR right now. ]]>
- Balance: %2$s BTC (%1$s XMR) + Balance: %2$s %3$s (%1$s XMR) ✔ Payment ID integrated Preparing your transaction @@ -76,13 +73,13 @@ Now we\'re stuck here! Uh-oh, SideShift.ai does not seem be available right now! - %1$s BTC = %2$s XMR - (Rate: %1$s BTC/XMR) + %1$s %3$s = %2$s XMR + (Rate: %1$s %2$s/XMR) Visit SideShift.ai for support & tracking Secret Key\nSideShift.ai SideShift.ai Secret Key - Destination BTC Address + Destination %1$s Address Amount Transaction ID @@ -256,11 +253,9 @@ TX ID TX Key Destination - Destination\n(BTC) Payment ID Block Amount - Amount\n(BTC) Fee Transfers Notes @@ -403,13 +398,6 @@ Receiver - SideShift.ai offline - try again later - BTC amount out of bounds - Invalid or outdated Payment URL - Too many requests - - SideShift.ai Service Error - EVERYTHING! Convert Ledger Seed @@ -434,8 +422,8 @@ This app allows you to create and use Monero wallets. You can store your sweet moneroj in them. Keep your seed safe The seed grants full access to whoever has it. If you lose it, we cannot help you recover it and you lose your beloved moneroj. - Send Bitcoin - Monerujo has SideShift.ai support built-in. Just paste or scan a Bitcoin address and you\'ll be sending BTC by spending XMR. + Send Crypto + Monerujo has SideShift.ai support built-in. Just paste or scan a BTC, LTC, ETH, DASH or DOGE address and you\'ll be sending these cryptos by spending XMR. Nodes, your way Nodes connect you to the Monero network. Choose between public nodes or go full cypherpunk using your own. Send with fingerprint @@ -459,4 +447,28 @@ Cannot get quote Check amount and try again + + Ambiguous address.
+ Please select the type above. + ]]>
+ + Please enter or scan a %1$s address.
+ You'll send XMR and the receiver will get %2$s using the SideShift.ai service. + ]]>
+ + Please enter or scan a Monero address. + ]]> + + + + Monero + Bitcoin + Dash + Dogecoin + Ethereum + Litecoin + diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 7b58d13..9359a13 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -95,6 +95,11 @@ + + +