Merge pull request #52 from m2049r/feature_kraken
Add support for USD/EUR on receive
This commit is contained in:
commit
c7e745cbc3
|
@ -45,6 +45,7 @@ import android.widget.Toast;
|
|||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.model.WalletManager;
|
||||
import com.m2049r.xmrwallet.service.WalletService;
|
||||
import com.m2049r.xmrwallet.util.AsyncExchangeRate;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -54,7 +55,8 @@ import java.io.IOException;
|
|||
import java.nio.channels.FileChannel;
|
||||
|
||||
public class LoginActivity extends AppCompatActivity
|
||||
implements LoginFragment.Listener, GenerateFragment.Listener, GenerateReviewFragment.Listener {
|
||||
implements LoginFragment.Listener, GenerateFragment.Listener,
|
||||
GenerateReviewFragment.Listener, ReceiveFragment.Listener {
|
||||
static final String TAG = "LoginActivity";
|
||||
private static final String GENERATE_STACK = "gen";
|
||||
|
||||
|
@ -194,7 +196,7 @@ public class LoginActivity extends AppCompatActivity
|
|||
|
||||
// copy + delete seems safer than rename because we call rollback easily
|
||||
boolean renameWallet(File walletFile, String newName) {
|
||||
if (copyWallet(walletFile, new File(walletFile.getParentFile(), newName), false)) {
|
||||
if (copyWallet(walletFile, new File(walletFile.getParentFile(), newName), false, true)) {
|
||||
deleteWallet(walletFile);
|
||||
return true;
|
||||
} else {
|
||||
|
@ -298,7 +300,7 @@ public class LoginActivity extends AppCompatActivity
|
|||
// TODO probably better to copy to a new file and then rename
|
||||
// then if something fails we have the old backup at least
|
||||
// or just create a new backup every time and keep n old backups
|
||||
return copyWallet(walletFile, backupFile, true);
|
||||
return copyWallet(walletFile, backupFile, true, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -700,6 +702,7 @@ public class LoginActivity extends AppCompatActivity
|
|||
|
||||
interface WalletCreator {
|
||||
boolean createWallet(File aFile, String password);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -764,7 +767,7 @@ public class LoginActivity extends AppCompatActivity
|
|||
final File newWalletFile = new File(new File(getStorageRoot(), ".new"), name);
|
||||
final File walletFolder = getStorageRoot();
|
||||
final File walletFile = new File(walletFolder, name);
|
||||
final boolean rc = copyWallet(newWalletFile, walletFile, false)
|
||||
final boolean rc = copyWallet(newWalletFile, walletFile, false, false)
|
||||
&&
|
||||
(testWallet(walletFile.getAbsolutePath(), password) == Wallet.Status.Status_Ok);
|
||||
if (rc) {
|
||||
|
@ -778,6 +781,12 @@ public class LoginActivity extends AppCompatActivity
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExchange(AsyncExchangeRate.Listener listener, String currencyA, String currencyB) {
|
||||
new AsyncExchangeRate(listener).execute(currencyA, currencyB);
|
||||
}
|
||||
|
||||
|
||||
Wallet.Status testWallet(String path, String password) {
|
||||
Log.d(TAG, "testing wallet " + path);
|
||||
Wallet aWallet = WalletManager.getInstance().openWallet(path, password);
|
||||
|
@ -802,7 +811,7 @@ public class LoginActivity extends AppCompatActivity
|
|||
}
|
||||
}
|
||||
|
||||
boolean copyWallet(File srcWallet, File dstWallet, boolean overwrite) {
|
||||
boolean copyWallet(File srcWallet, File dstWallet, boolean overwrite, boolean full) {
|
||||
//Log.d(TAG, "src=" + srcWallet.exists() + " dst=" + dstWallet.exists());
|
||||
if (walletExists(dstWallet, true) && !overwrite) return false;
|
||||
if (!walletExists(srcWallet, false)) return false;
|
||||
|
@ -813,7 +822,13 @@ public class LoginActivity extends AppCompatActivity
|
|||
File dstDir = dstWallet.getParentFile();
|
||||
String dstName = dstWallet.getName();
|
||||
try {
|
||||
copyFile(new File(srcDir, srcName), new File(dstDir, dstName));
|
||||
if (full) {
|
||||
// the cache is corrupt if we recover (!!) from seed
|
||||
// the cache is ok if we immediately do a full refresh()
|
||||
// recoveryheight is ignored but not on watchonly wallet ?! - find out why
|
||||
// so we just ignore the cache file and rebuild it on first sync
|
||||
copyFile(new File(srcDir, srcName), new File(dstDir, dstName));
|
||||
}
|
||||
copyFile(new File(srcDir, srcName + ".keys"), new File(dstDir, dstName + ".keys"));
|
||||
copyFile(new File(srcDir, srcName + ".address.txt"), new File(dstDir, dstName + ".address.txt"));
|
||||
success = true;
|
||||
|
|
|
@ -16,10 +16,13 @@
|
|||
|
||||
package com.m2049r.xmrwallet;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.text.Editable;
|
||||
import android.text.InputType;
|
||||
|
@ -30,10 +33,12 @@ import android.view.LayoutInflater;
|
|||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
|
@ -45,24 +50,72 @@ import com.google.zxing.qrcode.QRCodeWriter;
|
|||
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.model.WalletManager;
|
||||
import com.m2049r.xmrwallet.util.AsyncExchangeRate;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
public class ReceiveFragment extends Fragment {
|
||||
public class ReceiveFragment extends Fragment implements AsyncExchangeRate.Listener {
|
||||
static final String TAG = "ReceiveFragment";
|
||||
|
||||
ProgressBar pbProgress;
|
||||
TextView tvAddress;
|
||||
EditText etPaymentId;
|
||||
EditText etAmount;
|
||||
TextView tvAmountB;
|
||||
Button bPaymentId;
|
||||
Button bGenerate;
|
||||
ImageView qrCode;
|
||||
EditText etDummy;
|
||||
|
||||
Spinner sCurrencyA;
|
||||
Spinner sCurrencyB;
|
||||
|
||||
public interface Listener {
|
||||
void onExchange(AsyncExchangeRate.Listener listener, String currencyA, String currencyB);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exchange(String currencyA, String currencyB, double rate) {
|
||||
// first, make sure this is what we want
|
||||
String enteredCurrencyA = (String) sCurrencyA.getSelectedItem();
|
||||
String enteredCurrencyB = (String) sCurrencyB.getSelectedItem();
|
||||
if (!currencyA.equals(enteredCurrencyA) || !currencyB.equals(enteredCurrencyB)) {
|
||||
// something's wrong
|
||||
Log.e(TAG, "Currencies don't match!");
|
||||
tvAmountB.setText("");
|
||||
return;
|
||||
}
|
||||
String enteredAmount = etAmount.getText().toString();
|
||||
String xmrAmount = "";
|
||||
if (!enteredAmount.isEmpty()) {
|
||||
// losing precision using double here doesn't matter
|
||||
double amountA = Double.parseDouble(enteredAmount);
|
||||
double amountB = amountA * rate;
|
||||
if (enteredCurrencyA.equals("XMR")) {
|
||||
String validatedAmountA = Helper.getDisplayAmount(Wallet.getAmountFromString(enteredAmount));
|
||||
xmrAmount = validatedAmountA; // take what was entered in XMR
|
||||
etAmount.setText(xmrAmount); // display what we stick into the QR code
|
||||
String displayB = String.format(Locale.US, "%.2f", amountB);
|
||||
tvAmountB.setText(displayB);
|
||||
} else if (enteredCurrencyB.equals("XMR")) {
|
||||
xmrAmount = Wallet.getDisplayAmount(Wallet.getAmountFromDouble(amountB));
|
||||
// cut off at 5 decimals
|
||||
xmrAmount = xmrAmount.substring(0, xmrAmount.length() - (12 - 5));
|
||||
tvAmountB.setText(xmrAmount);
|
||||
} else { // no XMR currency
|
||||
tvAmountB.setText("");
|
||||
return; // and no qr code
|
||||
}
|
||||
} else {
|
||||
tvAmountB.setText("");
|
||||
}
|
||||
generateQr(xmrAmount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
@ -72,15 +125,21 @@ public class ReceiveFragment extends Fragment {
|
|||
pbProgress = (ProgressBar) view.findViewById(R.id.pbProgress);
|
||||
tvAddress = (TextView) view.findViewById(R.id.tvAddress);
|
||||
etPaymentId = (EditText) view.findViewById(R.id.etPaymentId);
|
||||
etAmount = (EditText) view.findViewById(R.id.etAmount);
|
||||
etAmount = (EditText) view.findViewById(R.id.etAmountA);
|
||||
tvAmountB = (TextView) view.findViewById(R.id.tvAmountB);
|
||||
bPaymentId = (Button) view.findViewById(R.id.bPaymentId);
|
||||
qrCode = (ImageView) view.findViewById(R.id.qrCode);
|
||||
bGenerate = (Button) view.findViewById(R.id.bGenerate);
|
||||
etDummy = (EditText) view.findViewById(R.id.etDummy);
|
||||
|
||||
sCurrencyA = (Spinner) view.findViewById(R.id.sCurrencyA);
|
||||
sCurrencyB = (Spinner) view.findViewById(R.id.sCurrencyB);
|
||||
|
||||
etPaymentId.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||
etDummy.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||
|
||||
loadPrefs();
|
||||
|
||||
etPaymentId.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_NEXT)) {
|
||||
|
@ -117,7 +176,7 @@ public class ReceiveFragment extends Fragment {
|
|||
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_DONE)) {
|
||||
if (paymentIdOk() && amountOk()) {
|
||||
Helper.hideKeyboard(getActivity());
|
||||
generateQr();
|
||||
startExchange();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -127,6 +186,7 @@ public class ReceiveFragment extends Fragment {
|
|||
etAmount.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void afterTextChanged(Editable editable) {
|
||||
tvAmountB.setText("");
|
||||
qrCode.setImageBitmap(getMoneroLogo());
|
||||
if (paymentIdOk() && amountOk()) {
|
||||
bGenerate.setEnabled(true);
|
||||
|
@ -150,7 +210,7 @@ public class ReceiveFragment extends Fragment {
|
|||
etPaymentId.setText((Wallet.generatePaymentId()));
|
||||
etPaymentId.setSelection(etPaymentId.getText().length());
|
||||
if (paymentIdOk() && amountOk()) {
|
||||
generateQr();
|
||||
startExchange();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -160,11 +220,42 @@ public class ReceiveFragment extends Fragment {
|
|||
public void onClick(View v) {
|
||||
if (paymentIdOk() && amountOk()) {
|
||||
Helper.hideKeyboard(getActivity());
|
||||
generateQr();
|
||||
startExchange();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
sCurrencyA.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
|
||||
if (position != 0) {
|
||||
sCurrencyB.setSelection(0, true);
|
||||
}
|
||||
startExchange();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parentView) {
|
||||
// nothing (yet?)
|
||||
}
|
||||
});
|
||||
|
||||
sCurrencyB.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
|
||||
if (position != 0) {
|
||||
sCurrencyA.setSelection(0, true);
|
||||
}
|
||||
tvAmountB.setText("");
|
||||
startExchange();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parentView) {
|
||||
// nothing (yet?)
|
||||
}
|
||||
});
|
||||
|
||||
showProgress();
|
||||
qrCode.setImageBitmap(getMoneroLogo());
|
||||
|
||||
|
@ -180,12 +271,26 @@ public class ReceiveFragment extends Fragment {
|
|||
return view;
|
||||
}
|
||||
|
||||
void startExchange() {
|
||||
if (paymentIdOk() && amountOk() && tvAddress.getText().length() > 0) {
|
||||
String enteredCurrencyA = (String) sCurrencyA.getSelectedItem();
|
||||
String enteredCurrencyB = (String) sCurrencyB.getSelectedItem();
|
||||
String enteredAmount = etAmount.getText().toString();
|
||||
tvAmountB.setText("");
|
||||
if (!enteredAmount.isEmpty()) { // start conversion
|
||||
listenerCallback.onExchange(ReceiveFragment.this, enteredCurrencyA, enteredCurrencyB);
|
||||
} else {
|
||||
generateQr("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
Log.d(TAG, "onResume()");
|
||||
if (paymentIdOk() && amountOk() && tvAddress.getText().length() > 0) {
|
||||
generateQr();
|
||||
startExchange();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,7 +301,7 @@ public class ReceiveFragment extends Fragment {
|
|||
bPaymentId.setEnabled(true);
|
||||
bGenerate.setEnabled(true);
|
||||
hideProgress();
|
||||
generateQr();
|
||||
startExchange();
|
||||
}
|
||||
|
||||
private void show(String walletPath, String password) {
|
||||
|
@ -245,12 +350,9 @@ public class ReceiveFragment extends Fragment {
|
|||
return paymentId.isEmpty() || Wallet.isPaymentIdValid(paymentId);
|
||||
}
|
||||
|
||||
private void generateQr() {
|
||||
private void generateQr(String xmrAmount) {
|
||||
String address = tvAddress.getText().toString();
|
||||
String paymentId = etPaymentId.getText().toString();
|
||||
String enteredAmount = etAmount.getText().toString();
|
||||
// that's a lot of converting ...
|
||||
String amount = (enteredAmount.isEmpty() ? enteredAmount : Helper.getDisplayAmount(Wallet.getAmountFromString(enteredAmount)));
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(ScannerFragment.QR_SCHEME).append(address);
|
||||
boolean first = true;
|
||||
|
@ -261,18 +363,17 @@ public class ReceiveFragment extends Fragment {
|
|||
}
|
||||
sb.append(ScannerFragment.QR_PAYMENTID).append('=').append(paymentId);
|
||||
}
|
||||
if (!amount.isEmpty()) {
|
||||
if (!xmrAmount.isEmpty()) {
|
||||
if (first) {
|
||||
sb.append("?");
|
||||
} else {
|
||||
sb.append("&");
|
||||
}
|
||||
sb.append(ScannerFragment.QR_AMOUNT).append('=').append(amount);
|
||||
sb.append(ScannerFragment.QR_AMOUNT).append('=').append(xmrAmount);
|
||||
}
|
||||
String text = sb.toString();
|
||||
Bitmap qr = generate(text, 500, 500);
|
||||
if (qr != null) {
|
||||
etAmount.setText(amount);
|
||||
qrCode.setImageBitmap(qr);
|
||||
etDummy.requestFocus();
|
||||
bGenerate.setEnabled(false);
|
||||
|
@ -346,4 +447,52 @@ public class ReceiveFragment extends Fragment {
|
|||
pbProgress.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
Listener listenerCallback = null;
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
if (context instanceof Listener) {
|
||||
this.listenerCallback = (Listener) context;
|
||||
} else {
|
||||
throw new ClassCastException(context.toString()
|
||||
+ " must implement Listener");
|
||||
}
|
||||
}
|
||||
|
||||
static final String PREF_CURRENCY_A = "PREF_CURRENCY_A";
|
||||
static final String PREF_CURRENCY_B = "PREF_CURRENCY_B";
|
||||
|
||||
void loadPrefs() {
|
||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
|
||||
int currencyA = sharedPreferences.getInt(PREF_CURRENCY_A, 0);
|
||||
int currencyB = sharedPreferences.getInt(PREF_CURRENCY_B, 0);
|
||||
|
||||
if (currencyA * currencyB != 0) { // make sure one of them is 0 (=XMR)
|
||||
currencyA = 0;
|
||||
}
|
||||
// in case we change the currency lists in the future
|
||||
if (currencyA >= sCurrencyA.getCount()) currencyA = 0;
|
||||
if (currencyB >= sCurrencyB.getCount()) currencyB = 0;
|
||||
sCurrencyA.setSelection(currencyA);
|
||||
sCurrencyB.setSelection(currencyB);
|
||||
}
|
||||
|
||||
void savePrefs() {
|
||||
int currencyA = sCurrencyA.getSelectedItemPosition();
|
||||
int currencyB = sCurrencyB.getSelectedItemPosition();
|
||||
|
||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.putInt(PREF_CURRENCY_A, currencyA);
|
||||
editor.putInt(PREF_CURRENCY_B, currencyB);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
Log.d(TAG, "onPause()");
|
||||
savePrefs();
|
||||
super.onPause();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package com.m2049r.xmrwallet;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
|
@ -24,6 +25,7 @@ import android.content.Intent;
|
|||
import android.content.ServiceConnection;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.PowerManager;
|
||||
|
@ -42,17 +44,22 @@ 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.AsyncExchangeRate;
|
||||
import com.m2049r.xmrwallet.util.BarcodeData;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.util.TxData;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class WalletActivity extends AppCompatActivity implements WalletFragment.Listener,
|
||||
WalletService.Observer, SendFragment.Listener, TxFragment.Listener,
|
||||
GenerateReviewFragment.ListenerWithWallet,
|
||||
ScannerFragment.Listener {
|
||||
ScannerFragment.Listener, ReceiveFragment.Listener {
|
||||
private static final String TAG = "WalletActivity";
|
||||
|
||||
public static final String REQUEST_ID = "id";
|
||||
|
@ -741,4 +748,8 @@ public class WalletActivity extends AppCompatActivity implements WalletFragment.
|
|||
Log.d(TAG, "ReceiveFragment placed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExchange(AsyncExchangeRate.Listener listener, String currencyA, String currencyB) {
|
||||
new AsyncExchangeRate(listener).execute(currencyA, currencyB);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* 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 android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class AsyncExchangeRate extends AsyncTask<String, Void, Boolean> {
|
||||
static final String TAG = "AsyncGetExchangeRate";
|
||||
|
||||
static final long TIME_REFRESH_INTERVAL = 60000; // refresh exchange rate max every minute
|
||||
|
||||
static protected long RateTime = 0;
|
||||
static protected double Rate = 0;
|
||||
static protected String Fiat = null;
|
||||
|
||||
public interface Listener {
|
||||
void exchange(String currencyA, String currencyB, double rate);
|
||||
}
|
||||
|
||||
Listener listener;
|
||||
|
||||
public AsyncExchangeRate(Listener listener) {
|
||||
super();
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
super.onPreExecute();
|
||||
}
|
||||
|
||||
boolean inverse = false;
|
||||
String currencyA = null;
|
||||
String currencyB = null;
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(String... params) {
|
||||
if (params.length != 2) return false;
|
||||
Log.d(TAG, "Getting " + params[0]);
|
||||
currencyA = params[0];
|
||||
currencyB = params[1];
|
||||
|
||||
String fiat = null;
|
||||
if (currencyA.equals("XMR")) {
|
||||
fiat = currencyB;
|
||||
inverse = false;
|
||||
}
|
||||
if (currencyB.equals("XMR")) {
|
||||
fiat = currencyA;
|
||||
inverse = true;
|
||||
}
|
||||
|
||||
if (currencyA.equals(currencyB)) {
|
||||
Fiat = null;
|
||||
Rate = 1;
|
||||
RateTime = System.currentTimeMillis();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fiat == null) {
|
||||
Fiat = null;
|
||||
Rate = 0;
|
||||
RateTime = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fiat.equals(Fiat)) { // new currency - reset all
|
||||
Fiat = fiat;
|
||||
Rate = 0;
|
||||
RateTime = 0;
|
||||
}
|
||||
|
||||
if (System.currentTimeMillis() > RateTime + TIME_REFRESH_INTERVAL) {
|
||||
Log.d(TAG, "Fetching " + Fiat);
|
||||
String closePrice = getExchangeRate(Fiat);
|
||||
if (closePrice != null) {
|
||||
try {
|
||||
Rate = Double.parseDouble(closePrice);
|
||||
RateTime = System.currentTimeMillis();
|
||||
return true;
|
||||
} catch (NumberFormatException ex) {
|
||||
Rate = 0;
|
||||
Log.e(TAG, ex.getLocalizedMessage());
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
Rate = 0;
|
||||
Log.e(TAG, "exchange url failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true; // no change but still valid
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean result) {
|
||||
super.onPostExecute(result);
|
||||
if (result) {
|
||||
Log.d(TAG, "yay! = " + Rate);
|
||||
if (listener != null) {
|
||||
listener.exchange(currencyA, currencyB, inverse ? (1 / Rate) : Rate);
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "nay!");
|
||||
}
|
||||
}
|
||||
|
||||
String getExchangeRate(String fiat) {
|
||||
String jsonResponse =
|
||||
Helper.getUrl("https://api.kraken.com/0/public/Ticker?pair=XMR" + fiat);
|
||||
if (jsonResponse == null) return null;
|
||||
try {
|
||||
JSONObject response = new JSONObject(jsonResponse);
|
||||
JSONArray errors = response.getJSONArray("error");
|
||||
Log.e(TAG, "errors=" + errors.toString());
|
||||
if (errors.length() == 0) {
|
||||
JSONObject result = response.getJSONObject("result");
|
||||
JSONObject pair = result.getJSONObject("XXMRZ" + fiat);
|
||||
JSONArray close = pair.getJSONArray("c");
|
||||
String closePrice = close.getString(0);
|
||||
Log.d(TAG, "closePrice=" + closePrice);
|
||||
return closePrice;
|
||||
}
|
||||
} catch (JSONException ex) {
|
||||
Log.e(TAG, ex.getLocalizedMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// "https://api.kraken.com/0/public/Ticker?pair=XMREUR"
|
||||
}
|
|
@ -38,9 +38,7 @@ import com.m2049r.xmrwallet.model.Wallet;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
|
@ -192,4 +190,30 @@ public class Helper {
|
|||
return bitmap;
|
||||
}
|
||||
|
||||
static public String getUrl(String httpsUrl) {
|
||||
HttpsURLConnection urlConnection = null;
|
||||
try {
|
||||
URL url = new URL(httpsUrl);
|
||||
urlConnection = (HttpsURLConnection) url.openConnection();
|
||||
InputStreamReader in = new InputStreamReader(urlConnection.getInputStream());
|
||||
StringBuffer sb = new StringBuffer();
|
||||
final int BUFFER_SIZE = 512;
|
||||
char[] buffer = new char[BUFFER_SIZE];
|
||||
int length = in.read(buffer, 0, BUFFER_SIZE);
|
||||
while (length >= 0) {
|
||||
sb.append(buffer, 0, length);
|
||||
length = in.read(buffer, 0, BUFFER_SIZE);
|
||||
}
|
||||
return sb.toString();
|
||||
} catch (MalformedURLException ex) {
|
||||
Log.e(TAG, "A " + ex.getLocalizedMessage());
|
||||
} catch (IOException ex) {
|
||||
Log.e(TAG, "B " + ex.getLocalizedMessage());
|
||||
} finally {
|
||||
if (urlConnection != null) {
|
||||
urlConnection.disconnect();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,26 +35,17 @@
|
|||
android:orientation="horizontal"
|
||||
android:weightSum="10">
|
||||
|
||||
<TextView
|
||||
style="@style/MoneroText"
|
||||
android:layout_width="0sp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="8sp"
|
||||
android:layout_weight="3"
|
||||
android:text="@string/receive_paymentid_label"
|
||||
android:textAlignment="textEnd" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etPaymentId"
|
||||
style="@style/MoneroEdit"
|
||||
android:layout_width="0sp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="5"
|
||||
android:layout_weight="8"
|
||||
android:enabled="false"
|
||||
android:hint="@string/receive_paymentid_hint"
|
||||
android:imeOptions="actionNext"
|
||||
android:inputType="textMultiLine"
|
||||
android:textAlignment="textStart" />
|
||||
android:textAlignment="center" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/bPaymentId"
|
||||
|
@ -73,29 +64,43 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4sp"
|
||||
android:layout_marginTop="4sp"
|
||||
android:orientation="horizontal"
|
||||
android:weightSum="10">
|
||||
|
||||
<TextView
|
||||
style="@style/MoneroText"
|
||||
android:layout_width="0sp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="8sp"
|
||||
android:layout_weight="3"
|
||||
android:text="@string/send_amount_label"
|
||||
android:textAlignment="textEnd" />
|
||||
android:orientation="horizontal">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etAmount"
|
||||
android:id="@+id/etAmountA"
|
||||
style="@style/MoneroEdit"
|
||||
android:layout_width="0sp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="7"
|
||||
android:enabled="false"
|
||||
android:layout_weight="1"
|
||||
android:hint="@string/receive_amount_hint"
|
||||
android:imeOptions="actionDone"
|
||||
android:inputType="numberDecimal"
|
||||
android:textAlignment="textStart" />
|
||||
android:textAlignment="textEnd" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/sCurrencyA"
|
||||
style="@style/MoneroSpinner"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:entries="@array/currency"
|
||||
android:textAlignment="center" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvAmountB"
|
||||
style="@style/MoneroText"
|
||||
android:layout_width="0sp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:textAlignment="textEnd" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/sCurrencyB"
|
||||
style="@style/MoneroSpinner"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:entries="@array/currency"
|
||||
android:textAlignment="center" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
|
|
|
@ -51,10 +51,11 @@
|
|||
android:id="@+id/tvBlockHeightProgress"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="8sp"
|
||||
android:gravity="right"
|
||||
android:text="Loading..."
|
||||
android:textSize="12sp"
|
||||
android:visibility="gone" />
|
||||
android:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvBalance"
|
||||
|
|
|
@ -2,15 +2,15 @@
|
|||
<resources>
|
||||
<color name="tx_green">#5C8447</color>
|
||||
<color name="tx_red">#AC2527</color>
|
||||
<color name="tx_pending">#4c4c4c</color>
|
||||
<color name="tx_pending">#e2e2e2</color>
|
||||
<color name="tx_failed">#FF80AB</color>
|
||||
|
||||
<color name="moneroOrange">#ff6600</color>
|
||||
<color name="moneroWhite">#ffffff</color>
|
||||
<color name="moneroOrange">#cc5100</color>
|
||||
<color name="moneroWhite">#e2e2e2</color>
|
||||
<color name="moneroBlack">#000000</color>
|
||||
<color name="moneroGray">#4c4c4c</color>
|
||||
|
||||
<color name="colorPrimary">#ff6600</color>
|
||||
<color name="colorPrimary">#cc5100</color>
|
||||
<color name="colorPrimaryDark">#61221A</color>
|
||||
<color name="textColorPrimary">#dcdcdc</color>
|
||||
<color name="windowBackground">#ffffff</color>
|
||||
|
|
|
@ -177,9 +177,9 @@
|
|||
<string name="receive_generate_hint">Show me the QR Code</string>
|
||||
<string name="receive_paymentid_button">Generate</string>
|
||||
<string name="receive_paymentid_label">PaymentID</string>
|
||||
<string name="receive_paymentid_hint">(optional)</string>
|
||||
<string name="receive_amount_label">Amount</string>
|
||||
<string name="receive_amount_hint">XMR (optional)</string>
|
||||
<string name="receive_paymentid_hint">Payment ID (optional)</string>
|
||||
<string name="receive_amount_hint">Amount</string>
|
||||
<string name="receive_amount_xmr_hint">XMR</string>
|
||||
<string name="receive_cannot_open">Could not open wallet!</string>
|
||||
|
||||
<string name="details_alert_message">Sensitive data will now be shown.\nLook over your shoulder!</string>
|
||||
|
@ -205,4 +205,10 @@
|
|||
<item>Medium Priority</item>
|
||||
<item>High Priority</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="currency">
|
||||
<item>XMR</item>
|
||||
<item>EUR</item>
|
||||
<item>USD</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
<style name="MoneroText" parent="@android:style/TextAppearance.DeviceDefault.Medium">
|
||||
<item name="android:textColor">?colorPrimary</item>
|
||||
<item name="android:textColorHint">?colorPrimaryDark</item>
|
||||
<item name="android:textColorHint">@color/moneroGray</item>
|
||||
</style>
|
||||
|
||||
<style name="MoneroButton" parent="@style/Widget.AppCompat.Button">
|
||||
|
@ -38,7 +38,6 @@
|
|||
|
||||
<style name="MoneroEdit" parent="MoneroText">
|
||||
<item name="android:textColor">?colorPrimary</item>
|
||||
<item name="android:textColorHint">?colorPrimaryDark</item>
|
||||
<item name="android:backgroundTint">?colorPrimary</item>
|
||||
<item name="android:foregroundTint">@color/moneroWhite</item>
|
||||
</style>
|
||||
|
@ -48,13 +47,16 @@
|
|||
<item name="android:progressBackgroundTint">?colorPrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="MoneroSpinner" parent="@style/Widget.AppCompat.Spinner">
|
||||
<!--item name="android:backgroundTint">@color/moneroWhite</item-->
|
||||
</style>
|
||||
<!--style name="MoneroSpinner" parent="@style/Widget.AppCompat.Spinner">
|
||||
</style-->
|
||||
|
||||
<style name="MoneroListView" parent="@android:style/Widget.ListView">
|
||||
<item name="android:divider">@null</item>
|
||||
<item name="android:dividerHeight">0dp</item>
|
||||
</style>
|
||||
|
||||
<style name="MoneroSpinner" parent="@style/Widget.AppCompat.Spinner">
|
||||
<item name="android:background">@android:drawable/screen_background_dark_transparent</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue