mirror of
https://codeberg.org/anoncontributorxmr/mysu.git
synced 2024-11-25 17:02:28 +00:00
Merge branch 'bugfix/pay-to-many-paymentids'
# Conflicts: # app/src/main/res/values/strings.xml
This commit is contained in:
commit
2ff408e622
4 changed files with 155 additions and 56 deletions
|
@ -4,6 +4,8 @@ import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.text.Editable;
|
||||||
|
import android.text.TextWatcher;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
@ -137,45 +139,19 @@ public class SendFragment extends Fragment {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
sendMaxButton.setOnClickListener(view1 -> {
|
sendMaxButton.setOnClickListener(view1 -> {
|
||||||
addOutputImageView.setVisibility(View.INVISIBLE);
|
mViewModel.setSendingMax(!isSendAll());
|
||||||
boolean currentValue = mViewModel.sendingMax.getValue() != null ? mViewModel.sendingMax.getValue() : false;
|
|
||||||
mViewModel.setSendingMax(!currentValue);
|
|
||||||
});
|
});
|
||||||
createButton.setOnClickListener(view1 -> {
|
createButton.setOnClickListener(view1 -> {
|
||||||
boolean sendAll = mViewModel.sendingMax.getValue() != null ? mViewModel.sendingMax.getValue() : false;
|
boolean outputsValid = checkDestsValidity(isSendAll());
|
||||||
ArrayList<Pair<String, String>> dests = new ArrayList<>();
|
|
||||||
for(int i = 0; i < getDestCount(); i++) {
|
|
||||||
ConstraintLayout entryView = getDestView(i);
|
|
||||||
EditText amountField = entryView.findViewById(R.id.amount_edittext);
|
|
||||||
EditText addressField = entryView.findViewById(R.id.address_edittext);
|
|
||||||
String amount = amountField.getText().toString().trim();
|
|
||||||
if(!sendAll) {
|
|
||||||
if(amount.isEmpty()) {
|
|
||||||
Toast.makeText(getActivity(), getString(R.string.send_amount_empty), Toast.LENGTH_SHORT).show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
long amountRaw = Wallet.getAmountFromString(amount);
|
if(outputsValid) {
|
||||||
long balance = BalanceService.getInstance().getUnlockedBalanceRaw();
|
Toast.makeText(getActivity(), getString(R.string.creating_tx), Toast.LENGTH_SHORT).show();
|
||||||
if (amountRaw >= balance || amountRaw <= 0) {
|
createButton.setEnabled(false);
|
||||||
Toast.makeText(getActivity(), getString(R.string.send_amount_invalid), Toast.LENGTH_SHORT).show();
|
sendMaxButton.setEnabled(false);
|
||||||
return;
|
createTx(getRawDests(), isSendAll(), priority);
|
||||||
}
|
} else {
|
||||||
}
|
Toast.makeText(getActivity(), getString(R.string.creating_tx_failed_invalid_outputs), Toast.LENGTH_SHORT).show();
|
||||||
|
|
||||||
String address = addressField.getText().toString().trim();
|
|
||||||
boolean isValidAddress = Wallet.isAddressValid(address);
|
|
||||||
if(!isValidAddress) {
|
|
||||||
Toast.makeText(getActivity(), getString(R.string.send_address_invalid), Toast.LENGTH_SHORT).show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
dests.add(new Pair<>(address, amount));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Toast.makeText(getActivity(), getString(R.string.creating_tx), Toast.LENGTH_SHORT).show();
|
|
||||||
createButton.setEnabled(false);
|
|
||||||
sendMaxButton.setEnabled(false);
|
|
||||||
createTx(dests, sendAll, priority);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
sendButton.setOnClickListener(view1 -> {
|
sendButton.setOnClickListener(view1 -> {
|
||||||
|
@ -188,21 +164,72 @@ public class SendFragment extends Fragment {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean checkDestsValidity(boolean sendAll) {
|
||||||
|
List<Pair<String, String>> dests = getRawDests();
|
||||||
|
for(Pair<String, String> dest : dests) {
|
||||||
|
String address = dest.component1();
|
||||||
|
String amount = dest.component2();
|
||||||
|
if(!sendAll) {
|
||||||
|
if(amount.isEmpty()) {
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.send_amount_empty), Toast.LENGTH_SHORT).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
long amountRaw = Wallet.getAmountFromString(amount);
|
||||||
|
long balance = BalanceService.getInstance().getUnlockedBalanceRaw();
|
||||||
|
if (amountRaw >= balance || amountRaw <= 0) {
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.send_amount_invalid), Toast.LENGTH_SHORT).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if(dests.size() > 1) {
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.send_amount_invalid_sendall_paytomany), Toast.LENGTH_SHORT).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UriData uriData = UriData.parse(address);
|
||||||
|
boolean isValidAddress = uriData != null;
|
||||||
|
if(!isValidAddress) {
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.send_address_invalid), Toast.LENGTH_SHORT).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dests.size() > 1 && uriData.hasPaymentId()) {
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.paymentid_paytomany), Toast.LENGTH_SHORT).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean destsHasPaymentId() {
|
||||||
|
List<Pair<String, String>> dests = getRawDests();
|
||||||
|
for(Pair<String, String> dest : dests) {
|
||||||
|
String address = dest.component1();
|
||||||
|
UriData uriData = UriData.parse(address);
|
||||||
|
if(uriData == null) return false;
|
||||||
|
if(uriData.hasPaymentId()) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private void bindObservers() {
|
private void bindObservers() {
|
||||||
mViewModel.sendingMax.observe(getViewLifecycleOwner(), sendingMax -> {
|
mViewModel.sendingMax.observe(getViewLifecycleOwner(), sendingMax -> {
|
||||||
if (mViewModel.pendingTransaction.getValue() == null) {
|
if (mViewModel.pendingTransaction.getValue() == null) {
|
||||||
if (sendingMax) {
|
if (sendingMax) {
|
||||||
addOutputImageView.setVisibility(View.GONE);
|
|
||||||
prepareOutputsForMaxSend();
|
prepareOutputsForMaxSend();
|
||||||
sendMaxButton.setText(getText(R.string.undo));
|
sendMaxButton.setText(getText(R.string.undo));
|
||||||
} else {
|
} else {
|
||||||
addOutputImageView.setVisibility(View.VISIBLE);
|
|
||||||
unprepareMaxSend();
|
unprepareMaxSend();
|
||||||
sendMaxButton.setText(getText(R.string.send_max));
|
sendMaxButton.setText(getText(R.string.send_max));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mViewModel.showAddOutputButton.observe(getViewLifecycleOwner(), show -> {
|
||||||
|
setAddOutputButtonVisibility((show && !destsHasPaymentId()) ? View.VISIBLE : View.INVISIBLE);
|
||||||
|
});
|
||||||
|
|
||||||
mViewModel.pendingTransaction.observe(getViewLifecycleOwner(), pendingTx -> {
|
mViewModel.pendingTransaction.observe(getViewLifecycleOwner(), pendingTx -> {
|
||||||
showConfirmationLayout(pendingTx != null);
|
showConfirmationLayout(pendingTx != null);
|
||||||
|
|
||||||
|
@ -220,7 +247,31 @@ public class SendFragment extends Fragment {
|
||||||
int index = getDestCount();
|
int index = getDestCount();
|
||||||
ConstraintLayout entryView = (ConstraintLayout)inflater.inflate(R.layout.transaction_output_item, null);
|
ConstraintLayout entryView = (ConstraintLayout)inflater.inflate(R.layout.transaction_output_item, null);
|
||||||
ImageButton removeOutputImageButton = entryView.findViewById(R.id.remove_output_imagebutton);
|
ImageButton removeOutputImageButton = entryView.findViewById(R.id.remove_output_imagebutton);
|
||||||
|
EditText addressField = entryView.findViewById(R.id.address_edittext);
|
||||||
|
addressField.addTextChangedListener(new TextWatcher() {
|
||||||
|
@Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
|
||||||
|
@Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
|
||||||
|
@Override
|
||||||
|
public void afterTextChanged(Editable editable) {
|
||||||
|
int currentOutputs = getDestCount();
|
||||||
|
UriData uriData = UriData.parse(editable.toString());
|
||||||
|
if(uriData != null) {
|
||||||
|
// we have valid address
|
||||||
|
boolean hasPaymentId = uriData.hasPaymentId();
|
||||||
|
if(currentOutputs > 1 && hasPaymentId) {
|
||||||
|
// multiple outputs when pasting/editing in integrated address. this is not allowed
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.paymentid_paytomany), Toast.LENGTH_SHORT).show();
|
||||||
|
addressField.setText(null);
|
||||||
|
} else if(currentOutputs == 1 && hasPaymentId) {
|
||||||
|
// show add output button: we are sending to integrated address
|
||||||
|
mViewModel.setShowAddOutputButton(false);
|
||||||
|
}
|
||||||
|
} else if(currentOutputs == 1 && !isSendAll()) {
|
||||||
|
// when send-all is false and this is our only dest and address is invalid, then show add output button
|
||||||
|
mViewModel.setShowAddOutputButton(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
entryView.findViewById(R.id.paste_amount_imagebutton).setOnClickListener(view1 -> {
|
entryView.findViewById(R.id.paste_amount_imagebutton).setOnClickListener(view1 -> {
|
||||||
Context ctx = getContext();
|
Context ctx = getContext();
|
||||||
if (ctx != null) {
|
if (ctx != null) {
|
||||||
|
@ -261,6 +312,24 @@ public class SendFragment extends Fragment {
|
||||||
return destList.getChildCount();
|
return destList.getChildCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Pair<String, String>> getRawDests() {
|
||||||
|
ArrayList<Pair<String, String>> dests = new ArrayList<>();
|
||||||
|
for(int i = 0; i < getDestCount(); i++) {
|
||||||
|
ConstraintLayout entryView = getDestView(i);
|
||||||
|
EditText amountField = entryView.findViewById(R.id.amount_edittext);
|
||||||
|
EditText addressField = entryView.findViewById(R.id.address_edittext);
|
||||||
|
String amount = amountField.getText().toString().trim();
|
||||||
|
String address = addressField.getText().toString().trim();
|
||||||
|
dests.add(new Pair<>(address, amount));
|
||||||
|
}
|
||||||
|
|
||||||
|
return dests;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSendAll() {
|
||||||
|
return mViewModel.sendingMax.getValue() != null ? mViewModel.sendingMax.getValue() : false;
|
||||||
|
}
|
||||||
|
|
||||||
private ConstraintLayout getDestView(int pos) {
|
private ConstraintLayout getDestView(int pos) {
|
||||||
return (ConstraintLayout) destList.getChildAt(pos);
|
return (ConstraintLayout) destList.getChildAt(pos);
|
||||||
}
|
}
|
||||||
|
@ -284,7 +353,7 @@ public class SendFragment extends Fragment {
|
||||||
private void showConfirmationLayout(boolean show) {
|
private void showConfirmationLayout(boolean show) {
|
||||||
if (show) {
|
if (show) {
|
||||||
destList.setVisibility(View.GONE);
|
destList.setVisibility(View.GONE);
|
||||||
addOutputImageView.setVisibility(View.GONE);
|
setAddOutputButtonVisibility(View.GONE);
|
||||||
sendMaxButton.setVisibility(View.GONE);
|
sendMaxButton.setVisibility(View.GONE);
|
||||||
createButton.setVisibility(View.GONE);
|
createButton.setVisibility(View.GONE);
|
||||||
feeRadioGroup.setVisibility(View.GONE);
|
feeRadioGroup.setVisibility(View.GONE);
|
||||||
|
@ -296,7 +365,7 @@ public class SendFragment extends Fragment {
|
||||||
amountTextView.setVisibility(View.VISIBLE);
|
amountTextView.setVisibility(View.VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
destList.setVisibility(View.VISIBLE);
|
destList.setVisibility(View.VISIBLE);
|
||||||
addOutputImageView.setVisibility(View.VISIBLE);
|
setAddOutputButtonVisibility(View.VISIBLE);
|
||||||
sendMaxButton.setVisibility(View.VISIBLE);
|
sendMaxButton.setVisibility(View.VISIBLE);
|
||||||
createButton.setVisibility(View.VISIBLE);
|
createButton.setVisibility(View.VISIBLE);
|
||||||
feeRadioGroup.setVisibility(View.VISIBLE);
|
feeRadioGroup.setVisibility(View.VISIBLE);
|
||||||
|
@ -322,31 +391,41 @@ public class SendFragment extends Fragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void pasteAddress(ConstraintLayout entryView, String clipboard, boolean pastingAmount) {
|
private void pasteAddress(ConstraintLayout entryView, String clipboard, boolean pastingAmount) {
|
||||||
|
if(pastingAmount) {
|
||||||
|
try {
|
||||||
|
Double.parseDouble(clipboard);
|
||||||
|
setAmount(entryView, clipboard);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.send_amount_invalid), Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UriData uriData = UriData.parse(clipboard);
|
UriData uriData = UriData.parse(clipboard);
|
||||||
if (uriData != null) {
|
if (uriData != null) {
|
||||||
|
int currentOutputs = getDestCount();
|
||||||
|
if(currentOutputs > 1 && uriData.hasPaymentId()) {
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.paymentid_paytomany), Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
} else if(currentOutputs == 1 && uriData.hasPaymentId()) {
|
||||||
|
mViewModel.setShowAddOutputButton(false);
|
||||||
|
}
|
||||||
EditText addressField = entryView.findViewById(R.id.address_edittext);
|
EditText addressField = entryView.findViewById(R.id.address_edittext);
|
||||||
addressField.setText(uriData.getAddress());
|
addressField.setText(uriData.getAddress());
|
||||||
if (uriData.hasAmount()) {
|
if (uriData.hasAmount()) {
|
||||||
sendMaxButton.setEnabled(false);
|
setAmount(entryView, uriData.getAmount());
|
||||||
EditText amountField = entryView.findViewById(R.id.amount_edittext);
|
|
||||||
amountField.setText(uriData.getAmount());
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(pastingAmount) {
|
Toast.makeText(getActivity(), getString(R.string.send_address_invalid), Toast.LENGTH_SHORT).show();
|
||||||
try {
|
|
||||||
Double.parseDouble(clipboard);
|
|
||||||
sendMaxButton.setEnabled(false);
|
|
||||||
EditText amountField = entryView.findViewById(R.id.amount_edittext);
|
|
||||||
amountField.setText(clipboard);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Toast.makeText(getActivity(), getString(R.string.send_amount_invalid), Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Toast.makeText(getActivity(), getString(R.string.send_address_invalid), Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setAmount(ConstraintLayout entryView, String amount) {
|
||||||
|
sendMaxButton.setEnabled(false);
|
||||||
|
EditText amountField = entryView.findViewById(R.id.amount_edittext);
|
||||||
|
amountField.setText(amount);
|
||||||
|
}
|
||||||
|
|
||||||
private void createTx(List<Pair<String, String>> dests, boolean sendAll, PendingTransaction.Priority feePriority) {
|
private void createTx(List<Pair<String, String>> dests, boolean sendAll, PendingTransaction.Priority feePriority) {
|
||||||
((MoneroApplication)getActivity().getApplication()).getExecutor().execute(() -> {
|
((MoneroApplication)getActivity().getApplication()).getExecutor().execute(() -> {
|
||||||
try {
|
try {
|
||||||
|
@ -393,4 +472,8 @@ public class SendFragment extends Fragment {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setAddOutputButtonVisibility(int visibility) {
|
||||||
|
addOutputImageView.setVisibility(visibility);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -9,11 +9,18 @@ import net.mynero.wallet.model.PendingTransaction;
|
||||||
public class SendViewModel extends ViewModel {
|
public class SendViewModel extends ViewModel {
|
||||||
private final MutableLiveData<Boolean> _sendingMax = new MutableLiveData<>(false);
|
private final MutableLiveData<Boolean> _sendingMax = new MutableLiveData<>(false);
|
||||||
public LiveData<Boolean> sendingMax = _sendingMax;
|
public LiveData<Boolean> sendingMax = _sendingMax;
|
||||||
|
private final MutableLiveData<Boolean> _showAddOutputButton = new MutableLiveData<>(true);
|
||||||
|
public LiveData<Boolean> showAddOutputButton = _showAddOutputButton;
|
||||||
private final MutableLiveData<PendingTransaction> _pendingTransaction = new MutableLiveData<>(null);
|
private final MutableLiveData<PendingTransaction> _pendingTransaction = new MutableLiveData<>(null);
|
||||||
public LiveData<PendingTransaction> pendingTransaction = _pendingTransaction;
|
public LiveData<PendingTransaction> pendingTransaction = _pendingTransaction;
|
||||||
|
|
||||||
public void setSendingMax(boolean value) {
|
public void setSendingMax(boolean value) {
|
||||||
_sendingMax.setValue(value);
|
_sendingMax.setValue(value);
|
||||||
|
setShowAddOutputButton(!value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShowAddOutputButton(boolean value) {
|
||||||
|
_showAddOutputButton.setValue(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPendingTransaction(PendingTransaction pendingTx) {
|
public void setPendingTransaction(PendingTransaction pendingTx) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package net.mynero.wallet.util;
|
package net.mynero.wallet.util;
|
||||||
|
|
||||||
import net.mynero.wallet.model.Wallet;
|
import net.mynero.wallet.model.Wallet;
|
||||||
|
import net.mynero.wallet.model.WalletManager;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
@ -46,6 +47,10 @@ public class UriData {
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasPaymentId() {
|
||||||
|
return !Wallet.getPaymentIdFromAddress(this.address, WalletManager.getInstance().getWallet().nettype()).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
public String getAmount() {
|
public String getAmount() {
|
||||||
String txAmount = params.get(Constants.URI_ARG_AMOUNT);
|
String txAmount = params.get(Constants.URI_ARG_AMOUNT);
|
||||||
if (txAmount == null) {
|
if (txAmount == null) {
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
<string name="bad_password">Incorrect password!</string>
|
<string name="bad_password">Incorrect password!</string>
|
||||||
|
|
||||||
<string name="send_address_invalid">Not a valid address</string>
|
<string name="send_address_invalid">Not a valid address</string>
|
||||||
|
<string name="send_amount_invalid">Not a valid amount</string>
|
||||||
|
<string name="send_amount_invalid_sendall_paytomany">Cannot send-all in pay-to-many</string>
|
||||||
|
|
||||||
<string name="tx_list_failed_text">failed</string>
|
<string name="tx_list_failed_text">failed</string>
|
||||||
<string name="tx_list_amount_negative">- %1$s</string>
|
<string name="tx_list_amount_negative">- %1$s</string>
|
||||||
|
@ -24,7 +26,6 @@
|
||||||
|
|
||||||
<string name="wallet_locked_balance_text">+ %1$s confirming</string>
|
<string name="wallet_locked_balance_text">+ %1$s confirming</string>
|
||||||
<string name="send_amount_empty">Please enter an amount</string>
|
<string name="send_amount_empty">Please enter an amount</string>
|
||||||
<string name="send_amount_invalid">Please enter a valid amount</string>
|
|
||||||
<string name="send_max">Max</string>
|
<string name="send_max">Max</string>
|
||||||
<string name="undo">Undo</string>
|
<string name="undo">Undo</string>
|
||||||
<string name="error_sending_tx">Error sending transaction</string>
|
<string name="error_sending_tx">Error sending transaction</string>
|
||||||
|
@ -61,6 +62,7 @@
|
||||||
<string name="tx_fee_text">Fee: %1$s XMR</string>
|
<string name="tx_fee_text">Fee: %1$s XMR</string>
|
||||||
<string name="receive">Receive</string>
|
<string name="receive">Receive</string>
|
||||||
<string name="creating_tx">Creating transaction…</string>
|
<string name="creating_tx">Creating transaction…</string>
|
||||||
|
<string name="creating_tx_failed_invalid_outputs">Invalid destination combination</string>
|
||||||
<string name="sending_tx">Sending transaction…</string>
|
<string name="sending_tx">Sending transaction…</string>
|
||||||
<string name="sent_tx">Sent transaction!</string>
|
<string name="sent_tx">Sent transaction!</string>
|
||||||
<string name="no_camera_permission">No camera permission</string>
|
<string name="no_camera_permission">No camera permission</string>
|
||||||
|
@ -124,4 +126,6 @@
|
||||||
<string name="auth">[ auth ]</string>
|
<string name="auth">[ auth ]</string>
|
||||||
<string name="to">To</string>
|
<string name="to">To</string>
|
||||||
<string name="max_outputs_allowed">Maximum allowed outputs</string>
|
<string name="max_outputs_allowed">Maximum allowed outputs</string>
|
||||||
|
<string name="paymentid_paytomany">Cannot send to integrated addresses in a pay-to-many transaction</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in a new issue