Merge pull request #52 from m2049r/feature_kraken

Add support for USD/EUR on receive
This commit is contained in:
m2049r 2017-09-09 22:16:02 +02:00 committed by GitHub
commit c7e745cbc3
10 changed files with 426 additions and 62 deletions

View File

@ -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;

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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"
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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"

View File

@ -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>

View File

@ -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>

View File

@ -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>