1
mirror of https://github.com/m2049r/xmrwallet synced 2024-11-29 10:20:23 +01:00

subaddresses (#322)

This commit is contained in:
m2049r 2018-06-18 09:43:32 +02:00 committed by GitHub
parent 091538752b
commit 01e7693425
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 268 additions and 60 deletions

View File

@ -552,9 +552,11 @@ Java_com_m2049r_xmrwallet_model_Wallet_setPassword(JNIEnv *env, jobject instance
JNIEXPORT jstring JNICALL
Java_com_m2049r_xmrwallet_model_Wallet_getAddressJ(JNIEnv *env, jobject instance,
jint accountIndex) {
jint accountIndex,
jint addressIndex) {
Bitmonero::Wallet *wallet = getHandle<Bitmonero::Wallet>(env, instance);
return env->NewStringUTF(wallet->address((uint32_t) accountIndex).c_str());
return env->NewStringUTF(
wallet->address((uint32_t) accountIndex, (uint32_t) addressIndex).c_str());
}
JNIEXPORT jstring JNICALL
@ -850,10 +852,10 @@ Java_com_m2049r_xmrwallet_model_Wallet_createTransactionJ(JNIEnv *env, jobject i
JNIEXPORT jlong JNICALL
Java_com_m2049r_xmrwallet_model_Wallet_createSweepTransaction(JNIEnv *env, jobject instance,
jstring dst_addr, jstring payment_id,
jint mixin_count,
jint priority,
jint accountIndex) {
jstring dst_addr, jstring payment_id,
jint mixin_count,
jint priority,
jint accountIndex) {
const char *_dst_addr = env->GetStringUTFChars(dst_addr, NULL);
const char *_payment_id = env->GetStringUTFChars(payment_id, NULL);
@ -988,7 +990,7 @@ Java_com_m2049r_xmrwallet_model_Wallet_getTxKey(JNIEnv *env, jobject instance,
//virtual void addSubaddressAccount(const std::string& label) = 0;
JNIEXPORT void JNICALL
Java_com_m2049r_xmrwallet_model_Wallet_addAccount(JNIEnv *env, jobject instance,
jstring label) {
jstring label) {
const char *_label = env->GetStringUTFChars(label, NULL);
@ -1027,13 +1029,44 @@ Java_com_m2049r_xmrwallet_model_Wallet_setSubaddressLabel(JNIEnv *env, jobject i
// virtual size_t numSubaddressAccounts() const = 0;
JNIEXPORT jint JNICALL
Java_com_m2049r_xmrwallet_model_Wallet_numSubaddressAccounts(JNIEnv *env, jobject instance) {
Java_com_m2049r_xmrwallet_model_Wallet_getNumAccounts(JNIEnv *env, jobject instance) {
Bitmonero::Wallet *wallet = getHandle<Bitmonero::Wallet>(env, instance);
return wallet->numSubaddressAccounts();
return static_cast<jint>(wallet->numSubaddressAccounts());
}
//virtual size_t numSubaddresses(uint32_t accountIndex) const = 0;
JNIEXPORT jint JNICALL
Java_com_m2049r_xmrwallet_model_Wallet_getNumSubaddresses(JNIEnv *env, jobject instance,
jint accountIndex) {
Bitmonero::Wallet *wallet = getHandle<Bitmonero::Wallet>(env, instance);
return static_cast<jint>(wallet->numSubaddresses(accountIndex));
}
//virtual void addSubaddress(uint32_t accountIndex, const std::string &label) = 0;
JNIEXPORT void JNICALL
Java_com_m2049r_xmrwallet_model_Wallet_addSubaddress(JNIEnv *env, jobject instance,
jint accountIndex,
jstring label) {
const char *_label = env->GetStringUTFChars(label, NULL);
Bitmonero::Wallet *wallet = getHandle<Bitmonero::Wallet>(env, instance);
wallet->addSubaddress(accountIndex, _label);
env->ReleaseStringUTFChars(label, _label);
}
/*JNIEXPORT jstring JNICALL
Java_com_m2049r_xmrwallet_model_Wallet_getLastSubaddress(JNIEnv *env, jobject instance,
jint accountIndex) {
Bitmonero::Wallet *wallet = getHandle<Bitmonero::Wallet>(env, instance);
size_t num = wallet->numSubaddresses(accountIndex);
//wallet->subaddress()->getAll()[num]->getAddress().c_str()
Monero::Subaddress *s = wallet->subaddress();
s->refresh(accountIndex);
std::vector<Monero::SubaddressRow *> v = s->getAll();
return env->NewStringUTF(v[num - 1]->getAddress().c_str());
}
*/
//virtual std::string signMessage(const std::string &message) = 0;
//virtual bool verifySignedMessage(const std::string &message, const std::string &addres, const std::string &signature) const = 0;
@ -1079,10 +1112,13 @@ jobject newTransferList(JNIEnv *env, Bitmonero::TransactionInfo *info) {
jobject newTransactionInfo(JNIEnv *env, Bitmonero::TransactionInfo *info) {
jmethodID c = env->GetMethodID(class_TransactionInfo, "<init>",
"(IZZJJJLjava/lang/String;JLjava/lang/String;IJLjava/util/List;)V");
"(IZZJJJLjava/lang/String;JLjava/lang/String;IIJLjava/util/List;)V");
jobject transfers = newTransferList(env, info);
jstring _hash = env->NewStringUTF(info->hash().c_str());
jstring _paymentId = env->NewStringUTF(info->paymentId().c_str());
uint32_t subaddrIndex = 0;
if (info->direction() == Bitmonero::TransactionInfo::Direction_In)
subaddrIndex = *(info->subaddrIndex().begin());
jobject result = env->NewObject(class_TransactionInfo, c,
info->direction(),
info->isPending(),
@ -1094,6 +1130,7 @@ jobject newTransactionInfo(JNIEnv *env, Bitmonero::TransactionInfo *info) {
static_cast<jlong> (info->timestamp()),
_paymentId,
info->subaddrAccount(),
subaddrIndex,
info->confirmations(),
transfers);
env->DeleteLocalRef(transfers);
@ -1104,6 +1141,7 @@ jobject newTransactionInfo(JNIEnv *env, Bitmonero::TransactionInfo *info) {
#include <stdio.h>
#include <stdlib.h>
jobject cpp2java(JNIEnv *env, std::vector<Bitmonero::TransactionInfo *> vector) {
jmethodID java_util_ArrayList_ = env->GetMethodID(class_ArrayList, "<init>", "(I)V");
@ -1161,11 +1199,13 @@ Java_com_m2049r_xmrwallet_model_PendingTransaction_getAmount(JNIEnv *env, jobjec
Bitmonero::PendingTransaction *tx = getHandle<Bitmonero::PendingTransaction>(env, instance);
return tx->amount();
}
JNIEXPORT jlong JNICALL
Java_com_m2049r_xmrwallet_model_PendingTransaction_getDust(JNIEnv *env, jobject instance) {
Bitmonero::PendingTransaction *tx = getHandle<Bitmonero::PendingTransaction>(env, instance);
return tx->dust();
}
JNIEXPORT jlong JNICALL
Java_com_m2049r_xmrwallet_model_PendingTransaction_getFee(JNIEnv *env, jobject instance) {
Bitmonero::PendingTransaction *tx = getHandle<Bitmonero::PendingTransaction>(env, instance);

View File

@ -62,6 +62,7 @@ import timber.log.Timber;
public class ReceiveFragment extends Fragment {
private ProgressBar pbProgress;
private TextView tvAddressLabel;
private TextView tvAddress;
private TextInputLayout etPaymentId;
private ExchangeView evAmount;
@ -71,6 +72,10 @@ public class ReceiveFragment extends Fragment {
private ImageView qrCodeFull;
private EditText etDummy;
private ImageButton bCopyAddress;
private Button bSubaddress;
private Wallet wallet = null;
private boolean isMyWallet = false;
public interface Listener {
void setToolbarButton(int type);
@ -87,6 +92,7 @@ public class ReceiveFragment extends Fragment {
View view = inflater.inflate(R.layout.fragment_receive, container, false);
pbProgress = (ProgressBar) view.findViewById(R.id.pbProgress);
tvAddressLabel = (TextView) view.findViewById(R.id.tvAddressLabel);
tvAddress = (TextView) view.findViewById(R.id.tvAddress);
etPaymentId = (TextInputLayout) view.findViewById(R.id.etPaymentId);
evAmount = (ExchangeView) view.findViewById(R.id.evAmount);
@ -96,6 +102,7 @@ public class ReceiveFragment extends Fragment {
qrCodeFull = (ImageView) view.findViewById(R.id.qrCodeFull);
etDummy = (EditText) view.findViewById(R.id.etDummy);
bCopyAddress = (ImageButton) view.findViewById(R.id.bCopyAddress);
bSubaddress = (Button) view.findViewById(R.id.bSubaddress);
etPaymentId.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
etDummy.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
@ -162,6 +169,18 @@ public class ReceiveFragment extends Fragment {
}
});
bSubaddress.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
enableSubaddressButton(false);
tvAddress.setText(wallet.getNewSubaddress());
tvAddressLabel.setText(getString(R.string.generate_address_label_sub,
wallet.getNumSubaddresses() - 1));
storeWallet();
generateQr();
}
});
qrCode.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@ -194,11 +213,25 @@ public class ReceiveFragment extends Fragment {
String password = b.getString("password");
loadAndShow(path, password);
} else {
show(walletName, address);
if (getActivity() instanceof GenerateReviewFragment.ListenerWithWallet) {
wallet = ((GenerateReviewFragment.ListenerWithWallet) getActivity()).getWallet();
show();
} else {
throw new IllegalStateException("no wallet info");
}
}
return view;
}
void enableSubaddressButton(boolean enable) {
bSubaddress.setEnabled(enable);
if (enable) {
bSubaddress.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.ic_settings_orange_24dp,0,0);
} else {
bSubaddress.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.ic_settings_gray_24dp,0,0);
}
}
void copyAddress() {
Helper.clipBoardCopy(getActivity(), getString(R.string.label_copy_address), tvAddress.getText().toString());
Toast.makeText(getActivity(), getString(R.string.message_copy_address), Toast.LENGTH_SHORT).show();
@ -228,17 +261,17 @@ public class ReceiveFragment extends Fragment {
super.onResume();
Timber.d("onResume()");
listenerCallback.setToolbarButton(Toolbar.BUTTON_BACK);
listenerCallback.setSubtitle(getString(R.string.receive_title));
listenerCallback.setSubtitle(wallet.getAccountLabel());
generateQr();
}
private boolean isLoaded = false;
private void show(String name, String address) {
Timber.d("name=%s", name);
private void show() {
Timber.d("name=%s", wallet.getName());
isLoaded = true;
listenerCallback.setTitle(name);
tvAddress.setText(address);
listenerCallback.setTitle(wallet.getName());
tvAddress.setText(wallet.getAddress());
etPaymentId.setEnabled(true);
bPaymentId.setEnabled(true);
bCopyAddress.setClickable(true);
@ -254,18 +287,14 @@ public class ReceiveFragment extends Fragment {
private class AsyncShow extends AsyncTask<String, Void, Boolean> {
String password;
String address;
String name;
@Override
protected Boolean doInBackground(String... params) {
if (params.length != 2) return false;
String walletPath = params[0];
password = params[1];
Wallet wallet = WalletManager.getInstance().openWallet(walletPath, password);
address = wallet.getAddress();
name = wallet.getName();
wallet.close();
wallet = WalletManager.getInstance().openWallet(walletPath, password);
isMyWallet = true;
return true;
}
@ -274,7 +303,7 @@ public class ReceiveFragment extends Fragment {
super.onPostExecute(result);
if (!isAdded()) return; // never mind
if (result) {
show(name, address);
show();
} else {
Toast.makeText(getActivity(), getString(R.string.receive_cannot_open), Toast.LENGTH_LONG).show();
hideProgress();
@ -282,6 +311,27 @@ public class ReceiveFragment extends Fragment {
}
}
private void storeWallet() {
new AsyncStore().executeOnExecutor(MoneroThreadPoolExecutor.MONERO_THREAD_POOL_EXECUTOR);
}
private class AsyncStore extends AsyncTask<String, Void, Boolean> {
@Override
protected Boolean doInBackground(String... params) {
if (params.length != 0) return false;
if (wallet != null) wallet.store();
return true;
}
@Override
protected void onPostExecute(Boolean result) {
enableSubaddressButton(true);
super.onPostExecute(result);
}
}
private boolean checkPaymentId() {
String paymentId = etPaymentId.getEditText().getText().toString();
boolean ok = paymentId.isEmpty() || Wallet.isPaymentIdValid(paymentId);
@ -418,4 +468,15 @@ public class ReceiveFragment extends Fragment {
Timber.d("onPause()");
super.onPause();
}
@Override
public void onDetach() {
Timber.d("onDetach()");
if ((wallet != null) && (isMyWallet)) {
wallet.close();
wallet = null;
isMyWallet = false;
}
super.onDetach();
}
}

View File

@ -224,7 +224,7 @@ public class TxFragment extends Fragment {
activityCallback.setSubtitle(getString(R.string.tx_title));
activityCallback.setToolbarButton(Toolbar.BUTTON_BACK);
tvAccount.setText("" + info.subaddrAccount);
tvAccount.setText(getString(R.string.tx_account_formatted, info.account, info.subaddress));
tvTxTimestamp.setText(TS_FORMATTER.format(new Date(info.timestamp * 1000)));
tvTxId.setText(info.hash);
@ -287,7 +287,10 @@ public class TxFragment extends Fragment {
}
} else {
sb.append("-");
dstSb.append(info.direction == TransactionInfo.Direction.Direction_In ? activityCallback.getWalletAddress() : "-");
dstSb.append(info.direction ==
TransactionInfo.Direction.Direction_In ?
activityCallback.getWalletSubaddress(info.account, info.subaddress) :
"-");
}
tvTxTransfers.setText(sb.toString());
tvDestination.setText(dstSb.toString());
@ -322,7 +325,7 @@ public class TxFragment extends Fragment {
Listener activityCallback;
public interface Listener {
String getWalletAddress();
String getWalletSubaddress(int accountIndex, int subaddressIndex);
String getTxKey(String hash);

View File

@ -491,8 +491,8 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
@Override
public boolean onRefreshed(final Wallet wallet, final boolean full) {
Timber.d("onRefreshed()");
if (numAccounts != wallet.numAccounts()) {
numAccounts = wallet.numAccounts();
if (numAccounts != wallet.getNumAccounts()) {
numAccounts = wallet.getNumAccounts();
runOnUiThread(new Runnable() {
public void run() {
updateAccountsList();
@ -740,8 +740,8 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
}
@Override
public String getWalletAddress() {
return getWallet().getAddress();
public String getWalletSubaddress(int accountIndex, int subaddressIndex) {
return getWallet().getSubaddress(accountIndex, subaddressIndex);
}
public String getWalletName() {
@ -891,7 +891,7 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
@Override
public void onWalletReceive() {
startReceive(getWalletAddress());
startReceive(getWallet().getAddress());
}
void startReceive(String address) {
@ -966,7 +966,8 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
Helper.getDisplayAmount(wallet.getBalanceAll(), 5)));
Menu menu = accountsView.getMenu();
menu.removeGroup(R.id.accounts_list);
for (int i = 0; i < wallet.numAccounts(); i++) {
final int n = wallet.getNumAccounts();
for (int i = 0; i < n; i++) {
final String label = wallet.getAccountLabel(i);
final MenuItem item = menu.add(R.id.accounts_list, getAccountId(i), 2 * i, label);
item.setIcon(R.drawable.ic_account_balance_wallet_black_24dp);
@ -1050,7 +1051,7 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
switch (id) {
case R.id.account_new:
getWallet().addAccount();
int newIdx = getWallet().numAccounts() - 1;
int newIdx = getWallet().getNumAccounts() - 1;
getWallet().setAccountIndex(newIdx);
Toast.makeText(this,
getString(R.string.accounts_new, newIdx),

View File

@ -166,7 +166,11 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
}
if ((userNotes.note.isEmpty())) {
this.tvPaymentId.setText(infoItem.paymentId.equals("0000000000000000") ? "" : infoItem.paymentId);
this.tvPaymentId.setText(infoItem.paymentId.equals("0000000000000000") ?
(infoItem.subaddress != 0 ?
(context.getString(R.string.tx_subaddress, infoItem.subaddress)) :
"") :
infoItem.paymentId);
} else {
this.tvPaymentId.setText(userNotes.note);
}

View File

@ -75,7 +75,7 @@ public class TransactionHistory {
Timber.d("refreshed %d", t.size());
for (Iterator<TransactionInfo> iterator = t.iterator(); iterator.hasNext(); ) {
TransactionInfo info = iterator.next();
if (info.subaddrAccount != accountIndex) {
if (info.account != accountIndex) {
iterator.remove();
Timber.d("removed %s", info.hash);
} else {

View File

@ -67,7 +67,8 @@ public class TransactionInfo implements Parcelable, Comparable<TransactionInfo>
public String hash;
public long timestamp;
public String paymentId;
public int subaddrAccount;
public int account;
public int subaddress;
public long confirmations;
public List<Transfer> transfers;
@ -84,7 +85,8 @@ public class TransactionInfo implements Parcelable, Comparable<TransactionInfo>
String hash,
long timestamp,
String paymentId,
int subaddrAccount,
int account,
int subaddress,
long confirmations,
List<Transfer> transfers) {
this.direction = Direction.values()[direction];
@ -96,7 +98,8 @@ public class TransactionInfo implements Parcelable, Comparable<TransactionInfo>
this.hash = hash;
this.timestamp = timestamp;
this.paymentId = paymentId;
this.subaddrAccount = subaddrAccount;
this.account = account;
this.subaddress = subaddress;
this.confirmations = confirmations;
this.transfers = transfers;
}
@ -116,7 +119,8 @@ public class TransactionInfo implements Parcelable, Comparable<TransactionInfo>
out.writeString(hash);
out.writeLong(timestamp);
out.writeString(paymentId);
out.writeInt(subaddrAccount);
out.writeInt(account);
out.writeInt(subaddress);
out.writeLong(confirmations);
out.writeList(transfers);
out.writeString(txKey);
@ -143,7 +147,8 @@ public class TransactionInfo implements Parcelable, Comparable<TransactionInfo>
hash = in.readString();
timestamp = in.readLong();
paymentId = in.readString();
subaddrAccount = in.readInt();
account = in.readInt();
subaddress = in.readInt();
confirmations = in.readLong();
transfers = in.readArrayList(Transfer.class.getClassLoader());
txKey = in.readString();

View File

@ -19,6 +19,9 @@ package com.m2049r.xmrwallet.model;
import com.m2049r.xmrwallet.data.TxData;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import timber.log.Timber;
@ -86,10 +89,22 @@ public class Wallet {
public native boolean setPassword(String password);
public String getAddress() {
return getAddressJ(accountIndex);
return getAddress(accountIndex);
}
private native String getAddressJ(int accountIndex);
public String getAddress(int accountIndex) {
return getAddressJ(accountIndex, 0);
}
public String getSubaddress(int addressIndex) {
return getAddressJ(accountIndex, addressIndex);
}
public String getSubaddress(int accountIndex, int addressIndex) {
return getAddressJ(accountIndex, addressIndex);
}
private native String getAddressJ(int accountIndex, int addressIndex);
public native String getPath();
@ -109,7 +124,9 @@ public class Wallet {
public native String getSecretSpendKey();
public boolean store() {
return store("");
final boolean ok = store("");
Timber.d("stored");
return ok;
}
public native boolean store(String path);
@ -323,17 +340,21 @@ public class Wallet {
public String getAccountLabel(int accountIndex) {
String label = getSubaddressLabel(accountIndex, 0);
if (label.equals(NEW_ACCOUNT_NAME)) {
String address = getAddressJ(accountIndex);
String address = getAddress(accountIndex);
int len = address.length();
return address.substring(0, 6) +
"\u2026" + address.substring(len - 6, len);
} else return label;
}
public String getSubaddressLabel(int addressIndex) {
return getSubaddressLabel(accountIndex, addressIndex);
}
public native String getSubaddressLabel(int accountIndex, int addressIndex);
public void setAccountLabel(String label) {
setSubaddressLabel(accountIndex, 0, label);
setAccountLabel(accountIndex, label);
}
public void setAccountLabel(int accountIndex, String label) {
@ -342,9 +363,30 @@ public class Wallet {
public native void setSubaddressLabel(int accountIndex, int addressIndex, String label);
public int numAccounts() {
return numSubaddressAccounts();
public native int getNumAccounts();
public int getNumSubaddresses() {
return getNumSubaddresses(accountIndex);
}
public native int getNumSubaddresses(int accountIndex);
public String getNewSubaddress() {
return getNewSubaddress(accountIndex);
}
public String getNewSubaddress(int accountIndex) {
String timeStamp = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss", Locale.US).format(new Date());
addSubaddress(accountIndex, timeStamp);
String subaddress = getLastSubaddress(accountIndex);
Timber.d("%d: %s", getNumSubaddresses(accountIndex) - 1, subaddress);
return subaddress;
}
public native void addSubaddress(int accountIndex, String label);
public String getLastSubaddress(int accountIndex) {
return getSubaddress(accountIndex, getNumSubaddresses(accountIndex) - 1);
}
public native int numSubaddressAccounts();
}

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="@color/moneroGray"
android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98s-0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.12,-0.22 -0.39,-0.3 -0.61,-0.22l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.23,-0.09 -0.49,0 -0.61,0.22l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98s0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.12,0.22 0.39,0.3 0.61,0.22l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.23,0.09 0.49,0 0.61,-0.22l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM12,15.5c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5 3.5,1.57 3.5,3.5 -1.57,3.5 -3.5,3.5z" />
</vector>

View File

@ -24,11 +24,13 @@
android:indeterminate="true"
android:visibility="gone" />
<FrameLayout
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:gravity="center">
<TextView
android:id="@+id/tvAddressLabel"
style="@style/MoneroLabel.Heading"
android:layout_width="wrap_content"
android:layout_height="match_parent"
@ -39,20 +41,44 @@
android:id="@+id/bCopyAddress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginEnd="80dp"
android:layout_marginStart="8dp"
android:background="?android:selectableItemBackground"
android:clickable="false"
android:src="@drawable/ic_content_nocopy_black_24dp" />
</FrameLayout>
</LinearLayout>
<TextView
android:id="@+id/tvAddress"
style="@style/MoneroText.Medium"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
tools:text="9wZnnNctRc7RaLya1rxykH21dUwfQpNGmVLjAvkvqe7nKT2Mw848AJNGMunW5xjoSZ5vCCU3uDnUoVqSSHxzRtQBE3f6crx" />
android:layout_marginTop="8dp"
android:orientation="horizontal"
android:weightSum="10">
<TextView
android:id="@+id/tvAddress"
style="@style/MoneroText.Medium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="10"
android:textAlignment="center"
tools:text="9wZnnNctRc7RaLya1rxykH21dUwfQpNGmVLjAvkvqe7nKT2Mw848AJNGMunW5xjoSZ5vCCU3uDnUoVqSSHxzRtQBE3f6crx" />
<Button
android:id="@+id/bSubaddress"
style="@style/MoneroText.Button.Small"
android:layout_width="56dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="8dp"
android:layout_weight="0"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:drawableTop="@drawable/ic_settings_orange_24dp"
android:text="@string/send_generate_paymentid_hint"
android:textColor="@color/moneroGray"
android:visibility="visible" />
</LinearLayout>
<com.m2049r.xmrwallet.widget.ExchangeView
android:id="@+id/evAmount"
@ -96,7 +122,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="0"
android:background="?android:selectableItemBackground"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:drawableTop="@drawable/ic_settings_orange_24dp"
android:text="@string/send_generate_paymentid_hint"
android:textColor="@color/moneroGray"
@ -122,10 +148,10 @@
android:visibility="invisible" />
<android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_margin="16dp"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_margin="16dp"
android:clickable="true"
android:foreground="?android:attr/selectableItemBackground"
card_view:cardCornerRadius="2dp"

View File

@ -318,4 +318,6 @@
<string name="accounts_new">Added new account #%1$d</string>
<string name="tx_account">Account #</string>
<string name="send_sweepall">Send all confirmed funds in this account!</string>
<string name="tx_subaddress">Subaddress #%1$d</string>
<string name="generate_address_label_sub">Public Subaddress #%1$d</string>
</resources>

View File

@ -303,4 +303,6 @@
<string name="accounts_new">Added new account #%1$d</string>
<string name="tx_account">Account #</string>
<string name="send_sweepall">Send all confirmed funds in this account!</string>
<string name="tx_subaddress">Subaddress #%1$d</string>
<string name="generate_address_label_sub">Public Subaddress #%1$d</string>
</resources>

View File

@ -321,4 +321,6 @@
<string name="accounts_new">Nouveau Compte #%1$d ajouté</string>
<string name="tx_account">Compte #</string>
<string name="send_sweepall">Send all confirmed funds in this account!</string>
<string name="tx_subaddress">Subaddress #%1$d</string>
<string name="generate_address_label_sub">Public Subaddress #%1$d</string>
</resources>

View File

@ -319,4 +319,6 @@
<string name="accounts_new">Added new account #%1$d</string>
<string name="tx_account">Account #</string>
<string name="send_sweepall">Send all confirmed funds in this account!</string>
<string name="tx_subaddress">Subaddress #%1$d</string>
<string name="generate_address_label_sub">Public Subaddress #%1$d</string>
</resources>

View File

@ -317,4 +317,6 @@
<string name="accounts_new">Added new account #%1$d</string>
<string name="tx_account">Account #</string>
<string name="send_sweepall">Send all confirmed funds in this account!</string>
<string name="tx_subaddress">Subaddress #%1$d</string>
<string name="generate_address_label_sub">Public Subaddress #%1$d</string>
</resources>

View File

@ -315,4 +315,6 @@
<string name="accounts_new">Added new account #%1$d</string>
<string name="tx_account">Account #</string>
<string name="send_sweepall">Send all confirmed funds in this account!</string>
<string name="tx_subaddress">Subaddress #%1$d</string>
<string name="generate_address_label_sub">Public Subaddress #%1$d</string>
</resources>

View File

@ -316,4 +316,6 @@
<string name="accounts_new">Added new account #%1$d</string>
<string name="tx_account">Account #</string>
<string name="send_sweepall">Send all confirmed funds in this account!</string>
<string name="tx_subaddress">Subaddress #%1$d</string>
<string name="generate_address_label_sub">Public Subaddress #%1$d</string>
</resources>

View File

@ -216,6 +216,7 @@
<string name="generate_mnemonic_hint">25-Word Mnemonic Seed</string>
<string name="generate_restoreheight_hint">Restore Height or Date (YYYY-MM-DD)</string>
<string name="generate_address_label_sub">Public Subaddress #%1$d</string>
<string name="generate_address_label">Public Address</string>
<string name="generate_viewkey_label">View Key</string>
<string name="generate_spendkey_label">Spend Key</string>
@ -365,4 +366,6 @@
<string name="accounts_drawer_new">Create Account</string>
<string name="accounts_drawer_title">Accounts</string>
<string name="tx_subaddress">Subaddress #%1$d</string>
<string name="tx_account_formatted" translatable="false">(%1$d, %2$d)</string>
</resources>