mirror of
https://codeberg.org/anoncontributorxmr/mysu.git
synced 2024-12-22 21:17:47 +00:00
Add ability to create multiple outputs on send screen. WIP
This commit is contained in:
parent
8dace455d6
commit
062d9dabe3
11 changed files with 432 additions and 214 deletions
|
@ -44,7 +44,8 @@ public class SendBottomSheetDialog extends BottomSheetDialogFragment {
|
||||||
private final MutableLiveData<Boolean> _sendingMax = new MutableLiveData<>(false);
|
private final MutableLiveData<Boolean> _sendingMax = new MutableLiveData<>(false);
|
||||||
private final MutableLiveData<PendingTransaction> _pendingTransaction = new MutableLiveData<>(null);
|
private final MutableLiveData<PendingTransaction> _pendingTransaction = new MutableLiveData<>(null);
|
||||||
public ArrayList<String> selectedUtxos = new ArrayList<>();
|
public ArrayList<String> selectedUtxos = new ArrayList<>();
|
||||||
public LiveData<Boolean> sendingMax = _sendingMax; private final ActivityResultLauncher<String> cameraPermissionsLauncher = registerForActivityResult(new ActivityResultContracts.RequestPermission(),
|
public LiveData<Boolean> sendingMax = _sendingMax;
|
||||||
|
private final ActivityResultLauncher<String> cameraPermissionsLauncher = registerForActivityResult(new ActivityResultContracts.RequestPermission(),
|
||||||
granted -> {
|
granted -> {
|
||||||
if (granted) {
|
if (granted) {
|
||||||
onScan();
|
onScan();
|
||||||
|
|
|
@ -71,8 +71,8 @@ public class HomeFragment extends Fragment implements TransactionInfoAdapter.TxI
|
||||||
});
|
});
|
||||||
|
|
||||||
sendButton.setOnClickListener(view1 -> {
|
sendButton.setOnClickListener(view1 -> {
|
||||||
SendBottomSheetDialog sendDialog = new SendBottomSheetDialog();
|
navigate(HomeFragmentDirections.navToSend());
|
||||||
sendDialog.show(getActivity().getSupportFragmentManager(), null);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
receiveButton.setOnClickListener(view1 -> {
|
receiveButton.setOnClickListener(view1 -> {
|
||||||
|
|
|
@ -1,47 +1,56 @@
|
||||||
package net.mynero.wallet.fragment.send;
|
package net.mynero.wallet.fragment.send;
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
import android.app.Activity;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.RadioGroup;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.FragmentActivity;
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.google.zxing.BarcodeFormat;
|
import net.mynero.wallet.MoneroApplication;
|
||||||
import com.google.zxing.EncodeHintType;
|
|
||||||
import com.google.zxing.WriterException;
|
|
||||||
import com.google.zxing.common.BitMatrix;
|
|
||||||
import com.google.zxing.qrcode.QRCodeWriter;
|
|
||||||
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
|
|
||||||
|
|
||||||
import net.mynero.wallet.R;
|
import net.mynero.wallet.R;
|
||||||
import net.mynero.wallet.adapter.SubaddressAdapter;
|
import net.mynero.wallet.model.PendingTransaction;
|
||||||
import net.mynero.wallet.data.Subaddress;
|
import net.mynero.wallet.model.Wallet;
|
||||||
import net.mynero.wallet.util.DayNightMode;
|
import net.mynero.wallet.service.BalanceService;
|
||||||
|
import net.mynero.wallet.service.TxService;
|
||||||
import net.mynero.wallet.util.Helper;
|
import net.mynero.wallet.util.Helper;
|
||||||
import net.mynero.wallet.util.NightmodeHelper;
|
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import timber.log.Timber;
|
import kotlin.Pair;
|
||||||
|
|
||||||
public class SendFragment extends Fragment {
|
public class SendFragment extends Fragment {
|
||||||
private TextView addressTextView = null;
|
|
||||||
private TextView addressLabelTextView = null;
|
|
||||||
private ImageView addressImageView = null;
|
|
||||||
private ImageButton copyAddressImageButton = null;
|
|
||||||
private SendViewModel mViewModel;
|
private SendViewModel mViewModel;
|
||||||
|
private Button sendMaxButton;
|
||||||
|
private ImageButton addOutputImageView;
|
||||||
|
private LinearLayout destList;
|
||||||
|
private LayoutInflater inflater;
|
||||||
|
private Button createButton;
|
||||||
|
private RadioGroup feeRadioGroup;
|
||||||
|
private TextView feeRadioGroupLabelTextView;
|
||||||
|
|
||||||
|
private TextView feeTextView;
|
||||||
|
private TextView addressTextView;
|
||||||
|
private TextView amountTextView;
|
||||||
|
|
||||||
|
public PendingTransaction.Priority priority;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||||
|
@ -53,63 +62,203 @@ public class SendFragment extends Fragment {
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
mViewModel = new ViewModelProvider(this).get(SendViewModel.class);
|
mViewModel = new ViewModelProvider(this).get(SendViewModel.class);
|
||||||
addressImageView = view.findViewById(R.id.monero_qr_imageview);
|
sendMaxButton = view.findViewById(R.id.send_max_button);
|
||||||
addressTextView = view.findViewById(R.id.address_textview);
|
addOutputImageView = view.findViewById(R.id.add_output_button);
|
||||||
addressLabelTextView = view.findViewById(R.id.address_label_textview);
|
destList = view.findViewById(R.id.transaction_destination_list);
|
||||||
copyAddressImageButton = view.findViewById(R.id.copy_address_imagebutton);
|
createButton = view.findViewById(R.id.create_tx_button);
|
||||||
bindListeners(view);
|
feeRadioGroup = view.findViewById(R.id.tx_fee_radiogroup);
|
||||||
bindObservers(view);
|
feeTextView = view.findViewById(R.id.fee_textview);
|
||||||
mViewModel.init();
|
addressTextView = view.findViewById(R.id.address_pending_textview);
|
||||||
|
amountTextView = view.findViewById(R.id.amount_pending_textview);
|
||||||
|
feeRadioGroup = view.findViewById(R.id.tx_fee_radiogroup);
|
||||||
|
feeRadioGroupLabelTextView = view.findViewById(R.id.tx_fee_radiogroup_label_textview);
|
||||||
|
|
||||||
|
FragmentActivity activity = getActivity();
|
||||||
|
if(activity != null) {
|
||||||
|
inflater = activity.getLayoutInflater();
|
||||||
|
}
|
||||||
|
bindListeners();
|
||||||
|
bindObservers();
|
||||||
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bindListeners(View view) {
|
private void init() {
|
||||||
ImageButton freshAddressImageView = view.findViewById(R.id.fresh_address_imageview);
|
addOutput();
|
||||||
freshAddressImageView.setOnClickListener(view1 -> {
|
}
|
||||||
mViewModel.getFreshSubaddress();
|
|
||||||
|
private void bindListeners() {
|
||||||
|
feeRadioGroup.check(R.id.low_fee_radiobutton);
|
||||||
|
priority = PendingTransaction.Priority.Priority_Low;
|
||||||
|
feeRadioGroup.setOnCheckedChangeListener((radioGroup, i) -> {
|
||||||
|
if (i == R.id.low_fee_radiobutton) {
|
||||||
|
priority = PendingTransaction.Priority.Priority_Low;
|
||||||
|
} else if (i == R.id.med_fee_radiobutton) {
|
||||||
|
priority = PendingTransaction.Priority.Priority_Medium;
|
||||||
|
} else if (i == R.id.high_fee_radiobutton) {
|
||||||
|
priority = PendingTransaction.Priority.Priority_High;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
addOutputImageView.setOnClickListener(view1 -> {
|
||||||
|
sendMaxButton.setVisibility(View.GONE);
|
||||||
|
addOutput();
|
||||||
|
});
|
||||||
|
sendMaxButton.setOnClickListener(view1 -> {
|
||||||
|
addOutputImageView.setVisibility(View.INVISIBLE);
|
||||||
|
boolean currentValue = mViewModel.sendingMax.getValue() != null ? mViewModel.sendingMax.getValue() : false;
|
||||||
|
mViewModel.setSendingMax(!currentValue);
|
||||||
|
});
|
||||||
|
createButton.setOnClickListener(view1 -> {
|
||||||
|
boolean sendAll = mViewModel.sendingMax.getValue() != null ? mViewModel.sendingMax.getValue() : false;
|
||||||
|
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);
|
||||||
|
long balance = BalanceService.getInstance().getUnlockedBalanceRaw();
|
||||||
|
if (amountRaw >= balance || amountRaw <= 0) {
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.send_amount_invalid), Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
createTx(dests, sendAll, priority);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bindObservers(View view) {
|
private void bindObservers() {
|
||||||
SubaddressAdapter adapter = new SubaddressAdapter(mViewModel::selectAddress);
|
mViewModel.sendingMax.observe(getViewLifecycleOwner(), sendingMax -> {
|
||||||
RecyclerView recyclerView = view.findViewById(R.id.address_list_recyclerview);
|
if (mViewModel.pendingTransaction.getValue() == null) {
|
||||||
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
|
if (sendingMax) {
|
||||||
recyclerView.setAdapter(adapter);
|
addOutputImageView.setVisibility(View.GONE);
|
||||||
mViewModel.address.observe(getViewLifecycleOwner(), this::setAddress);
|
prepareOutputsForMaxSend();
|
||||||
mViewModel.addresses.observe(getViewLifecycleOwner(), adapter::submitList);
|
sendMaxButton.setText(getText(R.string.undo));
|
||||||
}
|
|
||||||
|
|
||||||
private void setAddress(Subaddress subaddress) {
|
|
||||||
final String label = subaddress.getDisplayLabel();
|
|
||||||
final String address = getContext().getString(R.string.subbaddress_info_subtitle,
|
|
||||||
subaddress.getAddressIndex(), subaddress.getSquashedAddress());
|
|
||||||
addressLabelTextView.setText(label.isEmpty() ? address : label);
|
|
||||||
addressTextView.setText(subaddress.getAddress());
|
|
||||||
addressImageView.setImageBitmap(generate(subaddress.getAddress(), 256, 256));
|
|
||||||
copyAddressImageButton.setOnClickListener(view1 -> Helper.clipBoardCopy(getContext(), "address", subaddress.getAddress()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Bitmap generate(String text, int width, int height) {
|
|
||||||
if ((width <= 0) || (height <= 0)) return null;
|
|
||||||
Map<EncodeHintType, Object> hints = new HashMap<>();
|
|
||||||
hints.put(EncodeHintType.CHARACTER_SET, StandardCharsets.UTF_8);
|
|
||||||
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
|
|
||||||
try {
|
|
||||||
BitMatrix bitMatrix = new QRCodeWriter().encode(text, BarcodeFormat.QR_CODE, width, height, hints);
|
|
||||||
int[] pixels = new int[width * height];
|
|
||||||
for (int i = 0; i < height; i++) {
|
|
||||||
for (int j = 0; j < width; j++) {
|
|
||||||
boolean night = NightmodeHelper.getPreferredNightmode() == DayNightMode.NIGHT;
|
|
||||||
if (bitMatrix.get(j, i)) {
|
|
||||||
pixels[i * width + j] = night ? 0xffffffff : 0x00000000;
|
|
||||||
} else {
|
} else {
|
||||||
pixels[i * height + j] = getResources().getColor(R.color.oled_colorBackground);
|
addOutputImageView.setVisibility(View.VISIBLE);
|
||||||
|
unprepareMaxSend();
|
||||||
|
sendMaxButton.setText(getText(R.string.send_max));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mViewModel.pendingTransaction.observe(getViewLifecycleOwner(), pendingTx -> {
|
||||||
|
showConfirmationLayout(pendingTx != null);
|
||||||
|
|
||||||
|
if (pendingTx != null) {
|
||||||
|
String address = getDestCount() == 1 ? getAddressField(0).getText().toString() : "Multiple";
|
||||||
|
addressTextView.setText(getString(R.string.tx_address_text, address));
|
||||||
|
amountTextView.setText(getString(R.string.tx_amount_text, Helper.getDisplayAmount(pendingTx.getAmount())));
|
||||||
|
feeTextView.setText(getString(R.string.tx_fee_text, Helper.getDisplayAmount(pendingTx.getFee())));
|
||||||
}
|
}
|
||||||
return Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.RGB_565);
|
});
|
||||||
} catch (WriterException ex) {
|
|
||||||
Timber.e(ex);
|
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
|
private void addOutput() {
|
||||||
|
if (inflater != null) {
|
||||||
|
ConstraintLayout entryView = (ConstraintLayout)inflater.inflate(R.layout.transaction_output_item, null);
|
||||||
|
entryView.findViewById(R.id.remove_output_imagebutton).setOnClickListener(view -> {
|
||||||
|
int currentCount = getDestCount();
|
||||||
|
if(currentCount > 1) {
|
||||||
|
destList.removeView(entryView);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
destList.addView(entryView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getDestCount() {
|
||||||
|
return destList.getChildCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConstraintLayout getDestView(int pos) {
|
||||||
|
return (ConstraintLayout) destList.getChildAt(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
private EditText getAddressField(int pos) {
|
||||||
|
return (EditText) getDestView(pos).findViewById(R.id.address_edittext);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unprepareMaxSend() {
|
||||||
|
ConstraintLayout entryView = getDestView(0);
|
||||||
|
entryView.findViewById(R.id.sending_all_textview).setVisibility(View.GONE);
|
||||||
|
entryView.findViewById(R.id.amount_edittext).setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void prepareOutputsForMaxSend() {
|
||||||
|
ConstraintLayout entryView = getDestView(0);
|
||||||
|
entryView.findViewById(R.id.sending_all_textview).setVisibility(View.VISIBLE);
|
||||||
|
entryView.findViewById(R.id.amount_edittext).setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showConfirmationLayout(boolean show) {
|
||||||
|
if (show) {
|
||||||
|
destList.setVisibility(View.GONE);
|
||||||
|
addOutputImageView.setVisibility(View.GONE);
|
||||||
|
sendMaxButton.setVisibility(View.GONE);
|
||||||
|
createButton.setVisibility(View.GONE);
|
||||||
|
feeRadioGroup.setVisibility(View.GONE);
|
||||||
|
feeRadioGroupLabelTextView.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
feeTextView.setVisibility(View.VISIBLE);
|
||||||
|
addressTextView.setVisibility(View.VISIBLE);
|
||||||
|
amountTextView.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
destList.setVisibility(View.VISIBLE);
|
||||||
|
addOutputImageView.setVisibility(View.VISIBLE);
|
||||||
|
sendMaxButton.setVisibility(View.VISIBLE);
|
||||||
|
createButton.setVisibility(View.VISIBLE);
|
||||||
|
feeRadioGroup.setVisibility(View.VISIBLE);
|
||||||
|
feeRadioGroupLabelTextView.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
feeTextView.setVisibility(View.GONE);
|
||||||
|
addressTextView.setVisibility(View.GONE);
|
||||||
|
amountTextView.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createTx(List<Pair<String, String>> dests, boolean sendAll, PendingTransaction.Priority feePriority) {
|
||||||
|
((MoneroApplication)getActivity().getApplication()).getExecutor().execute(() -> {
|
||||||
|
try {
|
||||||
|
PendingTransaction pendingTx = TxService.getInstance().createTx(dests, sendAll, feePriority, new ArrayList<>());
|
||||||
|
if (pendingTx != null && pendingTx.getStatus() == PendingTransaction.Status.Status_Ok) {
|
||||||
|
mViewModel.setPendingTransaction(pendingTx);
|
||||||
|
} else {
|
||||||
|
Activity activity = getActivity();
|
||||||
|
if (activity != null) {
|
||||||
|
activity.runOnUiThread(() -> {
|
||||||
|
createButton.setEnabled(true);
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.error_creating_tx), Toast.LENGTH_SHORT).show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Activity activity = getActivity();
|
||||||
|
if (activity != null) {
|
||||||
|
activity.runOnUiThread(() -> {
|
||||||
|
createButton.setEnabled(true);
|
||||||
|
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,42 +4,19 @@ import androidx.lifecycle.LiveData;
|
||||||
import androidx.lifecycle.MutableLiveData;
|
import androidx.lifecycle.MutableLiveData;
|
||||||
import androidx.lifecycle.ViewModel;
|
import androidx.lifecycle.ViewModel;
|
||||||
|
|
||||||
import net.mynero.wallet.data.Subaddress;
|
import net.mynero.wallet.model.PendingTransaction;
|
||||||
import net.mynero.wallet.model.Wallet;
|
|
||||||
import net.mynero.wallet.model.WalletManager;
|
|
||||||
import net.mynero.wallet.service.AddressService;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class SendViewModel extends ViewModel {
|
public class SendViewModel extends ViewModel {
|
||||||
private final MutableLiveData<Subaddress> _address = new MutableLiveData<>();
|
private final MutableLiveData<Boolean> _sendingMax = new MutableLiveData<>(false);
|
||||||
public LiveData<Subaddress> address = _address;
|
public LiveData<Boolean> sendingMax = _sendingMax;
|
||||||
private final MutableLiveData<List<Subaddress>> _addresses = new MutableLiveData<>();
|
private final MutableLiveData<PendingTransaction> _pendingTransaction = new MutableLiveData<>(null);
|
||||||
public LiveData<List<Subaddress>> addresses = _addresses;
|
public LiveData<PendingTransaction> pendingTransaction = _pendingTransaction;
|
||||||
|
|
||||||
public void init() {
|
public void setSendingMax(boolean value) {
|
||||||
_address.setValue(AddressService.getInstance().currentSubaddress());
|
_sendingMax.setValue(value);
|
||||||
_addresses.setValue(getSubaddresses());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Subaddress> getSubaddresses() {
|
public void setPendingTransaction(PendingTransaction pendingTx) {
|
||||||
Wallet wallet = WalletManager.getInstance().getWallet();
|
_pendingTransaction.postValue(pendingTx);
|
||||||
ArrayList<Subaddress> subaddresses = new ArrayList<>();
|
|
||||||
int addressesSize = AddressService.getInstance().getLatestAddressIndex();
|
|
||||||
for(int i = addressesSize - 1; i >= 0; i--) {
|
|
||||||
subaddresses.add(wallet.getSubaddressObject(i));
|
|
||||||
}
|
|
||||||
return Collections.unmodifiableList(subaddresses);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void getFreshSubaddress() {
|
|
||||||
_address.setValue(AddressService.getInstance().freshSubaddress());
|
|
||||||
_addresses.setValue(getSubaddresses());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void selectAddress(Subaddress subaddress) {
|
|
||||||
_address.setValue(subaddress);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -33,6 +33,8 @@ import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import kotlin.Pair;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handy class for starting a new thread that has a looper. The looper can then be
|
* Handy class for starting a new thread that has a looper. The looper can then be
|
||||||
|
@ -131,23 +133,36 @@ public class MoneroHandlerThread extends Thread implements WalletListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
public PendingTransaction createTx(String address, String amountStr, boolean sendAll, PendingTransaction.Priority feePriority, ArrayList<String> selectedUtxos) throws Exception {
|
public PendingTransaction createTx(String address, String amountStr, boolean sendAll, PendingTransaction.Priority feePriority, ArrayList<String> selectedUtxos) throws Exception {
|
||||||
long amount = Wallet.getAmountFromString(amountStr);
|
ArrayList<Pair<String, String>> dests = new ArrayList<>();
|
||||||
|
dests.add(new Pair(address, amountStr));
|
||||||
|
return createTx(dests, sendAll, feePriority, selectedUtxos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PendingTransaction createTx(List<Pair<String, String>> dests, boolean sendAll, PendingTransaction.Priority feePriority, ArrayList<String> selectedUtxos) throws Exception {
|
||||||
|
long totalAmount = 0;
|
||||||
|
ArrayList<TransactionOutput> outputs = new ArrayList<>();
|
||||||
|
|
||||||
|
for(Pair<String, String> dest : dests) {
|
||||||
|
long amount = Wallet.getAmountFromString(dest.component2());
|
||||||
|
totalAmount += amount;
|
||||||
|
outputs.add(new TransactionOutput(dest.component1(), amount));
|
||||||
|
}
|
||||||
ArrayList<String> preferredInputs;
|
ArrayList<String> preferredInputs;
|
||||||
if (selectedUtxos.isEmpty()) {
|
if (selectedUtxos.isEmpty()) {
|
||||||
// no inputs manually selected, we are sending from home screen most likely, or user somehow broke the app
|
// no inputs manually selected, we are sending from home screen most likely, or user somehow broke the app
|
||||||
preferredInputs = UTXOService.getInstance().selectUtxos(amount, sendAll);
|
preferredInputs = UTXOService.getInstance().selectUtxos(totalAmount, sendAll);
|
||||||
} else {
|
} else {
|
||||||
preferredInputs = selectedUtxos;
|
preferredInputs = selectedUtxos;
|
||||||
checkSelectedAmounts(preferredInputs, amount, sendAll);
|
checkSelectedAmounts(preferredInputs, totalAmount, sendAll);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(sendAll) {
|
if(sendAll) {
|
||||||
|
Pair<String, String> dest = dests.get(0);
|
||||||
|
String address = dest.component1();
|
||||||
return wallet.createSweepTransaction(address, feePriority, preferredInputs);
|
return wallet.createSweepTransaction(address, feePriority, preferredInputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayList<TransactionOutput> outputs = new ArrayList<>();
|
List<TransactionOutput> finalOutputs = maybeAddDonationOutputs(totalAmount, outputs, preferredInputs);
|
||||||
outputs.add(new TransactionOutput(address, amount));
|
|
||||||
List<TransactionOutput> finalOutputs = maybeAddDonationOutputs(amount, outputs, preferredInputs);
|
|
||||||
return wallet.createTransactionMultDest(finalOutputs, feePriority, preferredInputs);
|
return wallet.createTransactionMultDest(finalOutputs, feePriority, preferredInputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,9 @@ package net.mynero.wallet.service;
|
||||||
import net.mynero.wallet.model.PendingTransaction;
|
import net.mynero.wallet.model.PendingTransaction;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import kotlin.Pair;
|
||||||
|
|
||||||
public class TxService extends ServiceBase {
|
public class TxService extends ServiceBase {
|
||||||
public static TxService instance = null;
|
public static TxService instance = null;
|
||||||
|
@ -20,6 +23,10 @@ public class TxService extends ServiceBase {
|
||||||
return this.getThread().createTx(address, amount, sendAll, feePriority, selectedUtxos);
|
return this.getThread().createTx(address, amount, sendAll, feePriority, selectedUtxos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PendingTransaction createTx(List<Pair<String, String>> dests, boolean sendAll, PendingTransaction.Priority feePriority, ArrayList<String> selectedUtxos) throws Exception {
|
||||||
|
return this.getThread().createTx(dests, sendAll, feePriority, selectedUtxos);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean sendTx(PendingTransaction pendingTransaction) {
|
public boolean sendTx(PendingTransaction pendingTransaction) {
|
||||||
return this.getThread().sendTx(pendingTransaction);
|
return this.getThread().sendTx(pendingTransaction);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:shape="rectangle">
|
android:shape="rectangle">
|
||||||
<padding
|
<padding
|
||||||
android:bottom="12dp"
|
android:bottom="8dp"
|
||||||
android:left="12dp"
|
android:left="12dp"
|
||||||
android:right="12dp"
|
android:right="12dp"
|
||||||
android:top="12dp" />
|
android:top="8dp" />
|
||||||
<solid android:color="@color/edittext_bg_color" />
|
<solid android:color="@color/edittext_bg_color" />
|
||||||
<corners android:radius="8dp" />
|
<corners android:radius="8dp" />
|
||||||
</shape>
|
</shape>
|
||||||
|
|
|
@ -4,69 +4,24 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:fillViewport="true"
|
||||||
android:fitsSystemWindows="true">
|
android:fitsSystemWindows="true">
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="0dp">
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/send_monero_textview"
|
android:id="@+id/send_monero_textview"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/send_monero"
|
android:text="@string/send_monero"
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
android:layout_marginEnd="24dp"
|
|
||||||
android:layout_marginStart="24dp"
|
android:layout_marginStart="24dp"
|
||||||
android:textSize="32sp"
|
android:textSize="32sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toStartOf="@id/add_output_button"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<!-- CREATE LAYOUT -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/selected_utxos_value_textview"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="24dp"
|
|
||||||
android:layout_marginStart="24dp"
|
|
||||||
android:text="@string/selected_utxos_value"
|
|
||||||
android:textSize="14sp"
|
|
||||||
android:visibility="visible"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/send_monero_textview" />
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/amount_edittext"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:layout_marginStart="24dp"
|
|
||||||
android:background="@drawable/edittext_bg"
|
|
||||||
android:hint="@string/amount"
|
|
||||||
android:inputType="numberDecimal"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/selected_utxos_value_textview"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/address_edittext"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/send_max_button"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
tools:visibility="visible" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/sending_all_textview"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="12dp"
|
|
||||||
android:paddingTop="12dp"
|
|
||||||
android:paddingBottom="12dp"
|
|
||||||
android:text="@string/sending_all"
|
|
||||||
android:layout_marginStart="24dp"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/amount_edittext"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/send_max_button"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/amount_edittext"
|
|
||||||
tools:visibility="visible" />
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/send_max_button"
|
android:id="@+id/send_max_button"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
@ -74,68 +29,44 @@
|
||||||
android:background="@drawable/button_bg"
|
android:background="@drawable/button_bg"
|
||||||
android:text="@string/send_max"
|
android:text="@string/send_max"
|
||||||
android:layout_marginEnd="24dp"
|
android:layout_marginEnd="24dp"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/amount_edittext"
|
app:layout_constraintBottom_toBottomOf="@id/send_monero_textview"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@id/amount_edittext"
|
app:layout_constraintStart_toEndOf="@id/add_output_button"
|
||||||
app:layout_constraintTop_toTopOf="@id/amount_edittext"
|
app:layout_constraintTop_toTopOf="@id/send_monero_textview"
|
||||||
tools:visibility="visible" />
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/address_edittext"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:layout_marginBottom="4dp"
|
|
||||||
android:background="@drawable/edittext_bg"
|
|
||||||
android:layout_marginStart="24dp"
|
|
||||||
android:ellipsize="middle"
|
|
||||||
android:hint="@string/address"
|
|
||||||
android:singleLine="true"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/paste_address_imagebutton"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/send_max_button"
|
|
||||||
tools:visibility="visible" />
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/donate_label_textview"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/donate_label"
|
|
||||||
android:layout_marginStart="24dp"
|
|
||||||
android:textSize="14sp"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/address_edittext"/>
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/paste_address_imagebutton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:background="@android:color/transparent"
|
|
||||||
android:minWidth="48dp"
|
|
||||||
android:minHeight="48dp"
|
|
||||||
android:src="@drawable/ic_content_paste_24dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/address_edittext"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/scan_address_imagebutton"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/address_edittext"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/address_edittext"
|
|
||||||
tools:ignore="SpeakableTextPresentCheck"
|
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/scan_address_imagebutton"
|
android:id="@+id/add_output_button"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:minWidth="48dp"
|
android:minWidth="48dp"
|
||||||
android:minHeight="48dp"
|
android:minHeight="48dp"
|
||||||
android:layout_marginEnd="24dp"
|
android:layout_marginEnd="24dp"
|
||||||
android:src="@drawable/ic_scan"
|
android:src="@android:drawable/ic_input_add"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/address_edittext"
|
app:layout_constraintBottom_toBottomOf="@id/send_monero_textview"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toStartOf="@id/send_max_button"
|
||||||
app:layout_constraintStart_toEndOf="@id/paste_address_imagebutton"
|
app:layout_constraintStart_toEndOf="@id/send_monero_textview"
|
||||||
app:layout_constraintTop_toTopOf="@id/address_edittext"
|
app:layout_constraintTop_toTopOf="@id/send_monero_textview"
|
||||||
tools:ignore="SpeakableTextPresentCheck"
|
tools:ignore="SpeakableTextPresentCheck"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<!-- CREATE LAYOUT -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/selected_utxos_value_textview"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
|
android:layout_marginStart="24dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="@string/selected_utxos_value"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:visibility="visible"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/send_monero_textview" />
|
||||||
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tx_fee_radiogroup_label_textview"
|
android:id="@+id/tx_fee_radiogroup_label_textview"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
@ -155,7 +86,7 @@
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
android:layout_marginEnd="24dp"
|
android:layout_marginEnd="24dp"
|
||||||
app:layout_constraintTop_toBottomOf="@id/donate_label_textview"
|
app:layout_constraintBottom_toTopOf="@id/create_tx_button"
|
||||||
app:layout_constraintStart_toEndOf="@id/tx_fee_radiogroup_label_textview"
|
app:layout_constraintStart_toEndOf="@id/tx_fee_radiogroup_label_textview"
|
||||||
app:layout_constraintEnd_toEndOf="parent">
|
app:layout_constraintEnd_toEndOf="parent">
|
||||||
<RadioButton
|
<RadioButton
|
||||||
|
@ -190,12 +121,25 @@
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
android:layout_marginEnd="24dp"
|
android:layout_marginEnd="24dp"
|
||||||
android:layout_marginStart="24dp"
|
android:layout_marginStart="24dp"
|
||||||
|
android:layout_marginBottom="24dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/tx_fee_radiogroup_label_textview"
|
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/transaction_destination_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:clickable="false"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/tx_fee_radiogroup"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/selected_utxos_value_textview">
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
<!-- SEND LAYOUT -->
|
<!-- SEND LAYOUT -->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/address_pending_textview"
|
android:id="@+id/address_pending_textview"
|
||||||
|
|
114
app/src/main/res/layout/transaction_output_item.xml
Normal file
114
app/src/main/res/layout/transaction_output_item.xml
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@color/oled_txBackgroundColor">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/amount_edittext"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
|
android:layout_marginStart="24dp"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:background="@drawable/edittext_bg"
|
||||||
|
android:hint="@string/amount"
|
||||||
|
android:inputType="numberDecimal"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/address_edittext"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/sending_all_textview"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
|
android:paddingTop="12dp"
|
||||||
|
android:paddingBottom="12dp"
|
||||||
|
android:text="@string/sending_all"
|
||||||
|
android:layout_marginStart="24dp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/address_edittext"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
tools:visibility="gone" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/to_address_label_textview"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/to"
|
||||||
|
android:layout_marginStart="24dp"
|
||||||
|
android:textSize="14sp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/address_edittext"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/address_edittext"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/address_edittext"/>
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/address_edittext"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
android:background="@drawable/edittext_bg"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:ellipsize="middle"
|
||||||
|
android:hint="@string/address"
|
||||||
|
android:singleLine="true"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/paste_address_imagebutton"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/to_address_label_textview"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/amount_edittext"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/paste_address_imagebutton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:minWidth="48dp"
|
||||||
|
android:minHeight="48dp"
|
||||||
|
android:src="@drawable/ic_content_paste_24dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/address_edittext"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/scan_address_imagebutton"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/address_edittext"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/address_edittext"
|
||||||
|
tools:ignore="SpeakableTextPresentCheck"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/scan_address_imagebutton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:minWidth="48dp"
|
||||||
|
android:minHeight="48dp"
|
||||||
|
android:src="@drawable/ic_scan"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/address_edittext"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/remove_output_imagebutton"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/paste_address_imagebutton"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/address_edittext"
|
||||||
|
tools:ignore="SpeakableTextPresentCheck"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/remove_output_imagebutton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:minWidth="48dp"
|
||||||
|
android:minHeight="48dp"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
|
android:src="@android:drawable/ic_delete"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/address_edittext"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/scan_address_imagebutton"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/address_edittext"
|
||||||
|
tools:ignore="SpeakableTextPresentCheck"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -17,6 +17,10 @@
|
||||||
android:id="@+id/nav_to_receive"
|
android:id="@+id/nav_to_receive"
|
||||||
app:destination="@id/receive_fragment">
|
app:destination="@id/receive_fragment">
|
||||||
</action>
|
</action>
|
||||||
|
<action
|
||||||
|
android:id="@+id/nav_to_send"
|
||||||
|
app:destination="@id/send_fragment">
|
||||||
|
</action>
|
||||||
<action
|
<action
|
||||||
android:id="@+id/nav_to_onboarding"
|
android:id="@+id/nav_to_onboarding"
|
||||||
app:destination="@id/onboarding_fragment">
|
app:destination="@id/onboarding_fragment">
|
||||||
|
@ -40,6 +44,12 @@
|
||||||
app:destination="@id/utxos_fragment">
|
app:destination="@id/utxos_fragment">
|
||||||
</action>
|
</action>
|
||||||
</fragment>
|
</fragment>
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/send_fragment"
|
||||||
|
android:name="net.mynero.wallet.fragment.send.SendFragment"
|
||||||
|
android:label="fragment_send_amount"
|
||||||
|
tools:layout="@layout/fragment_send">
|
||||||
|
</fragment>
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/receive_fragment"
|
android:id="@+id/receive_fragment"
|
||||||
android:name="net.mynero.wallet.fragment.receive.ReceiveFragment"
|
android:name="net.mynero.wallet.fragment.receive.ReceiveFragment"
|
||||||
|
|
|
@ -127,4 +127,5 @@
|
||||||
<string name="donate_label">Donate to MyNero</string>
|
<string name="donate_label">Donate to MyNero</string>
|
||||||
<string name="transactions">Transactions</string>
|
<string name="transactions">Transactions</string>
|
||||||
<string name="auth">[ auth ]</string>
|
<string name="auth">[ auth ]</string>
|
||||||
|
<string name="to">To</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in a new issue