parent
d855328c52
commit
f8e701aa07
|
@ -8,8 +8,8 @@ android {
|
|||
applicationId "com.m2049r.xmrwallet"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 25
|
||||
versionCode 51
|
||||
versionName "1.2.11"
|
||||
versionCode 62
|
||||
versionName "1.3.2 'Satoshis Dream'"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
|
|
|
@ -46,6 +46,7 @@ import com.google.zxing.WriterException;
|
|||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.qrcode.QRCodeWriter;
|
||||
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
|
||||
import com.m2049r.xmrwallet.data.BarcodeData;
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.model.WalletManager;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
|
@ -304,14 +305,14 @@ public class ReceiveFragment extends Fragment {
|
|||
return;
|
||||
}
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(ScannerFragment.QR_SCHEME).append(address);
|
||||
sb.append(BarcodeData.XMR_SCHEME).append(address);
|
||||
boolean first = true;
|
||||
if (!paymentId.isEmpty()) {
|
||||
if (first) {
|
||||
sb.append("?");
|
||||
first = false;
|
||||
}
|
||||
sb.append(ScannerFragment.QR_PAYMENTID).append('=').append(paymentId);
|
||||
sb.append(BarcodeData.XMR_PAYMENTID).append('=').append(paymentId);
|
||||
}
|
||||
if (!xmrAmount.isEmpty()) {
|
||||
if (first) {
|
||||
|
@ -319,7 +320,7 @@ public class ReceiveFragment extends Fragment {
|
|||
} else {
|
||||
sb.append("&");
|
||||
}
|
||||
sb.append(ScannerFragment.QR_AMOUNT).append('=').append(xmrAmount);
|
||||
sb.append(BarcodeData.XMR_AMOUNT).append('=').append(xmrAmount);
|
||||
}
|
||||
String text = sb.toString();
|
||||
int size = Math.min(qrCode.getHeight(), qrCode.getWidth());
|
||||
|
|
|
@ -36,7 +36,7 @@ public class ScannerFragment extends Fragment implements ZXingScannerView.Result
|
|||
private OnScannedListener onScannedListener;
|
||||
|
||||
public interface OnScannedListener {
|
||||
boolean onScanned(String uri);
|
||||
boolean onScanned(String qrCode);
|
||||
}
|
||||
|
||||
private ZXingScannerView mScannerView;
|
||||
|
@ -56,10 +56,6 @@ public class ScannerFragment extends Fragment implements ZXingScannerView.Result
|
|||
mScannerView.startCamera();
|
||||
}
|
||||
|
||||
static final String QR_SCHEME = "monero:";
|
||||
static final String QR_PAYMENTID = "tx_payment_id";
|
||||
static final String QR_AMOUNT = "tx_amount";
|
||||
|
||||
@Override
|
||||
public void handleResult(Result rawResult) {
|
||||
if ((rawResult.getBarcodeFormat() == BarcodeFormat.QR_CODE)) {
|
||||
|
|
|
@ -20,6 +20,10 @@ import android.os.Bundle;
|
|||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static android.view.WindowManager.LayoutParams;
|
||||
|
||||
public abstract class SecureActivity extends AppCompatActivity {
|
||||
|
@ -27,8 +31,9 @@ public abstract class SecureActivity extends AppCompatActivity {
|
|||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
File f = new File(Helper.getStorageRoot(this), "screenshot");
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,10 +30,13 @@ import android.view.View;
|
|||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.m2049r.xmrwallet.model.TransactionInfo;
|
||||
import com.m2049r.xmrwallet.model.Transfer;
|
||||
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 java.text.SimpleDateFormat;
|
||||
|
@ -68,12 +71,23 @@ public class TxFragment extends Fragment {
|
|||
private TextView etTxNotes;
|
||||
private Button bTxNotes;
|
||||
|
||||
// XMRTO stuff
|
||||
private View cvXmrTo;
|
||||
private TextView tvTxXmrToKey;
|
||||
private TextView tvDestinationBtc;
|
||||
private TextView tvTxAmountBtc;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
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);
|
||||
tvTxId = (TextView) view.findViewById(R.id.tvTxId);
|
||||
tvTxKey = (TextView) view.findViewById(R.id.tvTxKey);
|
||||
|
@ -94,7 +108,16 @@ public class TxFragment extends Fragment {
|
|||
info.notes = null; // force reload on next view
|
||||
bTxNotes.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;
|
||||
UserNotes userNotes = null;
|
||||
|
||||
void loadNotes(TransactionInfo info) {
|
||||
if (info.notes == null) {
|
||||
if ((userNotes == null) || (info.notes == null)) {
|
||||
info.notes = activityCallback.getTxNotes(info.hash);
|
||||
}
|
||||
etTxNotes.setText(info.notes);
|
||||
userNotes = new UserNotes(info.notes);
|
||||
etTxNotes.setText(userNotes.note);
|
||||
}
|
||||
|
||||
private void setTxColour(int clr) {
|
||||
|
@ -266,8 +291,21 @@ public class TxFragment extends Fragment {
|
|||
tvTxTransfers.setText(sb.toString());
|
||||
tvDestination.setText(dstSb.toString());
|
||||
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
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
|
|
@ -23,7 +23,6 @@ import android.content.DialogInterface;
|
|||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.PowerManager;
|
||||
|
@ -38,17 +37,18 @@ import com.m2049r.xmrwallet.data.BarcodeData;
|
|||
import com.m2049r.xmrwallet.data.TxData;
|
||||
import com.m2049r.xmrwallet.dialog.DonationFragment;
|
||||
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.TransactionInfo;
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.model.WalletManager;
|
||||
import com.m2049r.xmrwallet.service.WalletService;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.util.UserNotes;
|
||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
|
@ -465,7 +465,7 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onTransactionCreated(final PendingTransaction pendingTransaction) {
|
||||
public void onTransactionCreated(final String txTag, final PendingTransaction pendingTransaction) {
|
||||
try {
|
||||
final SendFragment sendFragment = (SendFragment)
|
||||
getSupportFragmentManager().findFragmentById(R.id.fragment_container);
|
||||
|
@ -477,7 +477,7 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
|
|||
getWallet().disposePendingTransaction();
|
||||
sendFragment.onCreateTransactionFailed(errorText);
|
||||
} else {
|
||||
sendFragment.onTransactionCreated(pendingTransaction);
|
||||
sendFragment.onTransactionCreated(txTag, pendingTransaction);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -588,11 +588,11 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
|
|||
///////////////////////////
|
||||
|
||||
@Override
|
||||
public void onSend(String notes) {
|
||||
public void onSend(UserNotes notes) {
|
||||
if (mIsBound) { // no point in talking to unbound service
|
||||
Intent intent = new Intent(getApplicationContext(), WalletService.class);
|
||||
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);
|
||||
Timber.d("SEND TX request sent");
|
||||
} else {
|
||||
|
@ -617,11 +617,12 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareSend(TxData txData) {
|
||||
public void onPrepareSend(final String tag, final TxData txData) {
|
||||
if (mIsBound) { // no point in talking to unbound service
|
||||
Intent intent = new Intent(getApplicationContext(), WalletService.class);
|
||||
intent.putExtra(WalletService.REQUEST, WalletService.REQUEST_CMD_TX);
|
||||
intent.putExtra(WalletService.REQUEST_CMD_TX_DATA, txData);
|
||||
intent.putExtra(WalletService.REQUEST_CMD_TX_TAG, tag);
|
||||
startService(intent);
|
||||
Timber.d("CREATE TX request sent");
|
||||
} else {
|
||||
|
@ -694,6 +695,7 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
|
|||
|
||||
@Override
|
||||
public void onDisposeRequest() {
|
||||
//TODO consider doing this through the WalletService to avoid concurrency issues
|
||||
getWallet().disposePendingTransaction();
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@ package com.m2049r.xmrwallet.data;
|
|||
import android.net.Uri;
|
||||
|
||||
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.Map;
|
||||
|
@ -34,7 +36,7 @@ public class BarcodeData {
|
|||
static final String BTC_AMOUNT = "amount";
|
||||
|
||||
public enum Asset {
|
||||
XMR
|
||||
XMR, BTC
|
||||
}
|
||||
|
||||
public Asset asset = null;
|
||||
|
@ -67,6 +69,14 @@ public class BarcodeData {
|
|||
if (bcData == null) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -134,4 +144,57 @@ public class BarcodeData {
|
|||
|
||||
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 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
|
||||
public class TxData implements Parcelable {
|
||||
|
||||
public TxData() {
|
||||
}
|
||||
|
||||
public TxData(TxData txData) {
|
||||
this.dst_addr = txData.dst_addr;
|
||||
this.dstAddr = txData.dstAddr;
|
||||
this.paymentId = txData.paymentId;
|
||||
this.amount = txData.amount;
|
||||
this.mixin = txData.mixin;
|
||||
this.priority = txData.priority;
|
||||
}
|
||||
|
||||
public TxData(String dst_addr,
|
||||
public TxData(String dstAddr,
|
||||
String paymentId,
|
||||
long amount,
|
||||
int mixin,
|
||||
PendingTransaction.Priority priority) {
|
||||
this.dst_addr = dst_addr;
|
||||
this.dstAddr = dstAddr;
|
||||
this.paymentId = paymentId;
|
||||
this.amount = amount;
|
||||
this.mixin = mixin;
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
public long getFee() {
|
||||
return 0L;
|
||||
}
|
||||
|
||||
public String getDestinationAddress() {
|
||||
return dst_addr;
|
||||
return dstAddr;
|
||||
}
|
||||
|
||||
public String getPaymentId() {
|
||||
|
@ -68,15 +70,45 @@ public class TxData implements Parcelable {
|
|||
return priority;
|
||||
}
|
||||
|
||||
final private String dst_addr;
|
||||
final private String paymentId;
|
||||
final private long amount;
|
||||
final private int mixin;
|
||||
final private PendingTransaction.Priority priority;
|
||||
public void setDestinationAddress(String dstAddr) {
|
||||
this.dstAddr = dstAddr;
|
||||
}
|
||||
|
||||
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
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeString(dst_addr);
|
||||
out.writeString(dstAddr);
|
||||
out.writeString(paymentId);
|
||||
out.writeLong(amount);
|
||||
out.writeInt(mixin);
|
||||
|
@ -94,8 +126,8 @@ public class TxData implements Parcelable {
|
|||
}
|
||||
};
|
||||
|
||||
private TxData(Parcel in) {
|
||||
dst_addr = in.readString();
|
||||
protected TxData(Parcel in) {
|
||||
dstAddr = in.readString();
|
||||
paymentId = in.readString();
|
||||
amount = in.readLong();
|
||||
mixin = in.readInt();
|
||||
|
@ -111,8 +143,8 @@ public class TxData implements Parcelable {
|
|||
@Override
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append("dst_addr:");
|
||||
sb.append(dst_addr);
|
||||
sb.append("dstAddr:");
|
||||
sb.append(dstAddr);
|
||||
sb.append(",paymentId:");
|
||||
sb.append(paymentId);
|
||||
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.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet;
|
||||
package com.m2049r.xmrwallet.fragment.send;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.design.widget.TextInputLayout;
|
||||
import android.support.v7.widget.CardView;
|
||||
import android.text.Editable;
|
||||
import android.text.Html;
|
||||
import android.text.InputType;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.KeyEvent;
|
||||
|
@ -32,9 +33,13 @@ import android.widget.Button;
|
|||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.m2049r.xmrwallet.R;
|
||||
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.WalletManager;
|
||||
import com.m2049r.xmrwallet.util.BitcoinAddressValidator;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
@ -56,12 +61,12 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||
return this;
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
void setAddress(final String address);
|
||||
|
||||
void setPaymentId(final String paymentId);
|
||||
|
||||
public interface Listener {
|
||||
void setBarcodeData(BarcodeData data);
|
||||
|
||||
void setMode(SendFragment.Mode mode);
|
||||
|
||||
TxData getTxData();
|
||||
}
|
||||
|
||||
private EditText etDummy;
|
||||
|
@ -71,6 +76,8 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||
private CardView cvScan;
|
||||
private View tvPaymentIdIntegrated;
|
||||
private View llPaymentId;
|
||||
private TextView tvXmrTo;
|
||||
private View llXmrTo;
|
||||
|
||||
OnScanListener onScanListener;
|
||||
|
||||
|
@ -89,6 +96,9 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||
|
||||
tvPaymentIdIntegrated = view.findViewById(R.id.tvPaymentIdIntegrated);
|
||||
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.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||
|
@ -113,12 +123,25 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||
public void afterTextChanged(Editable editable) {
|
||||
etAddress.setError(null);
|
||||
if (isIntegratedAddress()) {
|
||||
Timber.d("isIntegratedAddress");
|
||||
etPaymentId.getEditText().getText().clear();
|
||||
llPaymentId.setVisibility(View.GONE);
|
||||
llPaymentId.setVisibility(View.INVISIBLE);
|
||||
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);
|
||||
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() {
|
||||
String address = etAddress.getEditText().getText().toString();
|
||||
return Wallet.isAddressValid(address);
|
||||
return Wallet.isAddressValid(address)
|
||||
|| BitcoinAddressValidator.validate(address, WalletManager.getInstance().isTestNet());
|
||||
}
|
||||
|
||||
private boolean checkAddress() {
|
||||
boolean ok = checkAddressNoError();
|
||||
if (!ok) {
|
||||
etAddress.setError(getString(R.string.send_qr_address_invalid));
|
||||
etAddress.setError(getString(R.string.send_address_invalid));
|
||||
} else {
|
||||
etAddress.setError(null);
|
||||
}
|
||||
|
@ -203,7 +227,16 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||
|
||||
private boolean isIntegratedAddress() {
|
||||
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() {
|
||||
|
@ -235,8 +268,15 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||
}
|
||||
if (!ok) return false;
|
||||
if (sendListener != null) {
|
||||
sendListener.setAddress(etAddress.getEditText().getText().toString());
|
||||
sendListener.setPaymentId(etPaymentId.getEditText().getText().toString());
|
||||
TxData txData = sendListener.getTxData();
|
||||
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;
|
||||
}
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet;
|
||||
package com.m2049r.xmrwallet.fragment.send;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -22,10 +22,12 @@ 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.widget.ExchangeTextView;
|
||||
import com.m2049r.xmrwallet.data.TxData;
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.widget.ExchangeTextView;
|
||||
import com.m2049r.xmrwallet.widget.NumberPadView;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
@ -48,7 +50,7 @@ public class SendAmountWizardFragment extends SendWizardFragment {
|
|||
interface Listener {
|
||||
SendFragment.Listener getActivityCallback();
|
||||
|
||||
void setAmount(final long amount);
|
||||
TxData getTxData();
|
||||
|
||||
BarcodeData popBarcodeData();
|
||||
}
|
||||
|
@ -99,9 +101,9 @@ public class SendAmountWizardFragment extends SendWizardFragment {
|
|||
if (sendListener != null) {
|
||||
String xmr = evAmount.getAmount();
|
||||
if (xmr != null) {
|
||||
sendListener.setAmount(Wallet.getAmountFromString(xmr));
|
||||
sendListener.getTxData().setAmount(Wallet.getAmountFromString(xmr));
|
||||
} else {
|
||||
sendListener.setAmount(0L);
|
||||
sendListener.getTxData().setAmount(0L);
|
||||
}
|
||||
}
|
||||
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.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet;
|
||||
package com.m2049r.xmrwallet.fragment.send;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.design.widget.TextInputLayout;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.KeyEvent;
|
||||
|
@ -30,14 +31,16 @@ import android.view.inputmethod.EditorInfo;
|
|||
import android.widget.Button;
|
||||
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.Wallet;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.util.UserNotes;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
public class SendConfirmWizardFragment extends SendWizardFragment {
|
||||
public class SendConfirmWizardFragment extends SendWizardFragment implements SendConfirm {
|
||||
|
||||
public static SendConfirmWizardFragment newInstance(Listener listener) {
|
||||
SendConfirmWizardFragment instance = new SendConfirmWizardFragment();
|
||||
|
@ -57,11 +60,11 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
|
|||
|
||||
TxData getTxData();
|
||||
|
||||
String getNotes();
|
||||
|
||||
void commitTransaction();
|
||||
|
||||
void disposeTransaction();
|
||||
|
||||
SendFragment.Mode getMode();
|
||||
}
|
||||
|
||||
private TextView tvTxAddress;
|
||||
|
@ -122,8 +125,11 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
|
|||
|
||||
PendingTransaction pendingTransaction = null;
|
||||
|
||||
@Override
|
||||
// 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();
|
||||
if (isResumed) {
|
||||
this.pendingTransaction = pendingTransaction;
|
||||
|
@ -138,10 +144,22 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
|
|||
pbProgressSend.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
void sendFailed() {
|
||||
@Override
|
||||
public void sendFailed() {
|
||||
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
|
||||
public boolean onValidateFields() {
|
||||
return true;
|
||||
|
@ -173,9 +191,9 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
|
|||
} else {
|
||||
tvTxPaymentId.setText("-");
|
||||
}
|
||||
String notes = sendListener.getNotes();
|
||||
if ((notes != null) && (!notes.isEmpty())) {
|
||||
tvTxNotes.setText(sendListener.getNotes());
|
||||
UserNotes notes = sendListener.getTxData().getUserNotes();
|
||||
if ((notes != null) && (!notes.note.isEmpty())) {
|
||||
tvTxNotes.setText(notes.note);
|
||||
} else {
|
||||
tvTxNotes.setText("-");
|
||||
}
|
||||
|
@ -296,8 +314,10 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
|
|||
passwordDialog.show();
|
||||
}
|
||||
|
||||
// creates a pending transaction and calls us back with transactionCreated()
|
||||
// or createTransactionFailed()
|
||||
void prepareSend(TxData txData) {
|
||||
getActivityCallback().onPrepareSend(txData);
|
||||
getActivityCallback().onPrepareSend(null, txData);
|
||||
}
|
||||
|
||||
SendFragment.Listener getActivityCallback() {
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet;
|
||||
package com.m2049r.xmrwallet.fragment.send;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
@ -22,9 +22,8 @@ import android.os.Bundle;
|
|||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
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.v7.app.AlertDialog;
|
||||
import android.text.InputType;
|
||||
import android.util.SparseArray;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -36,12 +35,16 @@ import android.widget.Button;
|
|||
import android.widget.EditText;
|
||||
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.PendingTx;
|
||||
import com.m2049r.xmrwallet.data.TxData;
|
||||
import com.m2049r.xmrwallet.data.TxDataBtc;
|
||||
import com.m2049r.xmrwallet.layout.SpendViewPager;
|
||||
import com.m2049r.xmrwallet.model.PendingTransaction;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.util.UserNotes;
|
||||
import com.m2049r.xmrwallet.widget.DotBar;
|
||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||
|
||||
|
@ -62,11 +65,11 @@ public class SendFragment extends Fragment
|
|||
public interface Listener {
|
||||
long getTotalFunds();
|
||||
|
||||
void onPrepareSend(TxData data);
|
||||
void onPrepareSend(String tag, TxData data);
|
||||
|
||||
boolean verifyWalletPassword(String password);
|
||||
|
||||
void onSend(String notes);
|
||||
void onSend(UserNotes notes);
|
||||
|
||||
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_AMOUNT = 1;
|
||||
private static final int POS_SETTINGS = 2;
|
||||
|
@ -257,6 +295,7 @@ public class SendFragment extends Fragment
|
|||
|
||||
@Override
|
||||
public Object instantiateItem(ViewGroup container, int position) {
|
||||
Timber.d("instantiateItem %d", position);
|
||||
SendWizardFragment fragment = (SendWizardFragment) super.instantiateItem(container, position);
|
||||
myFragments.put(position, new WeakReference<>(fragment));
|
||||
return fragment;
|
||||
|
@ -264,6 +303,7 @@ public class SendFragment extends Fragment
|
|||
|
||||
@Override
|
||||
public void destroyItem(ViewGroup container, int position, Object object) {
|
||||
Timber.d("destroyItem %d", position);
|
||||
myFragments.remove(position);
|
||||
super.destroyItem(container, position, object);
|
||||
}
|
||||
|
@ -279,19 +319,39 @@ public class SendFragment extends Fragment
|
|||
@Override
|
||||
public SendWizardFragment getItem(int position) {
|
||||
Timber.d("getItem(%d) CREATE", position);
|
||||
switch (position) {
|
||||
case POS_ADDRESS:
|
||||
return SendAddressWizardFragment.newInstance(SendFragment.this);
|
||||
case POS_AMOUNT:
|
||||
return SendAmountWizardFragment.newInstance(SendFragment.this);
|
||||
case POS_SETTINGS:
|
||||
return SendSettingsWizardFragment.newInstance(SendFragment.this);
|
||||
case POS_CONFIRM:
|
||||
return SendConfirmWizardFragment.newInstance(SendFragment.this);
|
||||
case POS_SUCCESS:
|
||||
return SendSuccessWizardFragment.newInstance(SendFragment.this);
|
||||
default:
|
||||
throw new IllegalArgumentException("no such send position(" + position + ")");
|
||||
Timber.d("Mode=" + mode.toString());
|
||||
if (mode == Mode.XMR) {
|
||||
switch (position) {
|
||||
case POS_ADDRESS:
|
||||
return SendAddressWizardFragment.newInstance(SendFragment.this);
|
||||
case POS_AMOUNT:
|
||||
return SendAmountWizardFragment.newInstance(SendFragment.this);
|
||||
case POS_SETTINGS:
|
||||
return SendSettingsWizardFragment.newInstance(SendFragment.this);
|
||||
case POS_CONFIRM:
|
||||
return SendConfirmWizardFragment.newInstance(SendFragment.this);
|
||||
case POS_SUCCESS:
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@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
|
||||
public TxData getTxData() {
|
||||
return new TxData(sendAddress, sendPaymentId, sendAmount, sendMixin, sendPriority);
|
||||
return txData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNotes() {
|
||||
return sendNotes;
|
||||
}
|
||||
private TxData txData = new TxData();
|
||||
|
||||
private String sendAddress;
|
||||
private String sendPaymentId;
|
||||
private long sendAmount;
|
||||
private PendingTransaction.Priority sendPriority;
|
||||
private int sendMixin;
|
||||
private String sendNotes;
|
||||
private BarcodeData barcodeData;
|
||||
|
||||
// Listeners
|
||||
|
@ -347,36 +408,6 @@ public class SendFragment extends Fragment
|
|||
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() {
|
||||
return committedTx != null;
|
||||
}
|
||||
|
@ -391,9 +422,9 @@ public class SendFragment extends Fragment
|
|||
|
||||
@Override
|
||||
public void commitTransaction() {
|
||||
Timber.d("REALLY SEND A %s", getNotes());
|
||||
Timber.d("REALLY SEND");
|
||||
disableNavigation(); // committed - disable all navigation
|
||||
activityCallback.onSend(getNotes());
|
||||
activityCallback.onSend(txData.getUserNotes());
|
||||
committedTx = pendingTx;
|
||||
}
|
||||
|
||||
|
@ -418,12 +449,11 @@ public class SendFragment extends Fragment
|
|||
|
||||
// callbacks from send service
|
||||
|
||||
public void onTransactionCreated(PendingTransaction pendingTransaction) {
|
||||
//public void onTransactionCreated(TestTransaction pendingTransaction) {
|
||||
final SendConfirmWizardFragment confirmFragment = getConfirmFragment();
|
||||
if (confirmFragment != null) {
|
||||
public void onTransactionCreated(final String txTag, final PendingTransaction pendingTransaction) {
|
||||
final SendConfirm confirm = getSendConfirm();
|
||||
if (confirm != null) {
|
||||
pendingTx = new PendingTx(pendingTransaction);
|
||||
confirmFragment.transactionCreated(pendingTransaction);
|
||||
confirm.transactionCreated(txTag, pendingTransaction);
|
||||
} else {
|
||||
// not in confirm fragment => dispose & move on
|
||||
disposeTransaction();
|
||||
|
@ -443,23 +473,16 @@ public class SendFragment extends Fragment
|
|||
}
|
||||
|
||||
public void onCreateTransactionFailed(String errorText) {
|
||||
final SendConfirmWizardFragment confirmFragment = getConfirmFragment();
|
||||
if (confirmFragment != null) {
|
||||
confirmFragment.hideProgress();
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
builder.setCancelable(true).
|
||||
setTitle(getString(R.string.send_create_tx_error_title)).
|
||||
setMessage(errorText).
|
||||
create().
|
||||
show();
|
||||
final SendConfirm confirm = getSendConfirm();
|
||||
if (confirm != null) {
|
||||
confirm.createTransactionFailed(errorText);
|
||||
}
|
||||
}
|
||||
|
||||
SendConfirmWizardFragment getConfirmFragment() {
|
||||
SendConfirm getSendConfirm() {
|
||||
final SendWizardFragment fragment = pagerAdapter.getFragment(SpendPagerAdapter.POS_CONFIRM);
|
||||
if (fragment instanceof SendConfirmWizardFragment) {
|
||||
return (SendConfirmWizardFragment) fragment;
|
||||
if (fragment instanceof SendConfirm) {
|
||||
return (SendConfirm) fragment;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -469,8 +492,8 @@ public class SendFragment extends Fragment
|
|||
Timber.d("txid=%s", txId);
|
||||
pagerAdapter.addSuccess();
|
||||
Timber.d("numPages=%d", spendViewPager.getAdapter().getCount());
|
||||
spendViewPager.setCurrentItem(SpendPagerAdapter.POS_SUCCESS);
|
||||
activityCallback.setToolbarButton(Toolbar.BUTTON_NONE);
|
||||
spendViewPager.setCurrentItem(SpendPagerAdapter.POS_SUCCESS);
|
||||
}
|
||||
|
||||
public void onSendTransactionFailed(final String error) {
|
||||
|
@ -478,7 +501,7 @@ public class SendFragment extends Fragment
|
|||
committedTx = null;
|
||||
Toast.makeText(getContext(), getString(R.string.status_transaction_failed, error), Toast.LENGTH_SHORT).show();
|
||||
enableNavigation();
|
||||
final SendConfirmWizardFragment fragment = getConfirmFragment();
|
||||
final SendConfirm fragment = getSendConfirm();
|
||||
if (fragment != null) {
|
||||
fragment.sendFailed();
|
||||
}
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet;
|
||||
package com.m2049r.xmrwallet.fragment.send;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.text.InputType;
|
||||
|
@ -27,8 +27,11 @@ import android.widget.EditText;
|
|||
import android.widget.Spinner;
|
||||
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.util.Helper;
|
||||
import com.m2049r.xmrwallet.util.UserNotes;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
|
@ -48,12 +51,7 @@ public class SendSettingsWizardFragment extends SendWizardFragment {
|
|||
}
|
||||
|
||||
interface Listener {
|
||||
|
||||
void setPriority(final PendingTransaction.Priority priority);
|
||||
|
||||
void setMixin(final int mixin);
|
||||
|
||||
void setNotes(final String notes);
|
||||
TxData getTxData();
|
||||
}
|
||||
|
||||
final static int Mixins[] = {4, 7, 12, 25}; // must match the layout XML
|
||||
|
@ -103,13 +101,10 @@ public class SendSettingsWizardFragment extends SendWizardFragment {
|
|||
@Override
|
||||
public boolean onValidateFields() {
|
||||
if (sendListener != null) {
|
||||
int mixin = Mixins[sMixin.getSelectedItemPosition()];
|
||||
int priorityIndex = sPriority.getSelectedItemPosition();
|
||||
PendingTransaction.Priority priority = Priorities[priorityIndex];
|
||||
sendListener.setPriority(priority);
|
||||
sendListener.setMixin(mixin);
|
||||
String notes = etNotes.getText().toString();
|
||||
sendListener.setNotes(notes);
|
||||
TxData txData = sendListener.getTxData();
|
||||
txData.setPriority(Priorities[sPriority.getSelectedItemPosition()]);
|
||||
txData.setMixin(Mixins[sMixin.getSelectedItemPosition()]);
|
||||
txData.setUserNotes(new UserNotes(etNotes.getText().toString()));
|
||||
}
|
||||
return true;
|
||||
}
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet;
|
||||
package com.m2049r.xmrwallet.fragment.send;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -24,10 +24,10 @@ import android.widget.ImageButton;
|
|||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.R;
|
||||
import com.m2049r.xmrwallet.data.PendingTx;
|
||||
import com.m2049r.xmrwallet.data.TxData;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
|
@ -47,23 +47,21 @@ public class SendSuccessWizardFragment extends SendWizardFragment {
|
|||
}
|
||||
|
||||
interface Listener {
|
||||
String getNotes();
|
||||
|
||||
TxData getTxData();
|
||||
|
||||
PendingTx getCommittedTx();
|
||||
|
||||
void enableDone();
|
||||
|
||||
SendFragment.Mode getMode();
|
||||
}
|
||||
|
||||
ImageButton bCopyAddress;
|
||||
ImageButton bCopyTxId;
|
||||
private TextView tvTxId;
|
||||
private TextView tvTxAddress;
|
||||
private TextView tvTxPaymentId;
|
||||
private TextView tvTxNotes;
|
||||
private TextView tvTxAmount;
|
||||
private TextView tvTxFee;
|
||||
private TextView tvTxTotal;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
|
@ -74,21 +72,20 @@ public class SendSuccessWizardFragment extends SendWizardFragment {
|
|||
View view = inflater.inflate(
|
||||
R.layout.fragment_send_success, container, false);
|
||||
|
||||
bCopyAddress = (ImageButton) view.findViewById(R.id.bCopyAddress);
|
||||
bCopyAddress.setOnClickListener(new View.OnClickListener() {
|
||||
bCopyTxId = (ImageButton) view.findViewById(R.id.bCopyTxId);
|
||||
bCopyTxId.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
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);
|
||||
tvTxAddress = (TextView) view.findViewById(R.id.tvTxAddress);
|
||||
tvTxPaymentId = (TextView) view.findViewById(R.id.tvTxPaymentId);
|
||||
tvTxNotes = (TextView) view.findViewById(R.id.tvTxNotes);
|
||||
tvTxAmount = ((TextView) view.findViewById(R.id.tvTxAmount));
|
||||
tvTxFee = (TextView) view.findViewById(R.id.tvTxFee);
|
||||
tvTxTotal = (TextView) view.findViewById(R.id.tvTxTotal);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
@ -117,30 +114,15 @@ public class SendSuccessWizardFragment extends SendWizardFragment {
|
|||
} else {
|
||||
tvTxPaymentId.setText("-");
|
||||
}
|
||||
String notes = sendListener.getNotes();
|
||||
if ((notes != null) && (!notes.isEmpty())) {
|
||||
tvTxNotes.setText(sendListener.getNotes());
|
||||
} else {
|
||||
tvTxNotes.setText("-");
|
||||
}
|
||||
|
||||
final PendingTx committedTx = sendListener.getCommittedTx();
|
||||
if (committedTx != null) {
|
||||
tvTxId.setText(committedTx.txId);
|
||||
bCopyAddress.setEnabled(true);
|
||||
bCopyAddress.setImageResource(R.drawable.ic_content_copy_black_24dp);
|
||||
tvTxAmount.setText(Wallet.getDisplayAmount(committedTx.amount));
|
||||
tvTxFee.setText(Wallet.getDisplayAmount(committedTx.fee));
|
||||
//tvTxDust.setText(Wallet.getDisplayAmount(pendingTransaction.getDust()));
|
||||
tvTxTotal.setText(Wallet.getDisplayAmount(
|
||||
committedTx.fee + committedTx.amount));
|
||||
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)));
|
||||
}
|
||||
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.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet;
|
||||
package com.m2049r.xmrwallet.fragment.send;
|
||||
|
||||
import android.support.v4.app.Fragment;
|
||||
|
|
@ -21,7 +21,7 @@ import android.support.v4.view.ViewPager;
|
|||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import com.m2049r.xmrwallet.SendFragment;
|
||||
import com.m2049r.xmrwallet.fragment.send.SendFragment;
|
||||
|
||||
public class SpendViewPager extends ViewPager {
|
||||
|
||||
|
|
|
@ -22,11 +22,13 @@ import android.support.v7.widget.RecyclerView;
|
|||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.m2049r.xmrwallet.R;
|
||||
import com.m2049r.xmrwallet.model.TransactionInfo;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.util.UserNotes;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
|
@ -101,6 +103,7 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
|||
}
|
||||
|
||||
class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
|
||||
final ImageView ivTxType;
|
||||
final TextView tvAmount;
|
||||
final TextView tvFee;
|
||||
final TextView tvPaymentId;
|
||||
|
@ -109,10 +112,11 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
|||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
this.tvAmount = (TextView) itemView.findViewById(R.id.tx_amount);
|
||||
this.tvFee = (TextView) itemView.findViewById(R.id.tx_fee);
|
||||
this.tvPaymentId = (TextView) itemView.findViewById(R.id.tx_paymentid);
|
||||
this.tvDateTime = (TextView) itemView.findViewById(R.id.tx_datetime);
|
||||
ivTxType = (ImageView) itemView.findViewById(R.id.ivTxType);
|
||||
tvAmount = (TextView) itemView.findViewById(R.id.tx_amount);
|
||||
tvFee = (TextView) itemView.findViewById(R.id.tx_fee);
|
||||
tvPaymentId = (TextView) itemView.findViewById(R.id.tx_paymentid);
|
||||
tvDateTime = (TextView) itemView.findViewById(R.id.tx_datetime);
|
||||
}
|
||||
|
||||
private String getDateTime(long time) {
|
||||
|
@ -121,7 +125,6 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
|||
|
||||
private void setTxColour(int clr) {
|
||||
tvAmount.setTextColor(clr);
|
||||
tvFee.setTextColor(clr);
|
||||
}
|
||||
|
||||
void bind(int position) {
|
||||
|
@ -134,20 +137,23 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
|||
|
||||
String displayAmount = Helper.getDisplayAmount(realAmount, Helper.DISPLAY_DIGITS_INFO);
|
||||
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 {
|
||||
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)) {
|
||||
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 {
|
||||
this.tvFee.setText("");
|
||||
tvFee.setText("");
|
||||
tvFee.setVisibility(View.GONE);
|
||||
}
|
||||
if (infoItem.isFailed) {
|
||||
this.tvAmount.setText(context.getString(R.string.tx_list_amount_failed, displayAmount));
|
||||
this.tvFee.setText(context.getString(R.string.tx_list_failed_text));
|
||||
tvFee.setVisibility(View.VISIBLE);
|
||||
setTxColour(failedColour);
|
||||
} else if (infoItem.isPending) {
|
||||
setTxColour(pendingColour);
|
||||
|
@ -156,11 +162,20 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
|||
} else {
|
||||
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);
|
||||
} else {
|
||||
this.tvPaymentId.setText(infoItem.notes);
|
||||
this.tvPaymentId.setText(userNotes.note);
|
||||
}
|
||||
|
||||
this.tvDateTime.setText(getDateTime(infoItem.timestamp));
|
||||
|
||||
itemView.setOnClickListener(this);
|
||||
|
|
|
@ -30,12 +30,12 @@ import android.os.Process;
|
|||
|
||||
import com.m2049r.xmrwallet.R;
|
||||
import com.m2049r.xmrwallet.WalletActivity;
|
||||
import com.m2049r.xmrwallet.data.TxData;
|
||||
import com.m2049r.xmrwallet.model.PendingTransaction;
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.model.WalletListener;
|
||||
import com.m2049r.xmrwallet.model.WalletManager;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.data.TxData;
|
||||
|
||||
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_DATA = "data";
|
||||
public static final String REQUEST_CMD_TX_TAG = "tag";
|
||||
|
||||
public static final String REQUEST_CMD_SWEEP = "sweepTX";
|
||||
|
||||
|
@ -209,7 +210,7 @@ public class WalletService extends Service {
|
|||
|
||||
void onWalletStored(boolean success);
|
||||
|
||||
void onTransactionCreated(PendingTransaction pendingTransaction);
|
||||
void onTransactionCreated(String tag, PendingTransaction pendingTransaction);
|
||||
|
||||
void onTransactionSent(String txid);
|
||||
|
||||
|
@ -301,7 +302,9 @@ public class WalletService extends Service {
|
|||
} else if (cmd.equals(REQUEST_CMD_TX)) {
|
||||
Wallet myWallet = getWallet();
|
||||
Timber.d("CREATE TX for wallet: %s", myWallet.getName());
|
||||
myWallet.disposePendingTransaction(); // remove any old pending tx
|
||||
TxData txData = extras.getParcelable(REQUEST_CMD_TX_DATA);
|
||||
String txTag = extras.getString(REQUEST_CMD_TX_TAG);
|
||||
PendingTransaction pendingTransaction = myWallet.createTransaction(txData);
|
||||
PendingTransaction.Status status = pendingTransaction.getStatus();
|
||||
Timber.d("transaction status %s", status);
|
||||
|
@ -309,13 +312,15 @@ public class WalletService extends Service {
|
|||
Timber.w("Create Transaction failed: %s", pendingTransaction.getErrorString());
|
||||
}
|
||||
if (observer != null) {
|
||||
observer.onTransactionCreated(pendingTransaction);
|
||||
observer.onTransactionCreated(txTag, pendingTransaction);
|
||||
} else {
|
||||
myWallet.disposePendingTransaction();
|
||||
}
|
||||
} else if (cmd.equals(REQUEST_CMD_SWEEP)) {
|
||||
Wallet myWallet = getWallet();
|
||||
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.Status status = pendingTransaction.getStatus();
|
||||
Timber.d("transaction status %s", status);
|
||||
|
@ -323,7 +328,7 @@ public class WalletService extends Service {
|
|||
Timber.w("Create Transaction failed: %s", pendingTransaction.getErrorString());
|
||||
}
|
||||
if (observer != null) {
|
||||
observer.onTransactionCreated(pendingTransaction);
|
||||
observer.onTransactionCreated(txTag, pendingTransaction);
|
||||
} else {
|
||||
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.model.Wallet;
|
||||
import com.m2049r.xmrwallet.model.WalletManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -49,6 +50,7 @@ import java.util.Locale;
|
|||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
|
||||
import okhttp3.HttpUrl;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class Helper {
|
||||
|
@ -160,7 +162,7 @@ public class Helper {
|
|||
}
|
||||
|
||||
static public String getDisplayAmount(long amount) {
|
||||
return getDisplayAmount(amount, 20);
|
||||
return getDisplayAmount(amount, 12);
|
||||
}
|
||||
|
||||
static public String getDisplayAmount(long amount, int maxDecimals) {
|
||||
|
@ -271,4 +273,11 @@ public class Helper {
|
|||
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() {
|
||||
//TODO locale?
|
||||
if (tvAmountA.getText().toString().indexOf('.') == -1) {
|
||||
if (tvAmountA.getText().toString().isEmpty()) {
|
||||
tvAmountA.append("0");
|
||||
}
|
||||
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"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="@color/moneroBlack"
|
||||
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: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" />
|
||||
</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
|
||||
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" />
|
||||
<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
|
||||
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" />
|
||||
|
|
|
@ -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: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
|
||||
android:id="@+id/tvVersion"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -29,8 +36,8 @@
|
|||
style="@style/MoneroText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/header_top"
|
||||
android:layout_marginBottom="@dimen/header_top"
|
||||
android:layout_marginTop="@dimen/header_top"
|
||||
android:gravity="start"
|
||||
android:textSize="10sp"
|
||||
tools:text="@string/menu_help" />
|
||||
|
|
|
@ -277,7 +277,7 @@
|
|||
android:layout_marginTop="4dp"
|
||||
android:enabled="false"
|
||||
android:minHeight="36dp"
|
||||
android:text="@string/send_send_hint" />
|
||||
android:text="@string/send_send_label" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/bReallySend"
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout 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"
|
||||
android:orientation="vertical">
|
||||
|
@ -28,8 +29,8 @@
|
|||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="96dp"
|
||||
android:layout_marginBottom="4dp">
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="48dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvPaymentIdIntegrated"
|
||||
|
@ -37,17 +38,48 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start|center_vertical"
|
||||
android:layout_margin="8dp"
|
||||
android:drawablePadding="8dp"
|
||||
android:drawableStart="@drawable/ic_check_gray_24dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/info_paymentid_intergrated"
|
||||
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
|
||||
android:id="@+id/llPaymentId"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="visible"
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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_height="match_parent"
|
||||
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:enabled="true"
|
||||
android:padding="8dp"
|
||||
android:text="@string/send_send_hint" />
|
||||
android:text="@string/send_send_label" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/pbProgressSend"
|
||||
|
|
|
@ -13,30 +13,55 @@
|
|||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:gravity="center"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="96dp"
|
||||
android:layout_height="96dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_margin="16dp"
|
||||
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" />
|
||||
|
||||
<TextView
|
||||
style="@style/MoneroText.Sucess"
|
||||
android:layout_width="wrap_content"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="16dp"
|
||||
android:text="@string/label_send_success" />
|
||||
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="16dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
|
@ -47,7 +72,7 @@
|
|||
android:textAlignment="textStart" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/bCopyAddress"
|
||||
android:id="@+id/bCopyTxId"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
|
@ -86,15 +111,16 @@
|
|||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginTop="4dp"
|
||||
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"
|
||||
android:textAlignment="textStart" />
|
||||
android:text="@string/label_send_payment_id" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvTxPaymentId"
|
||||
|
@ -102,114 +128,8 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:textAlignment="textStart"
|
||||
tools:text="d666a38d4a28fb38" />
|
||||
</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>
|
||||
</ScrollView>
|
||||
|
|
|
@ -58,6 +58,114 @@
|
|||
tools:text="2017-10-09 12:44:13 +0200" />
|
||||
</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
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -16,11 +16,19 @@
|
|||
android:orientation="horizontal"
|
||||
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
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_weight="11"
|
||||
android:layout_weight="9"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
|
@ -29,7 +37,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
tools:text="999999.99999" />
|
||||
tools:text="999.999999" />
|
||||
|
||||
<TextView
|
||||
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>
|
||||
<string name="about_title">Acerca De</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">
|
||||
\"¡Donar, bastardos ingratos!\"
|
||||
|
|
|
@ -182,7 +182,6 @@
|
|||
<string name="send_qr_hint">Escanear</string>
|
||||
<string name="send_prepare_hint">Preparar</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_qr_invalid">No es un Código QR de monero</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_id">ID 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_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_transfers">Transferencias</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_key">Restaurar cartera con claves privadas</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>
|
||||
|
|
|
@ -2,14 +2,15 @@
|
|||
<resources>
|
||||
<string name="about_title">About</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">
|
||||
\"Donate you ungrateful bastards!\"
|
||||
</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[
|
||||
<b>Credits</b>
|
||||
|
@ -64,7 +65,7 @@
|
|||
</p>
|
||||
]]></string>
|
||||
|
||||
<string name="about_licenses"><![CDATA[
|
||||
<string name="about_licenses" translatable="false"><![CDATA[
|
||||
<h1>Open Source Licenses</h1>
|
||||
<h2>Licensed under the Apache License, Version 2.0</h2>
|
||||
<h3>monerujo (https://github.com/m2049r/xmrwallet)</h3>
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<color name="gradientOrange">#FFFF6105</color>
|
||||
<color name="gradientPink">#FFF0006B</color>
|
||||
|
||||
<color name="xmrtoYellow">#FFFFD700</color>
|
||||
|
||||
<color name="trafficGray">#9B9B9B</color>
|
||||
|
||||
<color name="take">#FF417505</color>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<resources>
|
||||
<string name="app_name">monerujo</string>
|
||||
<string name="login_activity_name">monerujo</string>
|
||||
<string name="app_name" translatable="false">monerujo</string>
|
||||
<string name="login_activity_name" translatable="false">monerujo</string>
|
||||
<string name="wallet_activity_name">Wallet</string>
|
||||
|
||||
<string name="menu_testnet">Testnet</string>
|
||||
|
@ -21,16 +21,75 @@
|
|||
<string name="label_cancel">Cancel</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_receive_info_gen_qr_code">Touch for QR Code</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_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_address">Destination Address</string>
|
||||
|
@ -74,6 +133,8 @@
|
|||
<string name="status_transaction_failed">Transaction failed: %1$s</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="prompt_rename">Rename %1$s</string>
|
||||
|
@ -96,8 +157,7 @@
|
|||
<string name="title_amount">Amount</string>
|
||||
<string name="title_date">Date</string>
|
||||
<string name="xmr_unconfirmed_amount">+ %1$s XMR unconfirmed</string>
|
||||
<!--string name="xmr_balance">%1$s XMR</string-->
|
||||
<string name="xmr">XMR</string>
|
||||
<string name="xmr" translatable="false">XMR</string>
|
||||
<string name="label_transactions">Transactions</string>
|
||||
<string name="text_daemonConnected">Daemon connected!</string>
|
||||
|
||||
|
@ -119,8 +179,11 @@
|
|||
|
||||
<string name="label_copy_viewkey">View Key</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_xmrtokey">XMR.TO Key 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_key">Selecting spend key 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_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_address">Enter valid Address</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_paymentid_hint">Payment ID (optional)</string>
|
||||
|
@ -188,13 +251,15 @@
|
|||
<string name="send_qr_hint">Scan</string>
|
||||
<string name="send_prepare_hint">Prepare</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_qr_invalid">Not a monero QR Code</string>
|
||||
<string name="send_qr_address_invalid">Invalid Monero address</string>
|
||||
<string name="send_qr_invalid">Not a QR Code</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_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_amount_title">Amount</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_label">Amount</string>
|
||||
<string name="send_fee_btc_label">Fee (XMR)</string>
|
||||
<string name="send_fee_label">Fee</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_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="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_positive">+ %1$s</string>
|
||||
|
||||
<string name="tx_status_btc">Status</string>
|
||||
<string name="tx_address">Address</string>
|
||||
<string name="tx_timestamp">Timestamp</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_destination">Destination</string>
|
||||
<string name="tx_destination_btc">Destination\n(BTC)</string>
|
||||
<string name="tx_paymentId">Payment ID</string>
|
||||
<string name="tx_blockheight">Block</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_transfers">Transfers</string>
|
||||
<string name="tx_notes">Notes</string>
|
||||
|
@ -248,6 +322,7 @@
|
|||
<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_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_empty">Enter value</string>
|
||||
|
@ -266,9 +341,9 @@
|
|||
<string name="archive_alert_yes">Yes, do that!</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 8</item>
|
||||
<item>Ringsize 13</item>
|
||||
|
@ -282,7 +357,7 @@
|
|||
<item>Priority High</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="currency">
|
||||
<string-array name="currency" translatable="false">
|
||||
<item>XMR</item>
|
||||
<item>EUR</item>
|
||||
<item>USD</item>
|
||||
|
|
|
@ -82,9 +82,7 @@
|
|||
</style>
|
||||
|
||||
<style name="MoneroText.Balance.Orange">
|
||||
<item name="android:textSize">32sp</item>
|
||||
<item name="android:textColor">@color/gradientOrange</item>
|
||||
<item name="android:textStyle">bold</item>
|
||||
</style>
|
||||
|
||||
<style name="MoneroText.Unconfirmed">
|
||||
|
@ -119,7 +117,7 @@
|
|||
|
||||
<!-- textSize is in dp here to match the layout of the numpad-->
|
||||
<style name="MoneroLabel.NumPad">
|
||||
<item name="android:textSize">36dp</item>
|
||||
<item name="android:textSize">36sp</item>
|
||||
<item name="android:textColor">@color/moneroBlack</item>
|
||||
</style>
|
||||
|
||||
|
@ -175,15 +173,15 @@
|
|||
</style>
|
||||
|
||||
<style name="MoneroText.Label">
|
||||
<item name="android:textSize">18dp</item>
|
||||
<item name="android:textSize">18sp</item>
|
||||
</style>
|
||||
|
||||
<style name="MoneroText.Confirm">
|
||||
<item name="android:textSize">16dp</item>
|
||||
<item name="android:textSize">16sp</item>
|
||||
</style>
|
||||
|
||||
<style name="MoneroText.Confirm.Label">
|
||||
<item name="android:textSize">16dp</item>
|
||||
<item name="android:textSize">16sp</item>
|
||||
<item name="android:textStyle">bold</item>
|
||||
</style>
|
||||
|
||||
|
@ -193,15 +191,15 @@
|
|||
</style>
|
||||
|
||||
<style name="MoneroText.Label.Medium">
|
||||
<item name="android:textSize">14dp</item>
|
||||
<item name="android:textSize">14sp</item>
|
||||
</style>
|
||||
|
||||
<style name="MoneroText.Small">
|
||||
<item name="android:textSize">10dp</item>
|
||||
<item name="android:textSize">10sp</item>
|
||||
</style>
|
||||
|
||||
<style name="MoneroText.Medium">
|
||||
<item name="android:textSize">12dp</item>
|
||||
<item name="android:textSize">12sp</item>
|
||||
</style>
|
||||
|
||||
<style name="MoneroText.Medium.Bold">
|
||||
|
@ -209,13 +207,19 @@
|
|||
</style>
|
||||
|
||||
<style name="MoneroText.Large">
|
||||
<item name="android:textSize">24dp</item>
|
||||
<item name="android:textSize">24sp</item>
|
||||
</style>
|
||||
|
||||
|
||||
<style name="MoneroText.Sucess">
|
||||
<item name="android:textSize">40dp</item>
|
||||
<item name="android:textColor">@color/gradientOrange</item>
|
||||
<style name="MoneroText.Success">
|
||||
<item name="android:textSize">18sp</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 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