parent
d855328c52
commit
f8e701aa07
|
@ -8,8 +8,8 @@ android {
|
||||||
applicationId "com.m2049r.xmrwallet"
|
applicationId "com.m2049r.xmrwallet"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 25
|
targetSdkVersion 25
|
||||||
versionCode 51
|
versionCode 62
|
||||||
versionName "1.2.11"
|
versionName "1.3.2 'Satoshis Dream'"
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
|
|
|
@ -46,6 +46,7 @@ import com.google.zxing.WriterException;
|
||||||
import com.google.zxing.common.BitMatrix;
|
import com.google.zxing.common.BitMatrix;
|
||||||
import com.google.zxing.qrcode.QRCodeWriter;
|
import com.google.zxing.qrcode.QRCodeWriter;
|
||||||
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
|
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
|
||||||
|
import com.m2049r.xmrwallet.data.BarcodeData;
|
||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
import com.m2049r.xmrwallet.model.WalletManager;
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
|
@ -304,14 +305,14 @@ public class ReceiveFragment extends Fragment {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
StringBuffer sb = new StringBuffer();
|
StringBuffer sb = new StringBuffer();
|
||||||
sb.append(ScannerFragment.QR_SCHEME).append(address);
|
sb.append(BarcodeData.XMR_SCHEME).append(address);
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
if (!paymentId.isEmpty()) {
|
if (!paymentId.isEmpty()) {
|
||||||
if (first) {
|
if (first) {
|
||||||
sb.append("?");
|
sb.append("?");
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
sb.append(ScannerFragment.QR_PAYMENTID).append('=').append(paymentId);
|
sb.append(BarcodeData.XMR_PAYMENTID).append('=').append(paymentId);
|
||||||
}
|
}
|
||||||
if (!xmrAmount.isEmpty()) {
|
if (!xmrAmount.isEmpty()) {
|
||||||
if (first) {
|
if (first) {
|
||||||
|
@ -319,7 +320,7 @@ public class ReceiveFragment extends Fragment {
|
||||||
} else {
|
} else {
|
||||||
sb.append("&");
|
sb.append("&");
|
||||||
}
|
}
|
||||||
sb.append(ScannerFragment.QR_AMOUNT).append('=').append(xmrAmount);
|
sb.append(BarcodeData.XMR_AMOUNT).append('=').append(xmrAmount);
|
||||||
}
|
}
|
||||||
String text = sb.toString();
|
String text = sb.toString();
|
||||||
int size = Math.min(qrCode.getHeight(), qrCode.getWidth());
|
int size = Math.min(qrCode.getHeight(), qrCode.getWidth());
|
||||||
|
|
|
@ -36,7 +36,7 @@ public class ScannerFragment extends Fragment implements ZXingScannerView.Result
|
||||||
private OnScannedListener onScannedListener;
|
private OnScannedListener onScannedListener;
|
||||||
|
|
||||||
public interface OnScannedListener {
|
public interface OnScannedListener {
|
||||||
boolean onScanned(String uri);
|
boolean onScanned(String qrCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ZXingScannerView mScannerView;
|
private ZXingScannerView mScannerView;
|
||||||
|
@ -56,10 +56,6 @@ public class ScannerFragment extends Fragment implements ZXingScannerView.Result
|
||||||
mScannerView.startCamera();
|
mScannerView.startCamera();
|
||||||
}
|
}
|
||||||
|
|
||||||
static final String QR_SCHEME = "monero:";
|
|
||||||
static final String QR_PAYMENTID = "tx_payment_id";
|
|
||||||
static final String QR_AMOUNT = "tx_amount";
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleResult(Result rawResult) {
|
public void handleResult(Result rawResult) {
|
||||||
if ((rawResult.getBarcodeFormat() == BarcodeFormat.QR_CODE)) {
|
if ((rawResult.getBarcodeFormat() == BarcodeFormat.QR_CODE)) {
|
||||||
|
|
|
@ -20,6 +20,10 @@ import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
import static android.view.WindowManager.LayoutParams;
|
import static android.view.WindowManager.LayoutParams;
|
||||||
|
|
||||||
public abstract class SecureActivity extends AppCompatActivity {
|
public abstract class SecureActivity extends AppCompatActivity {
|
||||||
|
@ -27,8 +31,9 @@ public abstract class SecureActivity extends AppCompatActivity {
|
||||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
File f = new File(Helper.getStorageRoot(this), "screenshot");
|
||||||
// set FLAG_SECURE to prevent screenshots in Release Mode
|
// set FLAG_SECURE to prevent screenshots in Release Mode
|
||||||
if (!BuildConfig.DEBUG) {
|
if ((!BuildConfig.DEBUG) && (!f.exists())) {
|
||||||
getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE);
|
getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,10 +30,13 @@ import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.model.TransactionInfo;
|
import com.m2049r.xmrwallet.model.TransactionInfo;
|
||||||
import com.m2049r.xmrwallet.model.Transfer;
|
import com.m2049r.xmrwallet.model.Transfer;
|
||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
|
import com.m2049r.xmrwallet.util.UserNotes;
|
||||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
@ -68,12 +71,23 @@ public class TxFragment extends Fragment {
|
||||||
private TextView etTxNotes;
|
private TextView etTxNotes;
|
||||||
private Button bTxNotes;
|
private Button bTxNotes;
|
||||||
|
|
||||||
|
// XMRTO stuff
|
||||||
|
private View cvXmrTo;
|
||||||
|
private TextView tvTxXmrToKey;
|
||||||
|
private TextView tvDestinationBtc;
|
||||||
|
private TextView tvTxAmountBtc;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
|
|
||||||
View view = inflater.inflate(R.layout.fragment_tx_info, container, false);
|
View view = inflater.inflate(R.layout.fragment_tx_info, container, false);
|
||||||
|
|
||||||
|
cvXmrTo = view.findViewById(R.id.cvXmrTo);
|
||||||
|
tvTxXmrToKey = (TextView) view.findViewById(R.id.tvTxXmrToKey);
|
||||||
|
tvDestinationBtc = (TextView) view.findViewById(R.id.tvDestinationBtc);
|
||||||
|
tvTxAmountBtc = (TextView) view.findViewById(R.id.tvTxAmountBtc);
|
||||||
|
|
||||||
tvTxTimestamp = (TextView) view.findViewById(R.id.tvTxTimestamp);
|
tvTxTimestamp = (TextView) view.findViewById(R.id.tvTxTimestamp);
|
||||||
tvTxId = (TextView) view.findViewById(R.id.tvTxId);
|
tvTxId = (TextView) view.findViewById(R.id.tvTxId);
|
||||||
tvTxKey = (TextView) view.findViewById(R.id.tvTxKey);
|
tvTxKey = (TextView) view.findViewById(R.id.tvTxKey);
|
||||||
|
@ -94,7 +108,16 @@ public class TxFragment extends Fragment {
|
||||||
info.notes = null; // force reload on next view
|
info.notes = null; // force reload on next view
|
||||||
bTxNotes.setEnabled(false);
|
bTxNotes.setEnabled(false);
|
||||||
etTxNotes.setEnabled(false);
|
etTxNotes.setEnabled(false);
|
||||||
activityCallback.onSetNote(info.hash, etTxNotes.getText().toString());
|
userNotes.setNote(etTxNotes.getText().toString());
|
||||||
|
activityCallback.onSetNote(info.hash, userNotes.txNotes);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
tvTxXmrToKey.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Helper.clipBoardCopy(getActivity(), getString(R.string.label_copy_xmrtokey), tvTxXmrToKey.getText().toString());
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.message_copy_xmrtokey), Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -175,12 +198,14 @@ public class TxFragment extends Fragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
TransactionInfo info = null;
|
TransactionInfo info = null;
|
||||||
|
UserNotes userNotes = null;
|
||||||
|
|
||||||
void loadNotes(TransactionInfo info) {
|
void loadNotes(TransactionInfo info) {
|
||||||
if (info.notes == null) {
|
if ((userNotes == null) || (info.notes == null)) {
|
||||||
info.notes = activityCallback.getTxNotes(info.hash);
|
info.notes = activityCallback.getTxNotes(info.hash);
|
||||||
}
|
}
|
||||||
etTxNotes.setText(info.notes);
|
userNotes = new UserNotes(info.notes);
|
||||||
|
etTxNotes.setText(userNotes.note);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setTxColour(int clr) {
|
private void setTxColour(int clr) {
|
||||||
|
@ -266,8 +291,21 @@ public class TxFragment extends Fragment {
|
||||||
tvTxTransfers.setText(sb.toString());
|
tvTxTransfers.setText(sb.toString());
|
||||||
tvDestination.setText(dstSb.toString());
|
tvDestination.setText(dstSb.toString());
|
||||||
this.info = info;
|
this.info = info;
|
||||||
|
showBtcInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void showBtcInfo() {
|
||||||
|
if (userNotes.xmrtoKey != null) {
|
||||||
|
cvXmrTo.setVisibility(View.VISIBLE);
|
||||||
|
tvTxXmrToKey.setText(userNotes.xmrtoKey);
|
||||||
|
tvDestinationBtc.setText(userNotes.xmrtoDestination);
|
||||||
|
tvTxAmountBtc.setText(userNotes.xmrtoAmount + " BTC");
|
||||||
|
} else {
|
||||||
|
cvXmrTo.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
|
@ -23,7 +23,6 @@ import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.ServiceConnection;
|
import android.content.ServiceConnection;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
|
@ -38,17 +37,18 @@ import com.m2049r.xmrwallet.data.BarcodeData;
|
||||||
import com.m2049r.xmrwallet.data.TxData;
|
import com.m2049r.xmrwallet.data.TxData;
|
||||||
import com.m2049r.xmrwallet.dialog.DonationFragment;
|
import com.m2049r.xmrwallet.dialog.DonationFragment;
|
||||||
import com.m2049r.xmrwallet.dialog.HelpFragment;
|
import com.m2049r.xmrwallet.dialog.HelpFragment;
|
||||||
|
import com.m2049r.xmrwallet.fragment.send.SendAddressWizardFragment;
|
||||||
|
import com.m2049r.xmrwallet.fragment.send.SendFragment;
|
||||||
import com.m2049r.xmrwallet.model.PendingTransaction;
|
import com.m2049r.xmrwallet.model.PendingTransaction;
|
||||||
import com.m2049r.xmrwallet.model.TransactionInfo;
|
import com.m2049r.xmrwallet.model.TransactionInfo;
|
||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
import com.m2049r.xmrwallet.model.WalletManager;
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
import com.m2049r.xmrwallet.service.WalletService;
|
import com.m2049r.xmrwallet.service.WalletService;
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
|
import com.m2049r.xmrwallet.util.UserNotes;
|
||||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
@ -465,7 +465,7 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTransactionCreated(final PendingTransaction pendingTransaction) {
|
public void onTransactionCreated(final String txTag, final PendingTransaction pendingTransaction) {
|
||||||
try {
|
try {
|
||||||
final SendFragment sendFragment = (SendFragment)
|
final SendFragment sendFragment = (SendFragment)
|
||||||
getSupportFragmentManager().findFragmentById(R.id.fragment_container);
|
getSupportFragmentManager().findFragmentById(R.id.fragment_container);
|
||||||
|
@ -477,7 +477,7 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
|
||||||
getWallet().disposePendingTransaction();
|
getWallet().disposePendingTransaction();
|
||||||
sendFragment.onCreateTransactionFailed(errorText);
|
sendFragment.onCreateTransactionFailed(errorText);
|
||||||
} else {
|
} else {
|
||||||
sendFragment.onTransactionCreated(pendingTransaction);
|
sendFragment.onTransactionCreated(txTag, pendingTransaction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -588,11 +588,11 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
|
||||||
///////////////////////////
|
///////////////////////////
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSend(String notes) {
|
public void onSend(UserNotes notes) {
|
||||||
if (mIsBound) { // no point in talking to unbound service
|
if (mIsBound) { // no point in talking to unbound service
|
||||||
Intent intent = new Intent(getApplicationContext(), WalletService.class);
|
Intent intent = new Intent(getApplicationContext(), WalletService.class);
|
||||||
intent.putExtra(WalletService.REQUEST, WalletService.REQUEST_CMD_SEND);
|
intent.putExtra(WalletService.REQUEST, WalletService.REQUEST_CMD_SEND);
|
||||||
intent.putExtra(WalletService.REQUEST_CMD_SEND_NOTES, notes);
|
intent.putExtra(WalletService.REQUEST_CMD_SEND_NOTES, notes.txNotes);
|
||||||
startService(intent);
|
startService(intent);
|
||||||
Timber.d("SEND TX request sent");
|
Timber.d("SEND TX request sent");
|
||||||
} else {
|
} else {
|
||||||
|
@ -617,11 +617,12 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPrepareSend(TxData txData) {
|
public void onPrepareSend(final String tag, final TxData txData) {
|
||||||
if (mIsBound) { // no point in talking to unbound service
|
if (mIsBound) { // no point in talking to unbound service
|
||||||
Intent intent = new Intent(getApplicationContext(), WalletService.class);
|
Intent intent = new Intent(getApplicationContext(), WalletService.class);
|
||||||
intent.putExtra(WalletService.REQUEST, WalletService.REQUEST_CMD_TX);
|
intent.putExtra(WalletService.REQUEST, WalletService.REQUEST_CMD_TX);
|
||||||
intent.putExtra(WalletService.REQUEST_CMD_TX_DATA, txData);
|
intent.putExtra(WalletService.REQUEST_CMD_TX_DATA, txData);
|
||||||
|
intent.putExtra(WalletService.REQUEST_CMD_TX_TAG, tag);
|
||||||
startService(intent);
|
startService(intent);
|
||||||
Timber.d("CREATE TX request sent");
|
Timber.d("CREATE TX request sent");
|
||||||
} else {
|
} else {
|
||||||
|
@ -694,6 +695,7 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisposeRequest() {
|
public void onDisposeRequest() {
|
||||||
|
//TODO consider doing this through the WalletService to avoid concurrency issues
|
||||||
getWallet().disposePendingTransaction();
|
getWallet().disposePendingTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@ package com.m2049r.xmrwallet.data;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
|
import com.m2049r.xmrwallet.util.BitcoinAddressValidator;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -34,7 +36,7 @@ public class BarcodeData {
|
||||||
static final String BTC_AMOUNT = "amount";
|
static final String BTC_AMOUNT = "amount";
|
||||||
|
|
||||||
public enum Asset {
|
public enum Asset {
|
||||||
XMR
|
XMR, BTC
|
||||||
}
|
}
|
||||||
|
|
||||||
public Asset asset = null;
|
public Asset asset = null;
|
||||||
|
@ -67,6 +69,14 @@ public class BarcodeData {
|
||||||
if (bcData == null) {
|
if (bcData == null) {
|
||||||
bcData = parseMoneroNaked(qrCode);
|
bcData = parseMoneroNaked(qrCode);
|
||||||
}
|
}
|
||||||
|
// check for btc uri
|
||||||
|
if (bcData == null) {
|
||||||
|
bcData = parseBitcoinUri(qrCode);
|
||||||
|
}
|
||||||
|
// check for naked btc addres
|
||||||
|
if (bcData == null) {
|
||||||
|
bcData = parseBitcoinNaked(qrCode);
|
||||||
|
}
|
||||||
return bcData;
|
return bcData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,4 +144,57 @@ public class BarcodeData {
|
||||||
|
|
||||||
return new BarcodeData(Asset.XMR, address);
|
return new BarcodeData(Asset.XMR, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bitcoin:mpQ84J43EURZHkCnXbyQ4PpNDLLBqdsMW2?amount=0.01
|
||||||
|
static public BarcodeData parseBitcoinUri(String uri) {
|
||||||
|
Timber.d("parseBitcoinUri=%s", uri);
|
||||||
|
|
||||||
|
if (uri == null) return null;
|
||||||
|
|
||||||
|
if (!uri.startsWith(BTC_SCHEME)) return null;
|
||||||
|
|
||||||
|
String noScheme = uri.substring(BTC_SCHEME.length());
|
||||||
|
Uri bitcoin = Uri.parse(noScheme);
|
||||||
|
Map<String, String> parms = new HashMap<>();
|
||||||
|
String query = bitcoin.getQuery();
|
||||||
|
if (query != null) {
|
||||||
|
String[] args = query.split("&");
|
||||||
|
for (String arg : args) {
|
||||||
|
String[] namevalue = arg.split("=");
|
||||||
|
if (namevalue.length == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
parms.put(Uri.decode(namevalue[0]).toLowerCase(),
|
||||||
|
namevalue.length > 1 ? Uri.decode(namevalue[1]) : "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String address = bitcoin.getPath();
|
||||||
|
String amount = parms.get(BTC_AMOUNT);
|
||||||
|
if (amount != null) {
|
||||||
|
try {
|
||||||
|
Double.parseDouble(amount);
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
Timber.d(ex.getLocalizedMessage());
|
||||||
|
return null; // we have an amount but its not a number!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!BitcoinAddressValidator.validate(address, WalletManager.getInstance().isTestNet())) {
|
||||||
|
Timber.d("address invalid");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new BarcodeData(BarcodeData.Asset.BTC, address, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
static public BarcodeData parseBitcoinNaked(String address) {
|
||||||
|
Timber.d("parseBitcoinNaked=%s", address);
|
||||||
|
|
||||||
|
if (address == null) return null;
|
||||||
|
|
||||||
|
if (!BitcoinAddressValidator.validate(address, WalletManager.getInstance().isTestNet())) {
|
||||||
|
Timber.d("address invalid");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BarcodeData(BarcodeData.Asset.BTC, address);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -20,36 +20,38 @@ import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.model.PendingTransaction;
|
import com.m2049r.xmrwallet.model.PendingTransaction;
|
||||||
|
import com.m2049r.xmrwallet.util.UserNotes;
|
||||||
|
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
// https://stackoverflow.com/questions/2139134/how-to-send-an-object-from-one-android-activity-to-another-using-intents
|
// https://stackoverflow.com/questions/2139134/how-to-send-an-object-from-one-android-activity-to-another-using-intents
|
||||||
public class TxData implements Parcelable {
|
public class TxData implements Parcelable {
|
||||||
|
|
||||||
|
public TxData() {
|
||||||
|
}
|
||||||
|
|
||||||
public TxData(TxData txData) {
|
public TxData(TxData txData) {
|
||||||
this.dst_addr = txData.dst_addr;
|
this.dstAddr = txData.dstAddr;
|
||||||
this.paymentId = txData.paymentId;
|
this.paymentId = txData.paymentId;
|
||||||
this.amount = txData.amount;
|
this.amount = txData.amount;
|
||||||
this.mixin = txData.mixin;
|
this.mixin = txData.mixin;
|
||||||
this.priority = txData.priority;
|
this.priority = txData.priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TxData(String dst_addr,
|
public TxData(String dstAddr,
|
||||||
String paymentId,
|
String paymentId,
|
||||||
long amount,
|
long amount,
|
||||||
int mixin,
|
int mixin,
|
||||||
PendingTransaction.Priority priority) {
|
PendingTransaction.Priority priority) {
|
||||||
this.dst_addr = dst_addr;
|
this.dstAddr = dstAddr;
|
||||||
this.paymentId = paymentId;
|
this.paymentId = paymentId;
|
||||||
this.amount = amount;
|
this.amount = amount;
|
||||||
this.mixin = mixin;
|
this.mixin = mixin;
|
||||||
this.priority = priority;
|
this.priority = priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getFee() {
|
|
||||||
return 0L;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDestinationAddress() {
|
public String getDestinationAddress() {
|
||||||
return dst_addr;
|
return dstAddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPaymentId() {
|
public String getPaymentId() {
|
||||||
|
@ -68,15 +70,45 @@ public class TxData implements Parcelable {
|
||||||
return priority;
|
return priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
final private String dst_addr;
|
public void setDestinationAddress(String dstAddr) {
|
||||||
final private String paymentId;
|
this.dstAddr = dstAddr;
|
||||||
final private long amount;
|
}
|
||||||
final private int mixin;
|
|
||||||
final private PendingTransaction.Priority priority;
|
public void setPaymentId(String paymentId) {
|
||||||
|
this.paymentId = paymentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAmount(long amount) {
|
||||||
|
this.amount = amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMixin(int mixin) {
|
||||||
|
this.mixin = mixin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPriority(PendingTransaction.Priority priority) {
|
||||||
|
this.priority = priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserNotes getUserNotes() {
|
||||||
|
return userNotes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserNotes(UserNotes userNotes) {
|
||||||
|
this.userNotes = userNotes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String dstAddr;
|
||||||
|
private String paymentId;
|
||||||
|
private long amount;
|
||||||
|
private int mixin;
|
||||||
|
private PendingTransaction.Priority priority;
|
||||||
|
|
||||||
|
private UserNotes userNotes;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeToParcel(Parcel out, int flags) {
|
public void writeToParcel(Parcel out, int flags) {
|
||||||
out.writeString(dst_addr);
|
out.writeString(dstAddr);
|
||||||
out.writeString(paymentId);
|
out.writeString(paymentId);
|
||||||
out.writeLong(amount);
|
out.writeLong(amount);
|
||||||
out.writeInt(mixin);
|
out.writeInt(mixin);
|
||||||
|
@ -94,8 +126,8 @@ public class TxData implements Parcelable {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private TxData(Parcel in) {
|
protected TxData(Parcel in) {
|
||||||
dst_addr = in.readString();
|
dstAddr = in.readString();
|
||||||
paymentId = in.readString();
|
paymentId = in.readString();
|
||||||
amount = in.readLong();
|
amount = in.readLong();
|
||||||
mixin = in.readInt();
|
mixin = in.readInt();
|
||||||
|
@ -111,8 +143,8 @@ public class TxData implements Parcelable {
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuffer sb = new StringBuffer();
|
StringBuffer sb = new StringBuffer();
|
||||||
sb.append("dst_addr:");
|
sb.append("dstAddr:");
|
||||||
sb.append(dst_addr);
|
sb.append(dstAddr);
|
||||||
sb.append(",paymentId:");
|
sb.append(",paymentId:");
|
||||||
sb.append(paymentId);
|
sb.append(paymentId);
|
||||||
sb.append(",amount:");
|
sb.append(",amount:");
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 m2049r
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.data;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.model.PendingTransaction;
|
||||||
|
|
||||||
|
public class TxDataBtc extends TxData {
|
||||||
|
|
||||||
|
private String xmrtoUuid;
|
||||||
|
private String btcAddress;
|
||||||
|
private double btcAmount;
|
||||||
|
|
||||||
|
public TxDataBtc() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TxDataBtc(TxDataBtc txDataBtc) {
|
||||||
|
super(txDataBtc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getXmrtoUuid() {
|
||||||
|
return xmrtoUuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setXmrtoUuid(String xmrtoUuid) {
|
||||||
|
this.xmrtoUuid = xmrtoUuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBtcAddress() {
|
||||||
|
return btcAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBtcAddress(String btcAddress) {
|
||||||
|
this.btcAddress = btcAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getBtcAmount() {
|
||||||
|
return btcAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBtcAmount(double btcAmount) {
|
||||||
|
this.btcAmount = btcAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel out, int flags) {
|
||||||
|
super.writeToParcel(out, flags);
|
||||||
|
out.writeString(xmrtoUuid);
|
||||||
|
out.writeString(btcAddress);
|
||||||
|
out.writeDouble(btcAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is used to regenerate your object. All Parcelables must have a CREATOR that implements these two methods
|
||||||
|
public static final Creator<TxDataBtc> CREATOR = new Creator<TxDataBtc>() {
|
||||||
|
public TxDataBtc createFromParcel(Parcel in) {
|
||||||
|
return new TxDataBtc(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TxDataBtc[] newArray(int size) {
|
||||||
|
return new TxDataBtc[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
protected TxDataBtc(Parcel in) {
|
||||||
|
super(in);
|
||||||
|
xmrtoUuid = in.readString();
|
||||||
|
btcAddress = in.readString();
|
||||||
|
btcAmount = in.readDouble();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuffer sb = new StringBuffer();
|
||||||
|
sb.append(",xmrtoUuid:");
|
||||||
|
sb.append(xmrtoUuid);
|
||||||
|
sb.append(",btcAddress:");
|
||||||
|
sb.append(btcAddress);
|
||||||
|
sb.append(",btcAmount:");
|
||||||
|
sb.append(btcAmount);
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,13 +14,14 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.m2049r.xmrwallet;
|
package com.m2049r.xmrwallet.fragment.send;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.design.widget.TextInputLayout;
|
import android.support.design.widget.TextInputLayout;
|
||||||
import android.support.v7.widget.CardView;
|
import android.support.v7.widget.CardView;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
|
import android.text.Html;
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
|
@ -32,9 +33,13 @@ import android.widget.Button;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.R;
|
||||||
import com.m2049r.xmrwallet.data.BarcodeData;
|
import com.m2049r.xmrwallet.data.BarcodeData;
|
||||||
|
import com.m2049r.xmrwallet.data.TxData;
|
||||||
|
import com.m2049r.xmrwallet.data.TxDataBtc;
|
||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
import com.m2049r.xmrwallet.model.WalletManager;
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
|
import com.m2049r.xmrwallet.util.BitcoinAddressValidator;
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
@ -56,12 +61,12 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Listener {
|
public interface Listener {
|
||||||
void setAddress(final String address);
|
|
||||||
|
|
||||||
void setPaymentId(final String paymentId);
|
|
||||||
|
|
||||||
void setBarcodeData(BarcodeData data);
|
void setBarcodeData(BarcodeData data);
|
||||||
|
|
||||||
|
void setMode(SendFragment.Mode mode);
|
||||||
|
|
||||||
|
TxData getTxData();
|
||||||
}
|
}
|
||||||
|
|
||||||
private EditText etDummy;
|
private EditText etDummy;
|
||||||
|
@ -71,6 +76,8 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
||||||
private CardView cvScan;
|
private CardView cvScan;
|
||||||
private View tvPaymentIdIntegrated;
|
private View tvPaymentIdIntegrated;
|
||||||
private View llPaymentId;
|
private View llPaymentId;
|
||||||
|
private TextView tvXmrTo;
|
||||||
|
private View llXmrTo;
|
||||||
|
|
||||||
OnScanListener onScanListener;
|
OnScanListener onScanListener;
|
||||||
|
|
||||||
|
@ -89,6 +96,9 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
||||||
|
|
||||||
tvPaymentIdIntegrated = view.findViewById(R.id.tvPaymentIdIntegrated);
|
tvPaymentIdIntegrated = view.findViewById(R.id.tvPaymentIdIntegrated);
|
||||||
llPaymentId = view.findViewById(R.id.llPaymentId);
|
llPaymentId = view.findViewById(R.id.llPaymentId);
|
||||||
|
llXmrTo = view.findViewById(R.id.llXmrTo);
|
||||||
|
tvXmrTo = (TextView) view.findViewById(R.id.tvXmrTo);
|
||||||
|
tvXmrTo.setText(Html.fromHtml(getString(R.string.info_xmrto)));
|
||||||
|
|
||||||
etAddress = (TextInputLayout) view.findViewById(R.id.etAddress);
|
etAddress = (TextInputLayout) view.findViewById(R.id.etAddress);
|
||||||
etAddress.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
etAddress.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||||
|
@ -113,12 +123,25 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
||||||
public void afterTextChanged(Editable editable) {
|
public void afterTextChanged(Editable editable) {
|
||||||
etAddress.setError(null);
|
etAddress.setError(null);
|
||||||
if (isIntegratedAddress()) {
|
if (isIntegratedAddress()) {
|
||||||
|
Timber.d("isIntegratedAddress");
|
||||||
etPaymentId.getEditText().getText().clear();
|
etPaymentId.getEditText().getText().clear();
|
||||||
llPaymentId.setVisibility(View.GONE);
|
llPaymentId.setVisibility(View.INVISIBLE);
|
||||||
tvPaymentIdIntegrated.setVisibility(View.VISIBLE);
|
tvPaymentIdIntegrated.setVisibility(View.VISIBLE);
|
||||||
} else { // we don't
|
llXmrTo.setVisibility(View.INVISIBLE);
|
||||||
|
sendListener.setMode(SendFragment.Mode.XMR);
|
||||||
|
} else if (isBitcoinAddress()) {
|
||||||
|
Timber.d("isBitcoinAddress");
|
||||||
|
etPaymentId.getEditText().getText().clear();
|
||||||
|
llPaymentId.setVisibility(View.INVISIBLE);
|
||||||
|
tvPaymentIdIntegrated.setVisibility(View.INVISIBLE);
|
||||||
|
llXmrTo.setVisibility(View.VISIBLE);
|
||||||
|
sendListener.setMode(SendFragment.Mode.BTC);
|
||||||
|
} else {
|
||||||
|
Timber.d("isStandardAddress");
|
||||||
llPaymentId.setVisibility(View.VISIBLE);
|
llPaymentId.setVisibility(View.VISIBLE);
|
||||||
tvPaymentIdIntegrated.setVisibility(View.GONE);
|
tvPaymentIdIntegrated.setVisibility(View.INVISIBLE);
|
||||||
|
llXmrTo.setVisibility(View.INVISIBLE);
|
||||||
|
sendListener.setMode(SendFragment.Mode.XMR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,13 +211,14 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
||||||
|
|
||||||
private boolean checkAddressNoError() {
|
private boolean checkAddressNoError() {
|
||||||
String address = etAddress.getEditText().getText().toString();
|
String address = etAddress.getEditText().getText().toString();
|
||||||
return Wallet.isAddressValid(address);
|
return Wallet.isAddressValid(address)
|
||||||
|
|| BitcoinAddressValidator.validate(address, WalletManager.getInstance().isTestNet());
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkAddress() {
|
private boolean checkAddress() {
|
||||||
boolean ok = checkAddressNoError();
|
boolean ok = checkAddressNoError();
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
etAddress.setError(getString(R.string.send_qr_address_invalid));
|
etAddress.setError(getString(R.string.send_address_invalid));
|
||||||
} else {
|
} else {
|
||||||
etAddress.setError(null);
|
etAddress.setError(null);
|
||||||
}
|
}
|
||||||
|
@ -203,7 +227,16 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
||||||
|
|
||||||
private boolean isIntegratedAddress() {
|
private boolean isIntegratedAddress() {
|
||||||
String address = etAddress.getEditText().getText().toString();
|
String address = etAddress.getEditText().getText().toString();
|
||||||
return (address.length() == INTEGRATED_ADDRESS_LENGTH) && Wallet.isAddressValid(address);
|
return (address.length() == INTEGRATED_ADDRESS_LENGTH)
|
||||||
|
&& Wallet.isAddressValid(address, WalletManager.getInstance().isTestNet());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBitcoinAddress() {
|
||||||
|
String address = etAddress.getEditText().getText().toString();
|
||||||
|
if ((address.length() >= 27) && (address.length() <= 34))
|
||||||
|
return BitcoinAddressValidator.validate(address, WalletManager.getInstance().isTestNet());
|
||||||
|
else
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkPaymentId() {
|
private boolean checkPaymentId() {
|
||||||
|
@ -235,8 +268,15 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
||||||
}
|
}
|
||||||
if (!ok) return false;
|
if (!ok) return false;
|
||||||
if (sendListener != null) {
|
if (sendListener != null) {
|
||||||
sendListener.setAddress(etAddress.getEditText().getText().toString());
|
TxData txData = sendListener.getTxData();
|
||||||
sendListener.setPaymentId(etPaymentId.getEditText().getText().toString());
|
if (isBitcoinAddress()) {
|
||||||
|
((TxDataBtc) txData).setBtcAddress(etAddress.getEditText().getText().toString());
|
||||||
|
txData.setDestinationAddress(null);
|
||||||
|
txData.setPaymentId("");
|
||||||
|
} else {
|
||||||
|
txData.setDestinationAddress(etAddress.getEditText().getText().toString());
|
||||||
|
txData.setPaymentId(etPaymentId.getEditText().getText().toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.m2049r.xmrwallet;
|
package com.m2049r.xmrwallet.fragment.send;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
@ -22,10 +22,12 @@ import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.R;
|
||||||
import com.m2049r.xmrwallet.data.BarcodeData;
|
import com.m2049r.xmrwallet.data.BarcodeData;
|
||||||
import com.m2049r.xmrwallet.widget.ExchangeTextView;
|
import com.m2049r.xmrwallet.data.TxData;
|
||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
|
import com.m2049r.xmrwallet.widget.ExchangeTextView;
|
||||||
import com.m2049r.xmrwallet.widget.NumberPadView;
|
import com.m2049r.xmrwallet.widget.NumberPadView;
|
||||||
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
@ -48,7 +50,7 @@ public class SendAmountWizardFragment extends SendWizardFragment {
|
||||||
interface Listener {
|
interface Listener {
|
||||||
SendFragment.Listener getActivityCallback();
|
SendFragment.Listener getActivityCallback();
|
||||||
|
|
||||||
void setAmount(final long amount);
|
TxData getTxData();
|
||||||
|
|
||||||
BarcodeData popBarcodeData();
|
BarcodeData popBarcodeData();
|
||||||
}
|
}
|
||||||
|
@ -99,9 +101,9 @@ public class SendAmountWizardFragment extends SendWizardFragment {
|
||||||
if (sendListener != null) {
|
if (sendListener != null) {
|
||||||
String xmr = evAmount.getAmount();
|
String xmr = evAmount.getAmount();
|
||||||
if (xmr != null) {
|
if (xmr != null) {
|
||||||
sendListener.setAmount(Wallet.getAmountFromString(xmr));
|
sendListener.getTxData().setAmount(Wallet.getAmountFromString(xmr));
|
||||||
} else {
|
} else {
|
||||||
sendListener.setAmount(0L);
|
sendListener.getTxData().setAmount(0L);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
|
@ -0,0 +1,261 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 m2049r
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.fragment.send;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.text.Html;
|
||||||
|
import android.text.Spanned;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.R;
|
||||||
|
import com.m2049r.xmrwallet.data.BarcodeData;
|
||||||
|
import com.m2049r.xmrwallet.data.TxDataBtc;
|
||||||
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
|
import com.m2049r.xmrwallet.util.OkHttpClientSingleton;
|
||||||
|
import com.m2049r.xmrwallet.widget.ExchangeBtcTextView;
|
||||||
|
import com.m2049r.xmrwallet.widget.NumberPadView;
|
||||||
|
import com.m2049r.xmrwallet.widget.SendProgressView;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.XmrToError;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.XmrToException;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.QueryOrderParameters;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.XmrToApi;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.XmrToCallback;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.network.XmrToApiImpl;
|
||||||
|
|
||||||
|
import java.text.NumberFormat;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import okhttp3.HttpUrl;
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
public class SendBtcAmountWizardFragment extends SendWizardFragment {
|
||||||
|
|
||||||
|
public static SendBtcAmountWizardFragment newInstance(SendAmountWizardFragment.Listener listener) {
|
||||||
|
SendBtcAmountWizardFragment instance = new SendBtcAmountWizardFragment();
|
||||||
|
instance.setSendListener(listener);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
SendAmountWizardFragment.Listener sendListener;
|
||||||
|
|
||||||
|
public SendBtcAmountWizardFragment setSendListener(SendAmountWizardFragment.Listener listener) {
|
||||||
|
this.sendListener = listener;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TextView tvFunds;
|
||||||
|
private ExchangeBtcTextView evAmount;
|
||||||
|
private NumberPadView numberPad;
|
||||||
|
|
||||||
|
private TextView tvXmrToParms;
|
||||||
|
private SendProgressView evParams;
|
||||||
|
private View llXmrToParms;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
|
||||||
|
Timber.d("onCreateView() %s", (String.valueOf(savedInstanceState)));
|
||||||
|
|
||||||
|
sendListener = (SendAmountWizardFragment.Listener) getParentFragment();
|
||||||
|
|
||||||
|
View view = inflater.inflate(R.layout.fragment_send_btc_amount, container, false);
|
||||||
|
|
||||||
|
tvFunds = (TextView) view.findViewById(R.id.tvFunds);
|
||||||
|
|
||||||
|
evParams = (SendProgressView) view.findViewById(R.id.evXmrToParms);
|
||||||
|
llXmrToParms = view.findViewById(R.id.llXmrToParms);
|
||||||
|
|
||||||
|
tvXmrToParms = (TextView) view.findViewById(R.id.tvXmrToParms);
|
||||||
|
|
||||||
|
evAmount = (ExchangeBtcTextView) view.findViewById(R.id.evAmount);
|
||||||
|
numberPad = (NumberPadView) view.findViewById(R.id.numberPad);
|
||||||
|
numberPad.setListener(evAmount);
|
||||||
|
|
||||||
|
Helper.hideKeyboard(getActivity());
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onValidateFields() {
|
||||||
|
if (!evAmount.validate(maxBtc, minBtc)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (sendListener != null) {
|
||||||
|
TxDataBtc txDataBtc = (TxDataBtc) sendListener.getTxData();
|
||||||
|
String btcString = evAmount.getAmount();
|
||||||
|
if (btcString != null) {
|
||||||
|
try {
|
||||||
|
double btc = Double.parseDouble(btcString);
|
||||||
|
Timber.d("setAmount %f", btc);
|
||||||
|
txDataBtc.setBtcAmount(btc);
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
Timber.d(ex.getLocalizedMessage());
|
||||||
|
txDataBtc.setBtcAmount(0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
txDataBtc.setBtcAmount(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
double maxBtc = 0;
|
||||||
|
double minBtc = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPauseFragment() {
|
||||||
|
llXmrToParms.setVisibility(View.INVISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResumeFragment() {
|
||||||
|
super.onResumeFragment();
|
||||||
|
Timber.d("onResumeFragment()");
|
||||||
|
Helper.hideKeyboard(getActivity());
|
||||||
|
final long funds = getTotalFunds();
|
||||||
|
tvFunds.setText(getString(R.string.send_available,
|
||||||
|
Wallet.getDisplayAmount(funds)));
|
||||||
|
if ((evAmount.getAmount() == null) || evAmount.getAmount().isEmpty()) {
|
||||||
|
final BarcodeData data = sendListener.popBarcodeData();
|
||||||
|
if ((data != null) && (data.amount != null)) {
|
||||||
|
evAmount.setAmount(data.amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
callXmrTo();
|
||||||
|
}
|
||||||
|
|
||||||
|
long getTotalFunds() {
|
||||||
|
return sendListener.getActivityCallback().getTotalFunds();
|
||||||
|
}
|
||||||
|
|
||||||
|
private QueryOrderParameters orderParameters = null;
|
||||||
|
|
||||||
|
private void processOrderParms(final QueryOrderParameters orderParameters) {
|
||||||
|
this.orderParameters = orderParameters;
|
||||||
|
getView().post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
evAmount.setRate(1.0d / orderParameters.getPrice());
|
||||||
|
NumberFormat df = NumberFormat.getInstance(Locale.US);
|
||||||
|
df.setMaximumFractionDigits(6);
|
||||||
|
String min = df.format(orderParameters.getLowerLimit());
|
||||||
|
String max = df.format(orderParameters.getUpperLimit());
|
||||||
|
String rate = df.format(orderParameters.getPrice());
|
||||||
|
Spanned xmrParmText = Html.fromHtml(getString(R.string.info_send_xmrto_parms, min, max, rate));
|
||||||
|
if (orderParameters.isZeroConfEnabled()) {
|
||||||
|
String zeroConf = df.format(orderParameters.getZeroConfMaxAmount());
|
||||||
|
Spanned zeroConfText = Html.fromHtml(getString(R.string.info_send_xmrto_zeroconf, zeroConf));
|
||||||
|
xmrParmText = (Spanned) TextUtils.concat(xmrParmText, " ", zeroConfText);
|
||||||
|
}
|
||||||
|
tvXmrToParms.setText(xmrParmText);
|
||||||
|
maxBtc = orderParameters.getUpperLimit();
|
||||||
|
minBtc = orderParameters.getLowerLimit();
|
||||||
|
Timber.d("minBtc=%f / maxBtc=%f", minBtc, maxBtc);
|
||||||
|
|
||||||
|
final long funds = getTotalFunds();
|
||||||
|
double availableXmr = 1.0 * funds / 1000000000000L;
|
||||||
|
maxBtc = Math.min(maxBtc, availableXmr * orderParameters.getPrice());
|
||||||
|
|
||||||
|
String availBtcString = df.format(availableXmr * orderParameters.getPrice());
|
||||||
|
String availXmrString = df.format(availableXmr);
|
||||||
|
tvFunds.setText(getString(R.string.send_available_btc,
|
||||||
|
availXmrString,
|
||||||
|
availBtcString));
|
||||||
|
llXmrToParms.setVisibility(View.VISIBLE);
|
||||||
|
evParams.hideProgress();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processOrderParmsError(final Exception ex) {
|
||||||
|
evAmount.setRate(0);
|
||||||
|
orderParameters = null;
|
||||||
|
maxBtc = 0;
|
||||||
|
minBtc = 0;
|
||||||
|
Timber.e(ex);
|
||||||
|
getView().post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (ex instanceof XmrToException) {
|
||||||
|
XmrToException xmrEx = (XmrToException) ex;
|
||||||
|
XmrToError xmrErr = xmrEx.getError();
|
||||||
|
if (xmrErr != null) {
|
||||||
|
if (xmrErr.isRetryable()) {
|
||||||
|
evParams.showMessage(xmrErr.getErrorId().toString(), xmrErr.getErrorMsg(),
|
||||||
|
getString(R.string.text_retry));
|
||||||
|
evParams.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
evParams.setOnClickListener(null);
|
||||||
|
callXmrTo();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
evParams.showMessage(xmrErr.getErrorId().toString(), xmrErr.getErrorMsg(),
|
||||||
|
getString(R.string.text_noretry));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
evParams.showMessage(getString(R.string.label_generic_xmrto_error),
|
||||||
|
getString(R.string.text_generic_xmrto_error, xmrEx.getCode()),
|
||||||
|
getString(R.string.text_noretry));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
evParams.showMessage(getString(R.string.label_generic_xmrto_error),
|
||||||
|
ex.getLocalizedMessage(),
|
||||||
|
getString(R.string.text_noretry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void callXmrTo() {
|
||||||
|
evParams.showProgress(getString(R.string.label_send_progress_queryparms));
|
||||||
|
getXmrToApi().queryOrderParameters(new XmrToCallback<QueryOrderParameters>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(final QueryOrderParameters orderParameters) {
|
||||||
|
processOrderParms(orderParameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(final Exception e) {
|
||||||
|
processOrderParmsError(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private XmrToApi xmrToApi = null;
|
||||||
|
|
||||||
|
private final XmrToApi getXmrToApi() {
|
||||||
|
if (xmrToApi == null) {
|
||||||
|
synchronized (this) {
|
||||||
|
if (xmrToApi == null) {
|
||||||
|
xmrToApi = new XmrToApiImpl(OkHttpClientSingleton.getOkHttpClient(),
|
||||||
|
Helper.getXmrToBaseUrl());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return xmrToApi;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,680 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 m2049r
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.fragment.send;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.support.design.widget.TextInputLayout;
|
||||||
|
import android.text.Editable;
|
||||||
|
import android.text.TextWatcher;
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.inputmethod.EditorInfo;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.R;
|
||||||
|
import com.m2049r.xmrwallet.data.TxData;
|
||||||
|
import com.m2049r.xmrwallet.data.TxDataBtc;
|
||||||
|
import com.m2049r.xmrwallet.model.PendingTransaction;
|
||||||
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
|
import com.m2049r.xmrwallet.util.OkHttpClientSingleton;
|
||||||
|
import com.m2049r.xmrwallet.widget.SendProgressView;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.XmrToError;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.XmrToException;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.CreateOrder;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.QueryOrderStatus;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.XmrToApi;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.XmrToCallback;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.network.XmrToApiImpl;
|
||||||
|
|
||||||
|
import java.text.NumberFormat;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import okhttp3.HttpUrl;
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
public class SendBtcConfirmWizardFragment extends SendWizardFragment implements SendConfirm {
|
||||||
|
private final int QUERY_INTERVAL = 500;//ms
|
||||||
|
|
||||||
|
public static SendBtcConfirmWizardFragment newInstance(SendConfirmWizardFragment.Listener listener) {
|
||||||
|
SendBtcConfirmWizardFragment instance = new SendBtcConfirmWizardFragment();
|
||||||
|
instance.setSendListener(listener);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
SendConfirmWizardFragment.Listener sendListener;
|
||||||
|
|
||||||
|
public SendBtcConfirmWizardFragment setSendListener(SendConfirmWizardFragment.Listener listener) {
|
||||||
|
this.sendListener = listener;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private View llStageA;
|
||||||
|
private SendProgressView evStageA;
|
||||||
|
private View llStageB;
|
||||||
|
private SendProgressView evStageB;
|
||||||
|
private View llStageC;
|
||||||
|
private SendProgressView evStageC;
|
||||||
|
private TextView tvTxBtcAmount;
|
||||||
|
private TextView tvTxBtcRate;
|
||||||
|
private TextView tvTxBtcAddress;
|
||||||
|
private TextView tvTxXmrToKey;
|
||||||
|
private TextView tvTxFee;
|
||||||
|
private TextView tvTxTotal;
|
||||||
|
private View llConfirmSend;
|
||||||
|
private Button bSend;
|
||||||
|
private View pbProgressSend;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
|
||||||
|
Timber.d("onCreateView(%s)", (String.valueOf(savedInstanceState)));
|
||||||
|
|
||||||
|
View view = inflater.inflate(
|
||||||
|
R.layout.fragment_send_btc_confirm, container, false);
|
||||||
|
|
||||||
|
tvTxBtcAddress = (TextView) view.findViewById(R.id.tvTxBtcAddress);
|
||||||
|
tvTxBtcAmount = ((TextView) view.findViewById(R.id.tvTxBtcAmount));
|
||||||
|
tvTxBtcRate = (TextView) view.findViewById(R.id.tvTxBtcRate);
|
||||||
|
tvTxXmrToKey = (TextView) view.findViewById(R.id.tvTxXmrToKey);
|
||||||
|
|
||||||
|
tvTxFee = (TextView) view.findViewById(R.id.tvTxFee);
|
||||||
|
tvTxTotal = (TextView) view.findViewById(R.id.tvTxTotal);
|
||||||
|
|
||||||
|
|
||||||
|
llStageA = view.findViewById(R.id.llStageA);
|
||||||
|
evStageA = (SendProgressView) view.findViewById(R.id.evStageA);
|
||||||
|
llStageB = view.findViewById(R.id.llStageB);
|
||||||
|
evStageB = (SendProgressView) view.findViewById(R.id.evStageB);
|
||||||
|
llStageC = view.findViewById(R.id.llStageC);
|
||||||
|
evStageC = (SendProgressView) view.findViewById(R.id.evStageC);
|
||||||
|
|
||||||
|
tvTxXmrToKey.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Helper.clipBoardCopy(getActivity(), getString(R.string.label_copy_xmrtokey), tvTxXmrToKey.getText().toString());
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.message_copy_xmrtokey), Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
llConfirmSend = view.findViewById(R.id.llConfirmSend);
|
||||||
|
pbProgressSend = view.findViewById(R.id.pbProgressSend);
|
||||||
|
|
||||||
|
bSend = (Button) view.findViewById(R.id.bSend);
|
||||||
|
bSend.setEnabled(false);
|
||||||
|
|
||||||
|
bSend.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Timber.d("bSend.setOnClickListener");
|
||||||
|
bSend.setEnabled(false);
|
||||||
|
preSend();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
int inProgress = 0;
|
||||||
|
final static int STAGE_X = 0;
|
||||||
|
final static int STAGE_A = 1;
|
||||||
|
final static int STAGE_B = 2;
|
||||||
|
final static int STAGE_C = 3;
|
||||||
|
|
||||||
|
private void showProgress(int stage, String progressText) {
|
||||||
|
Timber.d("showProgress(%d)", stage);
|
||||||
|
inProgress = stage;
|
||||||
|
switch (stage) {
|
||||||
|
case STAGE_A:
|
||||||
|
evStageA.showProgress(progressText);
|
||||||
|
break;
|
||||||
|
case STAGE_B:
|
||||||
|
evStageB.showProgress(progressText);
|
||||||
|
break;
|
||||||
|
case STAGE_C:
|
||||||
|
evStageC.showProgress(progressText);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("unknown stage " + stage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void hideProgress() {
|
||||||
|
Timber.d("hideProgress(%d)", inProgress);
|
||||||
|
switch (inProgress) {
|
||||||
|
case STAGE_A:
|
||||||
|
evStageA.hideProgress();
|
||||||
|
llStageA.setVisibility(View.VISIBLE);
|
||||||
|
break;
|
||||||
|
case STAGE_B:
|
||||||
|
evStageB.hideProgress();
|
||||||
|
llStageB.setVisibility(View.VISIBLE);
|
||||||
|
break;
|
||||||
|
case STAGE_C:
|
||||||
|
evStageC.hideProgress();
|
||||||
|
llStageC.setVisibility(View.VISIBLE);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("unknown stage " + inProgress);
|
||||||
|
}
|
||||||
|
inProgress = STAGE_X;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showStageError(String code, String message, String solution) {
|
||||||
|
switch (inProgress) {
|
||||||
|
case STAGE_A:
|
||||||
|
evStageA.showMessage(code, message, solution);
|
||||||
|
break;
|
||||||
|
case STAGE_B:
|
||||||
|
evStageB.showMessage(code, message, solution);
|
||||||
|
break;
|
||||||
|
case STAGE_C:
|
||||||
|
evStageC.showMessage(code, message, solution);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("unknown stage");
|
||||||
|
}
|
||||||
|
inProgress = STAGE_X;
|
||||||
|
}
|
||||||
|
|
||||||
|
PendingTransaction pendingTransaction = null;
|
||||||
|
|
||||||
|
void send() {
|
||||||
|
Timber.d("SEND @%d", sendCountdown);
|
||||||
|
if (sendCountdown <= 0) {
|
||||||
|
Timber.i("User waited too long in password dialog.");
|
||||||
|
Toast.makeText(getContext(), getString(R.string.send_xmrto_timeout), Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendListener.getTxData().getUserNotes().setXmrtoStatus(xmrtoStatus);
|
||||||
|
((TxDataBtc) sendListener.getTxData()).setXmrtoUuid(xmrtoStatus.getUuid());
|
||||||
|
// TODO make method in TxDataBtc to set both of the above in one go
|
||||||
|
sendListener.commitTransaction();
|
||||||
|
pbProgressSend.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendFailed() {
|
||||||
|
Timber.e("SEND FAILED");
|
||||||
|
pbProgressSend.setVisibility(View.INVISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
// callback from wallet when PendingTransaction created (started by prepareSend() here
|
||||||
|
public void transactionCreated(final String txTag, final PendingTransaction pendingTransaction) {
|
||||||
|
if (isResumed
|
||||||
|
&& (inProgress == STAGE_C)
|
||||||
|
&& (xmrtoStatus != null)
|
||||||
|
&& (xmrtoStatus.isCreated()
|
||||||
|
&& (xmrtoStatus.getUuid().equals(txTag)))) {
|
||||||
|
this.pendingTransaction = pendingTransaction;
|
||||||
|
getView().post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
hideProgress();
|
||||||
|
tvTxFee.setText(Wallet.getDisplayAmount(pendingTransaction.getFee()));
|
||||||
|
tvTxTotal.setText(Wallet.getDisplayAmount(
|
||||||
|
pendingTransaction.getFee() + pendingTransaction.getAmount()));
|
||||||
|
updateSendButton();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.pendingTransaction = null;
|
||||||
|
sendListener.disposeTransaction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createTransactionFailed(String errorText) {
|
||||||
|
Timber.e("CREATE TX FAILED");
|
||||||
|
if (pendingTransaction != null) {
|
||||||
|
throw new IllegalStateException("pendingTransaction is not null");
|
||||||
|
}
|
||||||
|
showStageError(getString(R.string.send_create_tx_error_title),
|
||||||
|
errorText,
|
||||||
|
getString(R.string.text_noretry_monero));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onValidateFields() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isResumed = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPauseFragment() {
|
||||||
|
isResumed = false;
|
||||||
|
stopSendTimer();
|
||||||
|
sendListener.disposeTransaction();
|
||||||
|
pendingTransaction = null;
|
||||||
|
inProgress = STAGE_X;
|
||||||
|
updateSendButton();
|
||||||
|
super.onPauseFragment();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResumeFragment() {
|
||||||
|
super.onResumeFragment();
|
||||||
|
Timber.d("onResumeFragment()");
|
||||||
|
if (sendListener.getMode() != SendFragment.Mode.BTC) {
|
||||||
|
throw new IllegalStateException("Mode is not BTC!");
|
||||||
|
}
|
||||||
|
Helper.hideKeyboard(getActivity());
|
||||||
|
llStageA.setVisibility(View.INVISIBLE);
|
||||||
|
evStageA.hideProgress();
|
||||||
|
llStageB.setVisibility(View.INVISIBLE);
|
||||||
|
evStageB.hideProgress();
|
||||||
|
llStageC.setVisibility(View.INVISIBLE);
|
||||||
|
evStageC.hideProgress();
|
||||||
|
isResumed = true;
|
||||||
|
if ((pendingTransaction == null) && (inProgress == STAGE_X)) {
|
||||||
|
createOrder();
|
||||||
|
} // otherwise just sit there blank
|
||||||
|
// TODO: don't sit there blank - can this happen? should we just die?
|
||||||
|
}
|
||||||
|
|
||||||
|
private int sendCountdown = 0;
|
||||||
|
private static final int XMRTO_COUNTDOWN = 10 * 60; // 10 minutes
|
||||||
|
private static final int XMRTO_COUNTDOWN_STEP = 1; // 1 second
|
||||||
|
|
||||||
|
Runnable updateRunnable = null;
|
||||||
|
|
||||||
|
void startSendTimer() {
|
||||||
|
Timber.d("startSendTimer()");
|
||||||
|
sendCountdown = XMRTO_COUNTDOWN;
|
||||||
|
updateRunnable = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (!isAdded())
|
||||||
|
return;
|
||||||
|
Timber.d("updateTimer()");
|
||||||
|
if (sendCountdown <= 0) {
|
||||||
|
bSend.setEnabled(false);
|
||||||
|
sendCountdown = 0;
|
||||||
|
Toast.makeText(getContext(), getString(R.string.send_xmrto_timeout), Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
int minutes = sendCountdown / 60;
|
||||||
|
int seconds = sendCountdown % 60;
|
||||||
|
String t = String.format("%d:%02d", minutes, seconds);
|
||||||
|
bSend.setText(getString(R.string.send_send_timed_label, t));
|
||||||
|
if (sendCountdown > 0) {
|
||||||
|
sendCountdown -= XMRTO_COUNTDOWN_STEP;
|
||||||
|
getView().postDelayed(this, XMRTO_COUNTDOWN_STEP * 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
getView().post(updateRunnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopSendTimer() {
|
||||||
|
getView().removeCallbacks(updateRunnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateSendButton() {
|
||||||
|
Timber.d("updateSendButton()");
|
||||||
|
if (pendingTransaction != null) {
|
||||||
|
llConfirmSend.setVisibility(View.VISIBLE);
|
||||||
|
bSend.setEnabled(sendCountdown > 0);
|
||||||
|
} else {
|
||||||
|
llConfirmSend.setVisibility(View.GONE);
|
||||||
|
bSend.setEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void preSend() {
|
||||||
|
final Activity activity = getActivity();
|
||||||
|
View promptsView = getLayoutInflater().inflate(R.layout.prompt_password, null);
|
||||||
|
android.app.AlertDialog.Builder alertDialogBuilder = new android.app.AlertDialog.Builder(activity);
|
||||||
|
alertDialogBuilder.setView(promptsView);
|
||||||
|
|
||||||
|
final TextInputLayout etPassword = (TextInputLayout) promptsView.findViewById(R.id.etPassword);
|
||||||
|
etPassword.setHint(getString(R.string.prompt_send_password));
|
||||||
|
|
||||||
|
etPassword.getEditText().addTextChangedListener(new TextWatcher() {
|
||||||
|
@Override
|
||||||
|
public void afterTextChanged(Editable s) {
|
||||||
|
if (etPassword.getError() != null) {
|
||||||
|
etPassword.setError(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeTextChanged(CharSequence s, int start,
|
||||||
|
int count, int after) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTextChanged(CharSequence s, int start,
|
||||||
|
int before, int count) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
alertDialogBuilder
|
||||||
|
.setCancelable(false)
|
||||||
|
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int id) {
|
||||||
|
String pass = etPassword.getEditText().getText().toString();
|
||||||
|
if (getActivityCallback().verifyWalletPassword(pass)) {
|
||||||
|
dialog.dismiss();
|
||||||
|
Helper.hideKeyboardAlways(activity);
|
||||||
|
send();
|
||||||
|
} else {
|
||||||
|
etPassword.setError(getString(R.string.bad_password));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton("Cancel",
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int id) {
|
||||||
|
Helper.hideKeyboardAlways(activity);
|
||||||
|
dialog.cancel();
|
||||||
|
bSend.setEnabled(sendCountdown > 0); // allow to try again
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
final android.app.AlertDialog passwordDialog = alertDialogBuilder.create();
|
||||||
|
passwordDialog.setOnShowListener(new DialogInterface.OnShowListener() {
|
||||||
|
@Override
|
||||||
|
public void onShow(DialogInterface dialog) {
|
||||||
|
Button button = ((android.app.AlertDialog) dialog).getButton(android.app.AlertDialog.BUTTON_POSITIVE);
|
||||||
|
button.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
String pass = etPassword.getEditText().getText().toString();
|
||||||
|
if (getActivityCallback().verifyWalletPassword(pass)) {
|
||||||
|
Helper.hideKeyboardAlways(activity);
|
||||||
|
passwordDialog.dismiss();
|
||||||
|
send();
|
||||||
|
} else {
|
||||||
|
etPassword.setError(getString(R.string.bad_password));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Helper.showKeyboard(passwordDialog);
|
||||||
|
|
||||||
|
// accept keyboard "ok"
|
||||||
|
etPassword.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||||
|
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||||
|
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_DONE)) {
|
||||||
|
String pass = etPassword.getEditText().getText().toString();
|
||||||
|
if (getActivityCallback().verifyWalletPassword(pass)) {
|
||||||
|
Helper.hideKeyboardAlways(activity);
|
||||||
|
passwordDialog.dismiss();
|
||||||
|
send();
|
||||||
|
} else {
|
||||||
|
etPassword.setError(getString(R.string.bad_password));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
passwordDialog.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
// creates a pending transaction and calls us back with transactionCreated()
|
||||||
|
// or createTransactionFailed()
|
||||||
|
void prepareSend() {
|
||||||
|
if (!isResumed) return;
|
||||||
|
if ((xmrtoStatus == null)) {
|
||||||
|
throw new IllegalStateException("xmrtoStatus is null");
|
||||||
|
}
|
||||||
|
if ((!xmrtoStatus.isCreated())) {
|
||||||
|
throw new IllegalStateException("order is not created");
|
||||||
|
}
|
||||||
|
showProgress(3, getString(R.string.label_send_progress_create_tx));
|
||||||
|
TxData txData = sendListener.getTxData();
|
||||||
|
txData.setDestinationAddress(xmrtoStatus.getXmrReceivingAddress());
|
||||||
|
txData.setPaymentId(xmrtoStatus.getXmrRequiredPaymentIdShort());
|
||||||
|
txData.setAmount(Wallet.getAmountFromDouble(xmrtoStatus.getXmrAmountTotal()));
|
||||||
|
getActivityCallback().onPrepareSend(xmrtoStatus.getUuid(), txData);
|
||||||
|
}
|
||||||
|
|
||||||
|
SendFragment.Listener getActivityCallback() {
|
||||||
|
return sendListener.getActivityCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
private CreateOrder xmrtoOrder = null;
|
||||||
|
|
||||||
|
private void processCreateOrder(final CreateOrder createOrder) {
|
||||||
|
Timber.d("processCreateOrder %s", createOrder.getUuid());
|
||||||
|
xmrtoOrder = createOrder;
|
||||||
|
if (QueryOrderStatus.State.TO_BE_CREATED.toString().equals(createOrder.getState())) {
|
||||||
|
getView().post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
tvTxXmrToKey.setText(createOrder.getUuid());
|
||||||
|
tvTxBtcAddress.setText(createOrder.getBtcDestAddress());
|
||||||
|
hideProgress();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
queryOrder(createOrder.getUuid());
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Create Order is not TO_BE_CREATED");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processCreateOrderError(final Exception ex) {
|
||||||
|
Timber.e("processCreateOrderError %s", ex.getLocalizedMessage());
|
||||||
|
getView().post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (ex instanceof XmrToException) {
|
||||||
|
XmrToException xmrEx = (XmrToException) ex;
|
||||||
|
XmrToError xmrErr = xmrEx.getError();
|
||||||
|
if (xmrErr != null) {
|
||||||
|
if (xmrErr.isRetryable()) {
|
||||||
|
showStageError(xmrErr.getErrorId().toString(), xmrErr.getErrorMsg(),
|
||||||
|
getString(R.string.text_retry));
|
||||||
|
evStageA.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
evStageA.setOnClickListener(null);
|
||||||
|
createOrder();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
showStageError(xmrErr.getErrorId().toString(), xmrErr.getErrorMsg(),
|
||||||
|
getString(R.string.text_noretry));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showStageError(getString(R.string.label_generic_xmrto_error),
|
||||||
|
getString(R.string.text_generic_xmrto_error, xmrEx.getCode()),
|
||||||
|
getString(R.string.text_noretry));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
evStageA.showMessage(getString(R.string.label_generic_xmrto_error),
|
||||||
|
ex.getLocalizedMessage(),
|
||||||
|
getString(R.string.text_noretry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createOrder() {
|
||||||
|
if (!isResumed) return;
|
||||||
|
Timber.d("createOrder");
|
||||||
|
xmrtoOrder = null;
|
||||||
|
xmrtoStatus = null;
|
||||||
|
showProgress(1, getString(R.string.label_send_progress_xmrto_create));
|
||||||
|
TxDataBtc txDataBtc = (TxDataBtc) sendListener.getTxData();
|
||||||
|
double btcAmount = txDataBtc.getBtcAmount();
|
||||||
|
getXmrToApi().createOrder(btcAmount, txDataBtc.getBtcAddress(), new XmrToCallback<CreateOrder>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(CreateOrder createOrder) {
|
||||||
|
if (!isResumed) return;
|
||||||
|
if (xmrtoOrder != null) {
|
||||||
|
Timber.w("another ongoing create order request");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
processCreateOrder(createOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Exception ex) {
|
||||||
|
if (!isResumed) return;
|
||||||
|
if (xmrtoOrder != null) {
|
||||||
|
Timber.w("another ongoing create order request");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
processCreateOrderError(ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private QueryOrderStatus xmrtoStatus = null;
|
||||||
|
|
||||||
|
private void processQueryOrder(final QueryOrderStatus status) {
|
||||||
|
Timber.d("processQueryOrder %s for %s", status.getState().toString(), status.getUuid());
|
||||||
|
xmrtoStatus = status;
|
||||||
|
if (status.isCreated()) {
|
||||||
|
getView().post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
NumberFormat df = NumberFormat.getInstance(Locale.US);
|
||||||
|
df.setMaximumFractionDigits(12);
|
||||||
|
String btcAmount = df.format(status.getBtcAmount());
|
||||||
|
String xmrAmountTotal = df.format(status.getXmrAmountTotal());
|
||||||
|
tvTxBtcAmount.setText(getString(R.string.text_send_btc_amount, btcAmount, xmrAmountTotal));
|
||||||
|
String xmrPriceBtc = df.format(status.getXmrPriceBtc());
|
||||||
|
tvTxBtcRate.setText(getString(R.string.text_send_btc_rate, xmrPriceBtc));
|
||||||
|
|
||||||
|
double calcRate = status.getBtcAmount() / status.getXmrPriceBtc();
|
||||||
|
Timber.i("Rates: %f / %f", calcRate, status.getXmrPriceBtc());
|
||||||
|
|
||||||
|
tvTxBtcAddress.setText(status.getBtcDestAddress()); // TODO test if this is different?
|
||||||
|
|
||||||
|
Timber.i("Expires @ %s, in %s seconds", status.getExpiresAt().toString(), status.getSecondsTillTimeout());
|
||||||
|
|
||||||
|
Timber.i("Status = %s", status.getState().toString());
|
||||||
|
tvTxXmrToKey.setText(status.getUuid());
|
||||||
|
|
||||||
|
Timber.d("AmountRemaining=%f, XmrAmountTotal=%f", status.getXmrAmountRemaining(), status.getXmrAmountTotal());
|
||||||
|
hideProgress();
|
||||||
|
startSendTimer();
|
||||||
|
prepareSend();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Timber.d("try again!");
|
||||||
|
handler.postDelayed(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
queryOrder(status.getUuid());
|
||||||
|
}
|
||||||
|
}, QUERY_INTERVAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Handler handler = new Handler();
|
||||||
|
|
||||||
|
private void processQueryOrderError(final Exception ex) {
|
||||||
|
Timber.e("processQueryOrderError %s", ex.getLocalizedMessage());
|
||||||
|
getView().post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (ex instanceof XmrToException) {
|
||||||
|
XmrToException xmrEx = (XmrToException) ex;
|
||||||
|
XmrToError xmrErr = xmrEx.getError();
|
||||||
|
if (xmrErr != null) {
|
||||||
|
if (xmrErr.isRetryable()) {
|
||||||
|
showStageError(xmrErr.getErrorId().toString(), xmrErr.getErrorMsg(),
|
||||||
|
getString(R.string.text_retry));
|
||||||
|
evStageB.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
evStageB.setOnClickListener(null);
|
||||||
|
queryOrder(xmrtoOrder.getUuid());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
showStageError(xmrErr.getErrorId().toString(), xmrErr.getErrorMsg(),
|
||||||
|
getString(R.string.text_noretry));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showStageError(getString(R.string.label_generic_xmrto_error),
|
||||||
|
getString(R.string.text_generic_xmrto_error, xmrEx.getCode()),
|
||||||
|
getString(R.string.text_noretry));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
evStageB.showMessage(getString(R.string.label_generic_xmrto_error),
|
||||||
|
ex.getLocalizedMessage(),
|
||||||
|
getString(R.string.text_noretry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void queryOrder(final String uuid) {
|
||||||
|
Timber.d("queryOrder(%s)", uuid);
|
||||||
|
if (!isResumed) return;
|
||||||
|
getView().post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
xmrtoStatus = null;
|
||||||
|
showProgress(2, getString(R.string.label_send_progress_xmrto_query));
|
||||||
|
getXmrToApi().queryOrderStatus(uuid, new XmrToCallback<QueryOrderStatus>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(QueryOrderStatus status) {
|
||||||
|
if (!isResumed) return;
|
||||||
|
if (xmrtoOrder == null) return;
|
||||||
|
if (!status.getUuid().equals(xmrtoOrder.getUuid())) {
|
||||||
|
Timber.d("Query UUID does not match");
|
||||||
|
// ignore (we got a response to a stale request)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (xmrtoStatus != null)
|
||||||
|
throw new IllegalStateException("xmrtoStatus must be null here!");
|
||||||
|
processQueryOrder(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Exception ex) {
|
||||||
|
if (!isResumed) return;
|
||||||
|
processQueryOrderError(ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private XmrToApi xmrToApi = null;
|
||||||
|
|
||||||
|
private final XmrToApi getXmrToApi() {
|
||||||
|
if (xmrToApi == null) {
|
||||||
|
synchronized (this) {
|
||||||
|
if (xmrToApi == null) {
|
||||||
|
xmrToApi = new XmrToApiImpl(OkHttpClientSingleton.getOkHttpClient(),
|
||||||
|
Helper.getXmrToBaseUrl());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return xmrToApi;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,267 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 m2049r
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.fragment.send;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.R;
|
||||||
|
import com.m2049r.xmrwallet.data.PendingTx;
|
||||||
|
import com.m2049r.xmrwallet.data.TxDataBtc;
|
||||||
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
|
import com.m2049r.xmrwallet.util.OkHttpClientSingleton;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.XmrToException;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.QueryOrderStatus;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.XmrToApi;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.XmrToCallback;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.network.XmrToApiImpl;
|
||||||
|
|
||||||
|
import java.text.NumberFormat;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import okhttp3.HttpUrl;
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
public class SendBtcSuccessWizardFragment extends SendWizardFragment {
|
||||||
|
|
||||||
|
public static SendBtcSuccessWizardFragment newInstance(SendSuccessWizardFragment.Listener listener) {
|
||||||
|
SendBtcSuccessWizardFragment instance = new SendBtcSuccessWizardFragment();
|
||||||
|
instance.setSendListener(listener);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
SendSuccessWizardFragment.Listener sendListener;
|
||||||
|
|
||||||
|
public SendBtcSuccessWizardFragment setSendListener(SendSuccessWizardFragment.Listener listener) {
|
||||||
|
this.sendListener = listener;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageButton bCopyTxId;
|
||||||
|
private TextView tvTxId;
|
||||||
|
private TextView tvTxAddress;
|
||||||
|
private TextView tvTxPaymentId;
|
||||||
|
private TextView tvTxAmount;
|
||||||
|
private TextView tvTxFee;
|
||||||
|
private TextView tvXmrToAmount;
|
||||||
|
private TextView tvXmrToStatus;
|
||||||
|
private ImageView ivXmrToStatus;
|
||||||
|
private ImageView ivXmrToStatusBig;
|
||||||
|
private ProgressBar pbXmrto;
|
||||||
|
private TextView tvTxXmrToKey;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
|
||||||
|
Timber.d("onCreateView() %s", (String.valueOf(savedInstanceState)));
|
||||||
|
|
||||||
|
View view = inflater.inflate(
|
||||||
|
R.layout.fragment_send_btc_success, container, false);
|
||||||
|
|
||||||
|
bCopyTxId = (ImageButton) view.findViewById(R.id.bCopyTxId);
|
||||||
|
bCopyTxId.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Helper.clipBoardCopy(getActivity(), getString(R.string.label_send_txid), tvTxId.getText().toString());
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.message_copy_txid), Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
tvXmrToAmount = (TextView) view.findViewById(R.id.tvXmrToAmount);
|
||||||
|
tvXmrToStatus = (TextView) view.findViewById(R.id.tvXmrToStatus);
|
||||||
|
ivXmrToStatus = (ImageView) view.findViewById(R.id.ivXmrToStatus);
|
||||||
|
ivXmrToStatusBig = (ImageView) view.findViewById(R.id.ivXmrToStatusBig);
|
||||||
|
|
||||||
|
tvTxId = (TextView) view.findViewById(R.id.tvTxId);
|
||||||
|
tvTxAddress = (TextView) view.findViewById(R.id.tvTxAddress);
|
||||||
|
tvTxPaymentId = (TextView) view.findViewById(R.id.tvTxPaymentId);
|
||||||
|
tvTxAmount = ((TextView) view.findViewById(R.id.tvTxAmount));
|
||||||
|
tvTxFee = (TextView) view.findViewById(R.id.tvTxFee);
|
||||||
|
|
||||||
|
pbXmrto = (ProgressBar) view.findViewById(R.id.pbXmrto);
|
||||||
|
pbXmrto.getIndeterminateDrawable().setColorFilter(0x61000000, android.graphics.PorterDuff.Mode.MULTIPLY);
|
||||||
|
|
||||||
|
tvTxXmrToKey = (TextView) view.findViewById(R.id.tvTxXmrToKey);
|
||||||
|
tvTxXmrToKey.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Helper.clipBoardCopy(getActivity(), getString(R.string.label_copy_xmrtokey), tvTxXmrToKey.getText().toString());
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.message_copy_xmrtokey), Toast.LENGTH_SHORT).show();
|
||||||
|
;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onValidateFields() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isResumed = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPauseFragment() {
|
||||||
|
isResumed = false;
|
||||||
|
super.onPauseFragment();
|
||||||
|
}
|
||||||
|
|
||||||
|
TxDataBtc btcData = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResumeFragment() {
|
||||||
|
super.onResumeFragment();
|
||||||
|
Timber.d("onResumeFragment()");
|
||||||
|
Helper.hideKeyboard(getActivity());
|
||||||
|
isResumed = true;
|
||||||
|
|
||||||
|
btcData = (TxDataBtc) sendListener.getTxData();
|
||||||
|
tvTxAddress.setText(btcData.getDestinationAddress());
|
||||||
|
String paymentId = btcData.getPaymentId();
|
||||||
|
if ((paymentId != null) && (!paymentId.isEmpty())) {
|
||||||
|
tvTxPaymentId.setText(btcData.getPaymentId());
|
||||||
|
} else {
|
||||||
|
tvTxPaymentId.setText("-");
|
||||||
|
}
|
||||||
|
|
||||||
|
final PendingTx committedTx = sendListener.getCommittedTx();
|
||||||
|
if (committedTx != null) {
|
||||||
|
tvTxId.setText(committedTx.txId);
|
||||||
|
bCopyTxId.setEnabled(true);
|
||||||
|
bCopyTxId.setImageResource(R.drawable.ic_content_copy_black_24dp);
|
||||||
|
tvTxAmount.setText(getString(R.string.send_amount, Helper.getDisplayAmount(committedTx.amount)));
|
||||||
|
tvTxFee.setText(getString(R.string.send_fee, Helper.getDisplayAmount(committedTx.fee)));
|
||||||
|
if (btcData != null) {
|
||||||
|
NumberFormat df = NumberFormat.getInstance(Locale.US);
|
||||||
|
df.setMaximumFractionDigits(12);
|
||||||
|
String btcAmount = df.format(btcData.getBtcAmount());
|
||||||
|
tvXmrToAmount.setText(getString(R.string.info_send_xmrto_success_btc, btcAmount));
|
||||||
|
//TODO btcData.getBtcAddress();
|
||||||
|
tvTxXmrToKey.setText(btcData.getXmrtoUuid());
|
||||||
|
queryOrder();
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("btcData is null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sendListener.enableDone();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final int QUERY_INTERVAL = 1000; // ms
|
||||||
|
|
||||||
|
private void processQueryOrder(final QueryOrderStatus status) {
|
||||||
|
Timber.d("processQueryOrder %s for %s", status.getState().toString(), status.getUuid());
|
||||||
|
if (!btcData.getXmrtoUuid().equals(status.getUuid()))
|
||||||
|
throw new IllegalStateException("UUIDs do not match!");
|
||||||
|
if (isResumed && (getView() != null))
|
||||||
|
getView().post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
showXmrToStatus(status);
|
||||||
|
if (!status.isTerminal()) {
|
||||||
|
getView().postDelayed(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
queryOrder();
|
||||||
|
}
|
||||||
|
}, QUERY_INTERVAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void queryOrder() {
|
||||||
|
Timber.d("queryOrder(%s)", btcData.getXmrtoUuid());
|
||||||
|
if (!isResumed) return;
|
||||||
|
getXmrToApi().queryOrderStatus(btcData.getXmrtoUuid(), new XmrToCallback<QueryOrderStatus>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(QueryOrderStatus status) {
|
||||||
|
if (!isAdded()) return;
|
||||||
|
processQueryOrder(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(final Exception ex) {
|
||||||
|
if (!isResumed) return;
|
||||||
|
Timber.e(ex);
|
||||||
|
getActivity().runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (ex instanceof XmrToException) {
|
||||||
|
Toast.makeText(getActivity(), ((XmrToException) ex).getError().getErrorMsg(), Toast.LENGTH_LONG).show();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getActivity(), ex.getLocalizedMessage(), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private int statusResource = 0;
|
||||||
|
|
||||||
|
void showXmrToStatus(final QueryOrderStatus status) {
|
||||||
|
if (status.isError()) {
|
||||||
|
tvXmrToStatus.setText(getString(R.string.info_send_xmrto_error, status.toString()));
|
||||||
|
statusResource = R.drawable.ic_error_red_24dp;
|
||||||
|
pbXmrto.getIndeterminateDrawable().setColorFilter(0xff8b0000, android.graphics.PorterDuff.Mode.MULTIPLY);
|
||||||
|
} else if (status.isSent()) {
|
||||||
|
tvXmrToStatus.setText(getString(R.string.info_send_xmrto_sent));
|
||||||
|
statusResource = R.drawable.ic_success_green_24dp;
|
||||||
|
pbXmrto.getIndeterminateDrawable().setColorFilter(0xFF417505, android.graphics.PorterDuff.Mode.MULTIPLY);
|
||||||
|
} else if (status.isPending()) {
|
||||||
|
if (status.isPaid()) {
|
||||||
|
tvXmrToStatus.setText(getString(R.string.info_send_xmrto_paid));
|
||||||
|
} else {
|
||||||
|
tvXmrToStatus.setText(getString(R.string.info_send_xmrto_unpaid));
|
||||||
|
}
|
||||||
|
statusResource = R.drawable.ic_pending_orange_24dp;
|
||||||
|
pbXmrto.getIndeterminateDrawable().setColorFilter(0xFFFF6105, android.graphics.PorterDuff.Mode.MULTIPLY);
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("status is broken: " + status.toString());
|
||||||
|
}
|
||||||
|
ivXmrToStatus.setImageResource(statusResource);
|
||||||
|
if (status.isTerminal()) {
|
||||||
|
pbXmrto.setVisibility(View.INVISIBLE);
|
||||||
|
ivXmrToStatus.setVisibility(View.GONE);
|
||||||
|
ivXmrToStatusBig.setImageResource(statusResource);
|
||||||
|
ivXmrToStatusBig.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private XmrToApi xmrToApi = null;
|
||||||
|
|
||||||
|
private final XmrToApi getXmrToApi() {
|
||||||
|
if (xmrToApi == null) {
|
||||||
|
synchronized (this) {
|
||||||
|
if (xmrToApi == null) {
|
||||||
|
xmrToApi = new XmrToApiImpl(OkHttpClientSingleton.getOkHttpClient(),
|
||||||
|
Helper.getXmrToBaseUrl());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return xmrToApi;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 m2049r
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.fragment.send;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.model.PendingTransaction;
|
||||||
|
|
||||||
|
interface SendConfirm {
|
||||||
|
void sendFailed();
|
||||||
|
|
||||||
|
void createTransactionFailed(String errorText);
|
||||||
|
|
||||||
|
void transactionCreated(String txTag, PendingTransaction pendingTransaction);
|
||||||
|
}
|
|
@ -14,12 +14,13 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.m2049r.xmrwallet;
|
package com.m2049r.xmrwallet.fragment.send;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.design.widget.TextInputLayout;
|
import android.support.design.widget.TextInputLayout;
|
||||||
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
|
@ -30,14 +31,16 @@ import android.view.inputmethod.EditorInfo;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.R;
|
||||||
import com.m2049r.xmrwallet.data.TxData;
|
import com.m2049r.xmrwallet.data.TxData;
|
||||||
import com.m2049r.xmrwallet.model.PendingTransaction;
|
import com.m2049r.xmrwallet.model.PendingTransaction;
|
||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
|
import com.m2049r.xmrwallet.util.UserNotes;
|
||||||
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
public class SendConfirmWizardFragment extends SendWizardFragment {
|
public class SendConfirmWizardFragment extends SendWizardFragment implements SendConfirm {
|
||||||
|
|
||||||
public static SendConfirmWizardFragment newInstance(Listener listener) {
|
public static SendConfirmWizardFragment newInstance(Listener listener) {
|
||||||
SendConfirmWizardFragment instance = new SendConfirmWizardFragment();
|
SendConfirmWizardFragment instance = new SendConfirmWizardFragment();
|
||||||
|
@ -57,11 +60,11 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
|
||||||
|
|
||||||
TxData getTxData();
|
TxData getTxData();
|
||||||
|
|
||||||
String getNotes();
|
|
||||||
|
|
||||||
void commitTransaction();
|
void commitTransaction();
|
||||||
|
|
||||||
void disposeTransaction();
|
void disposeTransaction();
|
||||||
|
|
||||||
|
SendFragment.Mode getMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
private TextView tvTxAddress;
|
private TextView tvTxAddress;
|
||||||
|
@ -122,8 +125,11 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
|
||||||
|
|
||||||
PendingTransaction pendingTransaction = null;
|
PendingTransaction pendingTransaction = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
// callback from wallet when PendingTransaction created
|
// callback from wallet when PendingTransaction created
|
||||||
void transactionCreated(PendingTransaction pendingTransaction) {
|
public void transactionCreated(String txTag, PendingTransaction pendingTransaction) {
|
||||||
|
// ignore txTag - the app flow ensures this is the correct tx
|
||||||
|
// TODO: use the txTag
|
||||||
hideProgress();
|
hideProgress();
|
||||||
if (isResumed) {
|
if (isResumed) {
|
||||||
this.pendingTransaction = pendingTransaction;
|
this.pendingTransaction = pendingTransaction;
|
||||||
|
@ -138,10 +144,22 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
|
||||||
pbProgressSend.setVisibility(View.VISIBLE);
|
pbProgressSend.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendFailed() {
|
@Override
|
||||||
|
public void sendFailed() {
|
||||||
pbProgressSend.setVisibility(View.INVISIBLE);
|
pbProgressSend.setVisibility(View.INVISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createTransactionFailed(String errorText) {
|
||||||
|
hideProgress();
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||||
|
builder.setCancelable(true).
|
||||||
|
setTitle(getString(R.string.send_create_tx_error_title)).
|
||||||
|
setMessage(errorText).
|
||||||
|
create().
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onValidateFields() {
|
public boolean onValidateFields() {
|
||||||
return true;
|
return true;
|
||||||
|
@ -173,9 +191,9 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
|
||||||
} else {
|
} else {
|
||||||
tvTxPaymentId.setText("-");
|
tvTxPaymentId.setText("-");
|
||||||
}
|
}
|
||||||
String notes = sendListener.getNotes();
|
UserNotes notes = sendListener.getTxData().getUserNotes();
|
||||||
if ((notes != null) && (!notes.isEmpty())) {
|
if ((notes != null) && (!notes.note.isEmpty())) {
|
||||||
tvTxNotes.setText(sendListener.getNotes());
|
tvTxNotes.setText(notes.note);
|
||||||
} else {
|
} else {
|
||||||
tvTxNotes.setText("-");
|
tvTxNotes.setText("-");
|
||||||
}
|
}
|
||||||
|
@ -296,8 +314,10 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
|
||||||
passwordDialog.show();
|
passwordDialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// creates a pending transaction and calls us back with transactionCreated()
|
||||||
|
// or createTransactionFailed()
|
||||||
void prepareSend(TxData txData) {
|
void prepareSend(TxData txData) {
|
||||||
getActivityCallback().onPrepareSend(txData);
|
getActivityCallback().onPrepareSend(null, txData);
|
||||||
}
|
}
|
||||||
|
|
||||||
SendFragment.Listener getActivityCallback() {
|
SendFragment.Listener getActivityCallback() {
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.m2049r.xmrwallet;
|
package com.m2049r.xmrwallet.fragment.send;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
@ -22,9 +22,8 @@ import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
import android.support.v4.app.FragmentManager;
|
import android.support.v4.app.FragmentManager;
|
||||||
import android.support.v4.app.FragmentPagerAdapter;
|
import android.support.v4.app.FragmentStatePagerAdapter;
|
||||||
import android.support.v4.view.ViewPager;
|
import android.support.v4.view.ViewPager;
|
||||||
import android.support.v7.app.AlertDialog;
|
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
@ -36,12 +35,16 @@ import android.widget.Button;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.OnBackPressedListener;
|
||||||
|
import com.m2049r.xmrwallet.R;
|
||||||
import com.m2049r.xmrwallet.data.BarcodeData;
|
import com.m2049r.xmrwallet.data.BarcodeData;
|
||||||
import com.m2049r.xmrwallet.data.PendingTx;
|
import com.m2049r.xmrwallet.data.PendingTx;
|
||||||
import com.m2049r.xmrwallet.data.TxData;
|
import com.m2049r.xmrwallet.data.TxData;
|
||||||
|
import com.m2049r.xmrwallet.data.TxDataBtc;
|
||||||
import com.m2049r.xmrwallet.layout.SpendViewPager;
|
import com.m2049r.xmrwallet.layout.SpendViewPager;
|
||||||
import com.m2049r.xmrwallet.model.PendingTransaction;
|
import com.m2049r.xmrwallet.model.PendingTransaction;
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
|
import com.m2049r.xmrwallet.util.UserNotes;
|
||||||
import com.m2049r.xmrwallet.widget.DotBar;
|
import com.m2049r.xmrwallet.widget.DotBar;
|
||||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||||
|
|
||||||
|
@ -62,11 +65,11 @@ public class SendFragment extends Fragment
|
||||||
public interface Listener {
|
public interface Listener {
|
||||||
long getTotalFunds();
|
long getTotalFunds();
|
||||||
|
|
||||||
void onPrepareSend(TxData data);
|
void onPrepareSend(String tag, TxData data);
|
||||||
|
|
||||||
boolean verifyWalletPassword(String password);
|
boolean verifyWalletPassword(String password);
|
||||||
|
|
||||||
void onSend(String notes);
|
void onSend(UserNotes notes);
|
||||||
|
|
||||||
void onDisposeRequest();
|
void onDisposeRequest();
|
||||||
|
|
||||||
|
@ -231,7 +234,42 @@ public class SendFragment extends Fragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SpendPagerAdapter extends FragmentPagerAdapter {
|
enum Mode {
|
||||||
|
XMR, BTC
|
||||||
|
}
|
||||||
|
|
||||||
|
Mode mode = Mode.XMR;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMode(Mode aMode) {
|
||||||
|
if (mode != aMode) {
|
||||||
|
mode = aMode;
|
||||||
|
switch (aMode) {
|
||||||
|
case XMR:
|
||||||
|
txData = new TxData();
|
||||||
|
break;
|
||||||
|
case BTC:
|
||||||
|
txData = new TxDataBtc();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Mode " + String.valueOf(aMode) + " unknown!");
|
||||||
|
}
|
||||||
|
getView().post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
pagerAdapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Timber.d("New Mode = " + mode.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mode getMode() {
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SpendPagerAdapter extends FragmentStatePagerAdapter {
|
||||||
private static final int POS_ADDRESS = 0;
|
private static final int POS_ADDRESS = 0;
|
||||||
private static final int POS_AMOUNT = 1;
|
private static final int POS_AMOUNT = 1;
|
||||||
private static final int POS_SETTINGS = 2;
|
private static final int POS_SETTINGS = 2;
|
||||||
|
@ -257,6 +295,7 @@ public class SendFragment extends Fragment
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object instantiateItem(ViewGroup container, int position) {
|
public Object instantiateItem(ViewGroup container, int position) {
|
||||||
|
Timber.d("instantiateItem %d", position);
|
||||||
SendWizardFragment fragment = (SendWizardFragment) super.instantiateItem(container, position);
|
SendWizardFragment fragment = (SendWizardFragment) super.instantiateItem(container, position);
|
||||||
myFragments.put(position, new WeakReference<>(fragment));
|
myFragments.put(position, new WeakReference<>(fragment));
|
||||||
return fragment;
|
return fragment;
|
||||||
|
@ -264,6 +303,7 @@ public class SendFragment extends Fragment
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroyItem(ViewGroup container, int position, Object object) {
|
public void destroyItem(ViewGroup container, int position, Object object) {
|
||||||
|
Timber.d("destroyItem %d", position);
|
||||||
myFragments.remove(position);
|
myFragments.remove(position);
|
||||||
super.destroyItem(container, position, object);
|
super.destroyItem(container, position, object);
|
||||||
}
|
}
|
||||||
|
@ -279,19 +319,39 @@ public class SendFragment extends Fragment
|
||||||
@Override
|
@Override
|
||||||
public SendWizardFragment getItem(int position) {
|
public SendWizardFragment getItem(int position) {
|
||||||
Timber.d("getItem(%d) CREATE", position);
|
Timber.d("getItem(%d) CREATE", position);
|
||||||
switch (position) {
|
Timber.d("Mode=" + mode.toString());
|
||||||
case POS_ADDRESS:
|
if (mode == Mode.XMR) {
|
||||||
return SendAddressWizardFragment.newInstance(SendFragment.this);
|
switch (position) {
|
||||||
case POS_AMOUNT:
|
case POS_ADDRESS:
|
||||||
return SendAmountWizardFragment.newInstance(SendFragment.this);
|
return SendAddressWizardFragment.newInstance(SendFragment.this);
|
||||||
case POS_SETTINGS:
|
case POS_AMOUNT:
|
||||||
return SendSettingsWizardFragment.newInstance(SendFragment.this);
|
return SendAmountWizardFragment.newInstance(SendFragment.this);
|
||||||
case POS_CONFIRM:
|
case POS_SETTINGS:
|
||||||
return SendConfirmWizardFragment.newInstance(SendFragment.this);
|
return SendSettingsWizardFragment.newInstance(SendFragment.this);
|
||||||
case POS_SUCCESS:
|
case POS_CONFIRM:
|
||||||
return SendSuccessWizardFragment.newInstance(SendFragment.this);
|
return SendConfirmWizardFragment.newInstance(SendFragment.this);
|
||||||
default:
|
case POS_SUCCESS:
|
||||||
throw new IllegalArgumentException("no such send position(" + position + ")");
|
return SendSuccessWizardFragment.newInstance(SendFragment.this);
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("no such send position(" + position + ")");
|
||||||
|
}
|
||||||
|
} else if (mode == Mode.BTC) {
|
||||||
|
switch (position) {
|
||||||
|
case POS_ADDRESS:
|
||||||
|
return SendAddressWizardFragment.newInstance(SendFragment.this);
|
||||||
|
case POS_AMOUNT:
|
||||||
|
return SendBtcAmountWizardFragment.newInstance(SendFragment.this);
|
||||||
|
case POS_SETTINGS:
|
||||||
|
return SendSettingsWizardFragment.newInstance(SendFragment.this);
|
||||||
|
case POS_CONFIRM:
|
||||||
|
return SendBtcConfirmWizardFragment.newInstance(SendFragment.this);
|
||||||
|
case POS_SUCCESS:
|
||||||
|
return SendBtcSuccessWizardFragment.newInstance(SendFragment.this);
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("no such send position(" + position + ")");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Unknown mode!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,24 +374,25 @@ public class SendFragment extends Fragment
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemPosition(Object object) {
|
||||||
|
Timber.d("getItemPosition %s", String.valueOf(object));
|
||||||
|
if ((object instanceof SendAddressWizardFragment) || (object instanceof SendSettingsWizardFragment)) {
|
||||||
|
return POSITION_UNCHANGED;
|
||||||
|
} else {
|
||||||
|
return POSITION_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TxData getTxData() {
|
public TxData getTxData() {
|
||||||
return new TxData(sendAddress, sendPaymentId, sendAmount, sendMixin, sendPriority);
|
return txData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private TxData txData = new TxData();
|
||||||
public String getNotes() {
|
|
||||||
return sendNotes;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String sendAddress;
|
|
||||||
private String sendPaymentId;
|
|
||||||
private long sendAmount;
|
|
||||||
private PendingTransaction.Priority sendPriority;
|
|
||||||
private int sendMixin;
|
|
||||||
private String sendNotes;
|
|
||||||
private BarcodeData barcodeData;
|
private BarcodeData barcodeData;
|
||||||
|
|
||||||
// Listeners
|
// Listeners
|
||||||
|
@ -347,36 +408,6 @@ public class SendFragment extends Fragment
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setAddress(final String address) {
|
|
||||||
sendAddress = address;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPaymentId(final String paymentId) {
|
|
||||||
sendPaymentId = paymentId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setAmount(final long amount) {
|
|
||||||
sendAmount = amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPriority(final PendingTransaction.Priority priority) {
|
|
||||||
sendPriority = priority;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setMixin(final int mixin) {
|
|
||||||
sendMixin = mixin;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setNotes(final String notes) {
|
|
||||||
sendNotes = notes;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isComitted() {
|
boolean isComitted() {
|
||||||
return committedTx != null;
|
return committedTx != null;
|
||||||
}
|
}
|
||||||
|
@ -391,9 +422,9 @@ public class SendFragment extends Fragment
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void commitTransaction() {
|
public void commitTransaction() {
|
||||||
Timber.d("REALLY SEND A %s", getNotes());
|
Timber.d("REALLY SEND");
|
||||||
disableNavigation(); // committed - disable all navigation
|
disableNavigation(); // committed - disable all navigation
|
||||||
activityCallback.onSend(getNotes());
|
activityCallback.onSend(txData.getUserNotes());
|
||||||
committedTx = pendingTx;
|
committedTx = pendingTx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,12 +449,11 @@ public class SendFragment extends Fragment
|
||||||
|
|
||||||
// callbacks from send service
|
// callbacks from send service
|
||||||
|
|
||||||
public void onTransactionCreated(PendingTransaction pendingTransaction) {
|
public void onTransactionCreated(final String txTag, final PendingTransaction pendingTransaction) {
|
||||||
//public void onTransactionCreated(TestTransaction pendingTransaction) {
|
final SendConfirm confirm = getSendConfirm();
|
||||||
final SendConfirmWizardFragment confirmFragment = getConfirmFragment();
|
if (confirm != null) {
|
||||||
if (confirmFragment != null) {
|
|
||||||
pendingTx = new PendingTx(pendingTransaction);
|
pendingTx = new PendingTx(pendingTransaction);
|
||||||
confirmFragment.transactionCreated(pendingTransaction);
|
confirm.transactionCreated(txTag, pendingTransaction);
|
||||||
} else {
|
} else {
|
||||||
// not in confirm fragment => dispose & move on
|
// not in confirm fragment => dispose & move on
|
||||||
disposeTransaction();
|
disposeTransaction();
|
||||||
|
@ -443,23 +473,16 @@ public class SendFragment extends Fragment
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onCreateTransactionFailed(String errorText) {
|
public void onCreateTransactionFailed(String errorText) {
|
||||||
final SendConfirmWizardFragment confirmFragment = getConfirmFragment();
|
final SendConfirm confirm = getSendConfirm();
|
||||||
if (confirmFragment != null) {
|
if (confirm != null) {
|
||||||
confirmFragment.hideProgress();
|
confirm.createTransactionFailed(errorText);
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
|
||||||
builder.setCancelable(true).
|
|
||||||
setTitle(getString(R.string.send_create_tx_error_title)).
|
|
||||||
setMessage(errorText).
|
|
||||||
create().
|
|
||||||
show();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SendConfirmWizardFragment getConfirmFragment() {
|
SendConfirm getSendConfirm() {
|
||||||
final SendWizardFragment fragment = pagerAdapter.getFragment(SpendPagerAdapter.POS_CONFIRM);
|
final SendWizardFragment fragment = pagerAdapter.getFragment(SpendPagerAdapter.POS_CONFIRM);
|
||||||
if (fragment instanceof SendConfirmWizardFragment) {
|
if (fragment instanceof SendConfirm) {
|
||||||
return (SendConfirmWizardFragment) fragment;
|
return (SendConfirm) fragment;
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -469,8 +492,8 @@ public class SendFragment extends Fragment
|
||||||
Timber.d("txid=%s", txId);
|
Timber.d("txid=%s", txId);
|
||||||
pagerAdapter.addSuccess();
|
pagerAdapter.addSuccess();
|
||||||
Timber.d("numPages=%d", spendViewPager.getAdapter().getCount());
|
Timber.d("numPages=%d", spendViewPager.getAdapter().getCount());
|
||||||
spendViewPager.setCurrentItem(SpendPagerAdapter.POS_SUCCESS);
|
|
||||||
activityCallback.setToolbarButton(Toolbar.BUTTON_NONE);
|
activityCallback.setToolbarButton(Toolbar.BUTTON_NONE);
|
||||||
|
spendViewPager.setCurrentItem(SpendPagerAdapter.POS_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onSendTransactionFailed(final String error) {
|
public void onSendTransactionFailed(final String error) {
|
||||||
|
@ -478,7 +501,7 @@ public class SendFragment extends Fragment
|
||||||
committedTx = null;
|
committedTx = null;
|
||||||
Toast.makeText(getContext(), getString(R.string.status_transaction_failed, error), Toast.LENGTH_SHORT).show();
|
Toast.makeText(getContext(), getString(R.string.status_transaction_failed, error), Toast.LENGTH_SHORT).show();
|
||||||
enableNavigation();
|
enableNavigation();
|
||||||
final SendConfirmWizardFragment fragment = getConfirmFragment();
|
final SendConfirm fragment = getSendConfirm();
|
||||||
if (fragment != null) {
|
if (fragment != null) {
|
||||||
fragment.sendFailed();
|
fragment.sendFailed();
|
||||||
}
|
}
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.m2049r.xmrwallet;
|
package com.m2049r.xmrwallet.fragment.send;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
|
@ -27,8 +27,11 @@ import android.widget.EditText;
|
||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.R;
|
||||||
|
import com.m2049r.xmrwallet.data.TxData;
|
||||||
import com.m2049r.xmrwallet.model.PendingTransaction;
|
import com.m2049r.xmrwallet.model.PendingTransaction;
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
|
import com.m2049r.xmrwallet.util.UserNotes;
|
||||||
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
@ -48,12 +51,7 @@ public class SendSettingsWizardFragment extends SendWizardFragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Listener {
|
interface Listener {
|
||||||
|
TxData getTxData();
|
||||||
void setPriority(final PendingTransaction.Priority priority);
|
|
||||||
|
|
||||||
void setMixin(final int mixin);
|
|
||||||
|
|
||||||
void setNotes(final String notes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final static int Mixins[] = {4, 7, 12, 25}; // must match the layout XML
|
final static int Mixins[] = {4, 7, 12, 25}; // must match the layout XML
|
||||||
|
@ -103,13 +101,10 @@ public class SendSettingsWizardFragment extends SendWizardFragment {
|
||||||
@Override
|
@Override
|
||||||
public boolean onValidateFields() {
|
public boolean onValidateFields() {
|
||||||
if (sendListener != null) {
|
if (sendListener != null) {
|
||||||
int mixin = Mixins[sMixin.getSelectedItemPosition()];
|
TxData txData = sendListener.getTxData();
|
||||||
int priorityIndex = sPriority.getSelectedItemPosition();
|
txData.setPriority(Priorities[sPriority.getSelectedItemPosition()]);
|
||||||
PendingTransaction.Priority priority = Priorities[priorityIndex];
|
txData.setMixin(Mixins[sMixin.getSelectedItemPosition()]);
|
||||||
sendListener.setPriority(priority);
|
txData.setUserNotes(new UserNotes(etNotes.getText().toString()));
|
||||||
sendListener.setMixin(mixin);
|
|
||||||
String notes = etNotes.getText().toString();
|
|
||||||
sendListener.setNotes(notes);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.m2049r.xmrwallet;
|
package com.m2049r.xmrwallet.fragment.send;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
@ -24,10 +24,10 @@ import android.widget.ImageButton;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.R;
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
|
||||||
import com.m2049r.xmrwallet.data.PendingTx;
|
import com.m2049r.xmrwallet.data.PendingTx;
|
||||||
import com.m2049r.xmrwallet.data.TxData;
|
import com.m2049r.xmrwallet.data.TxData;
|
||||||
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
@ -47,23 +47,21 @@ public class SendSuccessWizardFragment extends SendWizardFragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Listener {
|
interface Listener {
|
||||||
String getNotes();
|
|
||||||
|
|
||||||
TxData getTxData();
|
TxData getTxData();
|
||||||
|
|
||||||
PendingTx getCommittedTx();
|
PendingTx getCommittedTx();
|
||||||
|
|
||||||
void enableDone();
|
void enableDone();
|
||||||
|
|
||||||
|
SendFragment.Mode getMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageButton bCopyAddress;
|
ImageButton bCopyTxId;
|
||||||
private TextView tvTxId;
|
private TextView tvTxId;
|
||||||
private TextView tvTxAddress;
|
private TextView tvTxAddress;
|
||||||
private TextView tvTxPaymentId;
|
private TextView tvTxPaymentId;
|
||||||
private TextView tvTxNotes;
|
|
||||||
private TextView tvTxAmount;
|
private TextView tvTxAmount;
|
||||||
private TextView tvTxFee;
|
private TextView tvTxFee;
|
||||||
private TextView tvTxTotal;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
@ -74,21 +72,20 @@ public class SendSuccessWizardFragment extends SendWizardFragment {
|
||||||
View view = inflater.inflate(
|
View view = inflater.inflate(
|
||||||
R.layout.fragment_send_success, container, false);
|
R.layout.fragment_send_success, container, false);
|
||||||
|
|
||||||
bCopyAddress = (ImageButton) view.findViewById(R.id.bCopyAddress);
|
bCopyTxId = (ImageButton) view.findViewById(R.id.bCopyTxId);
|
||||||
bCopyAddress.setOnClickListener(new View.OnClickListener() {
|
bCopyTxId.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
copyAddress();
|
Helper.clipBoardCopy(getActivity(), getString(R.string.label_send_txid), tvTxId.getText().toString());
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.message_copy_address), Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
tvTxId = (TextView) view.findViewById(R.id.tvTxId);
|
tvTxId = (TextView) view.findViewById(R.id.tvTxId);
|
||||||
tvTxAddress = (TextView) view.findViewById(R.id.tvTxAddress);
|
tvTxAddress = (TextView) view.findViewById(R.id.tvTxAddress);
|
||||||
tvTxPaymentId = (TextView) view.findViewById(R.id.tvTxPaymentId);
|
tvTxPaymentId = (TextView) view.findViewById(R.id.tvTxPaymentId);
|
||||||
tvTxNotes = (TextView) view.findViewById(R.id.tvTxNotes);
|
|
||||||
tvTxAmount = ((TextView) view.findViewById(R.id.tvTxAmount));
|
tvTxAmount = ((TextView) view.findViewById(R.id.tvTxAmount));
|
||||||
tvTxFee = (TextView) view.findViewById(R.id.tvTxFee);
|
tvTxFee = (TextView) view.findViewById(R.id.tvTxFee);
|
||||||
tvTxTotal = (TextView) view.findViewById(R.id.tvTxTotal);
|
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
@ -117,30 +114,15 @@ public class SendSuccessWizardFragment extends SendWizardFragment {
|
||||||
} else {
|
} else {
|
||||||
tvTxPaymentId.setText("-");
|
tvTxPaymentId.setText("-");
|
||||||
}
|
}
|
||||||
String notes = sendListener.getNotes();
|
|
||||||
if ((notes != null) && (!notes.isEmpty())) {
|
|
||||||
tvTxNotes.setText(sendListener.getNotes());
|
|
||||||
} else {
|
|
||||||
tvTxNotes.setText("-");
|
|
||||||
}
|
|
||||||
|
|
||||||
final PendingTx committedTx = sendListener.getCommittedTx();
|
final PendingTx committedTx = sendListener.getCommittedTx();
|
||||||
if (committedTx != null) {
|
if (committedTx != null) {
|
||||||
tvTxId.setText(committedTx.txId);
|
tvTxId.setText(committedTx.txId);
|
||||||
bCopyAddress.setEnabled(true);
|
bCopyTxId.setEnabled(true);
|
||||||
bCopyAddress.setImageResource(R.drawable.ic_content_copy_black_24dp);
|
bCopyTxId.setImageResource(R.drawable.ic_content_copy_black_24dp);
|
||||||
tvTxAmount.setText(Wallet.getDisplayAmount(committedTx.amount));
|
tvTxAmount.setText(getString(R.string.send_amount, Helper.getDisplayAmount(committedTx.amount)));
|
||||||
tvTxFee.setText(Wallet.getDisplayAmount(committedTx.fee));
|
tvTxFee.setText(getString(R.string.send_fee, Helper.getDisplayAmount(committedTx.fee)));
|
||||||
//tvTxDust.setText(Wallet.getDisplayAmount(pendingTransaction.getDust()));
|
|
||||||
tvTxTotal.setText(Wallet.getDisplayAmount(
|
|
||||||
committedTx.fee + committedTx.amount));
|
|
||||||
}
|
}
|
||||||
sendListener.enableDone();
|
sendListener.enableDone();
|
||||||
}
|
}
|
||||||
|
|
||||||
void copyAddress() {
|
|
||||||
Helper.clipBoardCopy(getActivity(), getString(R.string.label_send_txid), tvTxId.getText().toString());
|
|
||||||
Toast.makeText(getActivity(), getString(R.string.message_copy_address), Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.m2049r.xmrwallet;
|
package com.m2049r.xmrwallet.fragment.send;
|
||||||
|
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
|
|
|
@ -21,7 +21,7 @@ import android.support.v4.view.ViewPager;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.SendFragment;
|
import com.m2049r.xmrwallet.fragment.send.SendFragment;
|
||||||
|
|
||||||
public class SpendViewPager extends ViewPager {
|
public class SpendViewPager extends ViewPager {
|
||||||
|
|
||||||
|
|
|
@ -22,11 +22,13 @@ import android.support.v7.widget.RecyclerView;
|
||||||
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.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.R;
|
import com.m2049r.xmrwallet.R;
|
||||||
import com.m2049r.xmrwallet.model.TransactionInfo;
|
import com.m2049r.xmrwallet.model.TransactionInfo;
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
|
import com.m2049r.xmrwallet.util.UserNotes;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -101,6 +103,7 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
|
class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
|
||||||
|
final ImageView ivTxType;
|
||||||
final TextView tvAmount;
|
final TextView tvAmount;
|
||||||
final TextView tvFee;
|
final TextView tvFee;
|
||||||
final TextView tvPaymentId;
|
final TextView tvPaymentId;
|
||||||
|
@ -109,10 +112,11 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
||||||
|
|
||||||
ViewHolder(View itemView) {
|
ViewHolder(View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
this.tvAmount = (TextView) itemView.findViewById(R.id.tx_amount);
|
ivTxType = (ImageView) itemView.findViewById(R.id.ivTxType);
|
||||||
this.tvFee = (TextView) itemView.findViewById(R.id.tx_fee);
|
tvAmount = (TextView) itemView.findViewById(R.id.tx_amount);
|
||||||
this.tvPaymentId = (TextView) itemView.findViewById(R.id.tx_paymentid);
|
tvFee = (TextView) itemView.findViewById(R.id.tx_fee);
|
||||||
this.tvDateTime = (TextView) itemView.findViewById(R.id.tx_datetime);
|
tvPaymentId = (TextView) itemView.findViewById(R.id.tx_paymentid);
|
||||||
|
tvDateTime = (TextView) itemView.findViewById(R.id.tx_datetime);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getDateTime(long time) {
|
private String getDateTime(long time) {
|
||||||
|
@ -121,7 +125,6 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
||||||
|
|
||||||
private void setTxColour(int clr) {
|
private void setTxColour(int clr) {
|
||||||
tvAmount.setTextColor(clr);
|
tvAmount.setTextColor(clr);
|
||||||
tvFee.setTextColor(clr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void bind(int position) {
|
void bind(int position) {
|
||||||
|
@ -134,20 +137,23 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
||||||
|
|
||||||
String displayAmount = Helper.getDisplayAmount(realAmount, Helper.DISPLAY_DIGITS_INFO);
|
String displayAmount = Helper.getDisplayAmount(realAmount, Helper.DISPLAY_DIGITS_INFO);
|
||||||
if (infoItem.direction == TransactionInfo.Direction.Direction_Out) {
|
if (infoItem.direction == TransactionInfo.Direction.Direction_Out) {
|
||||||
this.tvAmount.setText(context.getString(R.string.tx_list_amount_negative, displayAmount));
|
tvAmount.setText(context.getString(R.string.tx_list_amount_negative, displayAmount));
|
||||||
} else {
|
} else {
|
||||||
this.tvAmount.setText(context.getString(R.string.tx_list_amount_positive, displayAmount));
|
tvAmount.setText(context.getString(R.string.tx_list_amount_positive, displayAmount));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((infoItem.fee > 0)) {
|
if ((infoItem.fee > 0)) {
|
||||||
String fee = Helper.getDisplayAmount(infoItem.fee, 5);
|
String fee = Helper.getDisplayAmount(infoItem.fee, 5);
|
||||||
this.tvFee.setText(context.getString(R.string.tx_list_fee, fee));
|
tvFee.setText(context.getString(R.string.tx_list_fee, fee));
|
||||||
|
tvFee.setVisibility(View.VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
this.tvFee.setText("");
|
tvFee.setText("");
|
||||||
|
tvFee.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
if (infoItem.isFailed) {
|
if (infoItem.isFailed) {
|
||||||
this.tvAmount.setText(context.getString(R.string.tx_list_amount_failed, displayAmount));
|
this.tvAmount.setText(context.getString(R.string.tx_list_amount_failed, displayAmount));
|
||||||
this.tvFee.setText(context.getString(R.string.tx_list_failed_text));
|
this.tvFee.setText(context.getString(R.string.tx_list_failed_text));
|
||||||
|
tvFee.setVisibility(View.VISIBLE);
|
||||||
setTxColour(failedColour);
|
setTxColour(failedColour);
|
||||||
} else if (infoItem.isPending) {
|
} else if (infoItem.isPending) {
|
||||||
setTxColour(pendingColour);
|
setTxColour(pendingColour);
|
||||||
|
@ -156,11 +162,20 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
||||||
} else {
|
} else {
|
||||||
setTxColour(outboundColour);
|
setTxColour(outboundColour);
|
||||||
}
|
}
|
||||||
if ((infoItem.notes == null) || (infoItem.notes.isEmpty())) {
|
|
||||||
|
UserNotes userNotes = new UserNotes(infoItem.notes);
|
||||||
|
if (userNotes.xmrtoKey != null) {
|
||||||
|
ivTxType.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
ivTxType.setVisibility(View.INVISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((userNotes.note.isEmpty())) {
|
||||||
this.tvPaymentId.setText(infoItem.paymentId.equals("0000000000000000") ? "" : infoItem.paymentId);
|
this.tvPaymentId.setText(infoItem.paymentId.equals("0000000000000000") ? "" : infoItem.paymentId);
|
||||||
} else {
|
} else {
|
||||||
this.tvPaymentId.setText(infoItem.notes);
|
this.tvPaymentId.setText(userNotes.note);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.tvDateTime.setText(getDateTime(infoItem.timestamp));
|
this.tvDateTime.setText(getDateTime(infoItem.timestamp));
|
||||||
|
|
||||||
itemView.setOnClickListener(this);
|
itemView.setOnClickListener(this);
|
||||||
|
|
|
@ -30,12 +30,12 @@ import android.os.Process;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.R;
|
import com.m2049r.xmrwallet.R;
|
||||||
import com.m2049r.xmrwallet.WalletActivity;
|
import com.m2049r.xmrwallet.WalletActivity;
|
||||||
|
import com.m2049r.xmrwallet.data.TxData;
|
||||||
import com.m2049r.xmrwallet.model.PendingTransaction;
|
import com.m2049r.xmrwallet.model.PendingTransaction;
|
||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
import com.m2049r.xmrwallet.model.WalletListener;
|
import com.m2049r.xmrwallet.model.WalletListener;
|
||||||
import com.m2049r.xmrwallet.model.WalletManager;
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
import com.m2049r.xmrwallet.data.TxData;
|
|
||||||
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
@ -54,6 +54,7 @@ public class WalletService extends Service {
|
||||||
|
|
||||||
public static final String REQUEST_CMD_TX = "createTX";
|
public static final String REQUEST_CMD_TX = "createTX";
|
||||||
public static final String REQUEST_CMD_TX_DATA = "data";
|
public static final String REQUEST_CMD_TX_DATA = "data";
|
||||||
|
public static final String REQUEST_CMD_TX_TAG = "tag";
|
||||||
|
|
||||||
public static final String REQUEST_CMD_SWEEP = "sweepTX";
|
public static final String REQUEST_CMD_SWEEP = "sweepTX";
|
||||||
|
|
||||||
|
@ -209,7 +210,7 @@ public class WalletService extends Service {
|
||||||
|
|
||||||
void onWalletStored(boolean success);
|
void onWalletStored(boolean success);
|
||||||
|
|
||||||
void onTransactionCreated(PendingTransaction pendingTransaction);
|
void onTransactionCreated(String tag, PendingTransaction pendingTransaction);
|
||||||
|
|
||||||
void onTransactionSent(String txid);
|
void onTransactionSent(String txid);
|
||||||
|
|
||||||
|
@ -301,7 +302,9 @@ public class WalletService extends Service {
|
||||||
} else if (cmd.equals(REQUEST_CMD_TX)) {
|
} else if (cmd.equals(REQUEST_CMD_TX)) {
|
||||||
Wallet myWallet = getWallet();
|
Wallet myWallet = getWallet();
|
||||||
Timber.d("CREATE TX for wallet: %s", myWallet.getName());
|
Timber.d("CREATE TX for wallet: %s", myWallet.getName());
|
||||||
|
myWallet.disposePendingTransaction(); // remove any old pending tx
|
||||||
TxData txData = extras.getParcelable(REQUEST_CMD_TX_DATA);
|
TxData txData = extras.getParcelable(REQUEST_CMD_TX_DATA);
|
||||||
|
String txTag = extras.getString(REQUEST_CMD_TX_TAG);
|
||||||
PendingTransaction pendingTransaction = myWallet.createTransaction(txData);
|
PendingTransaction pendingTransaction = myWallet.createTransaction(txData);
|
||||||
PendingTransaction.Status status = pendingTransaction.getStatus();
|
PendingTransaction.Status status = pendingTransaction.getStatus();
|
||||||
Timber.d("transaction status %s", status);
|
Timber.d("transaction status %s", status);
|
||||||
|
@ -309,13 +312,15 @@ public class WalletService extends Service {
|
||||||
Timber.w("Create Transaction failed: %s", pendingTransaction.getErrorString());
|
Timber.w("Create Transaction failed: %s", pendingTransaction.getErrorString());
|
||||||
}
|
}
|
||||||
if (observer != null) {
|
if (observer != null) {
|
||||||
observer.onTransactionCreated(pendingTransaction);
|
observer.onTransactionCreated(txTag, pendingTransaction);
|
||||||
} else {
|
} else {
|
||||||
myWallet.disposePendingTransaction();
|
myWallet.disposePendingTransaction();
|
||||||
}
|
}
|
||||||
} else if (cmd.equals(REQUEST_CMD_SWEEP)) {
|
} else if (cmd.equals(REQUEST_CMD_SWEEP)) {
|
||||||
Wallet myWallet = getWallet();
|
Wallet myWallet = getWallet();
|
||||||
Timber.d("SWEEP TX for wallet: %s", myWallet.getName());
|
Timber.d("SWEEP TX for wallet: %s", myWallet.getName());
|
||||||
|
myWallet.disposePendingTransaction(); // remove any old pending tx
|
||||||
|
String txTag = extras.getString(REQUEST_CMD_TX_TAG);
|
||||||
PendingTransaction pendingTransaction = myWallet.createSweepUnmixableTransaction();
|
PendingTransaction pendingTransaction = myWallet.createSweepUnmixableTransaction();
|
||||||
PendingTransaction.Status status = pendingTransaction.getStatus();
|
PendingTransaction.Status status = pendingTransaction.getStatus();
|
||||||
Timber.d("transaction status %s", status);
|
Timber.d("transaction status %s", status);
|
||||||
|
@ -323,7 +328,7 @@ public class WalletService extends Service {
|
||||||
Timber.w("Create Transaction failed: %s", pendingTransaction.getErrorString());
|
Timber.w("Create Transaction failed: %s", pendingTransaction.getErrorString());
|
||||||
}
|
}
|
||||||
if (observer != null) {
|
if (observer != null) {
|
||||||
observer.onTransactionCreated(pendingTransaction);
|
observer.onTransactionCreated(txTag, pendingTransaction);
|
||||||
} else {
|
} else {
|
||||||
myWallet.disposePendingTransaction();
|
myWallet.disposePendingTransaction();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 m2049r er al.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.util;
|
||||||
|
|
||||||
|
// based on https://rosettacode.org/wiki/Bitcoin/address_validation#Java
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class BitcoinAddressValidator {
|
||||||
|
|
||||||
|
private static final String ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
||||||
|
|
||||||
|
public static boolean validate(String addrress, boolean testnet) {
|
||||||
|
if (addrress.length() < 26 || addrress.length() > 35)
|
||||||
|
return false;
|
||||||
|
byte[] decoded = decodeBase58To25Bytes(addrress);
|
||||||
|
if (decoded == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!testnet) {
|
||||||
|
if ((decoded[0] != 0x00) && (decoded[0] != 0x05)) return false;
|
||||||
|
} else {
|
||||||
|
if ((decoded[0] != 0x6f) && (decoded[0] != 0xc4)) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] hash1 = sha256(Arrays.copyOfRange(decoded, 0, 21));
|
||||||
|
byte[] hash2 = sha256(hash1);
|
||||||
|
|
||||||
|
return Arrays.equals(Arrays.copyOfRange(hash2, 0, 4), Arrays.copyOfRange(decoded, 21, 25));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] decodeBase58To25Bytes(String input) {
|
||||||
|
BigInteger num = BigInteger.ZERO;
|
||||||
|
for (char t : input.toCharArray()) {
|
||||||
|
int p = ALPHABET.indexOf(t);
|
||||||
|
if (p == -1)
|
||||||
|
return null;
|
||||||
|
num = num.multiply(BigInteger.valueOf(58)).add(BigInteger.valueOf(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] result = new byte[25];
|
||||||
|
byte[] numBytes = num.toByteArray();
|
||||||
|
System.arraycopy(numBytes, 0, result, result.length - numBytes.length, numBytes.length);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] sha256(byte[] data) {
|
||||||
|
try {
|
||||||
|
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||||
|
md.update(data);
|
||||||
|
return md.digest();
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,6 +38,7 @@ import android.view.inputmethod.InputMethodManager;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.R;
|
import com.m2049r.xmrwallet.R;
|
||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -49,6 +50,7 @@ import java.util.Locale;
|
||||||
|
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
|
|
||||||
|
import okhttp3.HttpUrl;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
public class Helper {
|
public class Helper {
|
||||||
|
@ -160,7 +162,7 @@ public class Helper {
|
||||||
}
|
}
|
||||||
|
|
||||||
static public String getDisplayAmount(long amount) {
|
static public String getDisplayAmount(long amount) {
|
||||||
return getDisplayAmount(amount, 20);
|
return getDisplayAmount(amount, 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
static public String getDisplayAmount(long amount, int maxDecimals) {
|
static public String getDisplayAmount(long amount, int maxDecimals) {
|
||||||
|
@ -271,4 +273,11 @@ public class Helper {
|
||||||
return ShakeAnimation;
|
return ShakeAnimation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static public HttpUrl getXmrToBaseUrl() {
|
||||||
|
if ((WalletManager.getInstance() == null) || WalletManager.getInstance().isTestNet()) {
|
||||||
|
return HttpUrl.parse("https://test.xmr.to/api/v2/xmr2btc/");
|
||||||
|
} else {
|
||||||
|
return HttpUrl.parse("https://xmr.to/api/v2/xmr2btc/");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 m2049r
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.util;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.QueryOrderStatus;
|
||||||
|
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
public class UserNotes {
|
||||||
|
public String txNotes = "";
|
||||||
|
public String note = "";
|
||||||
|
public String xmrtoKey = null;
|
||||||
|
public String xmrtoAmount = null; // could be a double - but we are not doing any calculations
|
||||||
|
public String xmrtoDestination = null;
|
||||||
|
|
||||||
|
public UserNotes(final String txNotes) {
|
||||||
|
if (txNotes == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.txNotes = txNotes;
|
||||||
|
Pattern p = Pattern.compile("^\\{(xmrto-\\w{6}),([0-9.]*)BTC,(\\w*)\\} ?(.*)");
|
||||||
|
Matcher m = p.matcher(txNotes);
|
||||||
|
if (m.find()) {
|
||||||
|
xmrtoKey = m.group(1);
|
||||||
|
xmrtoAmount = m.group(2);
|
||||||
|
xmrtoDestination = m.group(3);
|
||||||
|
note = m.group(4);
|
||||||
|
} else {
|
||||||
|
note = txNotes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNote(String newNote) {
|
||||||
|
if (newNote != null) {
|
||||||
|
note = newNote;
|
||||||
|
} else {
|
||||||
|
note = "";
|
||||||
|
}
|
||||||
|
txNotes = buildTxNote();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setXmrtoStatus(QueryOrderStatus xmrtoStatus) {
|
||||||
|
if (xmrtoStatus != null) {
|
||||||
|
xmrtoKey = xmrtoStatus.getUuid();
|
||||||
|
xmrtoAmount = String.valueOf(xmrtoStatus.getBtcAmount());
|
||||||
|
xmrtoDestination = xmrtoStatus.getBtcDestAddress();
|
||||||
|
} else {
|
||||||
|
xmrtoKey = null;
|
||||||
|
xmrtoAmount = null;
|
||||||
|
xmrtoDestination = null;
|
||||||
|
}
|
||||||
|
txNotes = buildTxNote();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildTxNote() {
|
||||||
|
StringBuffer sb = new StringBuffer();
|
||||||
|
if (xmrtoKey != null) {
|
||||||
|
if ((xmrtoAmount == null) || (xmrtoDestination == null))
|
||||||
|
throw new IllegalArgumentException("Broken notes");
|
||||||
|
sb.append("{");
|
||||||
|
sb.append(xmrtoKey);
|
||||||
|
sb.append(",");
|
||||||
|
sb.append(xmrtoAmount);
|
||||||
|
sb.append("BTC,");
|
||||||
|
sb.append(xmrtoDestination);
|
||||||
|
sb.append("}");
|
||||||
|
if ((note != null) && (!note.isEmpty()))
|
||||||
|
sb.append(" ");
|
||||||
|
}
|
||||||
|
sb.append(note);
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,198 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 m2049r
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// based on https://code.tutsplus.com/tutorials/creating-compound-views-on-android--cms-22889
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.widget;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.Spinner;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.R;
|
||||||
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
|
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
public class ExchangeBtcTextView extends LinearLayout
|
||||||
|
implements NumberPadView.NumberPadListener {
|
||||||
|
|
||||||
|
String btcAmount = null;
|
||||||
|
String xmrAmount = null;
|
||||||
|
|
||||||
|
private boolean validate(String amount, double max, double min) {
|
||||||
|
boolean ok = true;
|
||||||
|
if (amount != null) {
|
||||||
|
try {
|
||||||
|
double x = Double.parseDouble(amount);
|
||||||
|
if ((x < min) || (x > max)) {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
Timber.e(ex.getLocalizedMessage());
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean validate(double maxBtc, double minBtc) {
|
||||||
|
Timber.d("validate(maxBtc=%f,minBtc=%f)", maxBtc, minBtc);
|
||||||
|
boolean ok = true;
|
||||||
|
if (!validate(btcAmount, maxBtc, minBtc)) {
|
||||||
|
Timber.d("btcAmount invalid %s", btcAmount);
|
||||||
|
shakeAmountField();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void shakeAmountField() {
|
||||||
|
tvAmountA.startAnimation(Helper.getShakeAnimation(getContext()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void shakeExchangeField() {
|
||||||
|
tvAmountB.startAnimation(Helper.getShakeAnimation(getContext()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRate(double xmrBtcRate) {
|
||||||
|
this.xmrBtcRate = xmrBtcRate;
|
||||||
|
post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
exchange();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAmount(String btcAmount) {
|
||||||
|
this.btcAmount = btcAmount;
|
||||||
|
tvAmountA.setText(btcAmount);
|
||||||
|
xmrAmount = null;
|
||||||
|
exchange();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAmount() {
|
||||||
|
return btcAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextView tvAmountA;
|
||||||
|
TextView tvAmountB;
|
||||||
|
Spinner sCurrencyA;
|
||||||
|
Spinner sCurrencyB;
|
||||||
|
|
||||||
|
public ExchangeBtcTextView(Context context) {
|
||||||
|
super(context);
|
||||||
|
initializeViews(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExchangeBtcTextView(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
initializeViews(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExchangeBtcTextView(Context context,
|
||||||
|
AttributeSet attrs,
|
||||||
|
int defStyle) {
|
||||||
|
super(context, attrs, defStyle);
|
||||||
|
initializeViews(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inflates the views in the layout.
|
||||||
|
*
|
||||||
|
* @param context the current context for the view.
|
||||||
|
*/
|
||||||
|
private void initializeViews(Context context) {
|
||||||
|
LayoutInflater inflater = (LayoutInflater) context
|
||||||
|
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
inflater.inflate(R.layout.view_exchange_btc_text, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onFinishInflate() {
|
||||||
|
super.onFinishInflate();
|
||||||
|
tvAmountA = (TextView) findViewById(R.id.tvAmountA);
|
||||||
|
tvAmountB = (TextView) findViewById(R.id.tvAmountB);
|
||||||
|
sCurrencyA = (Spinner) findViewById(R.id.sCurrencyA);
|
||||||
|
sCurrencyB = (Spinner) findViewById(R.id.sCurrencyB);
|
||||||
|
|
||||||
|
ArrayAdapter<String> btcAdapter = new ArrayAdapter<String>(getContext(),
|
||||||
|
android.R.layout.simple_spinner_item,
|
||||||
|
new String[]{"BTC"});
|
||||||
|
sCurrencyA.setAdapter(btcAdapter);
|
||||||
|
sCurrencyA.setEnabled(false);
|
||||||
|
ArrayAdapter<String> xmrAdapter = new ArrayAdapter<String>(getContext(),
|
||||||
|
android.R.layout.simple_spinner_item,
|
||||||
|
new String[]{"XMR"});
|
||||||
|
sCurrencyB.setAdapter(xmrAdapter);
|
||||||
|
sCurrencyB.setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
double xmrBtcRate = 0;
|
||||||
|
|
||||||
|
public void exchange() {
|
||||||
|
btcAmount = tvAmountA.getText().toString();
|
||||||
|
if (!btcAmount.isEmpty() && (xmrBtcRate > 0)) {
|
||||||
|
double xmr = xmrBtcRate * Double.parseDouble(btcAmount);
|
||||||
|
xmrAmount = Helper.getFormattedAmount(xmr, true);
|
||||||
|
} else {
|
||||||
|
xmrAmount = "";
|
||||||
|
}
|
||||||
|
tvAmountB.setText(getResources().getString(R.string.send_amount_btc_xmr, xmrAmount));
|
||||||
|
Timber.d("%s BTC =%f> %s XMR", btcAmount, xmrBtcRate, xmrAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
// deal with attached numpad
|
||||||
|
@Override
|
||||||
|
public void onDigitPressed(final int digit) {
|
||||||
|
tvAmountA.append(String.valueOf(digit));
|
||||||
|
exchange();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPointPressed() {
|
||||||
|
//TODO locale?
|
||||||
|
if (tvAmountA.getText().toString().indexOf('.') == -1) {
|
||||||
|
if (tvAmountA.getText().toString().isEmpty()) {
|
||||||
|
tvAmountA.append("0");
|
||||||
|
}
|
||||||
|
tvAmountA.append(".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackSpacePressed() {
|
||||||
|
String entry = tvAmountA.getText().toString();
|
||||||
|
int length = entry.length();
|
||||||
|
if (length > 0) {
|
||||||
|
tvAmountA.setText(entry.substring(0, entry.length() - 1));
|
||||||
|
exchange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClearAll() {
|
||||||
|
tvAmountA.setText(null);
|
||||||
|
exchange();
|
||||||
|
}
|
||||||
|
}
|
|
@ -436,6 +436,9 @@ public class ExchangeTextView extends LinearLayout
|
||||||
public void onPointPressed() {
|
public void onPointPressed() {
|
||||||
//TODO locale?
|
//TODO locale?
|
||||||
if (tvAmountA.getText().toString().indexOf('.') == -1) {
|
if (tvAmountA.getText().toString().indexOf('.') == -1) {
|
||||||
|
if (tvAmountA.getText().toString().isEmpty()) {
|
||||||
|
tvAmountA.append("0");
|
||||||
|
}
|
||||||
tvAmountA.append(".");
|
tvAmountA.append(".");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 m2049r
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.widget;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.R;
|
||||||
|
|
||||||
|
public class SendProgressView extends LinearLayout {
|
||||||
|
|
||||||
|
public SendProgressView(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
initializeViews(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SendProgressView(Context context,
|
||||||
|
AttributeSet attrs,
|
||||||
|
int defStyle) {
|
||||||
|
super(context, attrs, defStyle);
|
||||||
|
initializeViews(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeViews(Context context) {
|
||||||
|
LayoutInflater inflater = (LayoutInflater) context
|
||||||
|
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
inflater.inflate(R.layout.view_send_progress, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
View pbProgress;
|
||||||
|
View llMessage;
|
||||||
|
TextView tvCode;
|
||||||
|
TextView tvMessage;
|
||||||
|
TextView tvSolution;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onFinishInflate() {
|
||||||
|
super.onFinishInflate();
|
||||||
|
pbProgress = findViewById(R.id.pbProgress);
|
||||||
|
llMessage = findViewById(R.id.llMessage);
|
||||||
|
tvCode = (TextView) findViewById(R.id.tvCode);
|
||||||
|
tvMessage = (TextView) findViewById(R.id.tvMessage);
|
||||||
|
tvSolution = (TextView) findViewById(R.id.tvSolution);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showProgress(String progressText) {
|
||||||
|
pbProgress.setVisibility(VISIBLE);
|
||||||
|
tvCode.setVisibility(INVISIBLE);
|
||||||
|
tvMessage.setText(progressText);
|
||||||
|
llMessage.setVisibility(VISIBLE);
|
||||||
|
tvSolution.setVisibility(INVISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void hideProgress() {
|
||||||
|
pbProgress.setVisibility(INVISIBLE);
|
||||||
|
llMessage.setVisibility(INVISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showMessage(String code, String message, String solution) {
|
||||||
|
tvCode.setText(code);
|
||||||
|
tvMessage.setText(message);
|
||||||
|
tvSolution.setText(solution);
|
||||||
|
tvCode.setVisibility(VISIBLE);
|
||||||
|
llMessage.setVisibility(VISIBLE);
|
||||||
|
tvSolution.setVisibility(VISIBLE);
|
||||||
|
pbProgress.setVisibility(INVISIBLE);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 m2049r et al.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.xmrto;
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
public class XmrToError {
|
||||||
|
private final Error errorId;
|
||||||
|
private final String errorMsg;
|
||||||
|
|
||||||
|
public enum Error {
|
||||||
|
XMRTO_ERROR_UNDEF,
|
||||||
|
XMRTO_ERROR_001, // (503) internal services not available try again later
|
||||||
|
XMRTO_ERROR_002, // (400) malformed bitcoin address check address validity
|
||||||
|
XMRTO_ERROR_003, // (400) invalid bitcoin amount check amount data type
|
||||||
|
XMRTO_ERROR_004, // (400) bitcoin amount out of bounds check min and max amount
|
||||||
|
XMRTO_ERROR_005, // (400) unexpected validation error contact support
|
||||||
|
XMRTO_ERROR_006, // (404) requested order not found check order UUID
|
||||||
|
XMRTO_ERROR_007, // (503) third party service not available try again later
|
||||||
|
XMRTO_ERROR_008, // (503) insufficient funds available try again later
|
||||||
|
XMRTO_ERROR_009 // (400) invalid request check request parameters
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRetryable() {
|
||||||
|
return (errorId == Error.XMRTO_ERROR_001)
|
||||||
|
|| (errorId == Error.XMRTO_ERROR_007)
|
||||||
|
|| (errorId == Error.XMRTO_ERROR_008);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getErrorIdString(Error anError) {
|
||||||
|
return anError.toString().replace('_', '-');
|
||||||
|
}
|
||||||
|
|
||||||
|
// mostly for testing
|
||||||
|
public XmrToError(String errorId, String message) {
|
||||||
|
Error error;
|
||||||
|
try {
|
||||||
|
error = Error.valueOf(errorId.replace('-', '_'));
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
error = Error.XMRTO_ERROR_UNDEF;
|
||||||
|
}
|
||||||
|
this.errorId = error;
|
||||||
|
this.errorMsg = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public XmrToError(final JSONObject jsonObject) throws JSONException {
|
||||||
|
final String errorId = jsonObject.getString("error");
|
||||||
|
Error error;
|
||||||
|
try {
|
||||||
|
error = Error.valueOf(errorId.replace('-', '_'));
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
error = Error.XMRTO_ERROR_UNDEF;
|
||||||
|
}
|
||||||
|
this.errorId = error;
|
||||||
|
this.errorMsg = jsonObject.getString("error_msg");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Error getErrorId() {
|
||||||
|
return errorId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getErrorMsg() {
|
||||||
|
return errorMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getErrorIdString(getErrorId()) + ": " + getErrorMsg();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Errors from Query Parameters
|
||||||
|
HTTP code XMR.TO error code Error message/reason Solution
|
||||||
|
503 XMRTO-ERROR-001 internal services not available try again later
|
||||||
|
503 XMRTO-ERROR-007 third party service not available try again later
|
||||||
|
503 XMRTO-ERROR-008 insufficient funds available try again later
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Errors from Create Order
|
||||||
|
HTTP code XMR.TO error code Error message/reason Solution
|
||||||
|
503 XMRTO-ERROR-001 internal services not available try again later
|
||||||
|
400 XMRTO-ERROR-002 malformed bitcoin address check address validity
|
||||||
|
400 XMRTO-ERROR-003 invalid bitcoin amount check amount data type
|
||||||
|
503 XMRTO-ERROR-004 bitcoin amount out of bounds check min and max amount
|
||||||
|
400 XMRTO-ERROR-005 unexpected validation error contact support
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Errors from Query Order
|
||||||
|
HTTP code XMR.TO error code Error message/reason Solution
|
||||||
|
400 XMRTO-ERROR-009 invalid request check request parameters
|
||||||
|
404 XMRTO-ERROR-006 requested order not found check order UUID
|
||||||
|
*/
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 m2049r et al.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.xmrto;
|
||||||
|
|
||||||
|
public class XmrToException extends Exception {
|
||||||
|
private int code;
|
||||||
|
private XmrToError error;
|
||||||
|
|
||||||
|
public XmrToException(final int code) {
|
||||||
|
super();
|
||||||
|
this.code = code;
|
||||||
|
this.error = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public XmrToException(final int code, final XmrToError error) {
|
||||||
|
super();
|
||||||
|
this.code = code;
|
||||||
|
this.error = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public XmrToError getError() {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 m2049r et al.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.xmrto.api;
|
||||||
|
|
||||||
|
public interface CreateOrder {
|
||||||
|
Double getBtcAmount();
|
||||||
|
|
||||||
|
String getBtcDestAddress();
|
||||||
|
|
||||||
|
String getState();
|
||||||
|
|
||||||
|
String getUuid();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 m2049r et al.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.xmrto.api;
|
||||||
|
|
||||||
|
public interface QueryOrderParameters {
|
||||||
|
|
||||||
|
double getLowerLimit(); // "lower_limit": <lower_order_limit_in_btc_as_float>,
|
||||||
|
|
||||||
|
double getPrice(); // "price": <price_of_1_btc_in_xmr_as_offered_by_service_as_float>,
|
||||||
|
|
||||||
|
double getUpperLimit(); // "upper_limit": <upper_order_limit_in_btc_as_float>,
|
||||||
|
|
||||||
|
boolean isZeroConfEnabled(); // "zero_conf_enabled": <true_if_zero_conf_is_enabled_as_boolean>,
|
||||||
|
|
||||||
|
double getZeroConfMaxAmount(); // "zero_conf_max_amount": <up_to_this_amount_zero_conf_is_possible_as_float>
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 m2049r et al.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.xmrto.api;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public interface QueryOrderStatus {
|
||||||
|
enum State {
|
||||||
|
UNDEF,
|
||||||
|
TO_BE_CREATED, // order creation pending
|
||||||
|
UNPAID, // waiting for Monero payment by user
|
||||||
|
UNDERPAID, // order partially paid
|
||||||
|
PAID_UNCONFIRMED, // order paid, waiting for enough confirmations
|
||||||
|
PAID, // order paid and sufficiently confirmed
|
||||||
|
BTC_SENT, // bitcoin payment sent
|
||||||
|
TIMED_OUT, // order timed out before payment was complete
|
||||||
|
NOT_FOUND // order wasn’t found in system (never existed or was purged)
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isCreated();
|
||||||
|
|
||||||
|
boolean isTerminal();
|
||||||
|
|
||||||
|
boolean isPending();
|
||||||
|
|
||||||
|
boolean isPaid();
|
||||||
|
|
||||||
|
boolean isSent();
|
||||||
|
|
||||||
|
boolean isError();
|
||||||
|
|
||||||
|
State getState(); // "state": "<order_state_as_string>",
|
||||||
|
|
||||||
|
double getBtcAmount(); // "btc_amount": <requested_amount_in_btc_as_float>,
|
||||||
|
|
||||||
|
String getBtcDestAddress(); // "btc_dest_address": "<requested_destination_address_as_string>",
|
||||||
|
|
||||||
|
String getUuid(); // "uuid": "<unique_order_identifier_as_12_character_string>"
|
||||||
|
|
||||||
|
int getBtcNumConfirmations(); // "btc_num_confirmations": <btc_num_confirmations_as_integer>,
|
||||||
|
|
||||||
|
int getBtcNumConfirmationsBeforePurge(); // "btc_num_confirmations_before_purge": <btc_num_confirmations_before_purge_as_integer>,
|
||||||
|
|
||||||
|
String getBtcTransactionId(); // "btc_transaction_id": "<btc_transaction_id_as_string>",
|
||||||
|
|
||||||
|
Date getCreatedAt(); // "created_at": "<timestamp_as_string>",
|
||||||
|
|
||||||
|
Date getExpiresAt(); // "expires_at": "<timestamp_as_string>",
|
||||||
|
|
||||||
|
int getSecondsTillTimeout(); // "seconds_till_timeout": <seconds_till_timeout_as_integer>,
|
||||||
|
|
||||||
|
double getXmrAmountTotal(); // "xmr_amount_total": <amount_in_xmr_for_this_order_as_float>,
|
||||||
|
|
||||||
|
double getXmrAmountRemaining(); // "xmr_amount_remaining": <amount_in_xmr_that_the_user_must_still_send_as_float>,
|
||||||
|
|
||||||
|
int getXmrNumConfirmationsRemaining(); // "xmr_num_confirmations_remaining": <num_xmr_confirmations_remaining_before_bitcoins_will_be_sent_as_integer>,
|
||||||
|
|
||||||
|
double getXmrPriceBtc(); // "xmr_price_btc": <price_of_1_btc_in_xmr_as_offered_by_service_as_float>,
|
||||||
|
|
||||||
|
String getXmrReceivingAddress(); // "xmr_receiving_address": "xmr_old_style_address_user_can_send_funds_to_as_string",
|
||||||
|
|
||||||
|
String getXmrReceivingIntegratedAddress(); // "xmr_receiving_integrated_address": "xmr_integrated_address_user_needs_to_send_funds_to_as_string",
|
||||||
|
|
||||||
|
int getXmrRecommendedMixin(); // "xmr_recommended_mixin": <xmr_recommended_mixin_as_integer>,
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
double getXmrRequiredAmount(); // "xmr_required_amount": <xmr_amount_user_needs_to_send_as_float>,
|
||||||
|
|
||||||
|
String getXmrRequiredPaymentIdLong(); // "xmr_required_payment_id_long": "xmr_payment_id_user_needs_to_include_when_using_old_stlye_address_as_string"
|
||||||
|
|
||||||
|
String getXmrRequiredPaymentIdShort(); // "xmr_required_payment_id_short": "xmr_payment_id_included_in_integrated_address_as_string"
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 m2049r et al.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.xmrto.api;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
public interface XmrToApi {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queries the order parameter.
|
||||||
|
*
|
||||||
|
* @param callback the callback with the OrderParameter object
|
||||||
|
*/
|
||||||
|
void queryOrderParameters(@NonNull final XmrToCallback<QueryOrderParameters> callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an order
|
||||||
|
*
|
||||||
|
* @param amount the desired amount
|
||||||
|
* @param address the target bitcoin address
|
||||||
|
*/
|
||||||
|
void createOrder(final double amount, @NonNull final String address, @NonNull final XmrToCallback<CreateOrder> callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queries the order status for given current order
|
||||||
|
*
|
||||||
|
* @param uuid the order uuid
|
||||||
|
* @param callback the callback with the OrderStatus object
|
||||||
|
*/
|
||||||
|
void queryOrderStatus(@NonNull final String uuid, @NonNull final XmrToCallback<QueryOrderStatus> callback);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 m2049r et al.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.xmrto.api;
|
||||||
|
|
||||||
|
public interface XmrToCallback<T> {
|
||||||
|
|
||||||
|
void onSuccess(T t);
|
||||||
|
|
||||||
|
void onError(Exception ex);
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 m2049r et al.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.xmrto.network;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.XmrToCallback;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.CreateOrder;
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
class CreateOrderImpl implements CreateOrder {
|
||||||
|
|
||||||
|
private final String state;
|
||||||
|
private final double btcAmount;
|
||||||
|
private final String btcDestAddress;
|
||||||
|
private final String uuid;
|
||||||
|
|
||||||
|
public Double getBtcAmount() {
|
||||||
|
return btcAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBtcDestAddress() {
|
||||||
|
return btcDestAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUuid() {
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateOrderImpl(final JSONObject jsonObject) throws JSONException {
|
||||||
|
this.state = jsonObject.getString("state");
|
||||||
|
this.btcAmount = jsonObject.getDouble("btc_amount");
|
||||||
|
this.btcDestAddress = jsonObject.getString("btc_dest_address");
|
||||||
|
this.uuid = jsonObject.getString("uuid");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void call(@NonNull final XmrToApiCall api, final double amount, @NonNull final String address,
|
||||||
|
@NonNull final XmrToCallback<CreateOrder> callback) {
|
||||||
|
try {
|
||||||
|
final JSONObject request = createRequest(amount, address);
|
||||||
|
api.call("order_create", request, new NetworkCallback() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(JSONObject jsonObject) {
|
||||||
|
try {
|
||||||
|
callback.onSuccess(new CreateOrderImpl(jsonObject));
|
||||||
|
} catch (JSONException ex) {
|
||||||
|
callback.onError(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Exception ex) {
|
||||||
|
callback.onError(ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (JSONException ex) {
|
||||||
|
callback.onError(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSONObject createRequest(final double amount, final String address) throws JSONException {
|
||||||
|
final JSONObject jsonObject = new JSONObject();
|
||||||
|
jsonObject.put("btc_amount", amount);
|
||||||
|
jsonObject.put("btc_dest_address", address);
|
||||||
|
return jsonObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 m2049r et al.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.xmrto.network;
|
||||||
|
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
interface NetworkCallback {
|
||||||
|
|
||||||
|
void onSuccess(JSONObject jsonObject);
|
||||||
|
|
||||||
|
void onError(Exception ex);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 m2049r et al.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.xmrto.network;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.XmrToCallback;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.QueryOrderParameters;
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
class QueryOrderParametersImpl implements QueryOrderParameters {
|
||||||
|
|
||||||
|
private double lowerLimit; // "lower_limit": <lower_order_limit_in_btc_as_float>,
|
||||||
|
private double price; // "price": <price_of_1_btc_in_xmr_as_offered_by_service_as_float>,
|
||||||
|
private double upperLimit; // "upper_limit": <upper_order_limit_in_btc_as_float>,
|
||||||
|
private boolean isZeroConfEnabled; // "zero_conf_enabled": <true_if_zero_conf_is_enabled_as_boolean>,
|
||||||
|
private double zeroConfMaxAmount; // "zero_conf_max_amount": <up_to_this_amount_zero_conf_is_possible_as_float>
|
||||||
|
|
||||||
|
public double getLowerLimit() {
|
||||||
|
return lowerLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getPrice() {
|
||||||
|
return price;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getUpperLimit() {
|
||||||
|
return upperLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isZeroConfEnabled() {
|
||||||
|
return isZeroConfEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getZeroConfMaxAmount() {
|
||||||
|
return zeroConfMaxAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryOrderParametersImpl(final JSONObject jsonObject) throws JSONException {
|
||||||
|
lowerLimit = jsonObject.getDouble("lower_limit");
|
||||||
|
price = jsonObject.getDouble("price");
|
||||||
|
upperLimit = jsonObject.getDouble("upper_limit");
|
||||||
|
isZeroConfEnabled = jsonObject.getBoolean("zero_conf_enabled");
|
||||||
|
zeroConfMaxAmount = jsonObject.getDouble("zero_conf_max_amount");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void call(@NonNull final XmrToApiCall api,
|
||||||
|
@NonNull final XmrToCallback<QueryOrderParameters> callback) {
|
||||||
|
api.call("order_parameter_query", new NetworkCallback() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(JSONObject jsonObject) {
|
||||||
|
try {
|
||||||
|
callback.onSuccess(new QueryOrderParametersImpl(jsonObject));
|
||||||
|
} catch (JSONException ex) {
|
||||||
|
callback.onError(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Exception ex) {
|
||||||
|
callback.onError(ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//{"zero_conf_enabled":true,"price":0.015537,"upper_limit":20.0,"lower_limit":0.001,"zero_conf_max_amount":0.1}
|
||||||
|
}
|
|
@ -0,0 +1,255 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 m2049r et al.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.xmrto.network;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.XmrToCallback;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.QueryOrderStatus;
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
class QueryOrderStatusImpl implements QueryOrderStatus {
|
||||||
|
public static final SimpleDateFormat DATETIME_FORMATTER = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
|
||||||
|
|
||||||
|
public static Date parseDate(String dateString) throws ParseException {
|
||||||
|
return DATETIME_FORMATTER.parse(dateString.replaceAll("Z$", "+0000"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private QueryOrderStatus.State state; // "state": "<order_state_as_string>",
|
||||||
|
private double btcAmount; // "btc_amount": <requested_amount_in_btc_as_float>,
|
||||||
|
private String btcDestAddress; // "btc_dest_address": "<requested_destination_address_as_string>",
|
||||||
|
private String uuid; // "uuid": "<unique_order_identifier_as_12_character_string>"
|
||||||
|
// the following are only returned if the state is "after" TO_BE_CREATED
|
||||||
|
private int btcNumConfirmations; // "btc_num_confirmations": <btc_num_confirmations_as_integer>,
|
||||||
|
private int btcNumConfirmationsBeforePurge; // "btc_num_confirmations_before_purge": <btc_num_confirmations_before_purge_as_integer>,
|
||||||
|
private String btcTransactionId; // "btc_transaction_id": "<btc_transaction_id_as_string>",
|
||||||
|
private Date createdAt; // "created_at": "<timestamp_as_string>",
|
||||||
|
private Date expiresAt; // "expires_at": "<timestamp_as_string>",
|
||||||
|
private int secondsTillTimeout; // "seconds_till_timeout": <seconds_till_timeout_as_integer>,
|
||||||
|
private double xmrAmountTotal; // "xmr_amount_total": <amount_in_xmr_for_this_order_as_float>,
|
||||||
|
private double xmrAmountRemaining; // "xmr_amount_remaining": <amount_in_xmr_that_the_user_must_still_send_as_float>,
|
||||||
|
private int xmrNumConfirmationsRemaining; // "xmr_num_confirmations_remaining": <num_xmr_confirmations_remaining_before_bitcoins_will_be_sent_as_integer>,
|
||||||
|
private double xmrPriceBtc; // "xmr_price_btc": <price_of_1_btc_in_xmr_as_offered_by_service_as_float>,
|
||||||
|
private String xmrReceivingAddress; // "xmr_receiving_address": "xmr_old_style_address_user_can_send_funds_to_as_string",
|
||||||
|
private String xmrReceivingIntegratedAddress; // "xmr_receiving_integrated_address": "xmr_integrated_address_user_needs_to_send_funds_to_as_string",
|
||||||
|
private int xmrRecommendedMixin; // "xmr_recommended_mixin": <xmr_recommended_mixin_as_integer>,
|
||||||
|
private double xmrRequiredAmount; // "xmr_required_amount": <xmr_amount_user_needs_to_send_as_float>,
|
||||||
|
private String xmrRequiredPaymentIdLong; // "xmr_required_payment_id_long": "xmr_payment_id_user_needs_to_include_when_using_old_stlye_address_as_string"
|
||||||
|
private String xmrRequiredPaymentIdShort; // "xmr_required_payment_id_short": "xmr_payment_id_included_in_integrated_address_as_string"
|
||||||
|
|
||||||
|
public QueryOrderStatus.State getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getBtcAmount() {
|
||||||
|
return btcAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBtcDestAddress() {
|
||||||
|
return btcDestAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUuid() {
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBtcNumConfirmations() {
|
||||||
|
return btcNumConfirmations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBtcNumConfirmationsBeforePurge() {
|
||||||
|
return btcNumConfirmationsBeforePurge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBtcTransactionId() {
|
||||||
|
return btcTransactionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreatedAt() {
|
||||||
|
return createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getExpiresAt() {
|
||||||
|
return expiresAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSecondsTillTimeout() {
|
||||||
|
return secondsTillTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getXmrAmountTotal() {
|
||||||
|
return xmrAmountTotal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getXmrAmountRemaining() {
|
||||||
|
return xmrAmountRemaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getXmrNumConfirmationsRemaining() {
|
||||||
|
return xmrNumConfirmationsRemaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getXmrPriceBtc() {
|
||||||
|
return xmrPriceBtc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getXmrReceivingAddress() {
|
||||||
|
return xmrReceivingAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getXmrReceivingIntegratedAddress() {
|
||||||
|
return xmrReceivingIntegratedAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getXmrRecommendedMixin() {
|
||||||
|
return xmrRecommendedMixin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getXmrRequiredAmount() {
|
||||||
|
return xmrRequiredAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getXmrRequiredPaymentIdLong() {
|
||||||
|
return xmrRequiredPaymentIdLong;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getXmrRequiredPaymentIdShort() {
|
||||||
|
return xmrRequiredPaymentIdShort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCreated() {
|
||||||
|
return (state.equals(State.UNPAID) ||
|
||||||
|
state.equals(State.BTC_SENT) ||
|
||||||
|
state.equals(State.PAID) ||
|
||||||
|
state.equals(State.PAID_UNCONFIRMED) ||
|
||||||
|
state.equals(State.UNDERPAID));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTerminal() {
|
||||||
|
return (state.equals(State.BTC_SENT) || isError());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean isError() {
|
||||||
|
return (state.equals(State.UNDEF) ||
|
||||||
|
state.equals(State.NOT_FOUND) ||
|
||||||
|
state.equals(State.TIMED_OUT));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPending() {
|
||||||
|
return (state.equals(State.TO_BE_CREATED) ||
|
||||||
|
state.equals(State.UNPAID) ||
|
||||||
|
state.equals(State.UNDERPAID) ||
|
||||||
|
state.equals(State.PAID_UNCONFIRMED) ||
|
||||||
|
state.equals(State.PAID));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPaid() {
|
||||||
|
return (state.equals(State.PAID_UNCONFIRMED) ||
|
||||||
|
state.equals(State.PAID));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSent() {
|
||||||
|
return state.equals(State.BTC_SENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QueryOrderStatusImpl(final JSONObject jsonObject) throws JSONException {
|
||||||
|
Timber.d(jsonObject.toString(4));
|
||||||
|
String stateName = jsonObject.getString("state"); // "state": "<order_state_as_string>",
|
||||||
|
State state;
|
||||||
|
try {
|
||||||
|
state = State.valueOf(stateName);
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
state = State.UNDEF; //TODO: throws IllegalArgumentException?
|
||||||
|
}
|
||||||
|
this.state = state;
|
||||||
|
|
||||||
|
btcAmount = jsonObject.getDouble("btc_amount"); // "btc_amount": <requested_amount_in_btc_as_float>,
|
||||||
|
btcDestAddress = jsonObject.getString("btc_dest_address"); // "btc_dest_address": "<requested_destination_address_as_string>",
|
||||||
|
uuid = jsonObject.getString("uuid"); // "uuid": "<unique_order_identifier_as_12_character_string>"
|
||||||
|
|
||||||
|
if (isCreated()) {
|
||||||
|
btcNumConfirmations = jsonObject.getInt("btc_num_confirmations"); // "btc_num_confirmations": <btc_num_confirmations_as_integer>,
|
||||||
|
btcNumConfirmationsBeforePurge = jsonObject.getInt("btc_num_confirmations_before_purge"); // "btc_num_confirmations_before_purge": <btc_num_confirmations_before_purge_as_integer>,
|
||||||
|
btcTransactionId = jsonObject.getString("btc_transaction_id"); // "btc_transaction_id": "<btc_transaction_id_as_string>",
|
||||||
|
try {
|
||||||
|
String created = jsonObject.getString("created_at"); // "created_at": "<timestamp_as_string>",
|
||||||
|
createdAt = parseDate(created);
|
||||||
|
String expires = jsonObject.getString("expires_at"); // "expires_at": "<timestamp_as_string>",
|
||||||
|
expiresAt = parseDate(expires);
|
||||||
|
} catch (ParseException ex) {
|
||||||
|
throw new JSONException(ex.getLocalizedMessage());
|
||||||
|
}
|
||||||
|
secondsTillTimeout = jsonObject.getInt("seconds_till_timeout"); // "seconds_till_timeout": <seconds_till_timeout_as_integer>,
|
||||||
|
xmrAmountTotal = jsonObject.getDouble("xmr_amount_total"); // "xmr_amount_total": <amount_in_xmr_for_this_order_as_float>,
|
||||||
|
xmrAmountRemaining = jsonObject.getDouble("xmr_amount_remaining"); // "xmr_amount_remaining": <amount_in_xmr_that_the_user_must_still_send_as_float>,
|
||||||
|
xmrNumConfirmationsRemaining = jsonObject.getInt("xmr_num_confirmations_remaining"); // "xmr_num_confirmations_remaining": <num_xmr_confirmations_remaining_before_bitcoins_will_be_sent_as_integer>,
|
||||||
|
xmrPriceBtc = jsonObject.getDouble("xmr_price_btc"); // "xmr_price_btc": <price_of_1_btc_in_xmr_as_offered_by_service_as_float>,
|
||||||
|
xmrReceivingAddress = jsonObject.getString("xmr_receiving_address"); // "xmr_receiving_address": "xmr_old_style_address_user_can_send_funds_to_as_string",
|
||||||
|
xmrReceivingIntegratedAddress = jsonObject.getString("xmr_receiving_integrated_address"); // "xmr_receiving_integrated_address": "xmr_integrated_address_user_needs_to_send_funds_to_as_string",
|
||||||
|
xmrRecommendedMixin = jsonObject.getInt("xmr_recommended_mixin"); // "xmr_recommended_mixin": <xmr_recommended_mixin_as_integer>,
|
||||||
|
xmrRequiredAmount = jsonObject.getDouble("xmr_required_amount"); // "xmr_required_amount": <xmr_amount_user_needs_to_send_as_float>,
|
||||||
|
xmrRequiredPaymentIdLong = jsonObject.getString("xmr_required_payment_id_long"); // "xmr_required_payment_id_long": "xmr_payment_id_user_needs_to_include_when_using_old_stlye_address_as_string"
|
||||||
|
xmrRequiredPaymentIdShort = jsonObject.getString("xmr_required_payment_id_short"); // "xmr_required_payment_id_short": "xmr_payment_id_included_in_integrated_address_as_string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void call(@NonNull final XmrToApiCall api, @NonNull final String uuid,
|
||||||
|
@NonNull final XmrToCallback<QueryOrderStatus> callback) {
|
||||||
|
try {
|
||||||
|
final JSONObject request = createRequest(uuid);
|
||||||
|
api.call("order_status_query", request, new NetworkCallback() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(JSONObject jsonObject) {
|
||||||
|
try {
|
||||||
|
callback.onSuccess(new QueryOrderStatusImpl(jsonObject));
|
||||||
|
} catch (JSONException ex) {
|
||||||
|
callback.onError(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Exception ex) {
|
||||||
|
callback.onError(ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (JSONException ex) {
|
||||||
|
callback.onError(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create JSON request object
|
||||||
|
*
|
||||||
|
* @param uuid unique_order_identifier_as_12_character_string
|
||||||
|
*/
|
||||||
|
|
||||||
|
static JSONObject createRequest(final String uuid) throws JSONException {
|
||||||
|
final JSONObject jsonObject = new JSONObject();
|
||||||
|
jsonObject.put("uuid", uuid);
|
||||||
|
return jsonObject;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 m2049r et al.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.xmrto.network;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
interface XmrToApiCall {
|
||||||
|
|
||||||
|
void call(@NonNull final String path, @NonNull final NetworkCallback callback);
|
||||||
|
|
||||||
|
void call(@NonNull final String path, final JSONObject request, @NonNull final NetworkCallback callback);
|
||||||
|
}
|
|
@ -0,0 +1,143 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 m2049r et al.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.xmrto.network;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.VisibleForTesting;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.XmrToCallback;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.XmrToError;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.XmrToException;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.CreateOrder;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.QueryOrderParameters;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.QueryOrderStatus;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.XmrToApi;
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import okhttp3.Call;
|
||||||
|
import okhttp3.HttpUrl;
|
||||||
|
import okhttp3.MediaType;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.RequestBody;
|
||||||
|
import okhttp3.Response;
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
public class XmrToApiImpl implements XmrToApi, XmrToApiCall {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final OkHttpClient okHttpClient;
|
||||||
|
|
||||||
|
private final HttpUrl baseUrl;
|
||||||
|
|
||||||
|
public XmrToApiImpl(@NonNull final OkHttpClient okHttpClient, final HttpUrl baseUrl) {
|
||||||
|
this.okHttpClient = okHttpClient;
|
||||||
|
this.baseUrl = baseUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public XmrToApiImpl(@NonNull final OkHttpClient okHttpClient) {
|
||||||
|
this(okHttpClient, HttpUrl.parse("https://xmr.to/api/v2/xmr2btc/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createOrder(final double amount, @NonNull final String address,
|
||||||
|
@NonNull final XmrToCallback<CreateOrder> callback) {
|
||||||
|
CreateOrderImpl.call(this, amount, address, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void queryOrderStatus(@NonNull final String uuid,
|
||||||
|
@NonNull final XmrToCallback<QueryOrderStatus> callback) {
|
||||||
|
QueryOrderStatusImpl.call(this, uuid, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void queryOrderParameters(@NonNull final XmrToCallback<QueryOrderParameters> callback) {
|
||||||
|
QueryOrderParametersImpl.call(this, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void call(@NonNull final String path, @NonNull final NetworkCallback callback) {
|
||||||
|
call(path, null, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void call(@NonNull final String path, final JSONObject request, @NonNull final NetworkCallback callback) {
|
||||||
|
final HttpUrl url = baseUrl.newBuilder()
|
||||||
|
.addPathSegment(path)
|
||||||
|
.addPathSegment("") // xmr.to needs a trailing slash!
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Timber.d(url.toString());
|
||||||
|
final Request httpRequest = createHttpRequest(request, url);
|
||||||
|
Timber.d(httpRequest.toString());
|
||||||
|
Timber.d(request == null ? "null request" : request.toString());
|
||||||
|
|
||||||
|
okHttpClient.newCall(httpRequest).enqueue(new okhttp3.Callback() {
|
||||||
|
@Override
|
||||||
|
public void onFailure(final Call call, final IOException ex) {
|
||||||
|
Timber.d("A");
|
||||||
|
callback.onError(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResponse(final Call call, final Response response) throws IOException {
|
||||||
|
Timber.d("onResponse code=%d", response.code());
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
try {
|
||||||
|
final JSONObject json = new JSONObject(response.body().string());
|
||||||
|
callback.onSuccess(json);
|
||||||
|
} catch (JSONException ex) {
|
||||||
|
callback.onError(ex);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
final JSONObject json = new JSONObject(response.body().string());
|
||||||
|
final XmrToError error = new XmrToError(json);
|
||||||
|
Timber.e("xmr.to says %d/%s", response.code(), error.toString());
|
||||||
|
callback.onError(new XmrToException(response.code(), error));
|
||||||
|
} catch (JSONException ex) {
|
||||||
|
callback.onError(new XmrToException(response.code()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private Request createHttpRequest(final JSONObject request, final HttpUrl url) {
|
||||||
|
if (request != null) {
|
||||||
|
final RequestBody body = RequestBody.create(
|
||||||
|
MediaType.parse("application/json"), request.toString());
|
||||||
|
|
||||||
|
return new Request.Builder()
|
||||||
|
.url(url)
|
||||||
|
.post(body)
|
||||||
|
.build();
|
||||||
|
} else {
|
||||||
|
return new Request.Builder()
|
||||||
|
.url(url)
|
||||||
|
.get()
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:aapt="http://schemas.android.com/aapt"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportHeight="58.0"
|
||||||
|
android:viewportWidth="58.0">
|
||||||
|
<path
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M17.11,23.49L13.05,27.55L26.1,40.6L55.1,11.6L51.04,7.54L26.1,32.48L17.11,23.49L17.11,23.49ZM52.2,29C52.2,41.76 41.76,52.2 29,52.2C16.24,52.2 5.8,41.76 5.8,29C5.8,16.24 16.24,5.8 29,5.8C31.32,5.8 33.35,6.09 35.38,6.67L40.02,2.03C36.54,0.87 32.77,0 29,0C13.05,0 0,13.05 0,29C0,44.95 13.05,58 29,58C44.95,58 58,44.95 58,29L52.2,29L52.2,29Z"
|
||||||
|
android:strokeColor="#00000000"
|
||||||
|
android:strokeWidth="1">
|
||||||
|
<aapt:attr name="android:fillColor">
|
||||||
|
<gradient
|
||||||
|
android:endX="58.0"
|
||||||
|
android:endY="6.439293516E-15"
|
||||||
|
android:startX="2.1746516868E-31"
|
||||||
|
android:startY="58.0"
|
||||||
|
android:type="linear">
|
||||||
|
<item
|
||||||
|
android:color="#FFF0006B"
|
||||||
|
android:offset="0.0" />
|
||||||
|
<item
|
||||||
|
android:color="#FFFF6600"
|
||||||
|
android:offset="1.0" />
|
||||||
|
</gradient>
|
||||||
|
</aapt:attr>
|
||||||
|
</path>
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFE"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M20,13C20,18.52 15.52,23 10,23C4.48,23 -0,18.52 -0,13C-0,7.48 4.48,3.01 10,3.01C15.52,3.01 20,7.48 20,13"
|
||||||
|
android:strokeColor="#00000000"
|
||||||
|
android:strokeWidth="1" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF6105"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M10,3.01C4.48,3.01 -0.01,7.49 0,13C0,14.11 0.18,15.17 0.51,16.16L3.5,16.16L3.5,7.75L10,14.25L16.49,7.75L16.49,16.16L19.49,16.16C19.82,15.17 19.99,14.11 19.99,13C20,7.48 15.52,3.01 10,3.01L10,3.01Z"
|
||||||
|
android:strokeColor="#00000000"
|
||||||
|
android:strokeWidth="1" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#464543"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M8.5,15.74L5.67,12.91L5.67,18.2L4.58,18.2L3.5,18.2L1.45,18.2C3.21,21.08 6.38,23 10,23C13.62,23 16.79,21.08 18.54,18.2L16.49,18.2L14.56,18.2L14.33,18.2L14.33,12.91L11.49,15.74L10,17.23L8.5,15.74L8.5,15.74Z"
|
||||||
|
android:strokeColor="#00000000"
|
||||||
|
android:strokeWidth="1" />
|
||||||
|
</vector>
|
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
|
@ -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/gradientOrange"
|
||||||
|
android:pathData="M8.59,16.34l4.58,-4.59 -4.58,-4.59L10,5.75l6,6 -6,6z" />
|
||||||
|
</vector>
|
|
@ -0,0 +1,26 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportHeight="58.0"
|
||||||
|
android:viewportWidth="58.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="@color/gradientPink"
|
||||||
|
android:pathData="M17.11,23.49L13.05,27.55L26.1,40.6L55.1,11.6L51.04,7.54L26.1,32.48L17.11,23.49L17.11,23.49ZM52.2,29C52.2,41.76 41.76,52.2 29,52.2C16.24,52.2 5.8,41.76 5.8,29C5.8,16.24 16.24,5.8 29,5.8C31.32,5.8 33.35,6.09 35.38,6.67L40.02,2.03C36.54,0.87 32.77,0 29,0C13.05,0 0,13.05 0,29C0,44.95 13.05,58 29,58C44.95,58 58,44.95 58,29L52.2,29L52.2,29Z"
|
||||||
|
android:strokeColor="#00000000"
|
||||||
|
android:strokeWidth="1" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFE"
|
||||||
|
android:pathData="M20,13C20,18.52 15.52,23 10,23C4.48,23 -0,18.52 -0,13C-0,7.48 4.48,3.01 10,3.01C15.52,3.01 20,7.48 20,13"
|
||||||
|
android:strokeColor="#00000000"
|
||||||
|
android:strokeWidth="1" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF6105"
|
||||||
|
android:pathData="M10,3.01C4.48,3.01 -0.01,7.49 0,13C0,14.11 0.18,15.17 0.51,16.16L3.5,16.16L3.5,7.75L10,14.25L16.49,7.75L16.49,16.16L19.49,16.16C19.82,15.17 19.99,14.11 19.99,13C20,7.48 15.52,3.01 10,3.01L10,3.01Z"
|
||||||
|
android:strokeColor="#00000000"
|
||||||
|
android:strokeWidth="1" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#464543"
|
||||||
|
android:pathData="M8.5,15.74L5.67,12.91L5.67,18.2L4.58,18.2L3.5,18.2L1.45,18.2C3.21,21.08 6.38,23 10,23C13.62,23 16.79,21.08 18.54,18.2L16.49,18.2L14.56,18.2L14.33,18.2L14.33,12.91L11.49,15.74L10,17.23L8.5,15.74L8.5,15.74Z"
|
||||||
|
android:strokeColor="#00000000"
|
||||||
|
android:strokeWidth="1" />
|
||||||
|
</vector>
|
|
@ -1,9 +1,9 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24.0"
|
android:viewportHeight="24.0"
|
||||||
android:viewportHeight="24.0">
|
android:viewportWidth="24.0">
|
||||||
<path
|
<path
|
||||||
android:fillColor="@color/moneroBlack"
|
android:fillColor="#FF000000"
|
||||||
android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM19,5L8,5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM19,21L8,21L8,7h11v14z"/>
|
android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM19,5L8,5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM19,21L8,21L8,7h11v14z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFffffff"
|
||||||
|
android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM19,5L8,5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM19,21L8,21L8,7h11v14z"/>
|
||||||
|
</vector>
|
|
@ -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="#ff8b0000"
|
||||||
|
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM17,13L7,13v-2h10v2z" />
|
||||||
|
</vector>
|
|
@ -1,9 +0,0 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24.0"
|
|
||||||
android:viewportHeight="24.0">
|
|
||||||
<path
|
|
||||||
android:fillColor="#FF000000"
|
|
||||||
android:pathData="M8.59,16.34l4.58,-4.59 -4.58,-4.59L10,5.75l6,6 -6,6z"/>
|
|
||||||
</vector>
|
|
|
@ -24,9 +24,6 @@
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FFffffff"
|
android:fillColor="#FFffffff"
|
||||||
android:pathData="M251.43,76.85a4.48,4.48 0,0 1,-1 3.24,4.61 4.61,0 0,1 -3.33,1h-2.43v4.67h3.56c5.93,0 8.85,-3 8.85,-8.88V35.07h-5.69Z" />
|
android:pathData="M251.43,76.85a4.48,4.48 0,0 1,-1 3.24,4.61 4.61,0 0,1 -3.33,1h-2.43v4.67h3.56c5.93,0 8.85,-3 8.85,-8.88V35.07h-5.69Z" />
|
||||||
<path
|
|
||||||
android:fillColor="#FFffffff"
|
|
||||||
android:pathData="M59.82,29.57a3.9,3.9 0,0 0,2.76 -6.64A3.85,3.85 0,0 0,56 25.69a3.8,3.8 0,0 0,1.1 2.75A3.64,3.64 0,0 0,59.82 29.57Z" />
|
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FFffffff"
|
android:fillColor="#FFffffff"
|
||||||
android:pathData="M59,38.31a13.12,13.12 0,0 0,-9.64 -3.79,13.81 13.81,0 0,0 -7.35,2A14,14 0,0 0,36.92 42a12,12 0,0 0,-4.82 -5.54A13.65,13.65 0,0 0,25 34.52q-7.7,0 -11.21,6.14V35.07H8V69.46h5.75V50.05q0,-5.2 2.54,-7.89a9.09,9.09 0,0 1,7 -2.69,9 9,0 0,1 6.91,2.69q2.5,2.69 2.5,7.89v19.4h5.64V50.05q0,-5.2 2.54,-7.89a9.06,9.06 0,0 1,6.92 -2.69,9 9,0 0,1 6.91,2.69c1.69,1.8 2.52,4.43 2.52,7.89V69.46l0,7.39a4.48,4.48 0,0 1,-0.95 3.24,4.59 4.59,0 0,1 -3.33,1H50.41v4.67H54c5.93,0 8.82,-3 8.82,-8.88V49.11C62.82,44.44 61.56,40.84 59,38.31Z" />
|
android:pathData="M59,38.31a13.12,13.12 0,0 0,-9.64 -3.79,13.81 13.81,0 0,0 -7.35,2A14,14 0,0 0,36.92 42a12,12 0,0 0,-4.82 -5.54A13.65,13.65 0,0 0,25 34.52q-7.7,0 -11.21,6.14V35.07H8V69.46h5.75V50.05q0,-5.2 2.54,-7.89a9.09,9.09 0,0 1,7 -2.69,9 9,0 0,1 6.91,2.69q2.5,2.69 2.5,7.89v19.4h5.64V50.05q0,-5.2 2.54,-7.89a9.06,9.06 0,0 1,6.92 -2.69,9 9,0 0,1 6.91,2.69c1.69,1.8 2.52,4.43 2.52,7.89V69.46l0,7.39a4.48,4.48 0,0 1,-0.95 3.24,4.59 4.59,0 0,1 -3.33,1H50.41v4.67H54c5.93,0 8.82,-3 8.82,-8.88V49.11C62.82,44.44 61.56,40.84 59,38.31Z" />
|
||||||
|
|
|
@ -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/give"
|
||||||
|
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM6.5,9L10,5.5 13.5,9L11,9v4L9,13L9,9L6.5,9zM17.5,15L14,18.5 10.5,15L13,15v-4h2v4h2.5z" />
|
||||||
|
</vector>
|
|
@ -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/take"
|
||||||
|
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM10,17l-5,-5 1.41,-1.41L10,14.17l7.59,-7.59L19,8l-9,9z" />
|
||||||
|
</vector>
|
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
|
@ -17,6 +17,13 @@
|
||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
android:src="@mipmap/ic_launcher" />
|
android:src="@mipmap/ic_launcher" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/MoneroLabel.Caps"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/about_whoami" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tvVersion"
|
android:id="@+id/tvVersion"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -29,8 +36,8 @@
|
||||||
style="@style/MoneroText"
|
style="@style/MoneroText"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/header_top"
|
|
||||||
android:layout_marginBottom="@dimen/header_top"
|
android:layout_marginBottom="@dimen/header_top"
|
||||||
|
android:layout_marginTop="@dimen/header_top"
|
||||||
android:gravity="start"
|
android:gravity="start"
|
||||||
android:textSize="10sp"
|
android:textSize="10sp"
|
||||||
tools:text="@string/menu_help" />
|
tools:text="@string/menu_help" />
|
||||||
|
|
|
@ -277,7 +277,7 @@
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
android:enabled="false"
|
android:enabled="false"
|
||||||
android:minHeight="36dp"
|
android:minHeight="36dp"
|
||||||
android:text="@string/send_send_hint" />
|
android:text="@string/send_send_label" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/bReallySend"
|
android:id="@+id/bReallySend"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
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:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
@ -28,8 +29,8 @@
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="96dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="4dp">
|
android:layout_marginBottom="48dp">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tvPaymentIdIntegrated"
|
android:id="@+id/tvPaymentIdIntegrated"
|
||||||
|
@ -37,17 +38,48 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="start|center_vertical"
|
android:layout_gravity="start|center_vertical"
|
||||||
|
android:layout_margin="8dp"
|
||||||
android:drawablePadding="8dp"
|
android:drawablePadding="8dp"
|
||||||
android:drawableStart="@drawable/ic_check_gray_24dp"
|
android:drawableStart="@drawable/ic_check_gray_24dp"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:text="@string/info_paymentid_intergrated"
|
android:text="@string/info_paymentid_intergrated"
|
||||||
android:textSize="18sp"
|
android:textSize="18sp"
|
||||||
android:visibility="gone" />
|
android:visibility="invisible" />
|
||||||
|
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llXmrTo"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:visibility="invisible">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="top"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:src="@drawable/gunther_24dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvXmrTo"
|
||||||
|
style="@style/MoneroText.Info"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
android:gravity="start|top"
|
||||||
|
android:singleLine="false"
|
||||||
|
android:textSize="18sp"
|
||||||
|
tools:text="@string/info_xmrto" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/llPaymentId"
|
android:id="@+id/llPaymentId"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
android:layout_marginBottom="4dp"
|
android:layout_marginBottom="4dp"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:visibility="visible"
|
android:visibility="visible"
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvFunds"
|
||||||
|
style="@style/MoneroText.Funds"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:gravity="center"
|
||||||
|
tools:text="@string/send_available_btc" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.m2049r.xmrwallet.widget.SendProgressView
|
||||||
|
android:id="@+id/evXmrToParms"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llXmrToParms"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:visibility="invisible">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="top"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:src="@drawable/ic_xmrto_32dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvXmrToParms"
|
||||||
|
style="@style/MoneroText.Info"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="start|top"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
android:singleLine="false"
|
||||||
|
tools:text="@string/info_send_xmrto_parms" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<com.m2049r.xmrwallet.widget.ExchangeBtcTextView
|
||||||
|
android:id="@+id/evAmount"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:orientation="vertical" />
|
||||||
|
|
||||||
|
<com.m2049r.xmrwallet.widget.NumberPadView
|
||||||
|
android:id="@+id/numberPad"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/white"
|
||||||
|
android:gravity="center" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -0,0 +1,252 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="16dp"
|
||||||
|
android:foreground="?android:attr/selectableItemBackground"
|
||||||
|
card_view:cardCornerRadius="2dp"
|
||||||
|
card_view:cardElevation="8dp"
|
||||||
|
card_view:contentPadding="8dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.m2049r.xmrwallet.widget.SendProgressView
|
||||||
|
android:id="@+id/evStageA"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llStageA"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="visible">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/MoneroText.Confirm.Label"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:drawablePadding="8dp"
|
||||||
|
android:drawableStart="@drawable/ic_xmrto_32dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:text="@string/label_send_btc_xmrto_key" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvTxXmrToKey"
|
||||||
|
style="@style/MoneroText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@color/dotGray"
|
||||||
|
android:drawableEnd="@drawable/ic_content_copy_white_24dp"
|
||||||
|
android:drawablePadding="16dp"
|
||||||
|
android:paddingBottom="8dp"
|
||||||
|
android:paddingEnd="8dp"
|
||||||
|
android:paddingStart="24dp"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
tools:text="XMR.TO-d2KQ" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/MoneroText.Medium"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:text="@string/label_send_btc_xmrto_info" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/MoneroText.Confirm.Label"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:text="@string/label_send_btc_address"
|
||||||
|
android:textAlignment="textStart" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvTxBtcAddress"
|
||||||
|
style="@style/MoneroText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAlignment="textStart"
|
||||||
|
tools:text="mpQ84J43EURZHkCnXbyQ4PpNDLLBqdsMW2" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:background="@android:color/darker_gray" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.m2049r.xmrwallet.widget.SendProgressView
|
||||||
|
android:id="@+id/evStageB"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llStageB"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="invisible">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/MoneroText.Confirm.Label"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:text="@string/label_send_btc_amount"
|
||||||
|
android:textAlignment="textStart" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvTxBtcAmount"
|
||||||
|
style="@style/MoneroText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAlignment="textStart"
|
||||||
|
tools:text="1.75 BTC = 84.118438761777 XMR" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvTxBtcRate"
|
||||||
|
style="@style/MoneroLabel.Gray"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAlignment="textStart"
|
||||||
|
android:textSize="16sp"
|
||||||
|
tools:text="(Rate: 0.020804 BTC/XMR)" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</android.support.v7.widget.CardView>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginStart="16dp">
|
||||||
|
|
||||||
|
<com.m2049r.xmrwallet.widget.SendProgressView
|
||||||
|
android:id="@+id/evStageC"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llStageC"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="invisible">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:weightSum="3">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvTxFeeLabel"
|
||||||
|
style="@style/MoneroLabel.Gray"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/send_fee_btc_label"
|
||||||
|
android:textAlignment="textStart"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvTxFee"
|
||||||
|
style="@style/MoneroText.Gray"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="2"
|
||||||
|
android:textAlignment="textEnd"
|
||||||
|
android:textSize="16sp"
|
||||||
|
tools:text="0.006817000000" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:weightSum="3">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvTxTotalLabel"
|
||||||
|
style="@style/MoneroLabel.Caps.Black"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/send_total_btc_label"
|
||||||
|
android:textAlignment="textStart"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvTxTotal"
|
||||||
|
style="@style/MoneroText.Black"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="2"
|
||||||
|
android:textAlignment="textEnd"
|
||||||
|
android:textSize="16sp"
|
||||||
|
tools:text="143.014817000000" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llConfirmSend"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="invisible">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/bSend"
|
||||||
|
style="@style/MoneroButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:enabled="true"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:text="@string/send_send_label" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/pbProgressSend"
|
||||||
|
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:indeterminate="true"
|
||||||
|
android:visibility="invisible" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -0,0 +1,260 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ScrollView 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="match_parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="72dp"
|
||||||
|
android:layout_height="72dp"
|
||||||
|
android:layout_gravity="top"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
|
android:padding="6dp"
|
||||||
|
android:src="@drawable/ic_check_circle_xmr" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/MoneroText.Success"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:text="@string/label_send_success" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvTxAmount"
|
||||||
|
style="@style/MoneroText.Balance.Orange"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="2"
|
||||||
|
android:textAlignment="textEnd"
|
||||||
|
tools:text="143.008000 XMR" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvTxFee"
|
||||||
|
style="@style/MoneroText.Gray.SuccessFee"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="2"
|
||||||
|
android:textAlignment="textEnd"
|
||||||
|
tools:text="+0.006817 Fee" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/MoneroText.Confirm.Label"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/label_send_txid"
|
||||||
|
android:textAlignment="textStart" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/bCopyTxId"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:background="?android:selectableItemBackground"
|
||||||
|
android:enabled="false"
|
||||||
|
android:src="@drawable/ic_content_nocopy_black_24dp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvTxId"
|
||||||
|
style="@style/MoneroText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:textAlignment="textStart"
|
||||||
|
tools:text="fcb12cbe9f43d4e8b9ee54f48d450a89a6937946db856506820df0539571801d" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/MoneroText.Confirm.Label"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="@string/label_send_address"
|
||||||
|
android:textAlignment="textStart" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvTxAddress"
|
||||||
|
style="@style/MoneroText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:textAlignment="textStart"
|
||||||
|
tools:text="4AdkPJoxn7JCvAby9szgnt93MSEwdnxdhaASxbTBm6x5dCwmsDep2UYN4FhStDn5i11nsJbpU7oj59ahg8gXb1Mg3viqCuk" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/labelPaymentId"
|
||||||
|
style="@style/MoneroText.Confirm.Label"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/label_send_payment_id" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvTxPaymentId"
|
||||||
|
style="@style/MoneroText.Confirm"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
tools:text="d666a38d4a28fb38" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/cvXmrTo"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
card_view:cardCornerRadius="2dp"
|
||||||
|
card_view:cardElevation="8dp"
|
||||||
|
card_view:contentPadding="8dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/flXmrtoProgress"
|
||||||
|
android:layout_width="72dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerInParent="true">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/pbXmrto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="72dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:backgroundTintMode="src_in"
|
||||||
|
android:indeterminate="true"
|
||||||
|
android:indeterminateTint="@color/moneroFab" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/ivXmrToStatus"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:src="@drawable/ic_pending_orange_24dp"
|
||||||
|
android:visibility="visible" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/ivXmrToStatusBig"
|
||||||
|
android:layout_width="72dp"
|
||||||
|
android:layout_height="72dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:visibility="invisible" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_gravity="top|start"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_marginTop="0dp"
|
||||||
|
android:src="@drawable/ic_xmrto_whitestroke_24px" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvXmrToStatus"
|
||||||
|
style="@style/MoneroText"
|
||||||
|
android:layout_width="72dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@+id/flXmrtoProgress"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/info_send_xmrto_query"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:text="Confirmation Pending" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="24dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/MoneroText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/info_send_xmrto_success_order_label"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvXmrToAmount"
|
||||||
|
style="@style/MoneroText.Balance.Orange"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="start"
|
||||||
|
android:gravity="center"
|
||||||
|
tools:text="0.001 BTC" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvTxXmrToKey"
|
||||||
|
style="@style/MoneroText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@color/dotGray"
|
||||||
|
android:drawableEnd="@drawable/ic_content_copy_white_24dp"
|
||||||
|
android:drawablePadding="8dp"
|
||||||
|
android:paddingBottom="8dp"
|
||||||
|
android:paddingEnd="8dp"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
tools:text="XMR.TO-d2KQ" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/MoneroText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="start"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:drawablePadding="4dp"
|
||||||
|
android:drawableStart="@drawable/ic_info_outline_gray_24dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/label_send_btc_xmrto_info"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</android.support.v7.widget.CardView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
|
@ -183,7 +183,7 @@
|
||||||
android:layout_marginTop="48dp"
|
android:layout_marginTop="48dp"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:padding="8dp"
|
android:padding="8dp"
|
||||||
android:text="@string/send_send_hint" />
|
android:text="@string/send_send_label" />
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/pbProgressSend"
|
android:id="@+id/pbProgressSend"
|
||||||
|
|
|
@ -13,30 +13,55 @@
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginStart="8dp"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="16dp"
|
||||||
android:gravity="center"
|
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:layout_width="96dp"
|
android:layout_width="72dp"
|
||||||
android:layout_height="96dp"
|
android:layout_height="72dp"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="top"
|
||||||
android:layout_margin="16dp"
|
android:layout_marginEnd="24dp"
|
||||||
|
android:padding="6dp"
|
||||||
android:src="@drawable/ic_check_circle" />
|
android:src="@drawable/ic_check_circle" />
|
||||||
|
|
||||||
<TextView
|
<LinearLayout
|
||||||
style="@style/MoneroText.Sucess"
|
android:layout_width="match_parent"
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_vertical"
|
android:orientation="vertical">
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:text="@string/label_send_success" />
|
<TextView
|
||||||
|
style="@style/MoneroText.Success"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:text="@string/label_send_success" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvTxAmount"
|
||||||
|
style="@style/MoneroText.Balance.Orange"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="2"
|
||||||
|
android:textAlignment="textEnd"
|
||||||
|
tools:text="143.008000 XMR" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvTxFee"
|
||||||
|
style="@style/MoneroText.Gray.SuccessFee"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="2"
|
||||||
|
android:textAlignment="textEnd"
|
||||||
|
tools:text="+0.006817 Fee" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -47,7 +72,7 @@
|
||||||
android:textAlignment="textStart" />
|
android:textAlignment="textStart" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/bCopyAddress"
|
android:id="@+id/bCopyTxId"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
|
@ -86,15 +111,16 @@
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/labelPaymentId"
|
||||||
style="@style/MoneroText.Confirm.Label"
|
style="@style/MoneroText.Confirm.Label"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/label_send_payment_id"
|
android:text="@string/label_send_payment_id" />
|
||||||
android:textAlignment="textStart" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tvTxPaymentId"
|
android:id="@+id/tvTxPaymentId"
|
||||||
|
@ -102,114 +128,8 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
android:textAlignment="textStart"
|
|
||||||
tools:text="d666a38d4a28fb38" />
|
tools:text="d666a38d4a28fb38" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="4dp"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
style="@style/MoneroText.Confirm.Label"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/label_send_notes"
|
|
||||||
android:textAlignment="textStart" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tvTxNotes"
|
|
||||||
style="@style/MoneroText.Confirm"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:textAlignment="textStart"
|
|
||||||
tools:text="gunegugumobil" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:background="@android:color/darker_gray" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tvTxAmountLabel"
|
|
||||||
style="@style/MoneroLabel.Gray"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:text="@string/send_amount_label"
|
|
||||||
android:textAlignment="textStart" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tvTxAmount"
|
|
||||||
style="@style/MoneroText.Gray"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="2"
|
|
||||||
android:textAlignment="textEnd"
|
|
||||||
tools:text="143.008000000000" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="4dp"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:weightSum="3">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tvTxFeeLabel"
|
|
||||||
style="@style/MoneroLabel.Gray"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:text="@string/send_fee_label"
|
|
||||||
android:textAlignment="textStart" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tvTxFee"
|
|
||||||
style="@style/MoneroText.Gray"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="2"
|
|
||||||
android:textAlignment="textEnd"
|
|
||||||
tools:text="0.006817000000" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="4dp"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:weightSum="3">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tvTxTotalLabel"
|
|
||||||
style="@style/MoneroLabel.Caps.Black"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:text="@string/send_total_label"
|
|
||||||
android:textAlignment="textStart" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tvTxTotal"
|
|
||||||
style="@style/MoneroText.Black"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="2"
|
|
||||||
android:textAlignment="textEnd"
|
|
||||||
tools:text="143.014817000000" />
|
|
||||||
</LinearLayout>
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
|
@ -58,6 +58,114 @@
|
||||||
tools:text="2017-10-09 12:44:13 +0200" />
|
tools:text="2017-10-09 12:44:13 +0200" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/cvXmrTo"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="16dp"
|
||||||
|
android:foreground="?android:attr/selectableItemBackground"
|
||||||
|
card_view:cardCornerRadius="2dp"
|
||||||
|
card_view:cardElevation="8dp"
|
||||||
|
card_view:contentPadding="8dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/MoneroText.Medium"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:drawablePadding="8dp"
|
||||||
|
android:drawableStart="@drawable/ic_xmrto_32dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/label_send_btc_xmrto_info" />
|
||||||
|
|
||||||
|
<TableLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:shrinkColumns="1">
|
||||||
|
|
||||||
|
<TableRow>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/MoneroLabel.Small"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:gravity="end"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:text="@string/tx_amount_btc" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvTxAmountBtc"
|
||||||
|
style="@style/MoneroText"
|
||||||
|
android:gravity="start"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:selectAllOnFocus="true"
|
||||||
|
android:textColor="@color/gradientOrange"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
tools:text="1.008 BTC" />
|
||||||
|
</TableRow>
|
||||||
|
|
||||||
|
<TableRow>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/labelDestinationBtc"
|
||||||
|
style="@style/MoneroLabel.Small"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="end"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:text="@string/tx_destination_btc" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvDestinationBtc"
|
||||||
|
style="@style/MoneroText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="start"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:selectAllOnFocus="true"
|
||||||
|
android:text="mjn127C5wRQCULksMYMFHLp9UTdQuCfbZ9"
|
||||||
|
android:textIsSelectable="true" />
|
||||||
|
</TableRow>
|
||||||
|
|
||||||
|
<TableRow>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/labelTxXmrToKey"
|
||||||
|
style="@style/MoneroLabel.Small"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:gravity="end"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:text="@string/label_send_btc_xmrto_key_lb" />
|
||||||
|
|
||||||
|
<LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvTxXmrToKey"
|
||||||
|
style="@style/MoneroText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@color/dotGray"
|
||||||
|
android:drawableEnd="@drawable/ic_content_copy_white_24dp"
|
||||||
|
android:drawablePadding="16dp"
|
||||||
|
android:paddingBottom="8dp"
|
||||||
|
android:paddingEnd="8dp"
|
||||||
|
android:paddingStart="24dp"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
tools:text="XMR.TO-d2KQ" />
|
||||||
|
</LinearLayout>
|
||||||
|
</TableRow>
|
||||||
|
|
||||||
|
</TableLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</android.support.v7.widget.CardView>
|
||||||
|
|
||||||
<TableLayout
|
<TableLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -16,11 +16,19 @@
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:padding="8dp">
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/ivTxType"
|
||||||
|
android:layout_width="16dp"
|
||||||
|
android:layout_height="16dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:src="@drawable/ic_xmrto_32dp"
|
||||||
|
android:visibility="visible"/>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_weight="11"
|
android:layout_weight="9"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -29,7 +37,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="end"
|
android:gravity="end"
|
||||||
tools:text="999999.99999" />
|
tools:text="999.999999" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tx_fee"
|
android:id="@+id/tx_fee"
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
tools:showIn="LinearLayout">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/sCurrencyA"
|
||||||
|
android:layout_width="56dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textAlignment="center" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvAmountA"
|
||||||
|
style="@style/MoneroText.Balance.Orange"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center|start"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_weight="3"
|
||||||
|
android:hint="@string/send_amount_hint"
|
||||||
|
android:padding="4dp"
|
||||||
|
android:singleLine="true"
|
||||||
|
tools:text="87.00000" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/sCurrencyB"
|
||||||
|
android:layout_width="56sp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textAlignment="center" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvAmountB"
|
||||||
|
style="@style/MoneroText"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center|start"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_weight="3"
|
||||||
|
android:hint="@string/send_amount_hint"
|
||||||
|
android:padding="4dp"
|
||||||
|
android:singleLine="true"
|
||||||
|
tools:text="87.00000" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</merge>
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
tools:showIn="LinearLayout">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/pbProgress"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:indeterminate="true"
|
||||||
|
android:visibility="invisible" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llMessage"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="visible">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvCode"
|
||||||
|
style="@style/MoneroText.Confirm.Label"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="start"
|
||||||
|
tools:text="XMRTO-ERROR-001" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvMessage"
|
||||||
|
style="@style/MoneroText.Confirm"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="start"
|
||||||
|
tools:text="internal services not available" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvSolution"
|
||||||
|
style="@style/MoneroText.Confirm.Label"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="start"
|
||||||
|
tools:text="Touch to retry" />
|
||||||
|
</LinearLayout>
|
||||||
|
</merge>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<resources>
|
<resources>
|
||||||
<string name="about_title">Acerca De</string>
|
<string name="about_title">Acerca De</string>
|
||||||
<string name="about_close">Cerrar</string>
|
<string name="about_close">Cerrar</string>
|
||||||
<string name="about_version">Soy monerujo %1$s (%2$d)</string>
|
<string name="about_version">Versión %1$s (%2$d)</string>
|
||||||
|
|
||||||
<string name="donation_text">
|
<string name="donation_text">
|
||||||
\"¡Donar, bastardos ingratos!\"
|
\"¡Donar, bastardos ingratos!\"
|
||||||
|
|
|
@ -182,7 +182,6 @@
|
||||||
<string name="send_qr_hint">Escanear</string>
|
<string name="send_qr_hint">Escanear</string>
|
||||||
<string name="send_prepare_hint">Preparar</string>
|
<string name="send_prepare_hint">Preparar</string>
|
||||||
<string name="send_dispose_hint">Disponer (Deshacer)</string>
|
<string name="send_dispose_hint">Disponer (Deshacer)</string>
|
||||||
<string name="send_send_hint">Gastar mis dulces Moneroj</string>
|
|
||||||
<string name="send_really_send_hint">Último Paso - ¡Confirma!</string>
|
<string name="send_really_send_hint">Último Paso - ¡Confirma!</string>
|
||||||
<string name="send_qr_invalid">No es un Código QR de monero</string>
|
<string name="send_qr_invalid">No es un Código QR de monero</string>
|
||||||
<string name="send_qr_address_invalid">Dirección de Monero inválida</string>
|
<string name="send_qr_address_invalid">Dirección de Monero inválida</string>
|
||||||
|
@ -215,10 +214,10 @@
|
||||||
<string name="tx_timestamp">Marca de tiempo</string>
|
<string name="tx_timestamp">Marca de tiempo</string>
|
||||||
<string name="tx_id">ID de Transacción</string>
|
<string name="tx_id">ID de Transacción</string>
|
||||||
<string name="tx_key">Clave de Transacción</string>
|
<string name="tx_key">Clave de Transacción</string>
|
||||||
<string name="tx_destination">Destinatario</string>
|
<string name="tx_destination">Destino</string>
|
||||||
<string name="tx_paymentId">ID de Pago</string>
|
<string name="tx_paymentId">ID de Pago</string>
|
||||||
<string name="tx_blockheight">Bloque</string>
|
<string name="tx_blockheight">Bloque</string>
|
||||||
<string name="tx_amount">Cantidad</string>
|
<string name="tx_amount">Monto</string>
|
||||||
<string name="tx_fee">Comisión</string>
|
<string name="tx_fee">Comisión</string>
|
||||||
<string name="tx_transfers">Transferencias</string>
|
<string name="tx_transfers">Transferencias</string>
|
||||||
<string name="tx_notes">Notas</string>
|
<string name="tx_notes">Notas</string>
|
||||||
|
@ -271,4 +270,67 @@
|
||||||
<string name="fab_restore_viewonly">Restaurar cartera de sólo vista</string>
|
<string name="fab_restore_viewonly">Restaurar cartera de sólo vista</string>
|
||||||
<string name="fab_restore_key">Restaurar cartera con claves privadas</string>
|
<string name="fab_restore_key">Restaurar cartera con claves privadas</string>
|
||||||
<string name="fab_restore_seed">Resturar cartera con semilla de 25 palabras</string>
|
<string name="fab_restore_seed">Resturar cartera con semilla de 25 palabras</string>
|
||||||
|
<string name="info_xmrto"><![CDATA[
|
||||||
|
<b>Ingresaste una dirección Bitcoin</b><br/>
|
||||||
|
<i>Vas a enviar XMR y el destinatario recibirá BTC usando el servicio <b>XMR.TO</b>.</i>
|
||||||
|
]]></string>
|
||||||
|
<string name="info_send_xmrto_success_sending">Enviando</string>
|
||||||
|
<string name="info_send_xmrto_success_status_label">Estado:</string>
|
||||||
|
<string name="info_send_xmrto_success_status">%1$s es %1$s (#%1$d)</string>
|
||||||
|
<string name="info_send_xmrto_success_btc">%1$s BTC</string>
|
||||||
|
<string name="info_txdetails_xmrto_key">Clave:</string>
|
||||||
|
<string name="info_txdetails_xmrto_address">Dirección:</string>
|
||||||
|
<string name="info_txdetails_xmrto_status">Estado:</string>
|
||||||
|
<string name="info_txdetails_xmrto_amount">%1$s BTC</string>
|
||||||
|
<string name="info_send_xmrto_paid">Confirmación pendiente</string>
|
||||||
|
<string name="info_send_xmrto_unpaid">Pago pendiente</string>
|
||||||
|
<string name="info_send_xmrto_error">Error de XMR.TO (%1$s)</string>
|
||||||
|
<string name="info_send_xmrto_sent">BTC Enviados!</string>
|
||||||
|
<string name="info_send_xmrto_query">Consultando …</string>
|
||||||
|
<string name="info_send_xmrto_parms"><![CDATA[
|
||||||
|
<b>Puedes enviar %1$s — %2$s BTC</b>.<br/>
|
||||||
|
<i><b>XMR.TO</b> está ofreciendo una tasa de cambio de <b>%3$s BTC</b> <u>en este momento</u></i>.
|
||||||
|
]]></string>
|
||||||
|
<string name="info_send_xmrto_zeroconf"><![CDATA[
|
||||||
|
<i>Montos hasta <b>%1$s BTC</b> serán enviados <u>en el momento</u>!</i>
|
||||||
|
]]></string>
|
||||||
|
<string name="send_available_btc">Saldo: %2$s BTC (%1$s XMR)</string>
|
||||||
|
<string name="label_send_progress_xmrto_create">Creando orden XMR.TO</string>
|
||||||
|
<string name="label_send_progress_xmrto_query">Consultando orden XMR.TO</string>
|
||||||
|
<string name="label_send_progress_create_tx">Preparando transacción Monero</string>
|
||||||
|
<string name="label_send_progress_queryparms">Consultando parámetros XMR.TO</string>
|
||||||
|
<string name="label_generic_xmrto_error">ERROR XMR.TO</string>
|
||||||
|
<string name="text_generic_xmrto_error">Código: %1$d</string>
|
||||||
|
<string name="text_retry">Toca para reintentar</string>
|
||||||
|
<string name="text_noretry_monero">Parece que estamos atascados!</string>
|
||||||
|
<string name="text_noretry">Oh-oh, parece que XMR.TO no está disponible ahora!</string>
|
||||||
|
<string name="text_send_btc_amount">%1$s BTC = %2$s XMR</string>
|
||||||
|
<string name="text_send_btc_rate">(Cambio: %1$s BTC/XMR)</string>
|
||||||
|
<string name="label_send_btc_details">Click para más detalles</string>
|
||||||
|
<string name="label_send_btc_xmrto_info">Visita https://xmr.to para soporte y rastreo</string>
|
||||||
|
<string name="label_send_txinfo">Mira en los datos de la TX para más detalles</string>
|
||||||
|
<string name="label_send_btc_xmrto_key_lb">Clave secreta\nXMR.TO</string>
|
||||||
|
<string name="label_send_btc_xmrto_key">Clave secreta XMR.TO</string>
|
||||||
|
<string name="label_send_btc_address">Dirección BTC destino</string>
|
||||||
|
<string name="label_send_btc_amount">Cantidad</string>
|
||||||
|
<string name="label_send_btc_create_order">Creando orden XMR.TO</string>
|
||||||
|
<string name="label_send_btc_retry">Toca para reintentar</string>
|
||||||
|
<string name="send_xmrto_timeout">Oye, esperaste demasiado!</string>
|
||||||
|
<string name="label_copy_xmrtokey">Clave XMR.TO</string>
|
||||||
|
<string name="message_copy_xmrtokey">¡Clave XMR.TO copiada al portapapeles!</string>
|
||||||
|
<string name="send_amount_btc_xmr">%1$s (indicativo)</string>
|
||||||
|
<string name="send_send_label">Gastar mis preciados moneroj</string>
|
||||||
|
<string name="send_send_timed_label">Gastar mis preciados moneroj (%1$s)</string>
|
||||||
|
<string name="send_address_invalid">No es una dirección válida</string>
|
||||||
|
<string name="send_fee_btc_label">Comisión (XMR)</string>
|
||||||
|
<string name="send_total_btc_label">Total (XMR)</string>
|
||||||
|
<string name="send_amount">%1$s XMR</string>
|
||||||
|
<string name="send_fee">+%1$s Comisión</string>
|
||||||
|
<string name="tx_status_btc">Estado</string>
|
||||||
|
<string name="tx_id_btc">TX ID\n(BTC)</string>
|
||||||
|
<string name="tx_destination_btc">Destino\n(BTC)</string>
|
||||||
|
<string name="tx_amount_btc">Monto\n(BTC)</string>
|
||||||
|
<string name="receive_bitcoin_paymentid_invalid">Debe quedar vacío con una dirección Bitcoin</string>
|
||||||
|
<string name="about_whoami">Soy monerujo</string>
|
||||||
|
<string name="info_send_xmrto_success_order_label">Orden XMR.TO</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -2,14 +2,15 @@
|
||||||
<resources>
|
<resources>
|
||||||
<string name="about_title">About</string>
|
<string name="about_title">About</string>
|
||||||
<string name="about_close">Close</string>
|
<string name="about_close">Close</string>
|
||||||
<string name="about_version">I am monerujo %1$s (%2$d)</string>
|
<string name="about_whoami">I am monerujo</string>
|
||||||
|
<string name="about_version">Version %1$s (%2$d)</string>
|
||||||
|
|
||||||
<string name="donation_text">
|
<string name="donation_text">
|
||||||
\"Donate you ungrateful bastards!\"
|
\"Donate you ungrateful bastards!\"
|
||||||
</string>
|
</string>
|
||||||
|
|
||||||
<string name="donation_address_label">Donations Address</string>
|
<string name="donation_address_label">Donations Address</string>
|
||||||
<string name="donation_address">4AdkPJoxn7JCvAby9szgnt93MSEwdnxdhaASxbTBm6x5dCwmsDep2UYN4FhStDn5i11nsJbpU7oj59ahg8gXb1Mg3viqCuk</string>
|
<string name="donation_address" translatable="false">4AdkPJoxn7JCvAby9szgnt93MSEwdnxdhaASxbTBm6x5dCwmsDep2UYN4FhStDn5i11nsJbpU7oj59ahg8gXb1Mg3viqCuk</string>
|
||||||
|
|
||||||
<string name="donation_credits"><![CDATA[
|
<string name="donation_credits"><![CDATA[
|
||||||
<b>Credits</b>
|
<b>Credits</b>
|
||||||
|
@ -64,7 +65,7 @@
|
||||||
</p>
|
</p>
|
||||||
]]></string>
|
]]></string>
|
||||||
|
|
||||||
<string name="about_licenses"><![CDATA[
|
<string name="about_licenses" translatable="false"><![CDATA[
|
||||||
<h1>Open Source Licenses</h1>
|
<h1>Open Source Licenses</h1>
|
||||||
<h2>Licensed under the Apache License, Version 2.0</h2>
|
<h2>Licensed under the Apache License, Version 2.0</h2>
|
||||||
<h3>monerujo (https://github.com/m2049r/xmrwallet)</h3>
|
<h3>monerujo (https://github.com/m2049r/xmrwallet)</h3>
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
<color name="gradientOrange">#FFFF6105</color>
|
<color name="gradientOrange">#FFFF6105</color>
|
||||||
<color name="gradientPink">#FFF0006B</color>
|
<color name="gradientPink">#FFF0006B</color>
|
||||||
|
|
||||||
|
<color name="xmrtoYellow">#FFFFD700</color>
|
||||||
|
|
||||||
<color name="trafficGray">#9B9B9B</color>
|
<color name="trafficGray">#9B9B9B</color>
|
||||||
|
|
||||||
<color name="take">#FF417505</color>
|
<color name="take">#FF417505</color>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">monerujo</string>
|
<string name="app_name" translatable="false">monerujo</string>
|
||||||
<string name="login_activity_name">monerujo</string>
|
<string name="login_activity_name" translatable="false">monerujo</string>
|
||||||
<string name="wallet_activity_name">Wallet</string>
|
<string name="wallet_activity_name">Wallet</string>
|
||||||
|
|
||||||
<string name="menu_testnet">Testnet</string>
|
<string name="menu_testnet">Testnet</string>
|
||||||
|
@ -21,16 +21,75 @@
|
||||||
<string name="label_cancel">Cancel</string>
|
<string name="label_cancel">Cancel</string>
|
||||||
<string name="label_wallet_advanced_details">Touch for detailed information</string>
|
<string name="label_wallet_advanced_details">Touch for detailed information</string>
|
||||||
|
|
||||||
<string name="label_send_success">Success!</string>
|
<string name="label_send_success">Successfully sent</string>
|
||||||
<string name="label_send_done">Done</string>
|
<string name="label_send_done">Done</string>
|
||||||
|
|
||||||
<string name="label_receive_info_gen_qr_code">Touch for QR Code</string>
|
<string name="label_receive_info_gen_qr_code">Touch for QR Code</string>
|
||||||
<string name="info_send_prio_fees">Higher Priority = Higher Fees</string>
|
<string name="info_send_prio_fees">Higher Priority = Higher Fees</string>
|
||||||
|
|
||||||
|
<string name="info_xmrto"><![CDATA[
|
||||||
|
<b>You entered a Bitcoin address.</b><br/>
|
||||||
|
<i>You'll send XMR and the receiver will get BTC using the <b>XMR.TO</b> service.</i>
|
||||||
|
]]></string>
|
||||||
|
|
||||||
|
<string name="info_send_xmrto_success_order_label">XMR.TO Order</string>
|
||||||
|
|
||||||
|
<string name="info_send_xmrto_success_sending">Sending</string>
|
||||||
|
<string name="info_send_xmrto_success_status_label">Status:</string>
|
||||||
|
<string name="info_send_xmrto_success_btc">%1$s BTC</string>
|
||||||
|
<string name="info_send_xmrto_success_status">%1$s is %1$s (#%1$d)</string>
|
||||||
|
|
||||||
|
<string name="info_txdetails_xmrto_key">Key:</string>
|
||||||
|
<string name="info_txdetails_xmrto_address">Address:</string>
|
||||||
|
<string name="info_txdetails_xmrto_status">Status:</string>
|
||||||
|
<string name="info_txdetails_xmrto_amount">%1$s BTC</string>
|
||||||
|
|
||||||
|
|
||||||
|
<string name="info_send_xmrto_paid">Confirmation Pending</string>
|
||||||
|
<string name="info_send_xmrto_unpaid">Payment Pending</string>
|
||||||
|
<string name="info_send_xmrto_error">XMR.TO Error (%1$s)</string>
|
||||||
|
<string name="info_send_xmrto_sent">BTC Sent!</string>
|
||||||
|
<string name="info_send_xmrto_query">Querying …</string>
|
||||||
|
|
||||||
|
<string name="info_send_xmrto_parms"><![CDATA[
|
||||||
|
<b>You can send %1$s — %2$s BTC</b>.<br/>
|
||||||
|
<i><b>XMR.TO</b> is giving you an exchange rate of <b>%3$s BTC</b> <u>right now</u></i>.
|
||||||
|
]]></string>
|
||||||
|
<string name="info_send_xmrto_zeroconf"><![CDATA[
|
||||||
|
<i>Amounts up to <b>%1$s BTC</b> will be sent <u>instantly</u>!</i>
|
||||||
|
]]></string>
|
||||||
|
|
||||||
|
<string name="send_available_btc">Balance: %2$s BTC (%1$s XMR)</string>
|
||||||
|
|
||||||
<string name="info_paymentid_intergrated">Payment ID integrated</string>
|
<string name="info_paymentid_intergrated">Payment ID integrated</string>
|
||||||
<string name="info_prepare_tx">Preparing your transaction</string>
|
<string name="info_prepare_tx">Preparing your transaction</string>
|
||||||
|
|
||||||
<string name="message_copy_txid">Transaction ID copied to clipboard!</string>
|
<string name="label_send_progress_xmrto_create">Creating XMR.TO Order</string>
|
||||||
|
<string name="label_send_progress_xmrto_query">Querying XMR.TO Order</string>
|
||||||
|
<string name="label_send_progress_create_tx">Preparing Monero Transaction</string>
|
||||||
|
|
||||||
|
<string name="label_send_progress_queryparms">Querying xmr.to parameters</string>
|
||||||
|
|
||||||
|
<string name="label_generic_xmrto_error">XMR.TO ERROR</string>
|
||||||
|
<string name="text_generic_xmrto_error">Code: %1$d</string>
|
||||||
|
|
||||||
|
<string name="text_retry">Touch to retry</string>
|
||||||
|
<string name="text_noretry_monero">Now we\'re stuck here!</string>
|
||||||
|
<string name="text_noretry">Uh-oh, XMR.TO does not seem be available right now!</string>
|
||||||
|
|
||||||
|
<string name="text_send_btc_amount">%1$s BTC = %2$s XMR</string>
|
||||||
|
<string name="text_send_btc_rate">(Rate: %1$s BTC/XMR)</string>
|
||||||
|
|
||||||
|
<string name="label_send_btc_details">Click for more details</string>
|
||||||
|
<string name="label_send_btc_xmrto_info">Visit xmr.to for support & tracking</string>
|
||||||
|
<string name="label_send_txinfo">See TX details for more details</string>
|
||||||
|
<string name="label_send_btc_xmrto_key_lb">Secret Key\nXMR.TO</string>
|
||||||
|
<string name="label_send_btc_xmrto_key">XMR.TO Secret Key</string>
|
||||||
|
<string name="label_send_btc_address">Destination BTC Address</string>
|
||||||
|
<string name="label_send_btc_amount">Amount</string>
|
||||||
|
<string name="label_send_btc_create_order">Creating XMR.TO Order</string>
|
||||||
|
|
||||||
|
<string name="label_send_btc_retry">Touch to retry</string>
|
||||||
|
|
||||||
<string name="label_send_txid">Transaction ID</string>
|
<string name="label_send_txid">Transaction ID</string>
|
||||||
<string name="label_send_address">Destination Address</string>
|
<string name="label_send_address">Destination Address</string>
|
||||||
|
@ -74,6 +133,8 @@
|
||||||
<string name="status_transaction_failed">Transaction failed: %1$s</string>
|
<string name="status_transaction_failed">Transaction failed: %1$s</string>
|
||||||
<string name="status_transaction_prepare_failed">Could not create transaction!</string>
|
<string name="status_transaction_prepare_failed">Could not create transaction!</string>
|
||||||
|
|
||||||
|
<string name="send_xmrto_timeout">Dude, you waited too long!</string>
|
||||||
|
|
||||||
<string name="service_busy">I am still busy with your last wallet …</string>
|
<string name="service_busy">I am still busy with your last wallet …</string>
|
||||||
|
|
||||||
<string name="prompt_rename">Rename %1$s</string>
|
<string name="prompt_rename">Rename %1$s</string>
|
||||||
|
@ -96,8 +157,7 @@
|
||||||
<string name="title_amount">Amount</string>
|
<string name="title_amount">Amount</string>
|
||||||
<string name="title_date">Date</string>
|
<string name="title_date">Date</string>
|
||||||
<string name="xmr_unconfirmed_amount">+ %1$s XMR unconfirmed</string>
|
<string name="xmr_unconfirmed_amount">+ %1$s XMR unconfirmed</string>
|
||||||
<!--string name="xmr_balance">%1$s XMR</string-->
|
<string name="xmr" translatable="false">XMR</string>
|
||||||
<string name="xmr">XMR</string>
|
|
||||||
<string name="label_transactions">Transactions</string>
|
<string name="label_transactions">Transactions</string>
|
||||||
<string name="text_daemonConnected">Daemon connected!</string>
|
<string name="text_daemonConnected">Daemon connected!</string>
|
||||||
|
|
||||||
|
@ -119,8 +179,11 @@
|
||||||
|
|
||||||
<string name="label_copy_viewkey">View Key</string>
|
<string name="label_copy_viewkey">View Key</string>
|
||||||
<string name="label_copy_address">Public Address</string>
|
<string name="label_copy_address">Public Address</string>
|
||||||
|
<string name="label_copy_xmrtokey">XMR.TO Key</string>
|
||||||
<string name="message_copy_viewkey">View Key copied to clipboard!</string>
|
<string name="message_copy_viewkey">View Key copied to clipboard!</string>
|
||||||
|
<string name="message_copy_xmrtokey">XMR.TO Key copied to clipboard!</string>
|
||||||
<string name="message_copy_address">Wallet Address copied to clipboard!</string>
|
<string name="message_copy_address">Wallet Address copied to clipboard!</string>
|
||||||
|
<string name="message_copy_txid">Transaction ID copied to clipboard!</string>
|
||||||
<string name="message_noselect_seed">Selecting seed disabled for security reasons!</string>
|
<string name="message_noselect_seed">Selecting seed disabled for security reasons!</string>
|
||||||
<string name="message_noselect_key">Selecting spend key disabled for security reasons!</string>
|
<string name="message_noselect_key">Selecting spend key disabled for security reasons!</string>
|
||||||
<string name="message_nocopy">Copy disabled for security reasons!</string>
|
<string name="message_nocopy">Copy disabled for security reasons!</string>
|
||||||
|
@ -171,11 +234,11 @@
|
||||||
<string name="generate_mnemonic_label">Mnemonic Seed</string>
|
<string name="generate_mnemonic_label">Mnemonic Seed</string>
|
||||||
<string name="generate_restoreheight_label">Restore Height:</string>
|
<string name="generate_restoreheight_label">Restore Height:</string>
|
||||||
|
|
||||||
<!--string name="generate_check_keys">Check your keys!</string-->
|
|
||||||
<string name="generate_check_key">Enter valid Key</string>
|
<string name="generate_check_key">Enter valid Key</string>
|
||||||
<string name="generate_check_address">Enter valid Address</string>
|
<string name="generate_check_address">Enter valid Address</string>
|
||||||
<string name="generate_check_mnemonic">Enter your 25 word seed</string>
|
<string name="generate_check_mnemonic">Enter your 25 word seed</string>
|
||||||
<!--string name="generate_check_something">Check your entry!</string-->
|
|
||||||
|
<string name="send_amount_btc_xmr">%1$s (indicative)</string>
|
||||||
|
|
||||||
<string name="send_address_hint">Receiver\'s Address</string>
|
<string name="send_address_hint">Receiver\'s Address</string>
|
||||||
<string name="send_paymentid_hint">Payment ID (optional)</string>
|
<string name="send_paymentid_hint">Payment ID (optional)</string>
|
||||||
|
@ -188,13 +251,15 @@
|
||||||
<string name="send_qr_hint">Scan</string>
|
<string name="send_qr_hint">Scan</string>
|
||||||
<string name="send_prepare_hint">Prepare</string>
|
<string name="send_prepare_hint">Prepare</string>
|
||||||
<string name="send_dispose_hint">Dispose (Undo)</string>
|
<string name="send_dispose_hint">Dispose (Undo)</string>
|
||||||
<string name="send_send_hint">Spend my sweet Moneroj</string>
|
<string name="send_send_label">Spend my sweet Moneroj</string>
|
||||||
|
<string name="send_send_timed_label">Spend my sweet Moneroj (%1$s)</string>
|
||||||
<string name="send_really_send_hint">Last Step - Confirm!</string>
|
<string name="send_really_send_hint">Last Step - Confirm!</string>
|
||||||
<string name="send_qr_invalid">Not a monero QR Code</string>
|
<string name="send_qr_invalid">Not a QR Code</string>
|
||||||
<string name="send_qr_address_invalid">Invalid Monero address</string>
|
<string name="send_qr_address_invalid">Not a valid payment QR code</string>
|
||||||
|
<string name="send_address_invalid">Not a valid address</string>
|
||||||
<string name="send_preparing_progress">Preparing transaction</string>
|
<string name="send_preparing_progress">Preparing transaction</string>
|
||||||
<string name="send_title">Send</string>
|
<string name="send_title">Send</string>
|
||||||
<string name="send_available">Available funds: %1$s XMR</string>
|
<string name="send_available">Balance: %1$s XMR</string>
|
||||||
<string name="send_address_title">Address</string>
|
<string name="send_address_title">Address</string>
|
||||||
<string name="send_amount_title">Amount</string>
|
<string name="send_amount_title">Amount</string>
|
||||||
<string name="send_settings_title">Settings</string>
|
<string name="send_settings_title">Settings</string>
|
||||||
|
@ -204,10 +269,15 @@
|
||||||
<string name="send_amount_too_large">Amount > Funds</string>
|
<string name="send_amount_too_large">Amount > Funds</string>
|
||||||
|
|
||||||
<string name="send_amount_label">Amount</string>
|
<string name="send_amount_label">Amount</string>
|
||||||
|
<string name="send_fee_btc_label">Fee (XMR)</string>
|
||||||
<string name="send_fee_label">Fee</string>
|
<string name="send_fee_label">Fee</string>
|
||||||
<string name="send_dust_label">Dust</string>
|
<string name="send_dust_label">Dust</string>
|
||||||
|
<string name="send_total_btc_label">Total (XMR)</string>
|
||||||
<string name="send_total_label">Total</string>
|
<string name="send_total_label">Total</string>
|
||||||
|
|
||||||
|
<string name="send_amount">%1$s XMR</string>
|
||||||
|
<string name="send_fee">+%1$s Fee</string>
|
||||||
|
|
||||||
<string name="send_create_tx_error_title">Create Transaction Error</string>
|
<string name="send_create_tx_error_title">Create Transaction Error</string>
|
||||||
|
|
||||||
<string name="tx_list_fee_pending">incl. %1$s fee</string>
|
<string name="tx_list_fee_pending">incl. %1$s fee</string>
|
||||||
|
@ -217,14 +287,18 @@
|
||||||
<string name="tx_list_amount_negative">- %1$s</string>
|
<string name="tx_list_amount_negative">- %1$s</string>
|
||||||
<string name="tx_list_amount_positive">+ %1$s</string>
|
<string name="tx_list_amount_positive">+ %1$s</string>
|
||||||
|
|
||||||
|
<string name="tx_status_btc">Status</string>
|
||||||
<string name="tx_address">Address</string>
|
<string name="tx_address">Address</string>
|
||||||
<string name="tx_timestamp">Timestamp</string>
|
<string name="tx_timestamp">Timestamp</string>
|
||||||
<string name="tx_id">TX ID</string>
|
<string name="tx_id">TX ID</string>
|
||||||
|
<string name="tx_id_btc">TX ID\n(BTC)</string>
|
||||||
<string name="tx_key">TX Key</string>
|
<string name="tx_key">TX Key</string>
|
||||||
<string name="tx_destination">Destination</string>
|
<string name="tx_destination">Destination</string>
|
||||||
|
<string name="tx_destination_btc">Destination\n(BTC)</string>
|
||||||
<string name="tx_paymentId">Payment ID</string>
|
<string name="tx_paymentId">Payment ID</string>
|
||||||
<string name="tx_blockheight">Block</string>
|
<string name="tx_blockheight">Block</string>
|
||||||
<string name="tx_amount">Amount</string>
|
<string name="tx_amount">Amount</string>
|
||||||
|
<string name="tx_amount_btc">Amount\n(BTC)</string>
|
||||||
<string name="tx_fee">Fee</string>
|
<string name="tx_fee">Fee</string>
|
||||||
<string name="tx_transfers">Transfers</string>
|
<string name="tx_transfers">Transfers</string>
|
||||||
<string name="tx_notes">Notes</string>
|
<string name="tx_notes">Notes</string>
|
||||||
|
@ -248,6 +322,7 @@
|
||||||
<string name="receive_cannot_open">Could not open wallet!</string>
|
<string name="receive_cannot_open">Could not open wallet!</string>
|
||||||
<string name="receive_paymentid_invalid">16 or 64 Hex characters (0-9,a-f)</string>
|
<string name="receive_paymentid_invalid">16 or 64 Hex characters (0-9,a-f)</string>
|
||||||
<string name="receive_integrated_paymentid_invalid">Must be empty with integrated address</string>
|
<string name="receive_integrated_paymentid_invalid">Must be empty with integrated address</string>
|
||||||
|
<string name="receive_bitcoin_paymentid_invalid">Must be empty with bitcoin address</string>
|
||||||
<string name="receive_amount_invalid">Must be > 0</string>
|
<string name="receive_amount_invalid">Must be > 0</string>
|
||||||
|
|
||||||
<string name="receive_amount_empty">Enter value</string>
|
<string name="receive_amount_empty">Enter value</string>
|
||||||
|
@ -266,9 +341,9 @@
|
||||||
<string name="archive_alert_yes">Yes, do that!</string>
|
<string name="archive_alert_yes">Yes, do that!</string>
|
||||||
<string name="archive_alert_no">No thanks!</string>
|
<string name="archive_alert_no">No thanks!</string>
|
||||||
|
|
||||||
<string name="big_amount">999999.999999999999</string>
|
<string name="big_amount" translatable="false">999999.999999999999</string>
|
||||||
|
|
||||||
<string-array name="mixin">
|
<string-array name="mixin" translatable="false">
|
||||||
<item>Ringsize 5</item>
|
<item>Ringsize 5</item>
|
||||||
<item>Ringsize 8</item>
|
<item>Ringsize 8</item>
|
||||||
<item>Ringsize 13</item>
|
<item>Ringsize 13</item>
|
||||||
|
@ -282,7 +357,7 @@
|
||||||
<item>Priority High</item>
|
<item>Priority High</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string-array name="currency">
|
<string-array name="currency" translatable="false">
|
||||||
<item>XMR</item>
|
<item>XMR</item>
|
||||||
<item>EUR</item>
|
<item>EUR</item>
|
||||||
<item>USD</item>
|
<item>USD</item>
|
||||||
|
|
|
@ -82,9 +82,7 @@
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="MoneroText.Balance.Orange">
|
<style name="MoneroText.Balance.Orange">
|
||||||
<item name="android:textSize">32sp</item>
|
|
||||||
<item name="android:textColor">@color/gradientOrange</item>
|
<item name="android:textColor">@color/gradientOrange</item>
|
||||||
<item name="android:textStyle">bold</item>
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="MoneroText.Unconfirmed">
|
<style name="MoneroText.Unconfirmed">
|
||||||
|
@ -119,7 +117,7 @@
|
||||||
|
|
||||||
<!-- textSize is in dp here to match the layout of the numpad-->
|
<!-- textSize is in dp here to match the layout of the numpad-->
|
||||||
<style name="MoneroLabel.NumPad">
|
<style name="MoneroLabel.NumPad">
|
||||||
<item name="android:textSize">36dp</item>
|
<item name="android:textSize">36sp</item>
|
||||||
<item name="android:textColor">@color/moneroBlack</item>
|
<item name="android:textColor">@color/moneroBlack</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
@ -175,15 +173,15 @@
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="MoneroText.Label">
|
<style name="MoneroText.Label">
|
||||||
<item name="android:textSize">18dp</item>
|
<item name="android:textSize">18sp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="MoneroText.Confirm">
|
<style name="MoneroText.Confirm">
|
||||||
<item name="android:textSize">16dp</item>
|
<item name="android:textSize">16sp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="MoneroText.Confirm.Label">
|
<style name="MoneroText.Confirm.Label">
|
||||||
<item name="android:textSize">16dp</item>
|
<item name="android:textSize">16sp</item>
|
||||||
<item name="android:textStyle">bold</item>
|
<item name="android:textStyle">bold</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
@ -193,15 +191,15 @@
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="MoneroText.Label.Medium">
|
<style name="MoneroText.Label.Medium">
|
||||||
<item name="android:textSize">14dp</item>
|
<item name="android:textSize">14sp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="MoneroText.Small">
|
<style name="MoneroText.Small">
|
||||||
<item name="android:textSize">10dp</item>
|
<item name="android:textSize">10sp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="MoneroText.Medium">
|
<style name="MoneroText.Medium">
|
||||||
<item name="android:textSize">12dp</item>
|
<item name="android:textSize">12sp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="MoneroText.Medium.Bold">
|
<style name="MoneroText.Medium.Bold">
|
||||||
|
@ -209,13 +207,19 @@
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="MoneroText.Large">
|
<style name="MoneroText.Large">
|
||||||
<item name="android:textSize">24dp</item>
|
<item name="android:textSize">24sp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
<style name="MoneroText.Sucess">
|
<style name="MoneroText.Success">
|
||||||
<item name="android:textSize">40dp</item>
|
<item name="android:textSize">18sp</item>
|
||||||
<item name="android:textColor">@color/gradientOrange</item>
|
<item name="android:textColor">@color/dotGray</item>
|
||||||
|
<item name="android:textAllCaps">true</item>
|
||||||
|
<item name="android:textStyle">bold</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="MoneroText.Gray.SuccessFee">
|
||||||
|
<item name="android:textSize">18sp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="MoneroText.Button" parent="@android:style/TextAppearance.DeviceDefault.Medium">
|
<style name="MoneroText.Button" parent="@android:style/TextAppearance.DeviceDefault.Medium">
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 m2049r
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.util;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
|
||||||
|
public class BitcoinAddressValidatorTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void validateBTC_shouldValidate() {
|
||||||
|
assertTrue(BitcoinAddressValidator.validate("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", false));
|
||||||
|
assertTrue(BitcoinAddressValidator.validate("1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9", false));
|
||||||
|
assertTrue(BitcoinAddressValidator.validate("3R2MPpTNQLCNs13qnHz89Rm82jQ27bAwft", false));
|
||||||
|
assertTrue(BitcoinAddressValidator.validate("34QjytsE8GVRbUBvYNheftqJ5CHfDHvQRD", false));
|
||||||
|
assertTrue(BitcoinAddressValidator.validate("3GsAUrD4dnCqtaTTUzzsQWoymHNkEFrgGF", false));
|
||||||
|
assertTrue(BitcoinAddressValidator.validate("3NagLCvw8fLwtoUrK7s2mJPy9k6hoyWvTU", false));
|
||||||
|
assertTrue(BitcoinAddressValidator.validate("mjn127C5wRQCULksMYMFHLp9UTdQuCfbZ9", true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void validateBTC_shouldNotValidate() {
|
||||||
|
assertTrue(BitcoinAddressValidator.validate("3NagLCvw8fLwtoUrK7s2mJPy9k6hoyWvTU", false));
|
||||||
|
assertTrue(BitcoinAddressValidator.validate("mjn127C5wRQCULksMYMFHLp9UTdQuCfbZ9", true));
|
||||||
|
assertTrue(!BitcoinAddressValidator.validate("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j", true));
|
||||||
|
assertTrue(!BitcoinAddressValidator.validate("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X", true));
|
||||||
|
assertTrue(!BitcoinAddressValidator.validate("1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", true));
|
||||||
|
assertTrue(!BitcoinAddressValidator.validate("1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", true));
|
||||||
|
assertTrue(!BitcoinAddressValidator.validate("BZbvjr", true));
|
||||||
|
assertTrue(!BitcoinAddressValidator.validate("i55j", true));
|
||||||
|
assertTrue(!BitcoinAddressValidator.validate("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62!", true));
|
||||||
|
assertTrue(!BitcoinAddressValidator.validate("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz", false));
|
||||||
|
assertTrue(!BitcoinAddressValidator.validate("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz", false));
|
||||||
|
assertTrue(!BitcoinAddressValidator.validate("1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9", false));
|
||||||
|
assertTrue(!BitcoinAddressValidator.validate("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I", false));
|
||||||
|
assertTrue(!BitcoinAddressValidator.validate("3NagLCvw8fLwtoUrK7s2mJPy9k6hoyWvTU ", false));
|
||||||
|
assertTrue(!BitcoinAddressValidator.validate(" 3NagLCvw8fLwtoUrK7s2mJPy9k6hoyWvTU ", false));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 m2049r
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.util;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public class UserNoteTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createFromTxNote_noNote() {
|
||||||
|
UserNotes userNotes = new UserNotes("{xmrto-iyrpxU,0.009BTC,mjn127C5wRQCULksMYMFHLp9UTdQuCfbZ9}");
|
||||||
|
assertTrue("xmrto-iyrpxU".equals(userNotes.xmrtoKey));
|
||||||
|
assertTrue("0.009".equals(userNotes.xmrtoAmount));
|
||||||
|
assertTrue("mjn127C5wRQCULksMYMFHLp9UTdQuCfbZ9".equals(userNotes.xmrtoDestination));
|
||||||
|
assertTrue(userNotes.note.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createFromTxNote_withNote() {
|
||||||
|
UserNotes userNotes = new UserNotes("{xmrto-iyrpxU,0.009BTC,mjn127C5wRQCULksMYMFHLp9UTdQuCfbZ9} aNote");
|
||||||
|
assertTrue("xmrto-iyrpxU".equals(userNotes.xmrtoKey));
|
||||||
|
assertTrue("0.009".equals(userNotes.xmrtoAmount));
|
||||||
|
assertTrue("mjn127C5wRQCULksMYMFHLp9UTdQuCfbZ9".equals(userNotes.xmrtoDestination));
|
||||||
|
assertTrue("aNote".equals(userNotes.note));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createFromTxNote_withNoteNoSpace() {
|
||||||
|
UserNotes userNotes = new UserNotes("{xmrto-iyrpxU,0.009BTC,mjn127C5wRQCULksMYMFHLp9UTdQuCfbZ9}aNote");
|
||||||
|
assertTrue("xmrto-iyrpxU".equals(userNotes.xmrtoKey));
|
||||||
|
assertTrue("0.009".equals(userNotes.xmrtoAmount));
|
||||||
|
assertTrue("mjn127C5wRQCULksMYMFHLp9UTdQuCfbZ9".equals(userNotes.xmrtoDestination));
|
||||||
|
assertTrue("aNote".equals(userNotes.note));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createFromTxNote_brokenA() {
|
||||||
|
String brokenNote = "{mrto-iyrpxU,0.009BTC,mjn127C5wRQCULksMYMFHLp9UTdQuCfbZ9}";
|
||||||
|
UserNotes userNotes = new UserNotes(brokenNote);
|
||||||
|
assertNull(userNotes.xmrtoKey);
|
||||||
|
assertNull(userNotes.xmrtoAmount);
|
||||||
|
assertNull(userNotes.xmrtoDestination);
|
||||||
|
assertTrue(brokenNote.equals(userNotes.note));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createFromTxNote_brokenB() {
|
||||||
|
String brokenNote = "{xmrto-iyrpxU,0.009BTC,mjn127C5wRQCULksMYMFHLp9UTdQuCfbZ9";
|
||||||
|
UserNotes userNotes = new UserNotes(brokenNote);
|
||||||
|
assertNull(userNotes.xmrtoKey);
|
||||||
|
assertNull(userNotes.xmrtoAmount);
|
||||||
|
assertNull(userNotes.xmrtoDestination);
|
||||||
|
assertTrue(brokenNote.equals(userNotes.note));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createFromTxNote_normal() {
|
||||||
|
String aNote = "aNote";
|
||||||
|
UserNotes userNotes = new UserNotes(aNote);
|
||||||
|
assertNull(userNotes.xmrtoKey);
|
||||||
|
assertNull(userNotes.xmrtoAmount);
|
||||||
|
assertNull(userNotes.xmrtoDestination);
|
||||||
|
assertTrue(aNote.equals(userNotes.note));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createFromTxNote_empty() {
|
||||||
|
String aNote = "";
|
||||||
|
UserNotes userNotes = new UserNotes(aNote);
|
||||||
|
assertNull(userNotes.xmrtoKey);
|
||||||
|
assertNull(userNotes.xmrtoAmount);
|
||||||
|
assertNull(userNotes.xmrtoDestination);
|
||||||
|
assertTrue(aNote.equals(userNotes.note));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createFromTxNote_null() {
|
||||||
|
UserNotes userNotes = new UserNotes(null);
|
||||||
|
assertNull(userNotes.xmrtoKey);
|
||||||
|
assertNull(userNotes.xmrtoAmount);
|
||||||
|
assertNull(userNotes.xmrtoDestination);
|
||||||
|
assertNotNull(userNotes.note);
|
||||||
|
assertTrue(userNotes.note.isEmpty());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,194 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 m2049r et al.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.xmrto.network;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.XmrToCallback;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.XmrToError;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.XmrToException;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.CreateOrder;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.XmrToApi;
|
||||||
|
|
||||||
|
import net.jodah.concurrentunit.Waiter;
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.mockwebserver.MockResponse;
|
||||||
|
import okhttp3.mockwebserver.MockWebServer;
|
||||||
|
import okhttp3.mockwebserver.RecordedRequest;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
public class XmrToApiCreateOrderTest {
|
||||||
|
|
||||||
|
private MockWebServer mockWebServer;
|
||||||
|
|
||||||
|
private XmrToApi xmrToApi;
|
||||||
|
|
||||||
|
private OkHttpClient okHttpClient = new OkHttpClient();
|
||||||
|
private Waiter waiter;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
XmrToCallback<CreateOrder> mockOrderXmrToCallback;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
mockWebServer = new MockWebServer();
|
||||||
|
mockWebServer.start();
|
||||||
|
|
||||||
|
waiter = new Waiter();
|
||||||
|
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
|
xmrToApi = new XmrToApiImpl(okHttpClient, mockWebServer.url("/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
mockWebServer.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createOrder_shouldBePostMethod()
|
||||||
|
throws InterruptedException, TimeoutException {
|
||||||
|
|
||||||
|
xmrToApi.createOrder(0.5, "btcsomething", mockOrderXmrToCallback);
|
||||||
|
|
||||||
|
RecordedRequest request = mockWebServer.takeRequest();
|
||||||
|
assertEquals("POST", request.getMethod());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createOrder_shouldBeContentTypeJson()
|
||||||
|
throws InterruptedException, TimeoutException {
|
||||||
|
|
||||||
|
xmrToApi.createOrder(0.5, "19y91nJyzXsLEuR7Nj9pc3o5SeHNc8A9RW", mockOrderXmrToCallback);
|
||||||
|
|
||||||
|
RecordedRequest request = mockWebServer.takeRequest();
|
||||||
|
assertEquals("application/json; charset=utf-8", request.getHeader("Content-Type"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createOrder_shouldContainValidBody()
|
||||||
|
throws InterruptedException, TimeoutException {
|
||||||
|
|
||||||
|
final String validBody = "{\"btc_amount\":0.1,\"btc_dest_address\":\"19y91nJyzXsLEuR7Nj9pc3o5SeHNc8A9RW\"}";
|
||||||
|
|
||||||
|
xmrToApi.createOrder(0.1, "19y91nJyzXsLEuR7Nj9pc3o5SeHNc8A9RW", mockOrderXmrToCallback);
|
||||||
|
|
||||||
|
RecordedRequest request = mockWebServer.takeRequest();
|
||||||
|
String body = request.getBody().readUtf8();
|
||||||
|
assertEquals(validBody, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createOrder_wasSuccessfulShouldRespondWithOrder()
|
||||||
|
throws InterruptedException, JSONException, TimeoutException {
|
||||||
|
final double amount = 1.23456789;
|
||||||
|
final String address = "19y91nJyzXsLEuR7Nj9pc3o5SeHNc8A9RW";
|
||||||
|
final String uuid = "xmrto-abcdef";
|
||||||
|
final String state = "TO_BE_CREATED";
|
||||||
|
MockResponse jsonMockResponse = new MockResponse().setBody(
|
||||||
|
createMockCreateOrderResponse(amount, address, uuid, state));
|
||||||
|
mockWebServer.enqueue(jsonMockResponse);
|
||||||
|
|
||||||
|
xmrToApi.createOrder(amount, address, new XmrToCallback<CreateOrder>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(final CreateOrder order) {
|
||||||
|
waiter.assertEquals(order.getBtcAmount(), amount);
|
||||||
|
waiter.assertEquals(order.getBtcDestAddress(), address);
|
||||||
|
waiter.assertEquals(order.getState(), state);
|
||||||
|
waiter.assertEquals(order.getUuid(), uuid);
|
||||||
|
waiter.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(final Exception e) {
|
||||||
|
waiter.fail(e);
|
||||||
|
waiter.resume();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
waiter.await();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createOrder_wasNotSuccessfulShouldCallOnError()
|
||||||
|
throws InterruptedException, JSONException, TimeoutException {
|
||||||
|
mockWebServer.enqueue(new MockResponse().setResponseCode(500));
|
||||||
|
xmrToApi.createOrder(0.5, "19y91nJyzXsLEuR7Nj9pc3o5SeHNc8A9RW", new XmrToCallback<CreateOrder>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(final CreateOrder order) {
|
||||||
|
waiter.fail();
|
||||||
|
waiter.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(final Exception e) {
|
||||||
|
waiter.assertTrue(e instanceof XmrToException);
|
||||||
|
waiter.assertTrue(((XmrToException) e).getCode() == 500);
|
||||||
|
waiter.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
waiter.await();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createOrder_malformedAddressShouldCallOnError()
|
||||||
|
throws InterruptedException, JSONException, TimeoutException {
|
||||||
|
mockWebServer.enqueue(new MockResponse().
|
||||||
|
setResponseCode(400).
|
||||||
|
setBody("{\"error_msg\":\"malformed bitcoin address\",\"error\":\"XMRTO-ERROR-002\"}"));
|
||||||
|
xmrToApi.createOrder(0.5, "xxx", new XmrToCallback<CreateOrder>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(final CreateOrder order) {
|
||||||
|
waiter.fail();
|
||||||
|
waiter.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(final Exception e) {
|
||||||
|
waiter.assertTrue(e instanceof XmrToException);
|
||||||
|
XmrToException xmrEx = (XmrToException) e;
|
||||||
|
waiter.assertTrue(xmrEx.getCode() == 400);
|
||||||
|
waiter.assertNotNull(xmrEx.getError());
|
||||||
|
waiter.assertEquals(xmrEx.getError().getErrorId(), XmrToError.Error.XMRTO_ERROR_002);
|
||||||
|
waiter.assertEquals(xmrEx.getError().getErrorMsg(), "malformed bitcoin address");
|
||||||
|
waiter.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
waiter.await();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String createMockCreateOrderResponse(final double amount, final String address,
|
||||||
|
final String uuid, final String state) {
|
||||||
|
return "{\n"
|
||||||
|
+ " \"state\": \"" + state + "\",\n"
|
||||||
|
+ " \"btc_amount\": \"" + amount + "\",\n"
|
||||||
|
+ " \"btc_dest_address\": \"" + address + "\",\n"
|
||||||
|
+ " \"uuid\": \"" + uuid + "\"\n"
|
||||||
|
+ "}";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,179 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 m2049r et al.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.xmrto.network;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.XmrToCallback;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.XmrToError;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.XmrToException;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.QueryOrderParameters;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.XmrToApi;
|
||||||
|
|
||||||
|
import net.jodah.concurrentunit.Waiter;
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.mockwebserver.MockResponse;
|
||||||
|
import okhttp3.mockwebserver.MockWebServer;
|
||||||
|
import okhttp3.mockwebserver.RecordedRequest;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
public class XmrToApiOrderParameterTest {
|
||||||
|
|
||||||
|
private MockWebServer mockWebServer;
|
||||||
|
|
||||||
|
private XmrToApi xmrToApi;
|
||||||
|
|
||||||
|
private OkHttpClient okHttpClient = new OkHttpClient();
|
||||||
|
private Waiter waiter;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
XmrToCallback<QueryOrderParameters> mockParametersXmrToCallback;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
mockWebServer = new MockWebServer();
|
||||||
|
mockWebServer.start();
|
||||||
|
|
||||||
|
waiter = new Waiter();
|
||||||
|
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
|
xmrToApi = new XmrToApiImpl(okHttpClient, mockWebServer.url("/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
mockWebServer.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void orderParameter_shouldBeGetMethod()
|
||||||
|
throws InterruptedException, TimeoutException {
|
||||||
|
|
||||||
|
xmrToApi.queryOrderParameters(mockParametersXmrToCallback);
|
||||||
|
|
||||||
|
RecordedRequest request = mockWebServer.takeRequest();
|
||||||
|
assertEquals("GET", request.getMethod());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void orderParameter_wasSuccessfulShouldRespondWithParameters()
|
||||||
|
throws InterruptedException, JSONException, TimeoutException {
|
||||||
|
final boolean isZeroConfEnabled = true;
|
||||||
|
final double price = 0.015537;
|
||||||
|
final double upperLimit = 20.0;
|
||||||
|
final double lowerLimit = 0.001;
|
||||||
|
final double zeroConfMaxAmount = 0.1;
|
||||||
|
|
||||||
|
MockResponse jsonMockResponse = new MockResponse().setBody(
|
||||||
|
createMockOrderParameterResponse(isZeroConfEnabled, price, upperLimit, lowerLimit, zeroConfMaxAmount));
|
||||||
|
mockWebServer.enqueue(jsonMockResponse);
|
||||||
|
|
||||||
|
xmrToApi.queryOrderParameters(new XmrToCallback<QueryOrderParameters>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(final QueryOrderParameters orderParameter) {
|
||||||
|
waiter.assertEquals(orderParameter.getLowerLimit(), lowerLimit);
|
||||||
|
waiter.assertEquals(orderParameter.getUpperLimit(), upperLimit);
|
||||||
|
waiter.assertEquals(orderParameter.getPrice(), price);
|
||||||
|
waiter.assertEquals(orderParameter.getZeroConfMaxAmount(), zeroConfMaxAmount);
|
||||||
|
waiter.assertEquals(orderParameter.isZeroConfEnabled(), isZeroConfEnabled);
|
||||||
|
waiter.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(final Exception e) {
|
||||||
|
waiter.fail(e);
|
||||||
|
waiter.resume();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
waiter.await();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void orderParameter_wasNotSuccessfulShouldCallOnError()
|
||||||
|
throws InterruptedException, JSONException, TimeoutException {
|
||||||
|
mockWebServer.enqueue(new MockResponse().setResponseCode(500));
|
||||||
|
xmrToApi.queryOrderParameters(new XmrToCallback<QueryOrderParameters>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(final QueryOrderParameters orderParameter) {
|
||||||
|
waiter.fail();
|
||||||
|
waiter.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(final Exception e) {
|
||||||
|
waiter.assertTrue(e instanceof XmrToException);
|
||||||
|
waiter.assertTrue(((XmrToException) e).getCode() == 500);
|
||||||
|
waiter.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
waiter.await();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void orderParameter_thirdPartyServiceNotAvailableShouldCallOnError()
|
||||||
|
throws InterruptedException, JSONException, TimeoutException {
|
||||||
|
mockWebServer.enqueue(new MockResponse().
|
||||||
|
setResponseCode(503).
|
||||||
|
setBody("{\"error_msg\":\"third party service not available\",\"error\":\"XMRTO-ERROR-007\"}"));
|
||||||
|
xmrToApi.queryOrderParameters(new XmrToCallback<QueryOrderParameters>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(final QueryOrderParameters orderParameter) {
|
||||||
|
waiter.fail();
|
||||||
|
waiter.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(final Exception e) {
|
||||||
|
waiter.assertTrue(e instanceof XmrToException);
|
||||||
|
XmrToException xmrEx = (XmrToException) e;
|
||||||
|
waiter.assertTrue(xmrEx.getCode() == 503);
|
||||||
|
waiter.assertNotNull(xmrEx.getError());
|
||||||
|
waiter.assertEquals(xmrEx.getError().getErrorId(), XmrToError.Error.XMRTO_ERROR_007);
|
||||||
|
waiter.assertEquals(xmrEx.getError().getErrorMsg(), "third party service not available");
|
||||||
|
waiter.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
waiter.await();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String createMockOrderParameterResponse(
|
||||||
|
final boolean isZeroConfEnabled,
|
||||||
|
final double price,
|
||||||
|
final double upperLimit,
|
||||||
|
final double lowerLimit,
|
||||||
|
final double zeroConfMaxAmount) {
|
||||||
|
return "{\n"
|
||||||
|
+ " \"zero_conf_enabled\": \"" + isZeroConfEnabled + "\",\n"
|
||||||
|
+ " \"price\": \"" + price + "\",\n"
|
||||||
|
+ " \"upper_limit\": \"" + upperLimit + "\",\n"
|
||||||
|
+ " \"lower_limit\": \"" + lowerLimit + "\",\n"
|
||||||
|
+ " \"zero_conf_max_amount\": \"" + zeroConfMaxAmount + "\"\n"
|
||||||
|
+ "}";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,300 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 m2049r et al.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.xmrto.network;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.XmrToCallback;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.XmrToError;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.XmrToException;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.QueryOrderStatus;
|
||||||
|
import com.m2049r.xmrwallet.xmrto.api.XmrToApi;
|
||||||
|
|
||||||
|
import net.jodah.concurrentunit.Waiter;
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.mockwebserver.MockResponse;
|
||||||
|
import okhttp3.mockwebserver.MockWebServer;
|
||||||
|
import okhttp3.mockwebserver.RecordedRequest;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
public class XmrToApiQueryOrderTest {
|
||||||
|
|
||||||
|
static final SimpleDateFormat DATETIME_FORMATTER = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
|
||||||
|
|
||||||
|
static Date ParseDate(String dateString) throws ParseException {
|
||||||
|
return DATETIME_FORMATTER.parse(dateString.replaceAll("Z$", "+0000"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private MockWebServer mockWebServer;
|
||||||
|
|
||||||
|
private XmrToApi xmrToApi;
|
||||||
|
|
||||||
|
private OkHttpClient okHttpClient = new OkHttpClient();
|
||||||
|
private Waiter waiter;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
XmrToCallback<QueryOrderStatus> mockQueryXmrToCallback;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
mockWebServer = new MockWebServer();
|
||||||
|
mockWebServer.start();
|
||||||
|
|
||||||
|
waiter = new Waiter();
|
||||||
|
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
|
xmrToApi = new XmrToApiImpl(okHttpClient, mockWebServer.url("/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
mockWebServer.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void orderStatus_shouldBePostMethod()
|
||||||
|
throws InterruptedException, TimeoutException {
|
||||||
|
|
||||||
|
xmrToApi.queryOrderStatus("xmrto - efMsiU", mockQueryXmrToCallback);
|
||||||
|
|
||||||
|
RecordedRequest request = mockWebServer.takeRequest();
|
||||||
|
assertEquals("POST", request.getMethod());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void orderStatus_shouldBeContentTypeJson()
|
||||||
|
throws InterruptedException, TimeoutException {
|
||||||
|
|
||||||
|
xmrToApi.queryOrderStatus("xmrto - efMsiU", mockQueryXmrToCallback);
|
||||||
|
|
||||||
|
RecordedRequest request = mockWebServer.takeRequest();
|
||||||
|
assertEquals("application/json; charset=utf-8", request.getHeader("Content-Type"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void orderStatus_shouldContainValidBody()
|
||||||
|
throws InterruptedException, TimeoutException {
|
||||||
|
|
||||||
|
final String validBody = "{\"uuid\":\"xmrto - efMsiU\"}";
|
||||||
|
|
||||||
|
xmrToApi.queryOrderStatus("xmrto - efMsiU", mockQueryXmrToCallback);
|
||||||
|
|
||||||
|
RecordedRequest request = mockWebServer.takeRequest();
|
||||||
|
String body = request.getBody().readUtf8();
|
||||||
|
assertEquals(validBody, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void orderStatus_wasSuccessfulShouldRespondWithOrder()
|
||||||
|
throws InterruptedException, JSONException, TimeoutException {
|
||||||
|
|
||||||
|
//TODO: state enum
|
||||||
|
// TODO dates are dates
|
||||||
|
final String state = "UNPAID";
|
||||||
|
final double btcAmount = 0.1;
|
||||||
|
final String btcDestAddress = "1FhnVJi2V1k4MqXm2nHoEbY5LV7FPai7bb";
|
||||||
|
final String uuid = "xmrto - efMsiU";
|
||||||
|
final int btcNumConfirmations = 0;
|
||||||
|
final int btcNumConfirmationsBeforePurge = 144;
|
||||||
|
final String btcTransactionId = "";
|
||||||
|
final String createdAt = "2017-11-17T12:20:02Z";
|
||||||
|
final String expiresAt = "2017-11-17T12:35:02Z";
|
||||||
|
final int secondsTillTimeout = 882;
|
||||||
|
final double xmrAmountTotal = 6.464;
|
||||||
|
final double xmrAmountRemaining = 6.464;
|
||||||
|
final int xmrNumConfirmationsRemaining = -1;
|
||||||
|
final double xmrPriceBtc = 0.0154703;
|
||||||
|
final String xmrReceivingAddress = "44TVPcCSHebEQp4LnapPkhb2pondb2Ed7GJJLc6TkKwtSyumUnQ6QzkCCkojZycH2MRfLcujCM7QR1gdnRULRraV4UpB5n4";
|
||||||
|
final String xmrReceivingIntegratedAddress = "4EAAQR1vtv7EQp4LnapPkhb2pondb2Ed7GJJLc6TkKwtSyumUnQ6QzkCCkojZycH2MRfLcujCM7QR1gdnRULRraV6B5rRtHLeXGQSECXy9";
|
||||||
|
final int xmrRecommendedMixin = 5;
|
||||||
|
final double xmrRequiredAmount = 6.464;
|
||||||
|
final String xmrRequiredPaymentIdLong = "56beabc3ca6d52a78c9a44cefebeb870054d8b367cc7065bff1bdb553caca85c";
|
||||||
|
final String xmrRequiredPaymentIdShort = "eeb6086436b267cf";
|
||||||
|
|
||||||
|
MockResponse jsonMockResponse = new MockResponse().setBody(
|
||||||
|
createMockQueryOrderResponse(
|
||||||
|
state,
|
||||||
|
btcAmount,
|
||||||
|
btcDestAddress,
|
||||||
|
uuid,
|
||||||
|
btcNumConfirmations,
|
||||||
|
btcNumConfirmationsBeforePurge,
|
||||||
|
btcTransactionId,
|
||||||
|
createdAt,
|
||||||
|
expiresAt,
|
||||||
|
secondsTillTimeout,
|
||||||
|
xmrAmountTotal,
|
||||||
|
xmrAmountRemaining,
|
||||||
|
xmrNumConfirmationsRemaining,
|
||||||
|
xmrPriceBtc,
|
||||||
|
xmrReceivingAddress,
|
||||||
|
xmrReceivingIntegratedAddress,
|
||||||
|
xmrRecommendedMixin,
|
||||||
|
xmrRequiredAmount,
|
||||||
|
xmrRequiredPaymentIdLong,
|
||||||
|
xmrRequiredPaymentIdShort));
|
||||||
|
mockWebServer.enqueue(jsonMockResponse);
|
||||||
|
|
||||||
|
xmrToApi.queryOrderStatus(uuid, new XmrToCallback<QueryOrderStatus>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(final QueryOrderStatus orderStatus) {
|
||||||
|
waiter.assertEquals(orderStatus.getState().toString(), state);
|
||||||
|
waiter.assertEquals(orderStatus.getBtcAmount(), btcAmount);
|
||||||
|
waiter.assertEquals(orderStatus.getBtcDestAddress(), btcDestAddress);
|
||||||
|
waiter.assertEquals(orderStatus.getUuid(), uuid);
|
||||||
|
waiter.assertEquals(orderStatus.getBtcNumConfirmations(), btcNumConfirmations);
|
||||||
|
waiter.assertEquals(orderStatus.getBtcNumConfirmationsBeforePurge(), btcNumConfirmationsBeforePurge);
|
||||||
|
waiter.assertEquals(orderStatus.getBtcTransactionId(), btcTransactionId);
|
||||||
|
try {
|
||||||
|
waiter.assertEquals(orderStatus.getCreatedAt(), ParseDate(createdAt));
|
||||||
|
waiter.assertEquals(orderStatus.getExpiresAt(), ParseDate(expiresAt));
|
||||||
|
} catch (ParseException ex) {
|
||||||
|
waiter.fail(ex);
|
||||||
|
}
|
||||||
|
waiter.assertEquals(orderStatus.getSecondsTillTimeout(), secondsTillTimeout);
|
||||||
|
waiter.assertEquals(orderStatus.getXmrAmountTotal(), xmrAmountTotal);
|
||||||
|
waiter.assertEquals(orderStatus.getXmrAmountRemaining(), xmrAmountRemaining);
|
||||||
|
waiter.assertEquals(orderStatus.getXmrNumConfirmationsRemaining(), xmrNumConfirmationsRemaining);
|
||||||
|
waiter.assertEquals(orderStatus.getXmrPriceBtc(), xmrPriceBtc);
|
||||||
|
waiter.assertEquals(orderStatus.getXmrReceivingAddress(), xmrReceivingAddress);
|
||||||
|
waiter.assertEquals(orderStatus.getXmrReceivingIntegratedAddress(), xmrReceivingIntegratedAddress);
|
||||||
|
waiter.assertEquals(orderStatus.getXmrRecommendedMixin(), xmrRecommendedMixin);
|
||||||
|
waiter.assertEquals(orderStatus.getXmrRequiredAmount(), xmrRequiredAmount);
|
||||||
|
waiter.assertEquals(orderStatus.getXmrRequiredPaymentIdLong(), xmrRequiredPaymentIdLong);
|
||||||
|
waiter.assertEquals(orderStatus.getXmrRequiredPaymentIdShort(), xmrRequiredPaymentIdShort);
|
||||||
|
waiter.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(final Exception e) {
|
||||||
|
waiter.fail(e);
|
||||||
|
waiter.resume();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
waiter.await();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void orderStatus_wasNotSuccessfulShouldCallOnError()
|
||||||
|
throws InterruptedException, JSONException, TimeoutException {
|
||||||
|
mockWebServer.enqueue(new MockResponse().setResponseCode(500));
|
||||||
|
xmrToApi.queryOrderStatus("xmrto - efMsiU", new XmrToCallback<QueryOrderStatus>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(final QueryOrderStatus orderStatus) {
|
||||||
|
waiter.fail();
|
||||||
|
waiter.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(final Exception e) {
|
||||||
|
waiter.assertTrue(e instanceof XmrToException);
|
||||||
|
waiter.assertTrue(((XmrToException) e).getCode() == 500);
|
||||||
|
waiter.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
waiter.await();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void orderStatus_orderNotFoundShouldCallOnError()
|
||||||
|
throws InterruptedException, JSONException, TimeoutException {
|
||||||
|
mockWebServer.enqueue(new MockResponse().
|
||||||
|
setResponseCode(404).
|
||||||
|
setBody("{\"error_msg\":\"requested order not found\",\"error\":\"XMRTO-ERROR-006\"}"));
|
||||||
|
xmrToApi.queryOrderStatus("xmrto - efMsiU", new XmrToCallback<QueryOrderStatus>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(final QueryOrderStatus orderStatus) {
|
||||||
|
waiter.fail();
|
||||||
|
waiter.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(final Exception e) {
|
||||||
|
waiter.assertTrue(e instanceof XmrToException);
|
||||||
|
XmrToException xmrEx = (XmrToException) e;
|
||||||
|
waiter.assertTrue(xmrEx.getCode() == 404);
|
||||||
|
waiter.assertNotNull(xmrEx.getError());
|
||||||
|
waiter.assertEquals(xmrEx.getError().getErrorId(), XmrToError.Error.XMRTO_ERROR_006);
|
||||||
|
waiter.assertEquals(xmrEx.getError().getErrorMsg(), "requested order not found");
|
||||||
|
waiter.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
waiter.await();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String createMockQueryOrderResponse(
|
||||||
|
final String state,
|
||||||
|
final double btcAmount,
|
||||||
|
final String btcDestAddress,
|
||||||
|
final String uuid,
|
||||||
|
final int btcNumConfirmations,
|
||||||
|
final int btcNumConfirmationsBeforePurge,
|
||||||
|
final String btcTransactionId,
|
||||||
|
final String createdAt,
|
||||||
|
final String expiresAt,
|
||||||
|
final int secondsTillTimeout,
|
||||||
|
final double xmrAmountTotal,
|
||||||
|
final double xmrAmountRemaining,
|
||||||
|
final int xmrNumConfirmationsRemaining,
|
||||||
|
final double xmrPriceBtc,
|
||||||
|
final String xmrReceivingAddress,
|
||||||
|
final String xmrReceivingIntegratedAddress,
|
||||||
|
final int xmrRecommendedMixin,
|
||||||
|
final double xmrRequiredAmount,
|
||||||
|
final String xmrRequiredPaymentIdLong,
|
||||||
|
final String xmrRequiredPaymentIdShort
|
||||||
|
) {
|
||||||
|
return "{\n" +
|
||||||
|
" \"xmr_price_btc\": \"" + xmrPriceBtc + "\",\n" +
|
||||||
|
" \"uuid\":\"" + uuid + "\",\n" +
|
||||||
|
" \"state\":\"" + state + "\",\n" +
|
||||||
|
" \"btc_amount\":\"" + btcAmount + "\",\n" +
|
||||||
|
" \"btc_dest_address\":\"" + btcDestAddress + "\",\n" +
|
||||||
|
" \"xmr_required_amount\":\"" + xmrRequiredAmount + "\",\n" +
|
||||||
|
" \"xmr_receiving_address\":\"" + xmrReceivingAddress + "\",\n" +
|
||||||
|
" \"xmr_receiving_integrated_address\":\"" + xmrReceivingIntegratedAddress + "\",\n" +
|
||||||
|
" \"xmr_required_payment_id_long\":\"" + xmrRequiredPaymentIdLong + "\",\n" +
|
||||||
|
" \"xmr_required_payment_id_short\":\"" + xmrRequiredPaymentIdShort + "\",\n" +
|
||||||
|
" \"created_at\":\"" + createdAt + "\",\n" +
|
||||||
|
" \"expires_at\":\"" + expiresAt + "\",\n" +
|
||||||
|
" \"seconds_till_timeout\":\"" + secondsTillTimeout + "\",\n" +
|
||||||
|
" \"xmr_amount_total\":\"" + xmrAmountTotal + "\",\n" +
|
||||||
|
" \"xmr_amount_remaining\":\"" + xmrAmountRemaining + "\",\n" +
|
||||||
|
" \"xmr_num_confirmations_remaining\":\"" + xmrNumConfirmationsRemaining + "\",\n" +
|
||||||
|
" \"xmr_recommended_mixin\":\"" + xmrRecommendedMixin + "\",\n" +
|
||||||
|
" \"btc_num_confirmations_before_purge\":\"" + btcNumConfirmationsBeforePurge + "\",\n" +
|
||||||
|
" \"btc_num_confirmations\":\"" + btcNumConfirmations + "\",\n" +
|
||||||
|
" \"btc_transaction_id\":\"" + btcTransactionId + "\""
|
||||||
|
+ "}";
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue