|
@ -8,8 +8,8 @@ android {
|
|||
applicationId "com.m2049r.xmrwallet"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 25
|
||||
versionCode 26
|
||||
versionName "1.0.3"
|
||||
versionCode 29
|
||||
versionName "1.1.2-alpha"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
|
|
|
@ -19,10 +19,9 @@ package com.m2049r.xmrwallet;
|
|||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.TextInputLayout;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.text.Editable;
|
||||
import android.text.InputType;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -32,10 +31,7 @@ import android.view.View;
|
|||
import android.view.ViewGroup;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.model.WalletManager;
|
||||
|
@ -46,60 +42,93 @@ import java.io.File;
|
|||
public class GenerateFragment extends Fragment {
|
||||
static final String TAG = "GenerateFragment";
|
||||
|
||||
EditText etWalletName;
|
||||
EditText etWalletPassword;
|
||||
EditText etWalletAddress;
|
||||
EditText etWalletMnemonic;
|
||||
LinearLayout llRestoreKeys;
|
||||
EditText etWalletViewKey;
|
||||
EditText etWalletSpendKey;
|
||||
EditText etWalletRestoreHeight;
|
||||
static final String TYPE = "type";
|
||||
static final String TYPE_NEW = "new";
|
||||
static final String TYPE_KEY = "key";
|
||||
static final String TYPE_SEED = "seed";
|
||||
static final String TYPE_VIEWONLY = "view";
|
||||
|
||||
TextInputLayout etWalletName;
|
||||
TextInputLayout etWalletPassword;
|
||||
TextInputLayout etWalletAddress;
|
||||
TextInputLayout etWalletMnemonic;
|
||||
TextInputLayout etWalletViewKey;
|
||||
TextInputLayout etWalletSpendKey;
|
||||
TextInputLayout etWalletRestoreHeight;
|
||||
Button bGenerate;
|
||||
|
||||
String type = null;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
View view = inflater.inflate(R.layout.gen_fragment, container, false);
|
||||
Bundle args = getArguments();
|
||||
this.type = args.getString(TYPE);
|
||||
|
||||
etWalletName = (EditText) view.findViewById(R.id.etWalletName);
|
||||
etWalletPassword = (EditText) view.findViewById(R.id.etWalletPassword);
|
||||
etWalletMnemonic = (EditText) view.findViewById(R.id.etWalletMnemonic);
|
||||
etWalletAddress = (EditText) view.findViewById(R.id.etWalletAddress);
|
||||
llRestoreKeys = (LinearLayout) view.findViewById(R.id.llRestoreKeys);
|
||||
etWalletViewKey = (EditText) view.findViewById(R.id.etWalletViewKey);
|
||||
etWalletSpendKey = (EditText) view.findViewById(R.id.etWalletSpendKey);
|
||||
etWalletRestoreHeight = (EditText) view.findViewById(R.id.etWalletRestoreHeight);
|
||||
View view = inflater.inflate(R.layout.fragment_generate, container, false);
|
||||
|
||||
etWalletName = (TextInputLayout) view.findViewById(R.id.etWalletName);
|
||||
etWalletPassword = (TextInputLayout) view.findViewById(R.id.etWalletPassword);
|
||||
etWalletMnemonic = (TextInputLayout) view.findViewById(R.id.etWalletMnemonic);
|
||||
etWalletAddress = (TextInputLayout) view.findViewById(R.id.etWalletAddress);
|
||||
etWalletViewKey = (TextInputLayout) view.findViewById(R.id.etWalletViewKey);
|
||||
etWalletSpendKey = (TextInputLayout) view.findViewById(R.id.etWalletSpendKey);
|
||||
etWalletRestoreHeight = (TextInputLayout) view.findViewById(R.id.etWalletRestoreHeight);
|
||||
bGenerate = (Button) view.findViewById(R.id.bGenerate);
|
||||
|
||||
etWalletMnemonic.setRawInputType(InputType.TYPE_CLASS_TEXT);
|
||||
etWalletAddress.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||
etWalletViewKey.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||
etWalletSpendKey.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||
etWalletMnemonic.getEditText().setRawInputType(InputType.TYPE_CLASS_TEXT);
|
||||
etWalletAddress.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||
etWalletViewKey.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||
etWalletSpendKey.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||
|
||||
Helper.showKeyboard(getActivity());
|
||||
etWalletName.addTextChangedListener(new TextWatcher() {
|
||||
etWalletName.getEditText().setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
||||
@Override
|
||||
public void afterTextChanged(Editable editable) {
|
||||
if (etWalletName.length() > 0) {
|
||||
bGenerate.setEnabled(true);
|
||||
} else {
|
||||
bGenerate.setEnabled(false);
|
||||
public void onFocusChange(View v, boolean hasFocus) {
|
||||
if (!hasFocus) {
|
||||
checkName();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
etWalletMnemonic.getEditText().setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
public void onFocusChange(View v, boolean hasFocus) {
|
||||
if (!hasFocus) {
|
||||
checkMnemonic();
|
||||
}
|
||||
}
|
||||
});
|
||||
etWalletName.setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||
etWalletAddress.getEditText().setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
||||
@Override
|
||||
public void onFocusChange(View v, boolean hasFocus) {
|
||||
if (!hasFocus) {
|
||||
checkAddress();
|
||||
}
|
||||
}
|
||||
});
|
||||
etWalletViewKey.getEditText().setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
||||
@Override
|
||||
public void onFocusChange(View v, boolean hasFocus) {
|
||||
if (!hasFocus) {
|
||||
checkViewKey();
|
||||
}
|
||||
}
|
||||
});
|
||||
etWalletSpendKey.getEditText().setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
||||
@Override
|
||||
public void onFocusChange(View v, boolean hasFocus) {
|
||||
if (!hasFocus) {
|
||||
checkSpendKey();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Helper.showKeyboard(getActivity());
|
||||
//##############
|
||||
etWalletName.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_NEXT)) {
|
||||
if (etWalletName.length() > 0) {
|
||||
if (checkName()) {
|
||||
etWalletPassword.requestFocus();
|
||||
} // otherwise ignore
|
||||
return true;
|
||||
|
@ -108,159 +137,112 @@ public class GenerateFragment extends Fragment {
|
|||
}
|
||||
});
|
||||
|
||||
etWalletPassword.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)) {
|
||||
if (etWalletAddress.length() > 0) {
|
||||
etWalletAddress.requestFocus();
|
||||
} else {
|
||||
etWalletMnemonic.requestFocus();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
etWalletMnemonic.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)) {
|
||||
if (etWalletMnemonic.length() == 0) {
|
||||
etWalletAddress.requestFocus();
|
||||
} else if (mnemonicOk()) {
|
||||
etWalletRestoreHeight.requestFocus();
|
||||
} else {
|
||||
Toast.makeText(getActivity(), getString(R.string.generate_check_mnemonic), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
etWalletMnemonic.addTextChangedListener(new
|
||||
|
||||
TextWatcher() {
|
||||
@Override
|
||||
public void afterTextChanged(Editable editable) {
|
||||
if (etWalletMnemonic.length() > 0) {
|
||||
etWalletRestoreHeight.setVisibility(View.VISIBLE);
|
||||
etWalletAddress.setVisibility(View.GONE);
|
||||
} else {
|
||||
etWalletAddress.setVisibility(View.VISIBLE);
|
||||
if (etWalletAddress.length() == 0) {
|
||||
etWalletRestoreHeight.setVisibility(View.GONE);
|
||||
} else {
|
||||
etWalletRestoreHeight.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
});
|
||||
|
||||
etWalletAddress.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)) {
|
||||
if (etWalletAddress.length() == 0) {
|
||||
if (bGenerate.getVisibility() == View.VISIBLE) {
|
||||
Helper.hideKeyboard(getActivity());
|
||||
generateWallet();
|
||||
}
|
||||
} else if (addressOk()) {
|
||||
etWalletViewKey.requestFocus();
|
||||
} else {
|
||||
Toast.makeText(getActivity(), getString(R.string.generate_check_address), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
etWalletAddress.addTextChangedListener(new
|
||||
|
||||
TextWatcher() {
|
||||
@Override
|
||||
public void afterTextChanged(Editable editable) {
|
||||
if (etWalletAddress.length() > 0) {
|
||||
llRestoreKeys.setVisibility(View.VISIBLE);
|
||||
etWalletMnemonic.setVisibility(View.INVISIBLE);
|
||||
etWalletRestoreHeight.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
llRestoreKeys.setVisibility(View.GONE);
|
||||
etWalletMnemonic.setVisibility(View.VISIBLE);
|
||||
if (etWalletMnemonic.length() == 0) {
|
||||
etWalletRestoreHeight.setVisibility(View.GONE);
|
||||
} else {
|
||||
etWalletRestoreHeight.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
});
|
||||
|
||||
etWalletViewKey.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)) {
|
||||
if (viewKeyOk()) {
|
||||
etWalletSpendKey.requestFocus();
|
||||
} else {
|
||||
Toast.makeText(getActivity(), getString(R.string.generate_check_key), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
etWalletSpendKey.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)) {
|
||||
if (spendKeyOk()) {
|
||||
etWalletRestoreHeight.requestFocus();
|
||||
} else {
|
||||
Toast.makeText(getActivity(), getString(R.string.generate_check_key), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
etWalletRestoreHeight.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)) {
|
||||
if (bGenerate.getVisibility() == View.VISIBLE) {
|
||||
if (type.equals(TYPE_NEW)) {
|
||||
etWalletPassword.getEditText().setImeOptions(EditorInfo.IME_ACTION_DONE);
|
||||
etWalletPassword.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)) {
|
||||
Helper.hideKeyboard(getActivity());
|
||||
generateWallet();
|
||||
} else {
|
||||
Toast.makeText(getActivity(), getString(R.string.generate_check_something), Toast.LENGTH_LONG).show();
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
} else if (type.equals(TYPE_SEED)) {
|
||||
etWalletPassword.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_NEXT)) {
|
||||
etWalletMnemonic.requestFocus();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
etWalletMnemonic.setVisibility(View.VISIBLE);
|
||||
etWalletMnemonic.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_NEXT)) {
|
||||
if (checkMnemonic()) {
|
||||
etWalletRestoreHeight.requestFocus();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
} else if (type.equals(TYPE_KEY) || type.equals(TYPE_VIEWONLY)) {
|
||||
etWalletPassword.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_NEXT)) {
|
||||
etWalletAddress.requestFocus();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
etWalletAddress.setVisibility(View.VISIBLE);
|
||||
etWalletAddress.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_NEXT)) {
|
||||
if (checkAddress()) {
|
||||
etWalletViewKey.requestFocus();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
etWalletViewKey.setVisibility(View.VISIBLE);
|
||||
etWalletViewKey.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_NEXT)) {
|
||||
if (checkViewKey()) {
|
||||
if (type.equals(TYPE_KEY)) {
|
||||
etWalletSpendKey.requestFocus();
|
||||
} else {
|
||||
etWalletRestoreHeight.requestFocus();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (type.equals(TYPE_KEY)) {
|
||||
etWalletSpendKey.setVisibility(View.VISIBLE);
|
||||
etWalletSpendKey.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_NEXT)) {
|
||||
if (checkSpendKey()) {
|
||||
etWalletRestoreHeight.requestFocus();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!type.equals(TYPE_NEW)) {
|
||||
etWalletRestoreHeight.setVisibility(View.VISIBLE);
|
||||
etWalletRestoreHeight.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)) {
|
||||
Helper.hideKeyboard(getActivity());
|
||||
generateWallet();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
bGenerate.setOnClickListener(new View.OnClickListener()
|
||||
|
||||
{
|
||||
|
@ -272,81 +254,112 @@ public class GenerateFragment extends Fragment {
|
|||
});
|
||||
|
||||
etWalletName.requestFocus();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
private boolean mnemonicOk() {
|
||||
String seed = etWalletMnemonic.getText().toString();
|
||||
return (seed.split("\\s").length == 25); // 25 words
|
||||
private boolean checkName() {
|
||||
String name = etWalletName.getEditText().getText().toString();
|
||||
boolean ok = true;
|
||||
if (name.length() == 0) {
|
||||
etWalletName.setError(getString(R.string.generate_wallet_name));
|
||||
ok = false;
|
||||
} else if (name.charAt(0) == '.') {
|
||||
etWalletName.setError(getString(R.string.generate_wallet_dot));
|
||||
ok = false;
|
||||
} else {
|
||||
File walletFile = Helper.getWalletFile(getActivity(), name);
|
||||
if (WalletManager.getInstance().walletExists(walletFile)) {
|
||||
etWalletName.setError(getString(R.string.generate_wallet_exists));
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
etWalletName.setError(null);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
private boolean addressOk() {
|
||||
String address = etWalletAddress.getText().toString();
|
||||
return Wallet.isAddressValid(address, WalletManager.getInstance().isTestNet());
|
||||
private boolean checkMnemonic() {
|
||||
String seed = etWalletMnemonic.getEditText().getText().toString();
|
||||
boolean ok = (seed.split("\\s").length == 25); // 25 words
|
||||
if (!ok) {
|
||||
etWalletMnemonic.setError(getString(R.string.generate_check_mnemonic));
|
||||
} else {
|
||||
etWalletMnemonic.setError(null);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
private boolean viewKeyOk() {
|
||||
String viewKey = etWalletViewKey.getText().toString();
|
||||
return (viewKey.length() == 64) && (viewKey.matches("^[0-9a-fA-F]+$"));
|
||||
private boolean checkAddress() {
|
||||
String address = etWalletAddress.getEditText().getText().toString();
|
||||
boolean ok = Wallet.isAddressValid(address, WalletManager.getInstance().isTestNet());
|
||||
if (!ok) {
|
||||
etWalletAddress.setError(getString(R.string.generate_check_address));
|
||||
} else {
|
||||
etWalletAddress.setError(null);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
private boolean spendKeyOk() {
|
||||
String spendKey = etWalletSpendKey.getText().toString();
|
||||
return ((spendKey.length() == 0) || ((spendKey.length() == 64) && (spendKey.matches("^[0-9a-fA-F]+$"))));
|
||||
private boolean checkViewKey() {
|
||||
String viewKey = etWalletViewKey.getEditText().getText().toString();
|
||||
boolean ok = (viewKey.length() == 64) && (viewKey.matches("^[0-9a-fA-F]+$"));
|
||||
if (!ok) {
|
||||
etWalletViewKey.setError(getString(R.string.generate_check_key));
|
||||
} else {
|
||||
etWalletViewKey.setError(null);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
private boolean checkSpendKey() {
|
||||
String spendKey = etWalletSpendKey.getEditText().getText().toString();
|
||||
boolean ok = ((spendKey.length() == 0) || ((spendKey.length() == 64) && (spendKey.matches("^[0-9a-fA-F]+$"))));
|
||||
if (!ok) {
|
||||
etWalletSpendKey.setError(getString(R.string.generate_check_key));
|
||||
} else {
|
||||
etWalletSpendKey.setError(null);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
private void generateWallet() {
|
||||
String name = etWalletName.getText().toString();
|
||||
if (name.length() == 0) return;
|
||||
if (name.charAt(0) == '.') {
|
||||
Toast.makeText(getActivity(), getString(R.string.generate_wallet_dot), Toast.LENGTH_LONG).show();
|
||||
etWalletName.requestFocus();
|
||||
}
|
||||
File walletFile = Helper.getWalletFile(getActivity(), name);
|
||||
if (WalletManager.getInstance().walletExists(walletFile)) {
|
||||
Toast.makeText(getActivity(), getString(R.string.generate_wallet_exists), Toast.LENGTH_LONG).show();
|
||||
etWalletName.requestFocus();
|
||||
return;
|
||||
}
|
||||
String password = etWalletPassword.getText().toString();
|
||||
|
||||
String seed = etWalletMnemonic.getText().toString();
|
||||
String address = etWalletAddress.getText().toString();
|
||||
if (!checkName()) return;
|
||||
String name = etWalletName.getEditText().getText().toString();
|
||||
String password = etWalletPassword.getEditText().getText().toString();
|
||||
|
||||
long height;
|
||||
try {
|
||||
height = Long.parseLong(etWalletRestoreHeight.getText().toString());
|
||||
height = Long.parseLong(etWalletRestoreHeight.getEditText().getText().toString());
|
||||
} catch (NumberFormatException ex) {
|
||||
height = 0; // Keep calm and carry on!
|
||||
}
|
||||
|
||||
// figure out how we want to create this wallet
|
||||
// A. from scratch
|
||||
if ((seed.length() == 0) && (address.length() == 0)) {
|
||||
bGenerate.setVisibility(View.GONE);
|
||||
if (type.equals(TYPE_NEW)) {
|
||||
bGenerate.setEnabled(false);
|
||||
activityCallback.onGenerate(name, password);
|
||||
} else
|
||||
// B. from seed
|
||||
if (mnemonicOk()) {
|
||||
bGenerate.setVisibility(View.GONE);
|
||||
activityCallback.onGenerate(name, password, seed, height);
|
||||
} else
|
||||
// C. from keys
|
||||
if (addressOk() && viewKeyOk() && (spendKeyOk())) {
|
||||
String viewKey = etWalletViewKey.getText().toString();
|
||||
String spendKey = etWalletSpendKey.getText().toString();
|
||||
bGenerate.setVisibility(View.GONE);
|
||||
activityCallback.onGenerate(name, password, address, viewKey, spendKey, height);
|
||||
} else
|
||||
// D. none of the above :)
|
||||
{
|
||||
Toast.makeText(getActivity(), getString(R.string.generate_check_something), Toast.LENGTH_LONG).show();
|
||||
} else if (type.equals(TYPE_SEED)) {
|
||||
if (!checkMnemonic()) return;
|
||||
String seed = etWalletMnemonic.getEditText().getText().toString();
|
||||
bGenerate.setEnabled(false);
|
||||
activityCallback.onGenerate(name, password, seed, height);
|
||||
} else if (type.equals(TYPE_KEY) || type.equals(TYPE_VIEWONLY)) {
|
||||
if (checkAddress() && checkViewKey() && checkSpendKey()) {
|
||||
bGenerate.setEnabled(false);
|
||||
String address = etWalletAddress.getEditText().getText().toString();
|
||||
String viewKey = etWalletViewKey.getEditText().getText().toString();
|
||||
String spendKey = "";
|
||||
if (type.equals(TYPE_KEY)) {
|
||||
spendKey = etWalletSpendKey.getEditText().getText().toString();
|
||||
}
|
||||
activityCallback.onGenerate(name, password, address, viewKey, spendKey, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void walletGenerateError() {
|
||||
bGenerate.setEnabled(etWalletName.length() > 0);
|
||||
bGenerate.setVisibility(View.VISIBLE);
|
||||
bGenerate.setEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -365,10 +378,7 @@ public class GenerateFragment extends Fragment {
|
|||
|
||||
void onGenerate(String name, String password, String address, String viewKey, String spendKey, long height);
|
||||
|
||||
File getStorageRoot();
|
||||
|
||||
void setTitle(String title);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -28,12 +28,17 @@ import android.view.MenuInflater;
|
|||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.m2049r.xmrwallet.layout.Toolbar;
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.model.WalletManager;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
|
||||
|
||||
public class GenerateReviewFragment extends Fragment {
|
||||
|
@ -42,6 +47,8 @@ public class GenerateReviewFragment extends Fragment {
|
|||
static final public String VIEW_TYPE_ACCEPT = "accept";
|
||||
static final public String VIEW_TYPE_WALLET = "wallet";
|
||||
|
||||
ScrollView scrollview;
|
||||
|
||||
ProgressBar pbProgress;
|
||||
TextView tvWalletName;
|
||||
TextView tvWalletPassword;
|
||||
|
@ -49,14 +56,18 @@ public class GenerateReviewFragment extends Fragment {
|
|||
TextView tvWalletMnemonic;
|
||||
TextView tvWalletViewKey;
|
||||
TextView tvWalletSpendKey;
|
||||
ImageButton bCopyAddress;
|
||||
LinearLayout llAdvancedInfo;
|
||||
Button bAdvancedInfo;
|
||||
Button bAccept;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
View view = inflater.inflate(R.layout.gen_review_fragment, container, false);
|
||||
View view = inflater.inflate(R.layout.fragment_review, container, false);
|
||||
|
||||
scrollview = (ScrollView) view.findViewById(R.id.scrollview);
|
||||
pbProgress = (ProgressBar) view.findViewById(R.id.pbProgress);
|
||||
tvWalletName = (TextView) view.findViewById(R.id.tvWalletName);
|
||||
tvWalletPassword = (TextView) view.findViewById(R.id.tvWalletPassword);
|
||||
|
@ -64,26 +75,15 @@ public class GenerateReviewFragment extends Fragment {
|
|||
tvWalletViewKey = (TextView) view.findViewById(R.id.tvWalletViewKey);
|
||||
tvWalletSpendKey = (TextView) view.findViewById(R.id.tvWalletSpendKey);
|
||||
tvWalletMnemonic = (TextView) view.findViewById(R.id.tvWalletMnemonic);
|
||||
bCopyAddress = (ImageButton) view.findViewById(R.id.bCopyAddress);
|
||||
bAdvancedInfo = (Button) view.findViewById(R.id.bAdvancedInfo);
|
||||
llAdvancedInfo = (LinearLayout) view.findViewById(R.id.llAdvancedInfo);
|
||||
|
||||
bAccept = (Button) view.findViewById(R.id.bAccept);
|
||||
|
||||
boolean testnet = WalletManager.getInstance().isTestNet();
|
||||
tvWalletMnemonic.setTextIsSelectable(testnet);
|
||||
tvWalletSpendKey.setTextIsSelectable(testnet);
|
||||
if (!testnet) {
|
||||
tvWalletMnemonic.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Toast.makeText(getActivity(), getString(R.string.message_noselect_seed), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
tvWalletSpendKey.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Toast.makeText(getActivity(), getString(R.string.message_noselect_key), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bAccept.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
|
@ -91,6 +91,36 @@ public class GenerateReviewFragment extends Fragment {
|
|||
acceptWallet();
|
||||
}
|
||||
});
|
||||
view.findViewById(R.id.bCopyViewKey).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
copyViewKey();
|
||||
}
|
||||
});
|
||||
bCopyAddress.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
copyAddress();
|
||||
}
|
||||
});
|
||||
view.findViewById(R.id.bCopySeed).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
nocopy();
|
||||
}
|
||||
});
|
||||
view.findViewById(R.id.bCopySepndKey).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
nocopy();
|
||||
}
|
||||
});
|
||||
view.findViewById(R.id.bAdvancedInfo).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
showAdvancedInfo();
|
||||
}
|
||||
});
|
||||
|
||||
showProgress();
|
||||
|
||||
|
@ -103,6 +133,31 @@ public class GenerateReviewFragment extends Fragment {
|
|||
return view;
|
||||
}
|
||||
|
||||
void copyViewKey() {
|
||||
Helper.clipBoardCopy(getActivity(), getString(R.string.label_copy_viewkey), tvWalletViewKey.getText().toString());
|
||||
Toast.makeText(getActivity(), getString(R.string.message_copy_viewkey), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
void copyAddress() {
|
||||
Helper.clipBoardCopy(getActivity(), getString(R.string.label_copy_address), tvWalletAddress.getText().toString());
|
||||
Toast.makeText(getActivity(), getString(R.string.message_copy_address), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
void nocopy() {
|
||||
Toast.makeText(getActivity(), getString(R.string.message_nocopy), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
void showAdvancedInfo() {
|
||||
llAdvancedInfo.setVisibility(View.VISIBLE);
|
||||
bAdvancedInfo.setVisibility(View.GONE);
|
||||
scrollview.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
scrollview.fullScroll(ScrollView.FOCUS_DOWN);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
String type;
|
||||
|
||||
private void acceptWallet() {
|
||||
|
@ -148,7 +203,7 @@ public class GenerateReviewFragment extends Fragment {
|
|||
address = wallet.getAddress();
|
||||
seed = wallet.getSeed();
|
||||
viewKey = wallet.getSecretViewKey();
|
||||
spendKey = isWatchOnly ? getActivity().getString(R.string.watchonly_label) : wallet.getSecretSpendKey();
|
||||
spendKey = isWatchOnly ? getActivity().getString(R.string.label_watchonly) : wallet.getSecretSpendKey();
|
||||
isWatchOnly = wallet.isWatchOnly();
|
||||
if (closeWallet) wallet.close();
|
||||
return true;
|
||||
|
@ -157,6 +212,7 @@ public class GenerateReviewFragment extends Fragment {
|
|||
@Override
|
||||
protected void onPostExecute(Boolean result) {
|
||||
super.onPostExecute(result);
|
||||
if (!isAdded()) return; // never mind
|
||||
tvWalletName.setText(name);
|
||||
if (result) {
|
||||
if (type.equals(GenerateReviewFragment.VIEW_TYPE_ACCEPT)) {
|
||||
|
@ -168,9 +224,14 @@ public class GenerateReviewFragment extends Fragment {
|
|||
tvWalletMnemonic.setText(seed);
|
||||
tvWalletViewKey.setText(viewKey);
|
||||
tvWalletSpendKey.setText(spendKey);
|
||||
bAdvancedInfo.setVisibility(View.VISIBLE);
|
||||
bCopyAddress.setEnabled(true);
|
||||
bCopyAddress.setImageResource(R.drawable.ic_content_copy_black_24dp);
|
||||
activityCallback.setTitle(name, getString(R.string.details_title));
|
||||
activityCallback.setToolbarButton(
|
||||
GenerateReviewFragment.VIEW_TYPE_ACCEPT.equals(type) ? Toolbar.BUTTON_NONE : Toolbar.BUTTON_BACK);
|
||||
} else {
|
||||
// TODO show proper error message
|
||||
// TODO end the fragment
|
||||
// TODO show proper error message and/or end the fragment?
|
||||
tvWalletAddress.setText(status.toString());
|
||||
tvWalletMnemonic.setText(status.toString());
|
||||
tvWalletViewKey.setText(status.toString());
|
||||
|
@ -180,38 +241,55 @@ public class GenerateReviewFragment extends Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
GenerateReviewFragment.Listener acceptCallback = null;
|
||||
GenerateReviewFragment.ListenerWithWallet walletCallback = null;
|
||||
Listener activityCallback = null;
|
||||
AcceptListener acceptCallback = null;
|
||||
ListenerWithWallet walletCallback = null;
|
||||
|
||||
public interface Listener {
|
||||
void setTitle(String title, String subtitle);
|
||||
|
||||
void setToolbarButton(int type);
|
||||
}
|
||||
|
||||
public interface AcceptListener {
|
||||
void onAccept(String name, String password);
|
||||
}
|
||||
|
||||
public interface ListenerWithWallet {
|
||||
Wallet getWallet();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
if (context instanceof GenerateReviewFragment.Listener) {
|
||||
this.acceptCallback = (GenerateReviewFragment.Listener) context;
|
||||
} else if (context instanceof GenerateReviewFragment.ListenerWithWallet) {
|
||||
this.walletCallback = (GenerateReviewFragment.ListenerWithWallet) context;
|
||||
} else {
|
||||
throw new ClassCastException(context.toString()
|
||||
+ " must implement Listener");
|
||||
if (context instanceof Listener) {
|
||||
this.activityCallback = (Listener) context;
|
||||
}
|
||||
if (context instanceof AcceptListener) {
|
||||
this.acceptCallback = (AcceptListener) context;
|
||||
}
|
||||
if (context instanceof ListenerWithWallet) {
|
||||
this.walletCallback = (ListenerWithWallet) context;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
Log.d(TAG, "onResume()");
|
||||
String name = tvWalletName.getText().toString();
|
||||
if (name.isEmpty()) name = null;
|
||||
activityCallback.setTitle(name, getString(R.string.details_title));
|
||||
activityCallback.setToolbarButton(
|
||||
GenerateReviewFragment.VIEW_TYPE_ACCEPT.equals(type) ? Toolbar.BUTTON_NONE : Toolbar.BUTTON_BACK);
|
||||
}
|
||||
|
||||
public void showProgress() {
|
||||
pbProgress.setIndeterminate(true);
|
||||
pbProgress.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
public void hideProgress() {
|
||||
pbProgress.setVisibility(View.INVISIBLE);
|
||||
pbProgress.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
boolean backOk() {
|
||||
|
|
|
@ -27,30 +27,32 @@ import android.content.pm.PackageManager;
|
|||
import android.media.MediaScannerConnection;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.StrictMode;
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.design.widget.TextInputLayout;
|
||||
import android.support.v4.app.Fragment;
|
||||
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.m2049r.xmrwallet.dialog.HelpFragment;
|
||||
import com.m2049r.xmrwallet.dialog.LicensesFragment;
|
||||
import com.m2049r.xmrwallet.layout.Toolbar;
|
||||
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 com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
|
||||
|
||||
|
@ -60,19 +62,41 @@ import java.io.FileOutputStream;
|
|||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.Date;
|
||||
|
||||
public class LoginActivity extends AppCompatActivity
|
||||
implements LoginFragment.Listener, GenerateFragment.Listener,
|
||||
GenerateReviewFragment.Listener, ReceiveFragment.Listener {
|
||||
GenerateReviewFragment.Listener, GenerateReviewFragment.AcceptListener, ReceiveFragment.Listener {
|
||||
static final String TAG = "LoginActivity";
|
||||
private static final String GENERATE_STACK = "gen";
|
||||
|
||||
static final int DAEMON_TIMEOUT = 500; // deamon must respond in 500ms
|
||||
static final int DAEMON_DNS_TIMEOUT = 5000; // how long to wait for DNS resolver
|
||||
|
||||
Toolbar toolbar;
|
||||
|
||||
@Override
|
||||
public void setToolbarButton(int type) {
|
||||
toolbar.setButton(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(String title) {
|
||||
toolbar.setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSubtitle(String subtitle) {
|
||||
toolbar.setSubtitle(subtitle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(String title, String subtitle) {
|
||||
toolbar.setTitle(title, subtitle);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
Log.d(TAG, "onCreate()");
|
||||
|
@ -81,9 +105,29 @@ public class LoginActivity extends AppCompatActivity
|
|||
// we don't store anything ourselves
|
||||
}
|
||||
|
||||
setContentView(R.layout.login_activity);
|
||||
setContentView(R.layout.activity_login);
|
||||
toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
getSupportActionBar().setDisplayShowTitleEnabled(false);
|
||||
|
||||
toolbar.setOnButtonListener(new Toolbar.OnButtonListener() {
|
||||
@Override
|
||||
public void onButton(int type) {
|
||||
switch (type) {
|
||||
case Toolbar.BUTTON_BACK:
|
||||
onBackPressed();
|
||||
break;
|
||||
case Toolbar.BUTTON_CLOSE:
|
||||
finish();
|
||||
break;
|
||||
case Toolbar.BUTTON_DONATE:
|
||||
Toast.makeText(LoginActivity.this, getString(R.string.label_donate), Toast.LENGTH_SHORT).show();
|
||||
case Toolbar.BUTTON_NONE:
|
||||
default:
|
||||
Log.e(TAG, "Button " + type + "pressed - how can this be?");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (Helper.getWritePermission(this)) {
|
||||
startLoginFragment();
|
||||
|
@ -102,37 +146,26 @@ public class LoginActivity extends AppCompatActivity
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean onWalletSelected(String daemon, final String walletName, boolean testnet) {
|
||||
public boolean onWalletSelected(String walletName, String daemon, boolean testnet) {
|
||||
if (daemon.length() == 0) {
|
||||
Toast.makeText(this, getString(R.string.prompt_daemon_missing), Toast.LENGTH_SHORT).show();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!checkAndSetWalletDaemon(daemon, testnet)) {
|
||||
Toast.makeText(this, getString(R.string.warn_daemon_unavailable), Toast.LENGTH_SHORT).show();
|
||||
if (checkServiceRunning()) return false;
|
||||
try {
|
||||
WalletNode aWalletNode = new WalletNode(walletName, daemon, testnet);
|
||||
new AsyncOpenWallet().execute(aWalletNode);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
Log.e(TAG, ex.getLocalizedMessage());
|
||||
Toast.makeText(this, ex.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (checkServiceRunning()) return true;
|
||||
Log.d(TAG, "selected wallet is ." + walletName + ".");
|
||||
// now it's getting real, check if wallet exists
|
||||
File walletFile = Helper.getWalletFile(this, walletName);
|
||||
if (WalletManager.getInstance().walletExists(walletFile)) {
|
||||
promptPassword(walletName, new PasswordAction() {
|
||||
@Override
|
||||
public void action(String walletName, String password) {
|
||||
startWallet(walletName, password);
|
||||
}
|
||||
});
|
||||
} else { // this cannot really happen as we prefilter choices
|
||||
Toast.makeText(this, getString(R.string.bad_wallet), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWalletDetails(final String walletName, boolean testnet) {
|
||||
checkAndSetWalletDaemon("", testnet); // just set selected net
|
||||
setNet(testnet);
|
||||
Log.d(TAG, "details for wallet ." + walletName + ".");
|
||||
if (checkServiceRunning()) return;
|
||||
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
|
||||
|
@ -170,7 +203,7 @@ public class LoginActivity extends AppCompatActivity
|
|||
|
||||
@Override
|
||||
public void onWalletReceive(String walletName, boolean testnet) {
|
||||
checkAndSetWalletDaemon("", testnet); // just set selected net
|
||||
setNet(testnet);
|
||||
Log.d(TAG, "receive for wallet ." + walletName + ".");
|
||||
if (checkServiceRunning()) return;
|
||||
final File walletFile = Helper.getWalletFile(this, walletName);
|
||||
|
@ -406,10 +439,10 @@ public class LoginActivity extends AppCompatActivity
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onAddWallet(boolean testnet) {
|
||||
checkAndSetWalletDaemon("", testnet);
|
||||
public void onAddWallet(boolean testnet, String type) {
|
||||
setNet(testnet);
|
||||
if (checkServiceRunning()) return;
|
||||
startGenerateFragment();
|
||||
startGenerateFragment(type);
|
||||
}
|
||||
|
||||
AlertDialog passwordDialog = null; // for preventing multiple clicks in wallet list
|
||||
|
@ -423,23 +456,33 @@ public class LoginActivity extends AppCompatActivity
|
|||
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context);
|
||||
alertDialogBuilder.setView(promptsView);
|
||||
|
||||
final EditText etPassword = (EditText) promptsView.findViewById(R.id.etPassword);
|
||||
final TextView tvPasswordLabel = (TextView) promptsView.findViewById(R.id.tvPasswordLabel);
|
||||
final TextInputLayout etPassword = (TextInputLayout) promptsView.findViewById(R.id.etPassword);
|
||||
etPassword.setHint(LoginActivity.this.getString(R.string.prompt_password, wallet));
|
||||
|
||||
tvPasswordLabel.setText(LoginActivity.this.getString(R.string.prompt_password, wallet));
|
||||
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) {
|
||||
}
|
||||
});
|
||||
|
||||
// set dialog message
|
||||
alertDialogBuilder
|
||||
.setCancelable(false)
|
||||
.setPositiveButton("OK",
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
Helper.hideKeyboardAlways(LoginActivity.this);
|
||||
String pass = etPassword.getText().toString();
|
||||
processPasswordEntry(wallet, pass, action);
|
||||
passwordDialog = null;
|
||||
}
|
||||
})
|
||||
.setPositiveButton("OK", null)
|
||||
.setNegativeButton("Cancel",
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
|
@ -448,20 +491,43 @@ public class LoginActivity extends AppCompatActivity
|
|||
passwordDialog = null;
|
||||
}
|
||||
});
|
||||
|
||||
passwordDialog = alertDialogBuilder.create();
|
||||
|
||||
passwordDialog.setOnShowListener(new DialogInterface.OnShowListener() {
|
||||
@Override
|
||||
public void onShow(DialogInterface dialog) {
|
||||
Button button = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_POSITIVE);
|
||||
button.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
String pass = etPassword.getEditText().getText().toString();
|
||||
if (processPasswordEntry(wallet, pass, action)) {
|
||||
passwordDialog.dismiss();
|
||||
passwordDialog = null;
|
||||
Helper.hideKeyboardAlways(LoginActivity.this);
|
||||
} else {
|
||||
etPassword.setError(getString(R.string.bad_password));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Helper.showKeyboard(passwordDialog);
|
||||
|
||||
// accept keyboard "ok"
|
||||
etPassword.setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||
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)) {
|
||||
Helper.hideKeyboardAlways(LoginActivity.this);
|
||||
String pass = etPassword.getText().toString();
|
||||
passwordDialog.cancel();
|
||||
processPasswordEntry(wallet, pass, action);
|
||||
passwordDialog = null;
|
||||
return false;
|
||||
String pass = etPassword.getEditText().getText().toString();
|
||||
if (processPasswordEntry(wallet, pass, action)) {
|
||||
passwordDialog.cancel();
|
||||
passwordDialog = null;
|
||||
} else {
|
||||
etPassword.setError(getString(R.string.bad_password));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -481,11 +547,12 @@ public class LoginActivity extends AppCompatActivity
|
|||
void action(String walletName, String password);
|
||||
}
|
||||
|
||||
private void processPasswordEntry(String walletName, String pass, PasswordAction action) {
|
||||
private boolean processPasswordEntry(String walletName, String pass, PasswordAction action) {
|
||||
if (checkWalletPassword(walletName, pass)) {
|
||||
action.action(walletName, pass);
|
||||
return true;
|
||||
} else {
|
||||
Toast.makeText(this, getString(R.string.bad_password), Toast.LENGTH_SHORT).show();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -505,22 +572,14 @@ public class LoginActivity extends AppCompatActivity
|
|||
////////////////////////////////////////
|
||||
////////////////////////////////////////
|
||||
|
||||
public void setTitle(String title) {
|
||||
toolbar.setTitle(title);
|
||||
}
|
||||
|
||||
public void setSubtitle(String subtitle) {
|
||||
toolbar.setSubtitle(subtitle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showNet(boolean testnet) {
|
||||
if (testnet) {
|
||||
toolbar.setBackgroundResource(R.color.colorPrimaryDark);
|
||||
} else {
|
||||
toolbar.setBackgroundResource(R.color.moneroOrange);
|
||||
toolbar.setBackgroundResource(R.drawable.backgound_toolbar_mainnet);
|
||||
}
|
||||
setSubtitle(getString(testnet ? R.string.connect_testnet : R.string.connect_mainnet));
|
||||
toolbar.setSubtitle(getString(testnet ? R.string.connect_testnet : R.string.connect_mainnet));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -532,9 +591,20 @@ public class LoginActivity extends AppCompatActivity
|
|||
ProgressDialog progressDialog = null;
|
||||
|
||||
private void showProgressDialog(int msgId) {
|
||||
showProgressDialog(msgId, 0);
|
||||
}
|
||||
|
||||
private void showProgressDialog(int msgId, long delay) {
|
||||
dismissProgressDialog(); // just in case
|
||||
progressDialog = new MyProgressDialog(LoginActivity.this, msgId);
|
||||
progressDialog.show();
|
||||
if (delay > 0) {
|
||||
Handler handler = new Handler();
|
||||
handler.postDelayed(new Runnable() {
|
||||
public void run() {
|
||||
if (progressDialog != null) progressDialog.show();
|
||||
}
|
||||
}, delay);
|
||||
}
|
||||
}
|
||||
|
||||
private void dismissProgressDialog() {
|
||||
|
@ -554,7 +624,6 @@ public class LoginActivity extends AppCompatActivity
|
|||
protected void onResume() {
|
||||
super.onResume();
|
||||
Log.d(TAG, "onResume()");
|
||||
setTitle(getString(R.string.login_activity_name));
|
||||
// wait for WalletService to finish
|
||||
if (WalletService.Running && (progressDialog == null)) {
|
||||
// and show a progress dialog, but only if there isn't one already
|
||||
|
@ -671,8 +740,10 @@ public class LoginActivity extends AppCompatActivity
|
|||
Log.d(TAG, "LoginFragment added");
|
||||
}
|
||||
|
||||
void startGenerateFragment() {
|
||||
replaceFragment(new GenerateFragment(), GENERATE_STACK, null);
|
||||
void startGenerateFragment(String type) {
|
||||
Bundle extras = new Bundle();
|
||||
extras.putString(GenerateFragment.TYPE, type);
|
||||
replaceFragment(new GenerateFragment(), GENERATE_STACK, extras);
|
||||
Log.d(TAG, "GenerateFragment placed");
|
||||
}
|
||||
|
||||
|
@ -705,7 +776,6 @@ public class LoginActivity extends AppCompatActivity
|
|||
//////////////////////////////////////////
|
||||
static final String MNEMONIC_LANGUAGE = "English"; // see mnemonics/electrum-words.cpp for more
|
||||
|
||||
|
||||
private class AsyncCreateWallet extends AsyncTask<Void, Void, Boolean> {
|
||||
String walletName;
|
||||
String walletPassword;
|
||||
|
@ -762,8 +832,6 @@ public class LoginActivity extends AppCompatActivity
|
|||
if (result) {
|
||||
startDetails(newWalletFile, walletPassword, GenerateReviewFragment.VIEW_TYPE_ACCEPT);
|
||||
} else {
|
||||
Toast.makeText(LoginActivity.this,
|
||||
getString(R.string.generate_wallet_create_failed), Toast.LENGTH_LONG).show();
|
||||
walletGenerateError();
|
||||
}
|
||||
}
|
||||
|
@ -797,7 +865,10 @@ public class LoginActivity extends AppCompatActivity
|
|||
Wallet newWallet = WalletManager.getInstance()
|
||||
.createWallet(aFile, password, MNEMONIC_LANGUAGE);
|
||||
boolean success = (newWallet.getStatus() == Wallet.Status.Status_Ok);
|
||||
if (!success) Log.e(TAG, newWallet.getErrorString());
|
||||
if (!success) {
|
||||
Log.e(TAG, newWallet.getErrorString());
|
||||
toast(newWallet.getErrorString());
|
||||
}
|
||||
newWallet.close();
|
||||
return success;
|
||||
}
|
||||
|
@ -816,6 +887,7 @@ public class LoginActivity extends AppCompatActivity
|
|||
success = success && newWallet.store();
|
||||
} else {
|
||||
Log.e(TAG, newWallet.getErrorString());
|
||||
toast(newWallet.getErrorString());
|
||||
}
|
||||
newWallet.close();
|
||||
return success;
|
||||
|
@ -838,6 +910,7 @@ public class LoginActivity extends AppCompatActivity
|
|||
success = success && newWallet.store();
|
||||
} else {
|
||||
Log.e(TAG, newWallet.getErrorString());
|
||||
toast(newWallet.getErrorString());
|
||||
}
|
||||
newWallet.close();
|
||||
return success;
|
||||
|
@ -845,6 +918,15 @@ public class LoginActivity extends AppCompatActivity
|
|||
});
|
||||
}
|
||||
|
||||
void toast(final String msg) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(LoginActivity.this, msg, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccept(final String name, final String password) {
|
||||
File walletFolder = getStorageRoot();
|
||||
|
@ -859,17 +941,10 @@ public class LoginActivity extends AppCompatActivity
|
|||
getString(R.string.generate_wallet_created), Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
Log.e(TAG, "Wallet store failed to " + walletFile.getAbsolutePath());
|
||||
Toast.makeText(LoginActivity.this,
|
||||
getString(R.string.generate_wallet_create_failed), Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(LoginActivity.this, getString(R.string.generate_wallet_create_failed), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
@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);
|
||||
|
@ -896,14 +971,12 @@ public class LoginActivity extends AppCompatActivity
|
|||
|
||||
boolean copyWallet(File srcWallet, File dstWallet, boolean backupMode) {
|
||||
if (walletExists(dstWallet, true) && !backupMode) return false;
|
||||
Log.d(TAG, "B " + backupMode);
|
||||
boolean success = false;
|
||||
File srcDir = srcWallet.getParentFile();
|
||||
String srcName = srcWallet.getName();
|
||||
File dstDir = dstWallet.getParentFile();
|
||||
String dstName = dstWallet.getName();
|
||||
try {
|
||||
Log.d(TAG, "C " + backupMode);
|
||||
try {
|
||||
copyFile(new File(srcDir, srcName), new File(dstDir, dstName));
|
||||
} catch (IOException ex) {
|
||||
|
@ -962,6 +1035,12 @@ public class LoginActivity extends AppCompatActivity
|
|||
if (((GenerateReviewFragment) f).backOk()) {
|
||||
super.onBackPressed();
|
||||
}
|
||||
} else if (f instanceof LoginFragment) {
|
||||
if (((LoginFragment) f).isFabOpen()) {
|
||||
((LoginFragment) f).animateFAB();
|
||||
} else {
|
||||
super.onBackPressed();
|
||||
}
|
||||
} else {
|
||||
super.onBackPressed();
|
||||
}
|
||||
|
@ -971,10 +1050,10 @@ public class LoginActivity extends AppCompatActivity
|
|||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_create_help:
|
||||
HelpFragment.displayHelp(getSupportFragmentManager(),R.raw.help_create);
|
||||
HelpFragment.displayHelp(getSupportFragmentManager(), R.raw.help_create);
|
||||
return true;
|
||||
case R.id.action_details_help:
|
||||
HelpFragment.displayHelp(getSupportFragmentManager(),R.raw.help_details);
|
||||
HelpFragment.displayHelp(getSupportFragmentManager(), R.raw.help_details);
|
||||
return true;
|
||||
case R.id.action_lincense_info:
|
||||
LicensesFragment.displayLicensesFragment(getSupportFragmentManager());
|
||||
|
@ -992,59 +1071,128 @@ public class LoginActivity extends AppCompatActivity
|
|||
}
|
||||
}
|
||||
|
||||
private boolean checkAndSetWalletDaemon(String daemon, boolean testnet) {
|
||||
String daemonAddress = "";
|
||||
String username = "";
|
||||
private void setNet(boolean testnet) {
|
||||
WalletManager.getInstance().setDaemon("", testnet, "", "");
|
||||
}
|
||||
|
||||
static class WalletNode {
|
||||
String name = null;
|
||||
String host = "";
|
||||
int port = 28081;
|
||||
String user = "";
|
||||
String password = "";
|
||||
if (!daemon.isEmpty()) { // no actual daemon is also fine
|
||||
boolean isTestnet;
|
||||
|
||||
WalletNode(String walletName, String daemon, boolean isTestnet) {
|
||||
if ((daemon == null) || daemon.isEmpty()) return;
|
||||
this.name = walletName;
|
||||
String daemonAddress;
|
||||
String a[] = daemon.split("@");
|
||||
if (a.length == 1) { // no credentials
|
||||
daemonAddress = a[0];
|
||||
} else if (a.length == 2) { // credentials
|
||||
String up[] = a[0].split(":");
|
||||
if (up.length != 2) return false;
|
||||
username = up[0];
|
||||
if (!username.isEmpty()) password = up[1];
|
||||
String userPassword[] = a[0].split(":");
|
||||
if (userPassword.length != 2)
|
||||
throw new IllegalArgumentException("User:Password invalid");
|
||||
user = userPassword[0];
|
||||
if (!user.isEmpty()) password = userPassword[1];
|
||||
daemonAddress = a[1];
|
||||
} else {
|
||||
return false;
|
||||
throw new IllegalArgumentException("Too many @");
|
||||
}
|
||||
|
||||
String da[] = daemonAddress.split(":");
|
||||
if ((da.length > 2) || (da.length < 1)) return false;
|
||||
String host = da[0];
|
||||
int port;
|
||||
if ((da.length > 2) || (da.length < 1))
|
||||
throw new IllegalArgumentException("Too many ':' or too few");
|
||||
host = da[0];
|
||||
if (da.length == 2) {
|
||||
try {
|
||||
port = Integer.parseInt(da[1]);
|
||||
} catch (NumberFormatException ex) {
|
||||
return false;
|
||||
throw new IllegalArgumentException("Port not numeric");
|
||||
}
|
||||
} else {
|
||||
port = (testnet ? 28081 : 18081);
|
||||
daemonAddress = daemonAddress + ":" + port;
|
||||
port = (isTestnet ? 28081 : 18081);
|
||||
}
|
||||
//Log.d(TAG, "DAEMON " + username + "/" + password + "/" + host + "/" + port);
|
||||
// if (android.os.Build.VERSION.SDK_INT > 9) {
|
||||
StrictMode.ThreadPolicy prevPolicy = StrictMode.getThreadPolicy();
|
||||
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder(prevPolicy).permitNetwork().build();
|
||||
StrictMode.setThreadPolicy(policy);
|
||||
this.isTestnet = isTestnet;
|
||||
}
|
||||
|
||||
String getAddress() {
|
||||
return host + ":" + port;
|
||||
}
|
||||
|
||||
boolean isValid() {
|
||||
return !host.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
private class AsyncOpenWallet extends AsyncTask<WalletNode, Void, Boolean> {
|
||||
|
||||
WalletNode walletNode;
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
super.onPreExecute();
|
||||
showProgressDialog(R.string.open_progress, DAEMON_TIMEOUT / 4);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(WalletNode... params) {
|
||||
if (params.length != 1) return false;
|
||||
this.walletNode = params[0];
|
||||
if (!walletNode.isValid()) return false;
|
||||
|
||||
Log.d(TAG, "checking " + walletNode.getAddress());
|
||||
|
||||
long timeDA = new Date().getTime();
|
||||
SocketAddress address = new InetSocketAddress(walletNode.host, walletNode.port);
|
||||
long timeDB = new Date().getTime();
|
||||
Log.d(TAG, "Resolving " + walletNode.host + " took " + (timeDB - timeDA) + "ms.");
|
||||
Socket socket = new Socket();
|
||||
long timeA = new Date().getTime();
|
||||
try {
|
||||
socket.connect(new InetSocketAddress(host, port), LoginActivity.DAEMON_TIMEOUT);
|
||||
socket.connect(address, LoginActivity.DAEMON_TIMEOUT);
|
||||
socket.close();
|
||||
} catch (IOException ex) {
|
||||
Log.d(TAG, "Cannot reach daemon " + host + "/" + port + " because " + ex.getLocalizedMessage());
|
||||
Log.d(TAG, "Cannot reach daemon " + walletNode.host + "/" + walletNode.port + " because " + ex.getMessage());
|
||||
return false;
|
||||
} finally {
|
||||
StrictMode.setThreadPolicy(prevPolicy);
|
||||
}
|
||||
long timeB = new Date().getTime();
|
||||
Log.d(TAG, "Daemon is " + (timeB - timeA) + "ms away.");
|
||||
long time = timeB - timeA;
|
||||
Log.d(TAG, "Daemon " + walletNode.host + " is " + time + "ms away.");
|
||||
return time < LoginActivity.DAEMON_TIMEOUT;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean result) {
|
||||
super.onPostExecute(result);
|
||||
if (isDestroyed()) {
|
||||
return;
|
||||
}
|
||||
dismissProgressDialog();
|
||||
if (result) {
|
||||
Log.d(TAG, "selected wallet is ." + walletNode.name + ".");
|
||||
// now it's getting real, check if wallet exists
|
||||
promptAndStart(walletNode);
|
||||
} else {
|
||||
Toast.makeText(LoginActivity.this, getString(R.string.status_wallet_connect_timeout), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void promptAndStart(WalletNode walletNode) {
|
||||
File walletFile = Helper.getWalletFile(this, walletNode.name);
|
||||
if (WalletManager.getInstance().walletExists(walletFile)) {
|
||||
WalletManager.getInstance().
|
||||
setDaemon(walletNode.getAddress(), walletNode.isTestnet, walletNode.user, walletNode.password);
|
||||
promptPassword(walletNode.name, new PasswordAction() {
|
||||
@Override
|
||||
public void action(String walletName, String password) {
|
||||
startWallet(walletName, password);
|
||||
}
|
||||
});
|
||||
} else { // this cannot really happen as we prefilter choices
|
||||
Toast.makeText(this, getString(R.string.bad_wallet), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
WalletManager mgr = WalletManager.getInstance();
|
||||
mgr.setDaemon(daemonAddress, testnet, username, password);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,13 +18,15 @@ package com.m2049r.xmrwallet;
|
|||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.drawable.AnimationDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.FloatingActionButton;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
|
@ -32,47 +34,42 @@ import android.view.MenuInflater;
|
|||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ListView;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.m2049r.xmrwallet.layout.DropDownEditText;
|
||||
import com.m2049r.xmrwallet.layout.Toolbar;
|
||||
import com.m2049r.xmrwallet.layout.WalletInfoAdapter;
|
||||
import com.m2049r.xmrwallet.model.WalletManager;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.util.NodeList;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
public class LoginFragment extends Fragment {
|
||||
public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInteractionListener,
|
||||
View.OnClickListener {
|
||||
private static final String TAG = "LoginFragment";
|
||||
public static final String WALLETNAME_PREAMBLE = "[------] ";
|
||||
public static final int WALLETNAME_PREAMBLE_LENGTH = WALLETNAME_PREAMBLE.length();
|
||||
|
||||
private WalletInfoAdapter adapter;
|
||||
|
||||
ListView listView;
|
||||
Set<String> walletList = new TreeSet<>(new Comparator<String>() {
|
||||
@Override
|
||||
public int compare(String o1, String o2) {
|
||||
return o1.substring(WALLETNAME_PREAMBLE_LENGTH).toLowerCase()
|
||||
.compareTo(o2.substring(WALLETNAME_PREAMBLE_LENGTH).toLowerCase());
|
||||
}
|
||||
});
|
||||
List<String> displayedList = new ArrayList<>();
|
||||
List<WalletManager.WalletInfo> walletList = new ArrayList<>();
|
||||
List<WalletManager.WalletInfo> displayedList = new ArrayList<>();
|
||||
|
||||
ImageView ivGuntherWallets;
|
||||
EditText etDummy;
|
||||
DropDownEditText etDaemonAddress;
|
||||
ArrayAdapter<String> nodeAdapter;
|
||||
FloatingActionButton fabAdd;
|
||||
|
||||
Listener activityCallback;
|
||||
|
||||
|
@ -82,7 +79,7 @@ public class LoginFragment extends Fragment {
|
|||
|
||||
File getStorageRoot();
|
||||
|
||||
boolean onWalletSelected(String daemon, String wallet, boolean testnet);
|
||||
boolean onWalletSelected(String wallet, String daemon, boolean testnet);
|
||||
|
||||
void onWalletDetails(String wallet, boolean testnet);
|
||||
|
||||
|
@ -94,9 +91,14 @@ public class LoginFragment extends Fragment {
|
|||
|
||||
void onWalletArchive(String walletName);
|
||||
|
||||
void onAddWallet(boolean testnet);
|
||||
void onAddWallet(boolean testnet, String type);
|
||||
|
||||
void showNet(boolean testnet);
|
||||
|
||||
void setToolbarButton(int type);
|
||||
|
||||
void setTitle(String title);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -121,55 +123,52 @@ public class LoginFragment extends Fragment {
|
|||
public void onResume() {
|
||||
super.onResume();
|
||||
Log.d(TAG, "onResume()");
|
||||
activityCallback.setTitle(null);
|
||||
activityCallback.setToolbarButton(Toolbar.BUTTON_DONATE);
|
||||
activityCallback.showNet(isTestnet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
Log.d(TAG, "onCreateView");
|
||||
View view = inflater.inflate(R.layout.login_fragment, container, false);
|
||||
View view = inflater.inflate(R.layout.fragment_login, container, false);
|
||||
|
||||
fabAdd = (FloatingActionButton) view.findViewById(R.id.fabAdd);
|
||||
fabAdd.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
activityCallback.onAddWallet(isTestnet());
|
||||
}
|
||||
});
|
||||
ivGuntherWallets = (ImageView) view.findViewById(R.id.ivGuntherWallets);
|
||||
|
||||
listView = (ListView) view.findViewById(R.id.list);
|
||||
ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity(),
|
||||
android.R.layout.simple_list_item_1, android.R.id.text1, this.displayedList);
|
||||
listView.setAdapter(adapter);
|
||||
registerForContextMenu(listView);
|
||||
fabScreen = (FrameLayout) view.findViewById(R.id.fabScreen);
|
||||
fab = (FloatingActionButton) view.findViewById(R.id.fab);
|
||||
fabNew = (FloatingActionButton) view.findViewById(R.id.fabNew);
|
||||
fabView = (FloatingActionButton) view.findViewById(R.id.fabView);
|
||||
fabKey = (FloatingActionButton) view.findViewById(R.id.fabKey);
|
||||
fabSeed = (FloatingActionButton) view.findViewById(R.id.fabSeed);
|
||||
|
||||
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
String itemValue = (String) listView.getItemAtPosition(position);
|
||||
fabNewL = (RelativeLayout) view.findViewById(R.id.fabNewL);
|
||||
fabViewL = (RelativeLayout) view.findViewById(R.id.fabViewL);
|
||||
fabKeyL = (RelativeLayout) view.findViewById(R.id.fabKeyL);
|
||||
fabSeedL = (RelativeLayout) view.findViewById(R.id.fabSeedL);
|
||||
|
||||
if (itemValue.length() <= (WALLETNAME_PREAMBLE_LENGTH)) {
|
||||
Toast.makeText(getActivity(), getString(R.string.panic), Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
fab_open_screen = AnimationUtils.loadAnimation(getContext(), R.anim.fab_open_screen);
|
||||
fab_close_screen = AnimationUtils.loadAnimation(getContext(), R.anim.fab_close_screen);
|
||||
fab_open = AnimationUtils.loadAnimation(getContext(), R.anim.fab_open);
|
||||
fab_close = AnimationUtils.loadAnimation(getContext(), R.anim.fab_close);
|
||||
rotate_forward = AnimationUtils.loadAnimation(getContext(), R.anim.rotate_forward);
|
||||
rotate_backward = AnimationUtils.loadAnimation(getContext(), R.anim.rotate_backward);
|
||||
fab.setOnClickListener(this);
|
||||
fabNew.setOnClickListener(this);
|
||||
fabView.setOnClickListener(this);
|
||||
fabKey.setOnClickListener(this);
|
||||
fabSeed.setOnClickListener(this);
|
||||
fabScreen.setOnClickListener(this);
|
||||
|
||||
String x = isTestnet() ? "9A-" : "4-";
|
||||
if (x.indexOf(itemValue.charAt(1)) < 0) {
|
||||
Toast.makeText(getActivity(), getString(R.string.prompt_wrong_net), Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
String wallet = itemValue.substring(WALLETNAME_PREAMBLE_LENGTH);
|
||||
|
||||
if (activityCallback.onWalletSelected(getDaemon(), wallet, isTestnet())) {
|
||||
savePrefs();
|
||||
}
|
||||
}
|
||||
});
|
||||
RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.list);
|
||||
registerForContextMenu(recyclerView);
|
||||
this.adapter = new WalletInfoAdapter(getActivity(), this);
|
||||
recyclerView.setAdapter(adapter);
|
||||
|
||||
etDummy = (EditText) view.findViewById(R.id.etDummy);
|
||||
etDaemonAddress = (DropDownEditText) view.findViewById(R.id.etDaemonAddress);
|
||||
nodeAdapter = new ArrayAdapter(getContext(), android.R.layout.simple_dropdown_item_1line);
|
||||
nodeAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_dropdown_item_1line);
|
||||
etDaemonAddress.setAdapter(nodeAdapter);
|
||||
|
||||
Helper.hideKeyboard(getActivity());
|
||||
|
@ -204,72 +203,66 @@ public class LoginFragment extends Fragment {
|
|||
}
|
||||
});
|
||||
|
||||
etDaemonAddress.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View arg1, int pos, long id) {
|
||||
Helper.hideKeyboard(getActivity());
|
||||
etDummy.requestFocus();
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
loadPrefs();
|
||||
return view;
|
||||
}
|
||||
|
||||
private void filterList() {
|
||||
displayedList.clear();
|
||||
String x = isTestnet() ? "9A" : "4";
|
||||
for (String s : walletList) {
|
||||
if (x.indexOf(s.charAt(1)) >= 0) displayedList.add(s);
|
||||
}
|
||||
}
|
||||
|
||||
public void loadList() {
|
||||
Log.d(TAG, "loadList()");
|
||||
// TODO this should probably be in LoginActivity
|
||||
WalletManager mgr = WalletManager.getInstance();
|
||||
List<WalletManager.WalletInfo> walletInfos =
|
||||
mgr.findWallets(activityCallback.getStorageRoot());
|
||||
|
||||
walletList.clear();
|
||||
for (WalletManager.WalletInfo walletInfo : walletInfos) {
|
||||
// ONCE the walletInfo.address was null - because the address.txt was empty
|
||||
// this was before the wallet generation was in its own therad with huge stack
|
||||
// TODO: keep an eye on Wallet.getAddress() returning empty
|
||||
String displayAddress = walletInfo.address;
|
||||
if ((displayAddress != null) && displayAddress.length() == 95) {
|
||||
displayAddress = walletInfo.address.substring(0, 6);
|
||||
walletList.add("[" + displayAddress + "] " + walletInfo.name);
|
||||
void showGunther() {
|
||||
ivGuntherWallets.setImageResource(R.drawable.gunther_wallets);
|
||||
final AnimationDrawable guntherWalletsAnim = (AnimationDrawable) ivGuntherWallets.getDrawable();
|
||||
final Handler handler = new Handler();
|
||||
handler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
guntherWalletsAnim.start();
|
||||
}
|
||||
}
|
||||
filterList();
|
||||
((BaseAdapter) listView.getAdapter()).notifyDataSetChanged();
|
||||
}, getResources().getInteger(R.integer.gunther_wallets_delay));
|
||||
}
|
||||
|
||||
void normalGunther() {
|
||||
ivGuntherWallets.setImageResource(R.drawable.gunther_wallets_00);
|
||||
}
|
||||
|
||||
// Callbacks from WalletInfoAdapter
|
||||
@Override
|
||||
public void onInteraction(final View view, final WalletManager.WalletInfo infoItem) {
|
||||
String x = isTestnet() ? "9A-" : "4-";
|
||||
if (x.indexOf(infoItem.address.charAt(0)) < 0) {
|
||||
Toast.makeText(getActivity(), getString(R.string.prompt_wrong_net), Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
if (activityCallback.onWalletSelected(infoItem.name, getDaemon(), isTestnet())) {
|
||||
savePrefs();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v,
|
||||
ContextMenu.ContextMenuInfo menuInfo) {
|
||||
super.onCreateContextMenu(menu, v, menuInfo);
|
||||
MenuInflater inflater = getActivity().getMenuInflater();
|
||||
inflater.inflate(R.menu.list_context_menu, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
|
||||
String listItem = (String) listView.getItemAtPosition(info.position);
|
||||
String name = nameFromListItem(listItem, isTestnet());
|
||||
if (name == null) {
|
||||
Toast.makeText(getActivity(), getString(R.string.panic), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
public boolean onContextInteraction(MenuItem item, WalletManager.WalletInfo listItem) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_info:
|
||||
showInfo(name);
|
||||
showInfo(listItem.name);
|
||||
break;
|
||||
case R.id.action_receive:
|
||||
showReceive(name);
|
||||
showReceive(listItem.name);
|
||||
break;
|
||||
case R.id.action_rename:
|
||||
activityCallback.onWalletRename(name);
|
||||
activityCallback.onWalletRename(listItem.name);
|
||||
break;
|
||||
case R.id.action_backup:
|
||||
activityCallback.onWalletBackup(name);
|
||||
activityCallback.onWalletBackup(listItem.name);
|
||||
break;
|
||||
case R.id.action_archive:
|
||||
activityCallback.onWalletArchive(name);
|
||||
activityCallback.onWalletArchive(listItem.name);
|
||||
break;
|
||||
default:
|
||||
return super.onContextItemSelected(item);
|
||||
|
@ -277,6 +270,31 @@ public class LoginFragment extends Fragment {
|
|||
return true;
|
||||
}
|
||||
|
||||
private void filterList() {
|
||||
displayedList.clear();
|
||||
String x = isTestnet() ? "9A" : "4";
|
||||
for (WalletManager.WalletInfo s : walletList) {
|
||||
if (x.indexOf(s.address.charAt(0)) >= 0) displayedList.add(s);
|
||||
}
|
||||
}
|
||||
|
||||
public void loadList() {
|
||||
Log.d(TAG, "loadList()");
|
||||
WalletManager mgr = WalletManager.getInstance();
|
||||
List<WalletManager.WalletInfo> walletInfos =
|
||||
mgr.findWallets(activityCallback.getStorageRoot());
|
||||
walletList.clear();
|
||||
walletList.addAll(walletInfos);
|
||||
filterList();
|
||||
adapter.setInfos(displayedList);
|
||||
adapter.notifyDataSetChanged();
|
||||
if (displayedList.isEmpty()) {
|
||||
showGunther();
|
||||
} else {
|
||||
normalGunther();
|
||||
}
|
||||
}
|
||||
|
||||
private void showInfo(@NonNull String name) {
|
||||
activityCallback.onWalletDetails(name, isTestnet());
|
||||
}
|
||||
|
@ -286,15 +304,6 @@ public class LoginFragment extends Fragment {
|
|||
return true;
|
||||
}
|
||||
|
||||
private String nameFromListItem(String listItem, boolean testnet) {
|
||||
String wallet = listItem.substring(WALLETNAME_PREAMBLE_LENGTH);
|
||||
String x = testnet ? "9A" : "4";
|
||||
if (x.indexOf(listItem.charAt(1)) < 0) {
|
||||
return null;
|
||||
}
|
||||
return wallet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
@ -392,4 +401,75 @@ public class LoginFragment extends Fragment {
|
|||
etDummy.requestFocus();
|
||||
Helper.hideKeyboard(getActivity());
|
||||
}
|
||||
|
||||
private boolean isFabOpen = false;
|
||||
private FloatingActionButton fab, fabNew, fabView, fabKey, fabSeed;
|
||||
private FrameLayout fabScreen;
|
||||
private RelativeLayout fabNewL, fabViewL, fabKeyL, fabSeedL;
|
||||
private Animation fab_open, fab_close, rotate_forward, rotate_backward, fab_open_screen, fab_close_screen;
|
||||
|
||||
public boolean isFabOpen() {
|
||||
return isFabOpen;
|
||||
}
|
||||
|
||||
public void animateFAB() {
|
||||
if (isFabOpen) {
|
||||
fabScreen.setVisibility(View.INVISIBLE);
|
||||
fabScreen.setClickable(false);
|
||||
fabScreen.startAnimation(fab_close_screen);
|
||||
fab.startAnimation(rotate_backward);
|
||||
fabNewL.startAnimation(fab_close);
|
||||
fabNew.setClickable(false);
|
||||
fabViewL.startAnimation(fab_close);
|
||||
fabView.setClickable(false);
|
||||
fabKeyL.startAnimation(fab_close);
|
||||
fabKey.setClickable(false);
|
||||
fabSeedL.startAnimation(fab_close);
|
||||
fabSeed.setClickable(false);
|
||||
isFabOpen = false;
|
||||
} else {
|
||||
fabScreen.setClickable(true);
|
||||
fabScreen.startAnimation(fab_open_screen);
|
||||
fab.startAnimation(rotate_forward);
|
||||
fabNewL.startAnimation(fab_open);
|
||||
fabNew.setClickable(true);
|
||||
fabViewL.startAnimation(fab_open);
|
||||
fabView.setClickable(true);
|
||||
fabKeyL.startAnimation(fab_open);
|
||||
fabKey.setClickable(true);
|
||||
fabSeedL.startAnimation(fab_open);
|
||||
fabSeed.setClickable(true);
|
||||
isFabOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int id = v.getId();
|
||||
switch (id) {
|
||||
case R.id.fab:
|
||||
animateFAB();
|
||||
break;
|
||||
case R.id.fabNew:
|
||||
fabScreen.setVisibility(View.INVISIBLE);
|
||||
isFabOpen = false;
|
||||
activityCallback.onAddWallet(isTestnet(), GenerateFragment.TYPE_NEW);
|
||||
break;
|
||||
case R.id.fabView:
|
||||
animateFAB();
|
||||
activityCallback.onAddWallet(isTestnet(), GenerateFragment.TYPE_VIEWONLY);
|
||||
break;
|
||||
case R.id.fabKey:
|
||||
animateFAB();
|
||||
activityCallback.onAddWallet(isTestnet(), GenerateFragment.TYPE_KEY);
|
||||
break;
|
||||
case R.id.fabSeed:
|
||||
animateFAB();
|
||||
activityCallback.onAddWallet(isTestnet(), GenerateFragment.TYPE_SEED);
|
||||
break;
|
||||
case R.id.fabScreen:
|
||||
animateFAB();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,12 +17,11 @@
|
|||
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.design.widget.TextInputLayout;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.text.Editable;
|
||||
import android.text.InputType;
|
||||
|
@ -33,12 +32,11 @@ 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.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
|
@ -48,151 +46,102 @@ 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.layout.ExchangeView;
|
||||
import com.m2049r.xmrwallet.layout.Toolbar;
|
||||
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 implements AsyncExchangeRate.Listener {
|
||||
public class ReceiveFragment extends Fragment {
|
||||
static final String TAG = "ReceiveFragment";
|
||||
|
||||
ProgressBar pbProgress;
|
||||
TextView tvAddress;
|
||||
EditText etPaymentId;
|
||||
EditText etAmount;
|
||||
TextView tvAmountB;
|
||||
TextInputLayout etPaymentId;
|
||||
ExchangeView evAmount;
|
||||
Button bPaymentId;
|
||||
Button bGenerate;
|
||||
ImageView qrCode;
|
||||
EditText etDummy;
|
||||
ImageButton bCopyAddress;
|
||||
|
||||
Spinner sCurrencyA;
|
||||
Spinner sCurrencyB;
|
||||
//String name;
|
||||
|
||||
public interface Listener {
|
||||
void onExchange(AsyncExchangeRate.Listener listener, String currencyA, String currencyB);
|
||||
}
|
||||
void setToolbarButton(int type);
|
||||
|
||||
@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);
|
||||
void setTitle(String title);
|
||||
|
||||
void setSubtitle(String subtitle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
View view = inflater.inflate(R.layout.receive_fragment, container, false);
|
||||
View view = inflater.inflate(R.layout.fragment_receive, container, false);
|
||||
|
||||
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.etAmountA);
|
||||
tvAmountB = (TextView) view.findViewById(R.id.tvAmountB);
|
||||
etPaymentId = (TextInputLayout) view.findViewById(R.id.etPaymentId);
|
||||
evAmount = (ExchangeView) view.findViewById(R.id.evAmount);
|
||||
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);
|
||||
bCopyAddress = (ImageButton) view.findViewById(R.id.bCopyAddress);
|
||||
|
||||
sCurrencyA = (Spinner) view.findViewById(R.id.sCurrencyA);
|
||||
sCurrencyB = (Spinner) view.findViewById(R.id.sCurrencyB);
|
||||
|
||||
etPaymentId.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||
etPaymentId.getEditText().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)) {
|
||||
if (paymentIdOk()) {
|
||||
etAmount.requestFocus();
|
||||
} // otherwise ignore
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
etPaymentId.addTextChangedListener(new TextWatcher() {
|
||||
bCopyAddress.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void afterTextChanged(Editable editable) {
|
||||
qrCode.setImageBitmap(getMoneroLogo());
|
||||
if (paymentIdOk() && amountOk()) {
|
||||
bGenerate.setEnabled(true);
|
||||
} else {
|
||||
bGenerate.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
public void onClick(View v) {
|
||||
copyAddress();
|
||||
}
|
||||
});
|
||||
|
||||
etAmount.setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||
evAmount.setOnNewAmountListener(new ExchangeView.OnNewAmountListener() {
|
||||
@Override
|
||||
public void onNewAmount(String xmr) {
|
||||
Log.d(TAG, "new amount = " + xmr);
|
||||
generateQr();
|
||||
}
|
||||
});
|
||||
/*
|
||||
evAmount.setOnAmountInvalidatedListener(new ExchangeView.OnAmountInvalidatedListener() {
|
||||
@Override
|
||||
public void onAmountInvalidated() {
|
||||
clearQR();
|
||||
}
|
||||
});
|
||||
|
||||
evAmount.setOnFailedExchangeListener(new ExchangeView.OnFailedExchangeListener() {
|
||||
@Override
|
||||
public void onFailedExchange() {
|
||||
Toast.makeText(getActivity(), getString(R.string.message_exchange_failed), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
*/
|
||||
etPaymentId.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)) {
|
||||
if (paymentIdOk() && amountOk()) {
|
||||
Helper.hideKeyboard(getActivity());
|
||||
startExchange();
|
||||
if (checkPaymentId()) { // && evAmount.checkXmrAmount(true)) {
|
||||
generateQr();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
etAmount.addTextChangedListener(new TextWatcher() {
|
||||
etPaymentId.getEditText().addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void afterTextChanged(Editable editable) {
|
||||
tvAmountB.setText("");
|
||||
qrCode.setImageBitmap(getMoneroLogo());
|
||||
if (paymentIdOk() && amountOk()) {
|
||||
bGenerate.setEnabled(true);
|
||||
} else {
|
||||
bGenerate.setEnabled(false);
|
||||
}
|
||||
clearQR();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -207,10 +156,10 @@ public class ReceiveFragment extends Fragment implements AsyncExchangeRate.Liste
|
|||
bPaymentId.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
etPaymentId.setText((Wallet.generatePaymentId()));
|
||||
etPaymentId.setSelection(etPaymentId.getText().length());
|
||||
if (paymentIdOk() && amountOk()) {
|
||||
startExchange();
|
||||
etPaymentId.getEditText().setText((Wallet.generatePaymentId()));
|
||||
etPaymentId.getEditText().setSelection(etPaymentId.getEditText().getText().length());
|
||||
if (checkPaymentId()) { //&& evAmount.checkXmrAmount(true)) {
|
||||
generateQr();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -218,101 +167,82 @@ public class ReceiveFragment extends Fragment implements AsyncExchangeRate.Liste
|
|||
bGenerate.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (paymentIdOk() && amountOk()) {
|
||||
Helper.hideKeyboard(getActivity());
|
||||
startExchange();
|
||||
if (checkPaymentId()) {
|
||||
evAmount.doExchange();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
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());
|
||||
clearQR();
|
||||
|
||||
Bundle b = getArguments();
|
||||
String address = b.getString("address");
|
||||
String walletName = b.getString("name");
|
||||
Log.d(TAG, "address=" + address + "/name=" + walletName);
|
||||
if (address == null) {
|
||||
String path = b.getString("path");
|
||||
String password = b.getString("password");
|
||||
show(path, password);
|
||||
loadAndShow(path, password);
|
||||
} else {
|
||||
show(address);
|
||||
show(walletName, address);
|
||||
}
|
||||
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("");
|
||||
}
|
||||
void copyAddress() {
|
||||
Helper.clipBoardCopy(getActivity(), getString(R.string.label_copy_address), tvAddress.getText().toString());
|
||||
Toast.makeText(getActivity(), getString(R.string.message_copy_address), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
boolean qrValid = true;
|
||||
|
||||
void clearQR() {
|
||||
if (qrValid) {
|
||||
qrCode.setImageBitmap(getMoneroLogo());
|
||||
qrValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
void setQR(Bitmap qr) {
|
||||
qrCode.setImageBitmap(qr);
|
||||
qrValid = true;
|
||||
Helper.hideKeyboard(getActivity());
|
||||
etDummy.requestFocus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
Log.d(TAG, "onResume()");
|
||||
if (paymentIdOk() && amountOk() && tvAddress.getText().length() > 0) {
|
||||
startExchange();
|
||||
}
|
||||
listenerCallback.setToolbarButton(Toolbar.BUTTON_BACK);
|
||||
listenerCallback.setSubtitle(getString(R.string.receive_title));
|
||||
generateQr();
|
||||
}
|
||||
|
||||
private void show(String address) {
|
||||
private void show(String name, String address) {
|
||||
Log.d(TAG, "name=" + name);
|
||||
listenerCallback.setTitle(name);
|
||||
tvAddress.setText(address);
|
||||
etPaymentId.setEnabled(true);
|
||||
etAmount.setEnabled(true);
|
||||
//etAmount.setEnabled(true);
|
||||
bPaymentId.setEnabled(true);
|
||||
bGenerate.setEnabled(true);
|
||||
bCopyAddress.setEnabled(true);
|
||||
bCopyAddress.setImageResource(R.drawable.ic_content_copy_black_24dp);
|
||||
hideProgress();
|
||||
startExchange();
|
||||
generateQr();
|
||||
}
|
||||
|
||||
private void show(String walletPath, String password) {
|
||||
private void loadAndShow(String walletPath, String password) {
|
||||
new AsyncShow().executeOnExecutor(MoneroThreadPoolExecutor.MONERO_THREAD_POOL_EXECUTOR,
|
||||
walletPath, password);
|
||||
}
|
||||
|
||||
private class AsyncShow extends AsyncTask<String, Void, Boolean> {
|
||||
String password;
|
||||
|
||||
String address;
|
||||
String name;
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(String... params) {
|
||||
|
@ -321,6 +251,7 @@ public class ReceiveFragment extends Fragment implements AsyncExchangeRate.Liste
|
|||
password = params[1];
|
||||
Wallet wallet = WalletManager.getInstance().openWallet(walletPath, password);
|
||||
address = wallet.getAddress();
|
||||
name = wallet.getName();
|
||||
wallet.close();
|
||||
return true;
|
||||
}
|
||||
|
@ -328,8 +259,9 @@ public class ReceiveFragment extends Fragment implements AsyncExchangeRate.Liste
|
|||
@Override
|
||||
protected void onPostExecute(Boolean result) {
|
||||
super.onPostExecute(result);
|
||||
if (!isAdded()) return; // never mind
|
||||
if (result) {
|
||||
show(address);
|
||||
show(name, address);
|
||||
} else {
|
||||
Toast.makeText(getActivity(), getString(R.string.receive_cannot_open), Toast.LENGTH_LONG).show();
|
||||
hideProgress();
|
||||
|
@ -337,22 +269,29 @@ public class ReceiveFragment extends Fragment implements AsyncExchangeRate.Liste
|
|||
}
|
||||
}
|
||||
|
||||
private boolean checkPaymentId() {
|
||||
String paymentId = etPaymentId.getEditText().getText().toString();
|
||||
boolean ok = paymentId.isEmpty() || Wallet.isPaymentIdValid(paymentId);
|
||||
|
||||
private boolean amountOk() {
|
||||
String amountEntry = etAmount.getText().toString();
|
||||
if (amountEntry.isEmpty()) return true;
|
||||
long amount = Wallet.getAmountFromString(amountEntry);
|
||||
return (amount > 0);
|
||||
if (!ok) {
|
||||
etPaymentId.setError(getString(R.string.receive_paymentid_invalid));
|
||||
} else {
|
||||
etPaymentId.setError(null);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
private boolean paymentIdOk() {
|
||||
String paymentId = etPaymentId.getText().toString();
|
||||
return paymentId.isEmpty() || Wallet.isPaymentIdValid(paymentId);
|
||||
}
|
||||
|
||||
private void generateQr(String xmrAmount) {
|
||||
private void generateQr() {
|
||||
Log.d(TAG, "GENQR");
|
||||
String address = tvAddress.getText().toString();
|
||||
String paymentId = etPaymentId.getText().toString();
|
||||
String paymentId = etPaymentId.getEditText().getText().toString();
|
||||
String xmrAmount = evAmount.getAmount();
|
||||
Log.d(TAG, xmrAmount + "/" + paymentId + "/" + address);
|
||||
if ((xmrAmount == null) || !Wallet.isAddressValid(address, WalletManager.getInstance().isTestNet())) {
|
||||
clearQR();
|
||||
Log.d(TAG, "CLEARQR");
|
||||
return;
|
||||
}
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(ScannerFragment.QR_SCHEME).append(address);
|
||||
boolean first = true;
|
||||
|
@ -374,9 +313,10 @@ public class ReceiveFragment extends Fragment implements AsyncExchangeRate.Liste
|
|||
String text = sb.toString();
|
||||
Bitmap qr = generate(text, 500, 500);
|
||||
if (qr != null) {
|
||||
qrCode.setImageBitmap(qr);
|
||||
setQR(qr);
|
||||
Log.d(TAG, "SETQR");
|
||||
etDummy.requestFocus();
|
||||
bGenerate.setEnabled(false);
|
||||
Helper.hideKeyboard(getActivity());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -439,7 +379,6 @@ public class ReceiveFragment extends Fragment implements AsyncExchangeRate.Liste
|
|||
}
|
||||
|
||||
public void showProgress() {
|
||||
pbProgress.setIndeterminate(true);
|
||||
pbProgress.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
|
@ -463,36 +402,9 @@ public class ReceiveFragment extends Fragment implements AsyncExchangeRate.Liste
|
|||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@ import android.widget.Toast;
|
|||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.Result;
|
||||
import com.m2049r.xmrwallet.util.BarcodeData;
|
||||
|
||||
import me.dm7.barcodescanner.zxing.ZXingScannerView;
|
||||
|
||||
|
@ -64,7 +63,6 @@ public class ScannerFragment extends Fragment implements ZXingScannerView.Result
|
|||
|
||||
@Override
|
||||
public void handleResult(Result rawResult) {
|
||||
//Log.d(TAG, rawResult.getBarcodeFormat().toString() + "/" + rawResult.getText());
|
||||
if ((rawResult.getBarcodeFormat() == BarcodeFormat.QR_CODE) &&
|
||||
(rawResult.getText().startsWith(QR_SCHEME))) {
|
||||
if (activityCallback.onAddressScanned(rawResult.getText())) {
|
||||
|
@ -101,7 +99,6 @@ public class ScannerFragment extends Fragment implements ZXingScannerView.Result
|
|||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
//Log.d(TAG, "attaching scan");
|
||||
if (context instanceof Listener) {
|
||||
this.activityCallback = (Listener) context;
|
||||
} else {
|
||||
|
|
|
@ -20,11 +20,10 @@ import android.content.Context;
|
|||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.design.widget.TextInputLayout;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.text.Editable;
|
||||
import android.text.InputType;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -35,24 +34,36 @@ import android.widget.Button;
|
|||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.m2049r.xmrwallet.layout.ExchangeView;
|
||||
import com.m2049r.xmrwallet.layout.Toolbar;
|
||||
import com.m2049r.xmrwallet.model.PendingTransaction;
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.model.WalletManager;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.util.AsyncExchangeRate;
|
||||
import com.m2049r.xmrwallet.util.BarcodeData;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.util.TxData;
|
||||
|
||||
public class SendFragment extends Fragment {
|
||||
static final String TAG = "SendFragment";
|
||||
|
||||
EditText etAddress;
|
||||
EditText etPaymentId;
|
||||
EditText etAmount;
|
||||
EditText etDummy;
|
||||
|
||||
ScrollView scrollview;
|
||||
|
||||
TextInputLayout etAddress;
|
||||
TextInputLayout etPaymentId;
|
||||
//TextInputLayout etAmount;
|
||||
ExchangeView evAmount;
|
||||
TextView tvAmountB;
|
||||
Spinner sCurrencyA;
|
||||
Spinner sCurrencyB;
|
||||
|
||||
Button bScan;
|
||||
Button bSweep;
|
||||
Spinner sMixin;
|
||||
Spinner sPriority;
|
||||
Button bPrepareSend;
|
||||
|
@ -61,7 +72,8 @@ public class SendFragment extends Fragment {
|
|||
LinearLayout llConfirmSend;
|
||||
TextView tvTxAmount;
|
||||
TextView tvTxFee;
|
||||
TextView tvTxDust;
|
||||
//TextView tvTxDust;
|
||||
TextView tvTxTotal;
|
||||
EditText etNotes;
|
||||
Button bSend;
|
||||
Button bReallySend;
|
||||
|
@ -78,15 +90,23 @@ public class SendFragment extends Fragment {
|
|||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
View view = inflater.inflate(R.layout.send_fragment, container, false);
|
||||
View view = inflater.inflate(R.layout.fragment_send, container, false);
|
||||
|
||||
etDummy = (EditText) view.findViewById(R.id.etDummy);
|
||||
etDummy.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||
|
||||
scrollview = (ScrollView) view.findViewById(R.id.scrollview);
|
||||
|
||||
sMixin = (Spinner) view.findViewById(R.id.sMixin);
|
||||
sPriority = (Spinner) view.findViewById(R.id.sPriority);
|
||||
etAddress = (EditText) view.findViewById(R.id.etAddress);
|
||||
etPaymentId = (EditText) view.findViewById(R.id.etPaymentId);
|
||||
etAmount = (EditText) view.findViewById(R.id.etAmount);
|
||||
etAddress = (TextInputLayout) view.findViewById(R.id.etAddress);
|
||||
etPaymentId = (TextInputLayout) view.findViewById(R.id.etPaymentId);
|
||||
evAmount = (ExchangeView) view.findViewById(R.id.evAmount);
|
||||
tvAmountB = (TextView) view.findViewById(R.id.tvAmountB);
|
||||
sCurrencyA = (Spinner) view.findViewById(R.id.sCurrencyA);
|
||||
sCurrencyB = (Spinner) view.findViewById(R.id.sCurrencyB);
|
||||
|
||||
bScan = (Button) view.findViewById(R.id.bScan);
|
||||
bSweep = (Button) view.findViewById(R.id.bSweep);
|
||||
bPrepareSend = (Button) view.findViewById(R.id.bPrepareSend);
|
||||
bPaymentId = (Button) view.findViewById(R.id.bPaymentId);
|
||||
bDispose = (Button) view.findViewById(R.id.bDispose);
|
||||
|
@ -94,101 +114,64 @@ public class SendFragment extends Fragment {
|
|||
llConfirmSend = (LinearLayout) view.findViewById(R.id.llConfirmSend);
|
||||
tvTxAmount = (TextView) view.findViewById(R.id.tvTxAmount);
|
||||
tvTxFee = (TextView) view.findViewById(R.id.tvTxFee);
|
||||
tvTxDust = (TextView) view.findViewById(R.id.tvTxDust);
|
||||
//tvTxDust = (TextView) view.findViewById(R.id.tvTxDust);
|
||||
tvTxTotal = (TextView) view.findViewById(R.id.tvTxTotal);
|
||||
etNotes = (EditText) view.findViewById(R.id.etNotes);
|
||||
bSend = (Button) view.findViewById(R.id.bSend);
|
||||
bReallySend = (Button) view.findViewById(R.id.bReallySend);
|
||||
|
||||
pbProgress = (ProgressBar) view.findViewById(R.id.pbProgress);
|
||||
|
||||
etAddress.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||
etPaymentId.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||
etAddress.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||
etPaymentId.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||
etNotes.setRawInputType(InputType.TYPE_CLASS_TEXT);
|
||||
|
||||
Helper.showKeyboard(getActivity());
|
||||
etAddress.requestFocus();
|
||||
etAddress.setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||
etAddress.getEditText().requestFocus();
|
||||
etAddress.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_NEXT)) {
|
||||
if (addressOk()) {
|
||||
if (checkAddress()) {
|
||||
evAmount.focus();
|
||||
} // otherwise ignore
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
evAmount.setOnNewAmountListener(new ExchangeView.OnNewAmountListener() {
|
||||
@Override
|
||||
public void onNewAmount(String xmr) {
|
||||
if ((xmr != null)) {
|
||||
// stupid workaround to not show error on open of screen
|
||||
if ((checkAddressNoError() && checkAmountWithError()) || checkAmount()) {
|
||||
etPaymentId.requestFocus();
|
||||
} // otherwise ignore
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
etAddress.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void afterTextChanged(Editable editable) {
|
||||
if (addressOk() && amountOk()) {
|
||||
bPrepareSend.setEnabled(true);
|
||||
} else {
|
||||
bPrepareSend.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
});
|
||||
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)) {
|
||||
if (paymentIdOk()) {
|
||||
etAmount.requestFocus();
|
||||
} // otherwise ignore
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
etAmount.setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||
etPaymentId.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)) {
|
||||
if (amountOk()) {
|
||||
if (checkPaymentId()) {
|
||||
etDummy.requestFocus();
|
||||
Helper.hideKeyboard(getActivity());
|
||||
disableEdit();
|
||||
prepareSend();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
etAmount.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void afterTextChanged(Editable editable) {
|
||||
if (addressOk() && amountOk()) {
|
||||
bPrepareSend.setEnabled(true);
|
||||
} else {
|
||||
bPrepareSend.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
});
|
||||
|
||||
setPrepareButtonState();
|
||||
bPrepareSend.setOnClickListener(new View.OnClickListener()
|
||||
|
||||
{
|
||||
bPrepareSend.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Helper.hideKeyboard(getActivity());
|
||||
disableEdit();
|
||||
prepareSend();
|
||||
if (checkAddress() && checkAmountWithError() && checkPaymentId()) {
|
||||
Helper.hideKeyboard(getActivity());
|
||||
prepareSend();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -210,27 +193,15 @@ public class SendFragment extends Fragment {
|
|||
bPaymentId.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
etPaymentId.setText((Wallet.generatePaymentId()));
|
||||
etPaymentId.setSelection(etPaymentId.getText().length());
|
||||
}
|
||||
});
|
||||
|
||||
bSweep.setOnClickListener(new View.OnClickListener()
|
||||
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Helper.hideKeyboard(getActivity());
|
||||
prepareSweep();
|
||||
etPaymentId.getEditText().setText((Wallet.generatePaymentId()));
|
||||
etPaymentId.getEditText().setSelection(etPaymentId.getEditText().getText().length());
|
||||
}
|
||||
});
|
||||
|
||||
etNotes.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)) {
|
||||
if (amountOk()) {
|
||||
Helper.hideKeyboard(getActivity());
|
||||
}
|
||||
Helper.hideKeyboard(getActivity());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -242,8 +213,8 @@ public class SendFragment extends Fragment {
|
|||
public void onClick(View v) {
|
||||
bSend.setEnabled(false);
|
||||
boolean testnet = WalletManager.getInstance().isTestNet();
|
||||
if (testnet) {
|
||||
send();
|
||||
if (!testnet) {
|
||||
//send();
|
||||
} else {
|
||||
etNotes.setEnabled(false);
|
||||
Handler handler = new Handler();
|
||||
|
@ -251,6 +222,13 @@ public class SendFragment extends Fragment {
|
|||
@Override
|
||||
public void run() {
|
||||
bReallySend.setVisibility(View.VISIBLE);
|
||||
bReallySend.setEnabled(true);
|
||||
scrollview.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
scrollview.fullScroll(ScrollView.FOCUS_DOWN);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
@ -264,40 +242,64 @@ public class SendFragment extends Fragment {
|
|||
send();
|
||||
}
|
||||
});
|
||||
|
||||
etDummy.requestFocus();
|
||||
Helper.hideKeyboard(getActivity());
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
private void setPrepareButtonState() {
|
||||
if (addressOk() && amountOk() && (bSend.getVisibility() != View.VISIBLE)) {
|
||||
bPrepareSend.setEnabled(true);
|
||||
} else {
|
||||
bPrepareSend.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean addressOk() {
|
||||
String address = etAddress.getText().toString();
|
||||
private boolean checkAddressNoError() {
|
||||
String address = etAddress.getEditText().getText().toString();
|
||||
return Wallet.isAddressValid(address, WalletManager.getInstance().isTestNet());
|
||||
}
|
||||
|
||||
private boolean amountOk() {
|
||||
long amount = Wallet.getAmountFromString(etAmount.getText().toString());
|
||||
return (amount > 0);
|
||||
private boolean checkAddress() {
|
||||
boolean ok = checkAddressNoError();
|
||||
if (!ok) {
|
||||
etAddress.setError(getString(R.string.send_qr_address_invalid));
|
||||
} else {
|
||||
etAddress.setError(null);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
private boolean paymentIdOk() {
|
||||
String paymentId = etPaymentId.getText().toString();
|
||||
return paymentId.isEmpty() || Wallet.isPaymentIdValid(paymentId);
|
||||
private boolean checkAmount() {
|
||||
String xmr = evAmount.getAmount();
|
||||
return (xmr != null) && (Wallet.getAmountFromString(xmr) > 0);
|
||||
}
|
||||
|
||||
private boolean checkAmountWithError() {
|
||||
boolean ok = checkAmount();
|
||||
if (!ok) {
|
||||
evAmount.setError(getString(R.string.receive_amount_empty));
|
||||
} else {
|
||||
evAmount.setError(null);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
private boolean checkPaymentId() {
|
||||
String paymentId = etPaymentId.getEditText().getText().toString();
|
||||
boolean ok = paymentId.isEmpty() || Wallet.isPaymentIdValid(paymentId);
|
||||
if (!ok) {
|
||||
etPaymentId.setError(getString(R.string.receive_paymentid_invalid));
|
||||
} else {
|
||||
etPaymentId.setError(null);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
private void prepareSend() {
|
||||
String dst_addr = etAddress.getText().toString();
|
||||
String paymentId = etPaymentId.getText().toString();
|
||||
long amount = Wallet.getAmountFromString(etAmount.getText().toString());
|
||||
etDummy.requestFocus();
|
||||
disableEdit();
|
||||
String dst_addr = etAddress.getEditText().getText().toString();
|
||||
String paymentId = etPaymentId.getEditText().getText().toString();
|
||||
long amount = Wallet.getAmountFromString(evAmount.getAmount());
|
||||
int mixin = Mixins[sMixin.getSelectedItemPosition()];
|
||||
int priorityIndex = sPriority.getSelectedItemPosition();
|
||||
PendingTransaction.Priority priority = Priorities[priorityIndex];
|
||||
//Log.d(TAG, dst_addr + "/" + paymentId + "/" + amount + "/" + mixin + "/" + priority.toString());
|
||||
Log.d(TAG, dst_addr + "/" + paymentId + "/" + amount + "/" + mixin + "/" + priority.toString());
|
||||
TxData txData = new TxData(
|
||||
dst_addr,
|
||||
paymentId,
|
||||
|
@ -308,105 +310,106 @@ public class SendFragment extends Fragment {
|
|||
activityCallback.onPrepareSend(txData);
|
||||
}
|
||||
|
||||
private void prepareSweep() {
|
||||
etAddress.setText(activityCallback.getWalletAddress());
|
||||
etPaymentId.setText("");
|
||||
etAmount.setText("");
|
||||
disableEdit();
|
||||
showProgress();
|
||||
activityCallback.onPrepareSweep();
|
||||
}
|
||||
|
||||
private void disableEdit() {
|
||||
sMixin.setEnabled(false);
|
||||
sPriority.setEnabled(false);
|
||||
etAddress.setEnabled(false);
|
||||
etPaymentId.setEnabled(false);
|
||||
etAmount.setEnabled(false);
|
||||
etAddress.getEditText().setEnabled(false);
|
||||
etPaymentId.getEditText().setEnabled(false);
|
||||
evAmount.enable(false);
|
||||
bScan.setEnabled(false);
|
||||
bPaymentId.setEnabled(false);
|
||||
bSweep.setEnabled(false);
|
||||
bPrepareSend.setEnabled(false);
|
||||
bPrepareSend.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
private void enableEdit() {
|
||||
sMixin.setEnabled(true);
|
||||
sPriority.setEnabled(true);
|
||||
etAddress.setEnabled(true);
|
||||
etPaymentId.setEnabled(true);
|
||||
etAmount.setEnabled(true);
|
||||
etAddress.getEditText().setEnabled(true);
|
||||
etPaymentId.getEditText().setEnabled(true);
|
||||
evAmount.enable(true);
|
||||
bScan.setEnabled(true);
|
||||
bPaymentId.setEnabled(true);
|
||||
bSweep.setEnabled(true);
|
||||
bPrepareSend.setEnabled(true);
|
||||
bPrepareSend.setVisibility(View.VISIBLE);
|
||||
|
||||
llConfirmSend.setVisibility(View.GONE);
|
||||
bSend.setEnabled(true);
|
||||
etNotes.setEnabled(true);
|
||||
bSend.setEnabled(false);
|
||||
bReallySend.setVisibility(View.GONE);
|
||||
bReallySend.setEnabled(false);
|
||||
etDummy.requestFocus();
|
||||
}
|
||||
|
||||
private void send() {
|
||||
etNotes.setEnabled(false);
|
||||
etDummy.requestFocus();
|
||||
String notes = etNotes.getText().toString();
|
||||
activityCallback.onSend(notes);
|
||||
}
|
||||
|
||||
SendFragment.Listener activityCallback;
|
||||
Listener activityCallback;
|
||||
|
||||
public interface Listener {
|
||||
void onPrepareSend(TxData data);
|
||||
|
||||
void onPrepareSweep();
|
||||
|
||||
void onSend(String notes);
|
||||
|
||||
String getWalletAddress();
|
||||
|
||||
String getWalletName();
|
||||
|
||||
void onDisposeRequest();
|
||||
|
||||
void onScanAddress();
|
||||
|
||||
BarcodeData getScannedData();
|
||||
BarcodeData popScannedData();
|
||||
|
||||
void onExchange(AsyncExchangeRate.Listener listener, String currencyA, String currencyB);
|
||||
|
||||
void setSubtitle(String subtitle);
|
||||
|
||||
void setToolbarButton(int type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
Log.d(TAG, "onResume");
|
||||
BarcodeData data = activityCallback.getScannedData();
|
||||
activityCallback.setToolbarButton(Toolbar.BUTTON_BACK);
|
||||
activityCallback.setSubtitle(getString(R.string.send_title));
|
||||
BarcodeData data = activityCallback.popScannedData();
|
||||
if (data != null) {
|
||||
Log.d(TAG, "GOT DATA");
|
||||
String scannedAddress = data.address;
|
||||
if (scannedAddress != null) {
|
||||
etAddress.setText(scannedAddress);
|
||||
etAddress.getEditText().setText(scannedAddress);
|
||||
checkAddress();
|
||||
} else {
|
||||
etAddress.getText().clear();
|
||||
etAddress.getEditText().getText().clear();
|
||||
etAddress.setError(null);
|
||||
}
|
||||
String scannedPaymenId = data.paymentId;
|
||||
if (scannedPaymenId != null) {
|
||||
etPaymentId.setText(scannedPaymenId);
|
||||
etPaymentId.getEditText().setText(scannedPaymenId);
|
||||
checkPaymentId();
|
||||
} else {
|
||||
etPaymentId.getText().clear();
|
||||
etPaymentId.getEditText().getText().clear();
|
||||
etPaymentId.setError(null);
|
||||
}
|
||||
if (data.amount >= 0) {
|
||||
if (data.amount > 0) {
|
||||
String scannedAmount = Helper.getDisplayAmount(data.amount);
|
||||
etAmount.setText(scannedAmount);
|
||||
evAmount.setAmount(scannedAmount);
|
||||
} else {
|
||||
etAmount.getText().clear();
|
||||
}
|
||||
etAmount.requestFocus();
|
||||
etAmount.setSelection(etAmount.getText().length());
|
||||
} else { // no scan data
|
||||
// jump to first empty field
|
||||
if (etAddress.getText().toString().isEmpty()) {
|
||||
etAddress.requestFocus();
|
||||
} else if (etPaymentId.getText().toString().isEmpty()) {
|
||||
etPaymentId.requestFocus();
|
||||
} else {
|
||||
etAmount.requestFocus();
|
||||
etAmount.setSelection(etAmount.getText().length());
|
||||
evAmount.setAmount("");
|
||||
}
|
||||
}
|
||||
if ((data != null) && (data.amount <= 0)) {
|
||||
evAmount.focus();
|
||||
} else {
|
||||
etDummy.requestFocus();
|
||||
Helper.hideKeyboard(getActivity());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -427,9 +430,18 @@ public class SendFragment extends Fragment {
|
|||
return;
|
||||
}
|
||||
llConfirmSend.setVisibility(View.VISIBLE);
|
||||
bSend.setEnabled(true);
|
||||
tvTxAmount.setText(Wallet.getDisplayAmount(pendingTransaction.getAmount()));
|
||||
tvTxFee.setText(Wallet.getDisplayAmount(pendingTransaction.getFee()));
|
||||
tvTxDust.setText(Wallet.getDisplayAmount(pendingTransaction.getDust()));
|
||||
//tvTxDust.setText(Wallet.getDisplayAmount(pendingTransaction.getDust()));
|
||||
tvTxTotal.setText(Wallet.getDisplayAmount(
|
||||
pendingTransaction.getFee() + pendingTransaction.getAmount()));
|
||||
scrollview.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
scrollview.fullScroll(ScrollView.FOCUS_DOWN);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void onCreatedTransactionFailed(String errorText) {
|
||||
|
@ -456,4 +468,5 @@ public class SendFragment extends Fragment {
|
|||
public void hideProgress() {
|
||||
pbProgress.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,19 +16,22 @@
|
|||
|
||||
package com.m2049r.xmrwallet;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.text.InputType;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.m2049r.xmrwallet.layout.Toolbar;
|
||||
import com.m2049r.xmrwallet.model.TransactionInfo;
|
||||
import com.m2049r.xmrwallet.model.Transfer;
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
|
@ -64,14 +67,13 @@ public class TxFragment extends Fragment {
|
|||
TextView tvTxFee;
|
||||
TextView tvTxTransfers;
|
||||
TextView etTxNotes;
|
||||
Button bCopy;
|
||||
Button bTxNotes;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
View view = inflater.inflate(R.layout.tx_fragment, container, false);
|
||||
View view = inflater.inflate(R.layout.fragment_tx_info, container, false);
|
||||
|
||||
tvTxTimestamp = (TextView) view.findViewById(R.id.tvTxTimestamp);
|
||||
tvTxId = (TextView) view.findViewById(R.id.tvTxId);
|
||||
|
@ -83,18 +85,10 @@ public class TxFragment extends Fragment {
|
|||
tvTxFee = (TextView) view.findViewById(R.id.tvTxFee);
|
||||
tvTxTransfers = (TextView) view.findViewById(R.id.tvTxTransfers);
|
||||
etTxNotes = (TextView) view.findViewById(R.id.etTxNotes);
|
||||
bCopy = (Button) view.findViewById(R.id.bCopy);
|
||||
bTxNotes = (Button) view.findViewById(R.id.bTxNotes);
|
||||
|
||||
etTxNotes.setRawInputType(InputType.TYPE_CLASS_TEXT);
|
||||
|
||||
bCopy.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
copyToClipboard();
|
||||
}
|
||||
});
|
||||
|
||||
bTxNotes.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
@ -119,28 +113,35 @@ public class TxFragment extends Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
void copyToClipboard() {
|
||||
void shareTxInfo() {
|
||||
if (this.info == null) return;
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(getString(R.string.tx_address)).append(": ");
|
||||
sb.append(activityCallback.getWalletAddress()).append("\n");
|
||||
sb.append(getString(R.string.tx_id)).append(": ");
|
||||
sb.append(info.hash).append("\n");
|
||||
sb.append(getString(R.string.tx_key)).append(": ");
|
||||
sb.append(info.txKey.isEmpty() ? "-" : info.txKey).append("\n");
|
||||
sb.append(getString(R.string.tx_paymentId)).append(": ");
|
||||
sb.append(info.paymentId).append("\n");
|
||||
sb.append(getString(R.string.tx_amount)).append(": ");
|
||||
|
||||
sb.append(getString(R.string.tx_timestamp)).append(":\n");
|
||||
sb.append(TS_FORMATTER.format(new Date(info.timestamp * 1000))).append("\n\n");
|
||||
|
||||
sb.append(getString(R.string.tx_amount)).append(":\n");
|
||||
sb.append((info.direction == TransactionInfo.Direction.Direction_In ? "+" : "-"));
|
||||
sb.append(Wallet.getDisplayAmount(info.amount)).append("\n");
|
||||
sb.append(getString(R.string.tx_fee)).append(": ");
|
||||
sb.append(Wallet.getDisplayAmount(info.fee)).append("\n");
|
||||
sb.append(getString(R.string.tx_notes)).append(": ");
|
||||
sb.append(getString(R.string.tx_fee)).append(":\n");
|
||||
sb.append(Wallet.getDisplayAmount(info.fee)).append("\n\n");
|
||||
|
||||
sb.append(getString(R.string.tx_notes)).append(":\n");
|
||||
String oneLineNotes = info.notes.replace("\n", " ; ");
|
||||
sb.append(oneLineNotes.isEmpty() ? "-" : oneLineNotes).append("\n");
|
||||
sb.append(getString(R.string.tx_timestamp)).append(": ");
|
||||
sb.append(TS_FORMATTER.format(new Date(info.timestamp * 1000))).append("\n");
|
||||
sb.append(getString(R.string.tx_blockheight)).append(": ");
|
||||
sb.append(oneLineNotes.isEmpty() ? "-" : oneLineNotes).append("\n\n");
|
||||
|
||||
sb.append(getString(R.string.tx_destination)).append(":\n");
|
||||
sb.append(tvDestination.getText()).append("\n\n");
|
||||
|
||||
sb.append(getString(R.string.tx_paymentId)).append(":\n");
|
||||
sb.append(info.paymentId).append("\n\n");
|
||||
|
||||
sb.append(getString(R.string.tx_id)).append(":\n");
|
||||
sb.append(info.hash).append("\n");
|
||||
sb.append(getString(R.string.tx_key)).append(":\n");
|
||||
sb.append(info.txKey.isEmpty() ? "-" : info.txKey).append("\n\n");
|
||||
|
||||
sb.append(getString(R.string.tx_blockheight)).append(":\n");
|
||||
if (info.isFailed) {
|
||||
sb.append(getString(R.string.tx_failed)).append("\n");
|
||||
} else if (info.isPending) {
|
||||
|
@ -148,7 +149,9 @@ public class TxFragment extends Fragment {
|
|||
} else {
|
||||
sb.append(info.blockheight).append("\n");
|
||||
}
|
||||
sb.append(getString(R.string.tx_transfers)).append(": ");
|
||||
sb.append("\n");
|
||||
|
||||
sb.append(getString(R.string.tx_transfers)).append(":\n");
|
||||
if (info.transfers != null) {
|
||||
boolean comma = false;
|
||||
for (Transfer transfer : info.transfers) {
|
||||
|
@ -163,12 +166,14 @@ public class TxFragment extends Fragment {
|
|||
} else {
|
||||
sb.append("-");
|
||||
}
|
||||
sb.append("\n");
|
||||
ClipboardManager clipboardManager = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
ClipData clip = ClipData.newPlainText(getString(R.string.tx_copy_label), sb.toString());
|
||||
clipboardManager.setPrimaryClip(clip);
|
||||
Toast.makeText(getActivity(), getString(R.string.tx_copy_message), Toast.LENGTH_SHORT).show();
|
||||
//Log.d(TAG, sb.toString());
|
||||
sb.append("\n\n");
|
||||
//Helper.clipBoardCopy(getActivity(), getString(R.string.tx_copy_label), sb.toString());
|
||||
//Toast.makeText(getActivity(), getString(R.string.tx_copy_message), Toast.LENGTH_SHORT).show();
|
||||
Intent sendIntent = new Intent();
|
||||
sendIntent.setAction(Intent.ACTION_SEND);
|
||||
sendIntent.putExtra(Intent.EXTRA_TEXT, sb.toString());
|
||||
sendIntent.setType("text/plain");
|
||||
startActivity(Intent.createChooser(sendIntent, null));
|
||||
}
|
||||
|
||||
TransactionInfo info = null;
|
||||
|
@ -176,17 +181,24 @@ public class TxFragment extends Fragment {
|
|||
void loadNotes(TransactionInfo info) {
|
||||
if (info.notes == null) {
|
||||
info.notes = activityCallback.getTxNotes(info.hash);
|
||||
//Log.d(TAG, "NOTES:" + info.notes + ":");
|
||||
}
|
||||
etTxNotes.setText(info.notes);
|
||||
}
|
||||
|
||||
private void setTxColour(int clr) {
|
||||
tvTxAmount.setTextColor(clr);
|
||||
tvTxFee.setTextColor(clr);
|
||||
}
|
||||
|
||||
private void show(TransactionInfo info) {
|
||||
if (info.txKey == null) {
|
||||
info.txKey = activityCallback.getTxKey(info.hash);
|
||||
//Log.d(TAG, "TXKEY:" + info.txKey + ":");
|
||||
}
|
||||
loadNotes(info);
|
||||
|
||||
activityCallback.setSubtitle(getString(R.string.tx_title));
|
||||
activityCallback.setToolbarButton(Toolbar.BUTTON_BACK);
|
||||
|
||||
tvTxTimestamp.setText(TS_FORMATTER.format(new Date(info.timestamp * 1000)));
|
||||
tvTxId.setText(info.hash);
|
||||
tvTxKey.setText(info.txKey.isEmpty() ? "-" : info.txKey);
|
||||
|
@ -199,8 +211,30 @@ public class TxFragment extends Fragment {
|
|||
tvTxBlockheight.setText("" + info.blockheight);
|
||||
}
|
||||
String sign = (info.direction == TransactionInfo.Direction.Direction_In ? "+" : "-");
|
||||
|
||||
tvTxAmount.setText(sign + Wallet.getDisplayAmount(info.amount));
|
||||
tvTxFee.setText(Wallet.getDisplayAmount(info.fee));
|
||||
if ((info.fee > 0)) {
|
||||
String fee = Wallet.getDisplayAmount(info.fee);
|
||||
if (info.isPending) {
|
||||
tvTxFee.setText(getString(R.string.tx_list_fee_pending, fee));
|
||||
} else {
|
||||
tvTxFee.setText(getString(R.string.tx_list_fee, fee));
|
||||
}
|
||||
} else {
|
||||
tvTxFee.setText(null);
|
||||
tvTxFee.setVisibility(View.GONE);
|
||||
}
|
||||
if (info.isFailed) {
|
||||
tvTxAmount.setText(getString(R.string.tx_list_amount_failed, Wallet.getDisplayAmount(info.amount)));
|
||||
tvTxFee.setText(getString(R.string.tx_list_failed_text));
|
||||
setTxColour(ContextCompat.getColor(getContext(), R.color.tx_failed));
|
||||
} else if (info.isPending) {
|
||||
setTxColour(ContextCompat.getColor(getContext(), R.color.tx_pending));
|
||||
} else if (info.direction == TransactionInfo.Direction.Direction_In) {
|
||||
setTxColour(ContextCompat.getColor(getContext(), R.color.tx_green));
|
||||
} else {
|
||||
setTxColour(ContextCompat.getColor(getContext(), R.color.tx_red));
|
||||
}
|
||||
Set<String> destinations = new HashSet<>();
|
||||
StringBuffer sb = new StringBuffer();
|
||||
StringBuffer dstSb = new StringBuffer();
|
||||
|
@ -232,10 +266,21 @@ public class TxFragment extends Fragment {
|
|||
tvTxTransfers.setText(sb.toString());
|
||||
tvDestination.setText(dstSb.toString());
|
||||
this.info = info;
|
||||
bCopy.setEnabled(true);
|
||||
}
|
||||
|
||||
TxFragment.Listener activityCallback;
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.tx_info_menu, menu);
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
}
|
||||
|
||||
Listener activityCallback;
|
||||
|
||||
public interface Listener {
|
||||
String getWalletAddress();
|
||||
|
@ -246,6 +291,10 @@ public class TxFragment extends Fragment {
|
|||
|
||||
void onSetNote(String txId, String notes);
|
||||
|
||||
void setToolbarButton(int type);
|
||||
|
||||
void setSubtitle(String subtitle);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package com.m2049r.xmrwallet;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
|
@ -25,7 +24,6 @@ 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;
|
||||
|
@ -34,11 +32,11 @@ import android.support.v4.app.Fragment;
|
|||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.util.Log;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.m2049r.xmrwallet.layout.Toolbar;
|
||||
import com.m2049r.xmrwallet.model.PendingTransaction;
|
||||
import com.m2049r.xmrwallet.model.TransactionInfo;
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
|
@ -49,16 +47,13 @@ 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,
|
||||
GenerateReviewFragment.Listener,
|
||||
ScannerFragment.Listener, ReceiveFragment.Listener {
|
||||
private static final String TAG = "WalletActivity";
|
||||
|
||||
|
@ -67,6 +62,27 @@ public class WalletActivity extends AppCompatActivity implements WalletFragment.
|
|||
|
||||
Toolbar toolbar;
|
||||
|
||||
@Override
|
||||
public void setToolbarButton(int type) {
|
||||
toolbar.setButton(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(String title, String subtitle) {
|
||||
toolbar.setTitle(title, subtitle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(String title) {
|
||||
Log.d(TAG, "setTitle:" + title + ".");
|
||||
toolbar.setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSubtitle(String subtitle) {
|
||||
toolbar.setSubtitle(subtitle);
|
||||
}
|
||||
|
||||
private boolean synced = false;
|
||||
|
||||
@Override
|
||||
|
@ -137,8 +153,11 @@ public class WalletActivity extends AppCompatActivity implements WalletFragment.
|
|||
case R.id.action_info:
|
||||
onWalletDetails();
|
||||
return true;
|
||||
case R.id.action_receive:
|
||||
onWalletReceive();
|
||||
case R.id.action_donate:
|
||||
onWalletDetails();
|
||||
return true;
|
||||
case R.id.action_share:
|
||||
onShareTxInfo();
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
|
@ -157,17 +176,35 @@ public class WalletActivity extends AppCompatActivity implements WalletFragment.
|
|||
return;
|
||||
}
|
||||
|
||||
setContentView(R.layout.wallet_activity);
|
||||
setContentView(R.layout.activity_wallet);
|
||||
toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
getSupportActionBar().setDisplayShowTitleEnabled(false);
|
||||
|
||||
toolbar.setTitle(R.string.app_name);
|
||||
toolbar.setOnButtonListener(new Toolbar.OnButtonListener() {
|
||||
@Override
|
||||
public void onButton(int type) {
|
||||
switch (type) {
|
||||
case Toolbar.BUTTON_BACK:
|
||||
onBackPressed();
|
||||
break;
|
||||
case Toolbar.BUTTON_CLOSE:
|
||||
finish();
|
||||
break;
|
||||
case Toolbar.BUTTON_DONATE:
|
||||
Toast.makeText(WalletActivity.this, getString(R.string.label_donate), Toast.LENGTH_SHORT).show();
|
||||
case Toolbar.BUTTON_NONE:
|
||||
default:
|
||||
Log.e(TAG, "Button " + type + "pressed - how can this be?");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
boolean testnet = WalletManager.getInstance().isTestNet();
|
||||
if (testnet) {
|
||||
toolbar.setBackgroundResource(R.color.colorPrimaryDark);
|
||||
} else {
|
||||
toolbar.setBackgroundResource(R.color.moneroOrange);
|
||||
toolbar.setBackgroundResource(R.drawable.backgound_toolbar_mainnet);
|
||||
}
|
||||
|
||||
Fragment walletFragment = new WalletFragment();
|
||||
|
@ -195,18 +232,15 @@ public class WalletActivity extends AppCompatActivity implements WalletFragment.
|
|||
// service that we know is running in our own process, we can
|
||||
// cast its IBinder to a concrete class and directly access it.
|
||||
mBoundService = ((WalletService.WalletServiceBinder) service).getService();
|
||||
//Log.d(TAG, "setting observer of " + mBoundService);
|
||||
mBoundService.setObserver(WalletActivity.this);
|
||||
Bundle extras = getIntent().getExtras();
|
||||
if (extras != null) {
|
||||
String walletId = extras.getString(REQUEST_ID);
|
||||
if (walletId != null) {
|
||||
setTitle(walletId);
|
||||
setSubtitle("");
|
||||
setTitle(walletId, getString(R.string.status_wallet_connecting));
|
||||
}
|
||||
}
|
||||
updateProgress();
|
||||
//TODO show current pbProgress (eg. if the service is already busy saving last wallet)
|
||||
Log.d(TAG, "CONNECTED");
|
||||
}
|
||||
|
||||
|
@ -216,8 +250,7 @@ public class WalletActivity extends AppCompatActivity implements WalletFragment.
|
|||
// Because it is running in our same process, we should never
|
||||
// see this happen.
|
||||
mBoundService = null;
|
||||
setTitle(getString(R.string.wallet_activity_name));
|
||||
setSubtitle("");
|
||||
setTitle(getString(R.string.wallet_activity_name), getString(R.string.status_wallet_disconnected));
|
||||
Log.d(TAG, "DISCONNECTED");
|
||||
}
|
||||
};
|
||||
|
@ -269,7 +302,7 @@ public class WalletActivity extends AppCompatActivity implements WalletFragment.
|
|||
wl.acquire();
|
||||
Log.d(TAG, "WakeLock acquired");
|
||||
} catch (SecurityException ex) {
|
||||
Log.d(TAG, "WakeLock NOT acquired: " + ex.getLocalizedMessage());
|
||||
Log.w(TAG, "WakeLock NOT acquired: " + ex.getLocalizedMessage());
|
||||
wl = null;
|
||||
}
|
||||
}
|
||||
|
@ -292,9 +325,9 @@ public class WalletActivity extends AppCompatActivity implements WalletFragment.
|
|||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
// WalletFragment.Listener
|
||||
//////////////////////////////////////////
|
||||
//////////////////////////////////////////
|
||||
// WalletFragment.Listener
|
||||
//////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public boolean hasBoundService() {
|
||||
|
@ -311,16 +344,6 @@ public class WalletActivity extends AppCompatActivity implements WalletFragment.
|
|||
return mBoundService.getDaemonHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(String title) {
|
||||
toolbar.setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSubtitle(String subtitle) {
|
||||
toolbar.setSubtitle(subtitle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSendRequest() {
|
||||
replaceFragment(new SendFragment(), null, null);
|
||||
|
@ -342,9 +365,9 @@ public class WalletActivity extends AppCompatActivity implements WalletFragment.
|
|||
}
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
// WalletService.Observer
|
||||
///////////////////////////
|
||||
///////////////////////////
|
||||
// WalletService.Observer
|
||||
///////////////////////////
|
||||
|
||||
// refresh and return if successful
|
||||
@Override
|
||||
|
@ -514,9 +537,9 @@ public class WalletActivity extends AppCompatActivity implements WalletFragment.
|
|||
}
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
// SendFragment.Listener
|
||||
///////////////////////////
|
||||
///////////////////////////
|
||||
// SendFragment.Listener
|
||||
///////////////////////////
|
||||
|
||||
@Override
|
||||
public void onSend(String notes) {
|
||||
|
@ -561,20 +584,13 @@ public class WalletActivity extends AppCompatActivity implements WalletFragment.
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareSweep() {
|
||||
if (mIsBound) { // no point in talking to unbound service
|
||||
Intent intent = new Intent(getApplicationContext(), WalletService.class);
|
||||
intent.putExtra(WalletService.REQUEST, WalletService.REQUEST_CMD_SWEEP);
|
||||
startService(intent);
|
||||
Log.d(TAG, "SWEEP TX request sent");
|
||||
} else {
|
||||
Log.e(TAG, "Service not bound");
|
||||
}
|
||||
public String getWalletAddress() {
|
||||
return getWallet().getAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWalletAddress() {
|
||||
return getWallet().getAddress();
|
||||
public String getWalletName() {
|
||||
return getWallet().getName();
|
||||
}
|
||||
|
||||
void popFragmentStack(String name) {
|
||||
|
@ -619,6 +635,18 @@ public class WalletActivity extends AppCompatActivity implements WalletFragment.
|
|||
.show();
|
||||
}
|
||||
|
||||
void onShareTxInfo() {
|
||||
try {
|
||||
TxFragment fragment = (TxFragment)
|
||||
getSupportFragmentManager().findFragmentById(R.id.fragment_container);
|
||||
fragment.shareTxInfo();
|
||||
} catch (ClassCastException ex) {
|
||||
// not in wallet fragment
|
||||
Log.e(TAG, ex.getLocalizedMessage());
|
||||
// keep calm and carry on
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisposeRequest() {
|
||||
getWallet().disposePendingTransaction();
|
||||
|
@ -710,7 +738,7 @@ public class WalletActivity extends AppCompatActivity implements WalletFragment.
|
|||
|
||||
|
||||
@Override
|
||||
public BarcodeData getScannedData() {
|
||||
public BarcodeData popScannedData() {
|
||||
BarcodeData data = scannedData;
|
||||
scannedData = null;
|
||||
return data;
|
||||
|
@ -745,6 +773,7 @@ public class WalletActivity extends AppCompatActivity implements WalletFragment.
|
|||
Log.d(TAG, "startReceive()");
|
||||
Bundle b = new Bundle();
|
||||
b.putString("address", address);
|
||||
b.putString("name", getWalletName());
|
||||
startReceiveFragment(b);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,22 +19,25 @@ package com.m2049r.xmrwallet;
|
|||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.constraint.ConstraintLayout;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.widget.DividerItemDecoration;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.m2049r.xmrwallet.layout.AsyncExchangeRate;
|
||||
import com.m2049r.xmrwallet.layout.Toolbar;
|
||||
import com.m2049r.xmrwallet.layout.TransactionInfoAdapter;
|
||||
import com.m2049r.xmrwallet.model.TransactionInfo;
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
|
@ -43,19 +46,24 @@ import com.m2049r.xmrwallet.util.Helper;
|
|||
import java.text.NumberFormat;
|
||||
import java.util.List;
|
||||
|
||||
public class WalletFragment extends Fragment implements TransactionInfoAdapter.OnInteractionListener {
|
||||
public class WalletFragment extends Fragment
|
||||
implements TransactionInfoAdapter.OnInteractionListener,
|
||||
AsyncExchangeRate.Listener {
|
||||
private static final String TAG = "WalletFragment";
|
||||
private TransactionInfoAdapter adapter;
|
||||
private NumberFormat formatter = NumberFormat.getInstance();
|
||||
|
||||
FrameLayout flExchange;
|
||||
TextView tvBalance;
|
||||
TextView tvUnconfirmedAmount;
|
||||
TextView tvBlockHeightProgress;
|
||||
ConstraintLayout clProgress;
|
||||
TextView tvProgress;
|
||||
ImageView ivSynced;
|
||||
ProgressBar pbProgress;
|
||||
Button bReceive;
|
||||
Button bSend;
|
||||
|
||||
Spinner sCurrency;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
@ -72,44 +80,145 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
|
|||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.wallet_fragment, container, false);
|
||||
View view = inflater.inflate(R.layout.fragment_wallet, container, false);
|
||||
|
||||
flExchange = (FrameLayout) view.findViewById(R.id.flExchange);
|
||||
((ProgressBar) view.findViewById(R.id.pbExchange)).getIndeterminateDrawable().
|
||||
setColorFilter(getResources().getColor(R.color.trafficGray),
|
||||
android.graphics.PorterDuff.Mode.MULTIPLY);
|
||||
|
||||
tvProgress = (TextView) view.findViewById(R.id.tvProgress);
|
||||
pbProgress = (ProgressBar) view.findViewById(R.id.pbProgress);
|
||||
clProgress = (ConstraintLayout) view.findViewById(R.id.clProgress);
|
||||
tvBalance = (TextView) view.findViewById(R.id.tvBalance);
|
||||
tvBalance.setText(getResources().getString(R.string.xmr_balance, Helper.getDisplayAmount(0)));
|
||||
tvBalance.setText(Helper.getDisplayAmount(0));
|
||||
tvUnconfirmedAmount = (TextView) view.findViewById(R.id.tvUnconfirmedAmount);
|
||||
tvUnconfirmedAmount.setText(getResources().getString(R.string.xmr_unconfirmed_amount, Helper.getDisplayAmount(0)));
|
||||
tvBlockHeightProgress = (TextView) view.findViewById(R.id.tvBlockHeightProgress);
|
||||
ivSynced = (ImageView) view.findViewById(R.id.ivSynced);
|
||||
|
||||
sCurrency = (Spinner) view.findViewById(R.id.sCurrency);
|
||||
sCurrency.setAdapter(ArrayAdapter.createFromResource(getContext(), R.array.currency, R.layout.item_spinner));
|
||||
|
||||
bSend = (Button) view.findViewById(R.id.bSend);
|
||||
bReceive = (Button) view.findViewById(R.id.bReceive);
|
||||
|
||||
RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.list);
|
||||
|
||||
this.adapter = new TransactionInfoAdapter(getActivity(), this);
|
||||
recyclerView.setAdapter(adapter);
|
||||
|
||||
bSend.setOnClickListener(new View.OnClickListener()
|
||||
|
||||
{
|
||||
bSend.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
activityCallback.onSendRequest();
|
||||
}
|
||||
});
|
||||
bReceive.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
activityCallback.onWalletReceive();
|
||||
}
|
||||
});
|
||||
|
||||
sCurrency.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
|
||||
refreshBalance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parentView) {
|
||||
// nothing (yet?)
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (activityCallback.isSynced()) {
|
||||
onSynced();
|
||||
}
|
||||
|
||||
// activityCallback.setTitle(getString(R.string.status_wallet_loading));
|
||||
|
||||
activityCallback.forceUpdate();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
String balanceCurrency = "XMR";
|
||||
double balanceRate = 1.0;
|
||||
|
||||
void refreshBalance() {
|
||||
if (sCurrency.getSelectedItemPosition() == 0) { // XMR
|
||||
double amountXmr = Double.parseDouble(Wallet.getDisplayAmount(unlockedBalance)); // assume this cannot fail!
|
||||
tvBalance.setText(Helper.getFormattedAmount(amountXmr, true));
|
||||
} else { // not XMR
|
||||
String currency = (String) sCurrency.getSelectedItem();
|
||||
if (!currency.equals(balanceCurrency) || (balanceRate <= 0)) {
|
||||
showExchanging();
|
||||
new AsyncExchangeRate(this).execute("XMR", currency);
|
||||
} else {
|
||||
exchange("XMR", balanceCurrency, balanceRate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean isExchanging = false;
|
||||
|
||||
void showExchanging() {
|
||||
isExchanging = true;
|
||||
tvBalance.setVisibility(View.GONE);
|
||||
flExchange.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
void hideExchanging() {
|
||||
isExchanging = false;
|
||||
tvBalance.setVisibility(View.VISIBLE);
|
||||
flExchange.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
// Callbacks from AsyncExchangeRate
|
||||
|
||||
// callback from AsyncExchangeRate when it can't get exchange rate
|
||||
public void exchangeFailed() {
|
||||
sCurrency.setSelection(0, true); // default to XMR
|
||||
double amountXmr = Double.parseDouble(Wallet.getDisplayAmount(unlockedBalance)); // assume this cannot fail!
|
||||
tvBalance.setText(Helper.getFormattedAmount(amountXmr, true));
|
||||
hideExchanging();
|
||||
}
|
||||
|
||||
void updateBalance() {
|
||||
if (isExchanging) return; // wait for exchange to finish - it will fire this itself then.
|
||||
// at this point selection is XMR in case of error
|
||||
String displayB;
|
||||
double amountA = Double.parseDouble(Wallet.getDisplayAmount(unlockedBalance)); // assume this cannot fail!
|
||||
if (!"XMR".equals(balanceCurrency)) { // not XMR
|
||||
double amountB = amountA * balanceRate;
|
||||
displayB = Helper.getFormattedAmount(amountB, false);
|
||||
} else { // XMR
|
||||
displayB = Helper.getFormattedAmount(amountA, true);
|
||||
}
|
||||
tvBalance.setText(displayB);
|
||||
}
|
||||
|
||||
// callback from AsyncExchangeRate when we have a rate
|
||||
public void exchange(String currencyA, String currencyB, double rate) {
|
||||
hideExchanging();
|
||||
if (!"XMR".equals(currencyA)) {
|
||||
Log.e(TAG, "Not XMR");
|
||||
sCurrency.setSelection(0, true);
|
||||
balanceCurrency = "XMR";
|
||||
balanceRate = 1.0;
|
||||
} else {
|
||||
int spinnerPosition = ((ArrayAdapter) sCurrency.getAdapter()).getPosition(currencyB);
|
||||
if (spinnerPosition < 0) { // requested currency not in list
|
||||
Log.e(TAG, "Requested currency not in list " + currencyB);
|
||||
sCurrency.setSelection(0, true);
|
||||
} else {
|
||||
sCurrency.setSelection(spinnerPosition, true);
|
||||
}
|
||||
balanceCurrency = currencyB;
|
||||
balanceRate = rate;
|
||||
}
|
||||
updateBalance();
|
||||
}
|
||||
|
||||
// Callbacks from TransactionInfoAdapter
|
||||
@Override
|
||||
public void onInteraction(final View view, final TransactionInfo infoItem) {
|
||||
|
@ -117,6 +226,7 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
|
|||
}
|
||||
|
||||
// called from activity
|
||||
|
||||
public void onRefreshed(final Wallet wallet, final boolean full) {
|
||||
Log.d(TAG, "onRefreshed()");
|
||||
if (full) {
|
||||
|
@ -134,13 +244,17 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
|
|||
}
|
||||
}
|
||||
|
||||
public void setProgressText(final String text) {
|
||||
tvProgress.setText(text);
|
||||
}
|
||||
|
||||
public void onProgress(final String text) {
|
||||
if (text != null) {
|
||||
tvProgress.setText(text);
|
||||
showProgress();
|
||||
setProgressText(text);
|
||||
pbProgress.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
hideProgress();
|
||||
tvProgress.setText(getString(R.string.status_working));
|
||||
pbProgress.setVisibility(View.INVISIBLE);
|
||||
setProgressText(getString(R.string.status_working));
|
||||
onProgress(-1);
|
||||
}
|
||||
}
|
||||
|
@ -154,48 +268,35 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
|
|||
}
|
||||
}
|
||||
|
||||
public void showProgress() {
|
||||
clProgress.setVisibility(View.VISIBLE);
|
||||
tvBlockHeightProgress.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
public void hideProgress() {
|
||||
clProgress.setVisibility(View.GONE);
|
||||
tvBlockHeightProgress.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
String setActivityTitle(Wallet wallet) {
|
||||
if (wallet == null) return null;
|
||||
String shortName = wallet.getName();
|
||||
if (shortName.length() > 16) {
|
||||
shortName = shortName.substring(0, 14) + "...";
|
||||
}
|
||||
// TODO very very rarely this craches because getAddress returns "" or so ...
|
||||
// maybe because this runs in the ui thread and not in a 5MB thread
|
||||
String title = "[" + wallet.getAddress().substring(0, 6) + "] " + shortName;
|
||||
activityCallback.setTitle(title);
|
||||
|
||||
String watchOnly = (wallet.isWatchOnly() ? " " + getString(R.string.watchonly_label) : "");
|
||||
String net = (wallet.isTestNet() ? getString(R.string.connect_testnet) : getString(R.string.connect_mainnet));
|
||||
activityCallback.setSubtitle(net + " " + watchOnly);
|
||||
Log.d(TAG, "wallet title is " + title);
|
||||
return title;
|
||||
void setActivityTitle(Wallet wallet) {
|
||||
if (wallet == null) return;
|
||||
walletTitle = wallet.getName();
|
||||
String watchOnly = (wallet.isWatchOnly() ? getString(R.string.label_watchonly) : "");
|
||||
walletSubtitle = wallet.getAddress().substring(0, 16) + "…" + watchOnly;
|
||||
activityCallback.setTitle(walletTitle, walletSubtitle);
|
||||
Log.d(TAG, "wallet title is " + walletTitle);
|
||||
}
|
||||
|
||||
private long firstBlock = 0;
|
||||
private String walletTitle = null;
|
||||
private String walletSubtitle = null;
|
||||
private long unlockedBalance = 0;
|
||||
|
||||
private void updateStatus(Wallet wallet) {
|
||||
if (!isAdded()) return;
|
||||
Log.d(TAG, "updateStatus()");
|
||||
if (walletTitle == null) {
|
||||
walletTitle = setActivityTitle(wallet);
|
||||
setActivityTitle(wallet);
|
||||
onProgress(100); // of loading
|
||||
}
|
||||
long balance = wallet.getBalance();
|
||||
long unlockedBalance = wallet.getUnlockedBalance();
|
||||
tvBalance.setText(getResources().getString(R.string.xmr_balance, Helper.getDisplayAmount(unlockedBalance)));
|
||||
tvUnconfirmedAmount.setText(getResources().getString(R.string.xmr_unconfirmed_amount, Helper.getDisplayAmount(balance - unlockedBalance)));
|
||||
unlockedBalance = wallet.getUnlockedBalance();
|
||||
refreshBalance();
|
||||
double amountXmr = Double.parseDouble(Helper.getDisplayAmount(balance - unlockedBalance)); // assume this cannot fail!
|
||||
String unconfirmed = Helper.getFormattedAmount(amountXmr, true);
|
||||
tvUnconfirmedAmount.setText(getResources().getString(R.string.xmr_unconfirmed_amount, unconfirmed));
|
||||
//tvUnconfirmedAmount.setText(getResources().getString(R.string.xmr_unconfirmed_amount,
|
||||
// Helper.getDisplayAmount(balance - unlockedBalance, Helper.DISPLAY_DIGITS_SHORT)));
|
||||
String sync = "";
|
||||
if (!activityCallback.hasBoundService())
|
||||
throw new IllegalStateException("WalletService not bound.");
|
||||
|
@ -212,13 +313,13 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
|
|||
onProgress(getString(R.string.status_syncing) + " " + sync);
|
||||
if (x == 0) x = -1;
|
||||
onProgress(x);
|
||||
ivSynced.setVisibility(View.GONE);
|
||||
} else {
|
||||
sync = getString(R.string.status_synced) + ": " + formatter.format(wallet.getBlockChainHeight());
|
||||
ivSynced.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
tvBlockHeightProgress.setText(sync);
|
||||
//String net = (wallet.isTestNet() ? getString(R.string.connect_testnet) : getString(R.string.connect_mainnet));
|
||||
//activityCallback.setSubtitle(net + " " + daemonConnected.toString().substring(17));
|
||||
setProgressText(sync);
|
||||
// TODO show connected status somewhere
|
||||
}
|
||||
|
||||
|
@ -234,10 +335,6 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
|
|||
|
||||
long getDaemonHeight(); //mBoundService.getDaemonHeight();
|
||||
|
||||
void setTitle(String title);
|
||||
|
||||
void setSubtitle(String subtitle);
|
||||
|
||||
void onSendRequest();
|
||||
|
||||
void onTxDetailsRequest(TransactionInfo info);
|
||||
|
@ -251,6 +348,12 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
|
|||
void onWalletReceive();
|
||||
|
||||
boolean hasWallet();
|
||||
|
||||
void setToolbarButton(int type);
|
||||
|
||||
void setTitle(String title, String subtitle);
|
||||
|
||||
void setSubtitle(String subtitle);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -263,4 +366,12 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
|
|||
+ " must implement Listener");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
Log.d(TAG, "onResume()");
|
||||
activityCallback.setTitle(walletTitle, walletSubtitle);
|
||||
activityCallback.setToolbarButton(Toolbar.BUTTON_CLOSE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import android.support.v4.app.DialogFragment;
|
|||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.webkit.WebView;
|
||||
|
@ -43,6 +44,7 @@ import java.io.InputStreamReader;
|
|||
* http://speakman.net.nz
|
||||
*/
|
||||
public class HelpFragment extends DialogFragment {
|
||||
static final String TAG = "HelpFragment";
|
||||
private static final String FRAGMENT_TAG = "com.m2049r.xmrwallet.dialog.HelpFragment";
|
||||
private static final String HELP_ID = "HELP_ID";
|
||||
|
||||
|
@ -67,7 +69,6 @@ public class HelpFragment extends DialogFragment {
|
|||
if (prev != null) {
|
||||
ft.remove(prev);
|
||||
}
|
||||
ft.addToBackStack(null);
|
||||
|
||||
// Create and show the dialog.
|
||||
DialogFragment newFragment = HelpFragment.newInstance(helpResourceId);
|
||||
|
@ -100,7 +101,7 @@ public class HelpFragment extends DialogFragment {
|
|||
@SuppressLint("InflateParams")
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
View content = LayoutInflater.from(getActivity()).inflate(R.layout.help_fragment, null);
|
||||
View content = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_help, null);
|
||||
webView = (WebView) content.findViewById(R.id.helpFragmentWebView);
|
||||
progress = (ProgressBar) content.findViewById(R.id.helpFragmentProgress);
|
||||
|
||||
|
@ -136,8 +137,8 @@ public class HelpFragment extends DialogFragment {
|
|||
sb.append("\n");
|
||||
}
|
||||
bufferedReader.close();
|
||||
} catch (IOException e) {
|
||||
// TODO You may want to include some logging here.
|
||||
} catch (IOException ex) {
|
||||
Log.e(TAG, ex.getLocalizedMessage());
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
|
|
|
@ -16,22 +16,17 @@
|
|||
|
||||
package com.m2049r.xmrwallet.dialog;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
//TODO If you don't support Android 2.x, you should use the non-support version!
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.webkit.WebView;
|
||||
|
@ -41,11 +36,17 @@ import android.widget.TextView;
|
|||
import com.m2049r.xmrwallet.BuildConfig;
|
||||
import com.m2049r.xmrwallet.R;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
/**
|
||||
* Created by Adam Speakman on 24/09/13.
|
||||
* http://speakman.net.nz
|
||||
*/
|
||||
public class LicensesFragment extends DialogFragment {
|
||||
static final String TAG = "LicensesFragment";
|
||||
int versionCode = BuildConfig.VERSION_CODE;
|
||||
String versionName = BuildConfig.VERSION_NAME;
|
||||
|
||||
|
@ -102,7 +103,7 @@ public class LicensesFragment extends DialogFragment {
|
|||
@SuppressLint("InflateParams")
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
View content = LayoutInflater.from(getActivity()).inflate(R.layout.licenses_fragment, null);
|
||||
View content = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_licenses, null);
|
||||
mWebView = (WebView) content.findViewById(R.id.licensesFragmentWebView);
|
||||
mIndeterminateProgress = (ProgressBar) content.findViewById(R.id.licensesFragmentIndeterminateProgress);
|
||||
|
||||
|
@ -140,8 +141,8 @@ public class LicensesFragment extends DialogFragment {
|
|||
sb.append("\n");
|
||||
}
|
||||
bufferedReader.close();
|
||||
} catch (IOException e) {
|
||||
// TODO You may want to include some logging here.
|
||||
} catch (IOException ex) {
|
||||
Log.e(TAG, ex.getLocalizedMessage());
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* 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.layout;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public class AsyncExchangeRate extends AsyncTask<String, Void, Boolean> {
|
||||
static final String TAG = "AsyncExchangeRate";
|
||||
static final long TIME_REFRESH_INTERVAL = 60000; // refresh exchange rate max every minute
|
||||
|
||||
public interface Listener {
|
||||
void exchangeFailed();
|
||||
|
||||
// callback from AsyncExchangeRate when we have a rate
|
||||
void exchange(String currencyA, String currencyB, double rate);
|
||||
}
|
||||
|
||||
static long RateTime = 0;
|
||||
static double Rate = 0;
|
||||
static String Fiat = null;
|
||||
|
||||
private final WeakReference<Listener> exchangeViewRef;
|
||||
|
||||
public AsyncExchangeRate(Listener exchangeView) {
|
||||
super();
|
||||
exchangeViewRef = new WeakReference<>(exchangeView);
|
||||
}
|
||||
|
||||
@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);
|
||||
Listener exchangeView = exchangeViewRef.get();
|
||||
if (result) {
|
||||
Log.d(TAG, "yay! = " + Rate);
|
||||
if (exchangeView != null) {
|
||||
exchangeView.exchange(currencyA, currencyB, inverse ? (1 / Rate) : Rate);
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "nay!");
|
||||
if (exchangeView != null) {
|
||||
exchangeView.exchangeFailed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// "https://api.kraken.com/0/public/Ticker?pair=XMREUR"
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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 from https://stackoverflow.com/a/45325876 (which did not work for me)
|
||||
|
||||
package com.m2049r.xmrwallet.layout;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.design.widget.TextInputLayout;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.EditText;
|
||||
|
||||
public class CTextInputLayout extends TextInputLayout {
|
||||
public CTextInputLayout(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public CTextInputLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public CTextInputLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBaseline() {
|
||||
EditText editText = getEditText();
|
||||
return editText.getBaseline() - (getMeasuredHeight() - editText.getMeasuredHeight());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,399 @@
|
|||
/*
|
||||
* 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.layout;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.design.widget.TextInputLayout;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.m2049r.xmrwallet.R;
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class ExchangeView extends LinearLayout implements AsyncExchangeRate.Listener {
|
||||
static final String TAG = "ExchangeView";
|
||||
|
||||
public boolean focus() {
|
||||
return etAmount.requestFocus();
|
||||
}
|
||||
|
||||
public void enable(boolean enable) {
|
||||
etAmount.setEnabled(enable);
|
||||
sCurrencyA.setEnabled(enable);
|
||||
sCurrencyB.setEnabled(enable);
|
||||
}
|
||||
|
||||
String xmrAmount = null;
|
||||
String notXmrAmount = null;
|
||||
|
||||
void setXmr(String xmr) {
|
||||
xmrAmount = xmr;
|
||||
if (onNewAmountListener != null) {
|
||||
onNewAmountListener.onNewAmount(xmr);
|
||||
}
|
||||
}
|
||||
|
||||
public void setAmount(String xmrAmount) {
|
||||
if (xmrAmount != null) {
|
||||
setCurrencyA(0);
|
||||
setXmr(xmrAmount);
|
||||
this.notXmrAmount = null;
|
||||
doExchange();
|
||||
} else {
|
||||
setXmr(null);
|
||||
this.notXmrAmount = null;
|
||||
tvAmountB.setText("--");
|
||||
}
|
||||
}
|
||||
|
||||
public String getAmount() {
|
||||
return xmrAmount;
|
||||
}
|
||||
|
||||
public void setError(String msg) {
|
||||
etAmount.setError(msg);
|
||||
}
|
||||
|
||||
TextInputLayout etAmount;
|
||||
TextView tvAmountB;
|
||||
Spinner sCurrencyA;
|
||||
Spinner sCurrencyB;
|
||||
ImageView evExchange;
|
||||
ProgressBar pbExchange;
|
||||
|
||||
|
||||
public void setCurrencyA(int currency) {
|
||||
if ((currency != 0) && (getCurrencyB() != 0)) {
|
||||
setCurrencyB(0);
|
||||
}
|
||||
sCurrencyA.setSelection(currency, true);
|
||||
doExchange();
|
||||
}
|
||||
|
||||
public void setCurrencyB(int currency) {
|
||||
if ((currency != 0) && (getCurrencyA() != 0)) {
|
||||
setCurrencyA(0);
|
||||
}
|
||||
sCurrencyB.setSelection(currency, true);
|
||||
doExchange();
|
||||
}
|
||||
|
||||
public int getCurrencyA() {
|
||||
return sCurrencyA.getSelectedItemPosition();
|
||||
}
|
||||
|
||||
public int getCurrencyB() {
|
||||
return sCurrencyB.getSelectedItemPosition();
|
||||
}
|
||||
|
||||
public ExchangeView(Context context) {
|
||||
super(context);
|
||||
initializeViews(context);
|
||||
}
|
||||
|
||||
public ExchangeView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initializeViews(context);
|
||||
}
|
||||
|
||||
public ExchangeView(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, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
etAmount = (TextInputLayout) findViewById(R.id.etAmount);
|
||||
tvAmountB = (TextView) findViewById(R.id.tvAmountB);
|
||||
sCurrencyA = (Spinner) findViewById(R.id.sCurrencyA);
|
||||
sCurrencyB = (Spinner) findViewById(R.id.sCurrencyB);
|
||||
evExchange = (ImageView) findViewById(R.id.evExchange);
|
||||
pbExchange = (ProgressBar) findViewById(R.id.pbExchange);
|
||||
|
||||
// make progress circle gray
|
||||
pbExchange.getIndeterminateDrawable().
|
||||
setColorFilter(getResources().getColor(R.color.trafficGray),
|
||||
android.graphics.PorterDuff.Mode.MULTIPLY);
|
||||
|
||||
|
||||
sCurrencyA.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
|
||||
if (position != 0) { // if not XMR, select XMR on other
|
||||
sCurrencyB.setSelection(0, true);
|
||||
}
|
||||
doExchange();
|
||||
}
|
||||
|
||||
@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) { // if not XMR, select XMR on other
|
||||
sCurrencyA.setSelection(0, true);
|
||||
}
|
||||
doExchange();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parentView) {
|
||||
// nothing (yet?)
|
||||
}
|
||||
});
|
||||
|
||||
etAmount.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)) {
|
||||
doExchange();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
etAmount.getEditText().addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void afterTextChanged(Editable editable) {
|
||||
etAmount.setError(null);
|
||||
if ((xmrAmount != null) || (notXmrAmount != null)) {
|
||||
tvAmountB.setText("--");
|
||||
setXmr(null);
|
||||
notXmrAmount = 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) {
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
final static double MAX_AMOUNT_XMR = 1000;
|
||||
final static double MAX_AMOUNT_NOTXMR = 100000;
|
||||
|
||||
public boolean checkEnteredAmount() {
|
||||
boolean ok = true;
|
||||
Log.d(TAG, "checkEnteredAmount");
|
||||
String amountEntry = etAmount.getEditText().getText().toString();
|
||||
if (!amountEntry.isEmpty()) {
|
||||
try {
|
||||
double a = Double.parseDouble(amountEntry);
|
||||
double maxAmount = (getCurrencyA() == 0) ? MAX_AMOUNT_XMR : MAX_AMOUNT_NOTXMR;
|
||||
if (a > (maxAmount)) {
|
||||
etAmount.setError(getResources().
|
||||
getString(R.string.receive_amount_too_big,
|
||||
String.format(Locale.US, "%,.0f", maxAmount)));
|
||||
ok = false;
|
||||
} else if (a < 0) {
|
||||
etAmount.setError(getResources().getString(R.string.receive_amount_negative));
|
||||
ok = false;
|
||||
}
|
||||
} catch (NumberFormatException ex) {
|
||||
etAmount.setError(getResources().getString(R.string.receive_amount_nan));
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
etAmount.setError(null);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
int selectedNotXmrCurrency() {
|
||||
return Math.max(getCurrencyA(), getCurrencyB());
|
||||
}
|
||||
|
||||
public void doExchange() {
|
||||
tvAmountB.setText("--");
|
||||
// TODO cache & use cached exchange rate here
|
||||
startExchange();
|
||||
}
|
||||
|
||||
void startExchange() {
|
||||
showProgress();
|
||||
String currencyA = (String) sCurrencyA.getSelectedItem();
|
||||
String currencyB = (String) sCurrencyB.getSelectedItem();
|
||||
new AsyncExchangeRate(this).execute(currencyA, currencyB);
|
||||
}
|
||||
|
||||
public void exchange(double rate) {
|
||||
if (getCurrencyA() == 0) {
|
||||
if (!xmrAmount.isEmpty() && (rate > 0)) {
|
||||
double amountB = rate * Double.parseDouble(xmrAmount);
|
||||
notXmrAmount = Helper.getFormattedAmount(amountB, getCurrencyB() == 0);
|
||||
} else {
|
||||
notXmrAmount = "";
|
||||
}
|
||||
tvAmountB.setText(notXmrAmount);
|
||||
} else if (getCurrencyB() == 0) {
|
||||
if (!notXmrAmount.isEmpty() && (rate > 0)) {
|
||||
double amountB = rate * Double.parseDouble(notXmrAmount);
|
||||
setXmr(Helper.getFormattedAmount(amountB, true));
|
||||
} else {
|
||||
setXmr("");
|
||||
}
|
||||
tvAmountB.setText(xmrAmount);
|
||||
} else { // no XMR currency - cannot happen!
|
||||
Log.e(TAG, "No XMR currency!");
|
||||
setXmr(null);
|
||||
notXmrAmount = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
boolean prepareExchange() {
|
||||
Log.d(TAG, "prepareExchange()");
|
||||
if (checkEnteredAmount()) {
|
||||
String enteredAmount = etAmount.getEditText().getText().toString();
|
||||
if (!enteredAmount.isEmpty()) {
|
||||
String cleanAmount = "";
|
||||
if (getCurrencyA() == 0) {
|
||||
// sanitize the input
|
||||
cleanAmount = Helper.getDisplayAmount(Wallet.getAmountFromString(enteredAmount));
|
||||
setXmr(cleanAmount);
|
||||
notXmrAmount = null;
|
||||
Log.d(TAG, "cleanAmount = " + cleanAmount);
|
||||
} else if (getCurrencyB() == 0) { // we use B & 0 here for the else below ...
|
||||
// sanitize the input
|
||||
double amountA = Double.parseDouble(enteredAmount);
|
||||
cleanAmount = String.format(Locale.US, "%.2f", amountA);
|
||||
setXmr(null);
|
||||
notXmrAmount = cleanAmount;
|
||||
} else { // no XMR currency - cannot happen!
|
||||
Log.e(TAG, "No XMR currency!");
|
||||
setXmr(null);
|
||||
notXmrAmount = null;
|
||||
return false;
|
||||
}
|
||||
Log.d(TAG, "prepareExchange() " + cleanAmount);
|
||||
//etAmount.getEditText().setText(cleanAmount); // display what we use
|
||||
} else {
|
||||
setXmr("");
|
||||
notXmrAmount = "";
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
setXmr(null);
|
||||
notXmrAmount = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// callback from AsyncExchangeRate when it failed getting a rate
|
||||
public void exchangeFailed() {
|
||||
hideProgress();
|
||||
exchange(0);
|
||||
// TODO Toast it failed - I think this happens elsewhere already
|
||||
}
|
||||
|
||||
// callback from AsyncExchangeRate when we have a rate
|
||||
public void exchange(String currencyA, String currencyB, double rate) {
|
||||
hideProgress();
|
||||
// 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!");
|
||||
return;
|
||||
}
|
||||
if (prepareExchange()) {
|
||||
exchange(rate);
|
||||
}
|
||||
}
|
||||
|
||||
private void showProgress() {
|
||||
pbExchange.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
private void hideProgress() {
|
||||
pbExchange.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
// Hooks
|
||||
public interface OnNewAmountListener {
|
||||
void onNewAmount(String xmr);
|
||||
}
|
||||
|
||||
OnNewAmountListener onNewAmountListener;
|
||||
|
||||
public void setOnNewAmountListener(OnNewAmountListener listener) {
|
||||
onNewAmountListener = listener;
|
||||
}
|
||||
|
||||
public interface OnAmountInvalidatedListener {
|
||||
void onAmountInvalidated();
|
||||
}
|
||||
|
||||
OnAmountInvalidatedListener onAmountInvalidatedListener;
|
||||
|
||||
public void setOnAmountInvalidatedListener(OnAmountInvalidatedListener listener) {
|
||||
onAmountInvalidatedListener = listener;
|
||||
}
|
||||
|
||||
public interface OnFailedExchangeListener {
|
||||
void onFailedExchange();
|
||||
}
|
||||
|
||||
OnFailedExchangeListener onFailedExchangeListener;
|
||||
|
||||
public void setOnFailedExchangeListener(OnFailedExchangeListener listener) {
|
||||
onFailedExchangeListener = listener;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* 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.layout;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.m2049r.xmrwallet.R;
|
||||
|
||||
public class Toolbar extends android.support.v7.widget.Toolbar {
|
||||
static final String TAG = "Toolbar";
|
||||
|
||||
public interface OnButtonListener {
|
||||
void onButton(int type);
|
||||
}
|
||||
|
||||
OnButtonListener onButtonListener;
|
||||
|
||||
public void setOnButtonListener(OnButtonListener listener) {
|
||||
onButtonListener = listener;
|
||||
}
|
||||
|
||||
ImageView toolbarImage;
|
||||
TextView toolbarTitle;
|
||||
TextView toolbarSubtitle;
|
||||
Button bDonate;
|
||||
|
||||
public Toolbar(Context context) {
|
||||
super(context);
|
||||
initializeViews(context);
|
||||
}
|
||||
|
||||
public Toolbar(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initializeViews(context);
|
||||
}
|
||||
|
||||
public Toolbar(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_toolbar, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
toolbarImage = (ImageView) findViewById(R.id.toolbarImage);
|
||||
toolbarTitle = (TextView) findViewById(R.id.toolbarTitle);
|
||||
toolbarSubtitle = (TextView) findViewById(R.id.toolbarSubtitle);
|
||||
bDonate = (Button) findViewById(R.id.bDonate);
|
||||
bDonate.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
if (onButtonListener != null) {
|
||||
onButtonListener.onButton(buttonType);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setTitle(String title, String subtitle) {
|
||||
setTitle(title);
|
||||
setSubtitle(subtitle);
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
toolbarTitle.setText(title);
|
||||
if (title != null) {
|
||||
toolbarImage.setVisibility(View.INVISIBLE);
|
||||
toolbarTitle.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
toolbarImage.setVisibility(View.VISIBLE);
|
||||
toolbarTitle.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
public final static int BUTTON_NONE = 0;
|
||||
public final static int BUTTON_BACK = 1;
|
||||
public final static int BUTTON_CLOSE = 2;
|
||||
public final static int BUTTON_DONATE = 3;
|
||||
|
||||
int buttonType = BUTTON_DONATE;
|
||||
|
||||
public void setButton(int type) {
|
||||
switch (type) {
|
||||
case BUTTON_BACK:
|
||||
Log.d(TAG, "BUTTON_BACK");
|
||||
bDonate.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_arrow_back_white_24dp, 0, 0, 0);
|
||||
bDonate.setText(null);
|
||||
bDonate.setVisibility(View.VISIBLE);
|
||||
break;
|
||||
case BUTTON_CLOSE:
|
||||
Log.d(TAG, "BUTTON_CLOSE");
|
||||
bDonate.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_close_white_24dp, 0, 0, 0);
|
||||
bDonate.setText(R.string.label_close);
|
||||
bDonate.setVisibility(View.VISIBLE);
|
||||
break;
|
||||
case BUTTON_DONATE:
|
||||
Log.d(TAG, "BUTTON_DONATE");
|
||||
bDonate.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_favorite_white_24dp, 0, 0, 0);
|
||||
bDonate.setText(R.string.label_donate);
|
||||
bDonate.setVisibility(View.VISIBLE);
|
||||
break;
|
||||
case BUTTON_NONE:
|
||||
default:
|
||||
Log.d(TAG, "BUTTON_NONE");
|
||||
bDonate.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
|
||||
bDonate.setText(null);
|
||||
bDonate.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
buttonType = type;
|
||||
}
|
||||
|
||||
public void setSubtitle(String subtitle) {
|
||||
toolbarSubtitle.setText(subtitle);
|
||||
if (subtitle != null) {
|
||||
toolbarSubtitle.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
toolbarSubtitle.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,7 +17,6 @@
|
|||
package com.m2049r.xmrwallet.layout;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.Log;
|
||||
|
@ -28,13 +27,12 @@ import android.widget.TextView;
|
|||
|
||||
import com.m2049r.xmrwallet.R;
|
||||
import com.m2049r.xmrwallet.model.TransactionInfo;
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
@ -69,7 +67,7 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
|||
outboundColour = ContextCompat.getColor(context, R.color.tx_red);
|
||||
pendingColour = ContextCompat.getColor(context, R.color.tx_pending);
|
||||
failedColour = ContextCompat.getColor(context, R.color.tx_failed);
|
||||
this.infoItems = new ArrayList<>();
|
||||
infoItems = new ArrayList<>();
|
||||
this.listener = listener;
|
||||
Calendar cal = Calendar.getInstance();
|
||||
TimeZone tz = cal.getTimeZone(); //get the local time zone.
|
||||
|
@ -79,7 +77,7 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
|||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.transaction_item, parent, false);
|
||||
.inflate(R.layout.item_transaction, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
|
@ -99,22 +97,8 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
|||
this.infoItems.clear();
|
||||
if (data != null) {
|
||||
Log.d(TAG, "setInfos " + data.size());
|
||||
// sort by block height
|
||||
Collections.sort(data, new Comparator<TransactionInfo>() {
|
||||
@Override
|
||||
public int compare(TransactionInfo o1, TransactionInfo o2) {
|
||||
long b1 = o1.timestamp;
|
||||
long b2 = o2.timestamp;
|
||||
if (b1 > b2) {
|
||||
return -1;
|
||||
} else if (b1 < b2) {
|
||||
return 1;
|
||||
} else {
|
||||
return o1.hash.compareTo(o2.hash);
|
||||
}
|
||||
}
|
||||
});
|
||||
this.infoItems.addAll(data);
|
||||
infoItems.addAll(data);
|
||||
Collections.sort(infoItems);
|
||||
} else {
|
||||
Log.d(TAG, "setInfos null");
|
||||
}
|
||||
|
@ -147,36 +131,41 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
|||
|
||||
void bind(int position) {
|
||||
this.infoItem = infoItems.get(position);
|
||||
String displayAmount = Wallet.getDisplayAmount(infoItem.amount);
|
||||
// TODO fix this with i8n code but cryptonote::print_money always uses '.' for decimal point
|
||||
String amount = displayAmount.substring(0, displayAmount.length() - (12 - 5));
|
||||
this.tvAmount.setText(amount);
|
||||
|
||||
long realAmount = infoItem.amount;
|
||||
if (infoItem.isPending) {
|
||||
realAmount = realAmount - infoItem.fee;
|
||||
}
|
||||
|
||||
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));
|
||||
} else {
|
||||
this.tvAmount.setText(context.getString(R.string.tx_list_amount_positive, displayAmount));
|
||||
}
|
||||
|
||||
if ((infoItem.fee > 0)) {
|
||||
String feeAmount = Wallet.getDisplayAmount(infoItem.fee);
|
||||
String fee = feeAmount.substring(0, feeAmount.length() - (12 - 5));
|
||||
if (infoItem.isPending) {
|
||||
this.tvFee.setText(context.getString(R.string.tx_list_fee_pending, fee));
|
||||
} else {
|
||||
this.tvFee.setText(context.getString(R.string.tx_list_fee, fee));
|
||||
}
|
||||
String fee = Helper.getDisplayAmount(infoItem.fee, 5);
|
||||
this.tvFee.setText(context.getString(R.string.tx_list_fee, fee));
|
||||
} else {
|
||||
this.tvFee.setText("");
|
||||
}
|
||||
if (infoItem.isFailed) {
|
||||
this.tvAmount.setText(context.getString(R.string.tx_list_amount_failed, amount));
|
||||
this.tvAmount.setText(context.getString(R.string.tx_list_amount_failed, displayAmount));
|
||||
this.tvFee.setText(context.getString(R.string.tx_list_failed_text));
|
||||
setTxColour(failedColour);
|
||||
} else if (infoItem.isPending) {
|
||||
setTxColour(pendingColour);
|
||||
if (infoItem.direction == TransactionInfo.Direction.Direction_Out) {
|
||||
this.tvAmount.setText(context.getString(R.string.tx_list_amount_negative, amount));
|
||||
}
|
||||
} else if (infoItem.direction == TransactionInfo.Direction.Direction_In) {
|
||||
setTxColour(inboundColour);
|
||||
} else {
|
||||
setTxColour(outboundColour);
|
||||
}
|
||||
this.tvPaymentId.setText(infoItem.paymentId.equals("0000000000000000") ? "" : infoItem.paymentId);
|
||||
if ((infoItem.notes == null) || (infoItem.notes.isEmpty())) {
|
||||
this.tvPaymentId.setText(infoItem.paymentId.equals("0000000000000000") ? "" : infoItem.paymentId);
|
||||
} else {
|
||||
this.tvPaymentId.setText(infoItem.notes);
|
||||
}
|
||||
this.tvDateTime.setText(getDateTime(infoItem.timestamp));
|
||||
|
||||
itemView.setOnClickListener(this);
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* 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.layout;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v7.widget.PopupMenu;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.m2049r.xmrwallet.R;
|
||||
import com.m2049r.xmrwallet.model.WalletManager;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public class WalletInfoAdapter extends RecyclerView.Adapter<WalletInfoAdapter.ViewHolder> {
|
||||
private static final String TAG = "WalletInfoAdapter";
|
||||
|
||||
private final SimpleDateFormat DATETIME_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm");
|
||||
|
||||
public interface OnInteractionListener {
|
||||
void onInteraction(View view, WalletManager.WalletInfo item);
|
||||
|
||||
boolean onContextInteraction(MenuItem item, WalletManager.WalletInfo infoItem);
|
||||
}
|
||||
|
||||
private final List<WalletManager.WalletInfo> infoItems;
|
||||
private final OnInteractionListener listener;
|
||||
|
||||
Context context;
|
||||
|
||||
public WalletInfoAdapter(Context context, OnInteractionListener listener) {
|
||||
this.context = context;
|
||||
this.infoItems = new ArrayList<>();
|
||||
this.listener = listener;
|
||||
Calendar cal = Calendar.getInstance();
|
||||
TimeZone tz = cal.getTimeZone(); //get the local time zone.
|
||||
DATETIME_FORMATTER.setTimeZone(tz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.item_wallet, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(final ViewHolder holder, int position) {
|
||||
holder.bind(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return infoItems.size();
|
||||
}
|
||||
|
||||
public WalletManager.WalletInfo getItem(int position) {
|
||||
return infoItems.get(position);
|
||||
}
|
||||
|
||||
public void setInfos(List<WalletManager.WalletInfo> data) {
|
||||
// TODO do stuff with data so we can really recycle elements (i.e. add only new tx)
|
||||
// as the WalletInfo items are always recreated, we cannot recycle
|
||||
infoItems.clear();
|
||||
if (data != null) {
|
||||
Log.d(TAG, "setInfos " + data.size());
|
||||
infoItems.addAll(data);
|
||||
Collections.sort(infoItems);
|
||||
} else {
|
||||
Log.d(TAG, "setInfos null");
|
||||
}
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
|
||||
final TextView tvName;
|
||||
final TextView tvAddress;
|
||||
final ImageButton ibOptions;
|
||||
WalletManager.WalletInfo infoItem;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
tvName = (TextView) itemView.findViewById(R.id.tvName);
|
||||
tvAddress = (TextView) itemView.findViewById(R.id.tvAddress);
|
||||
ibOptions = (ImageButton) itemView.findViewById(R.id.ibOptions);
|
||||
ibOptions.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
//creating a popup menu
|
||||
PopupMenu popup = new PopupMenu(context, ibOptions);
|
||||
//inflating menu from xml resource
|
||||
popup.inflate(R.menu.list_context_menu);
|
||||
//adding click listener
|
||||
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
if (listener != null) {
|
||||
return listener.onContextInteraction(item, infoItem);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
//displaying the popup
|
||||
popup.show();
|
||||
|
||||
}
|
||||
});
|
||||
itemView.setOnClickListener(this);
|
||||
}
|
||||
|
||||
private String getDateTime(long time) {
|
||||
return DATETIME_FORMATTER.format(new Date(time * 1000));
|
||||
}
|
||||
|
||||
void bind(int position) {
|
||||
infoItem = infoItems.get(position);
|
||||
tvName.setText(infoItem.name);
|
||||
tvAddress.setText(infoItem.address.substring(0, 16) + "...");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (listener != null) {
|
||||
int position = getAdapterPosition(); // gets item position
|
||||
if (position != RecyclerView.NO_POSITION) { // Check if an item was deleted, but the user clicked it before the UI removed it
|
||||
listener.onInteraction(view, infoItems.get(position));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,6 +30,12 @@ public class TransactionHistory {
|
|||
this.handle = handle;
|
||||
}
|
||||
|
||||
public void loadNotes(Wallet wallet) {
|
||||
for (TransactionInfo info : transactions) {
|
||||
info.notes = wallet.getUserNote(info.hash);
|
||||
}
|
||||
}
|
||||
|
||||
public native int getCount();
|
||||
|
||||
//private native long getTransactionByIndexJ(int i);
|
||||
|
@ -42,6 +48,11 @@ public class TransactionHistory {
|
|||
|
||||
private List<TransactionInfo> transactions = new ArrayList<>();
|
||||
|
||||
public void refreshWithNotes(Wallet wallet) {
|
||||
refresh();
|
||||
loadNotes(wallet);
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
transactions = refreshJ();
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ import java.util.Random;
|
|||
|
||||
// this is not the TransactionInfo from the API as that is owned by the TransactionHistory
|
||||
// this is a POJO for the TransactionInfoAdapter
|
||||
public class TransactionInfo implements Parcelable {
|
||||
public class TransactionInfo implements Parcelable, Comparable<TransactionInfo> {
|
||||
static final String TAG = "TransactionInfo";
|
||||
|
||||
public enum Direction {
|
||||
|
@ -92,7 +92,6 @@ public class TransactionInfo implements Parcelable {
|
|||
this.confirmations = confirmations;
|
||||
this.transfers = transfers;
|
||||
}
|
||||
Random rnd = new Random();
|
||||
|
||||
public String toString() {
|
||||
return direction + "@" + blockheight + " " + amount;
|
||||
|
@ -146,4 +145,17 @@ public class TransactionInfo implements Parcelable {
|
|||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(TransactionInfo another) {
|
||||
long b1 = this.timestamp;
|
||||
long b2 = another.timestamp;
|
||||
if (b1 > b2) {
|
||||
return -1;
|
||||
} else if (b1 < b2) {
|
||||
return 1;
|
||||
} else {
|
||||
return this.hash.compareTo(another.hash);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -144,10 +144,20 @@ public class WalletManager {
|
|||
|
||||
//public native List<String> findWallets(String path); // this does not work - some error in boost
|
||||
|
||||
public class WalletInfo {
|
||||
public class WalletInfo implements Comparable<WalletInfo> {
|
||||
public File path;
|
||||
public String name;
|
||||
public String address;
|
||||
|
||||
@Override
|
||||
public int compareTo(WalletInfo another) {
|
||||
int n = name.toLowerCase().compareTo(another.name.toLowerCase());
|
||||
if (n != 0) {
|
||||
return n;
|
||||
} else { // wallet names are the same
|
||||
return address.compareTo(another.address);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public WalletInfo getWalletInfo(File wallet) {
|
||||
|
|
|
@ -147,7 +147,7 @@ public class WalletService extends Service {
|
|||
if (updated) {
|
||||
if (observer != null) {
|
||||
updateDaemonState(wallet, 0);
|
||||
wallet.getHistory().refresh();
|
||||
wallet.getHistory().refreshWithNotes(wallet);
|
||||
if (observer != null) {
|
||||
updated = !observer.onRefreshed(wallet, true);
|
||||
}
|
||||
|
@ -297,7 +297,7 @@ public class WalletService extends Service {
|
|||
boolean rc = myWallet.store();
|
||||
Log.d(TAG, "wallet stored: " + myWallet.getName() + " with rc=" + rc);
|
||||
if (!rc) {
|
||||
Log.d(TAG, "Wallet store failed: " + myWallet.getErrorString());
|
||||
Log.w(TAG, "Wallet store failed: " + myWallet.getErrorString());
|
||||
}
|
||||
if (observer != null) observer.onWalletStored(rc);
|
||||
} else if (cmd.equals(REQUEST_CMD_TX)) {
|
||||
|
@ -309,7 +309,7 @@ public class WalletService extends Service {
|
|||
PendingTransaction.Status status = pendingTransaction.getStatus();
|
||||
Log.d(TAG, "transaction status " + status);
|
||||
if (status != PendingTransaction.Status.Status_Ok) {
|
||||
Log.d(TAG, "Create Transaction failed: " + pendingTransaction.getErrorString());
|
||||
Log.w(TAG, "Create Transaction failed: " + pendingTransaction.getErrorString());
|
||||
}
|
||||
if (observer != null) {
|
||||
observer.onCreatedTransaction(pendingTransaction);
|
||||
|
@ -323,7 +323,7 @@ public class WalletService extends Service {
|
|||
PendingTransaction.Status status = pendingTransaction.getStatus();
|
||||
Log.d(TAG, "transaction status " + status);
|
||||
if (status != PendingTransaction.Status.Status_Ok) {
|
||||
Log.d(TAG, "Create Transaction failed: " + pendingTransaction.getErrorString());
|
||||
Log.w(TAG, "Create Transaction failed: " + pendingTransaction.getErrorString());
|
||||
}
|
||||
if (observer != null) {
|
||||
observer.onCreatedTransaction(pendingTransaction);
|
||||
|
@ -352,7 +352,7 @@ public class WalletService extends Service {
|
|||
boolean rc = myWallet.store();
|
||||
Log.d(TAG, "wallet stored: " + myWallet.getName() + " with rc=" + rc);
|
||||
if (!rc) {
|
||||
Log.d(TAG, "Wallet store failed: " + myWallet.getErrorString());
|
||||
Log.w(TAG, "Wallet store failed: " + myWallet.getErrorString());
|
||||
}
|
||||
if (observer != null) observer.onWalletStored(rc);
|
||||
listener.updated = true;
|
||||
|
@ -372,7 +372,7 @@ public class WalletService extends Service {
|
|||
boolean rc = myWallet.store();
|
||||
Log.d(TAG, "wallet stored: " + myWallet.getName() + " with rc=" + rc);
|
||||
if (!rc) {
|
||||
Log.d(TAG, "Wallet store failed: " + myWallet.getErrorString());
|
||||
Log.w(TAG, "Wallet store failed: " + myWallet.getErrorString());
|
||||
}
|
||||
if (observer != null) observer.onWalletStored(rc);
|
||||
}
|
||||
|
@ -505,17 +505,12 @@ public class WalletService extends Service {
|
|||
}
|
||||
|
||||
private Wallet loadWallet(String walletName, String walletPassword) {
|
||||
//String path = Helper.getWalletPath(getApplicationContext(), walletName);
|
||||
//Log.d(TAG, "open wallet " + path);
|
||||
Wallet wallet = openWallet(walletName, walletPassword);
|
||||
//Log.d(TAG, "wallet opened: " + wallet);
|
||||
if (wallet != null) {
|
||||
//Log.d(TAG, wallet.getStatus().toString());
|
||||
Log.d(TAG, "Using daemon " + WalletManager.getInstance().getDaemonAddress());
|
||||
showProgress(55);
|
||||
wallet.init(0);
|
||||
showProgress(90);
|
||||
//Log.d(TAG, wallet.getConnectionStatus().toString());
|
||||
}
|
||||
return wallet;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@ package com.m2049r.xmrwallet.util;
|
|||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
|
@ -40,7 +42,9 @@ import java.io.File;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URL;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
|
||||
|
@ -48,6 +52,9 @@ public class Helper {
|
|||
static private final String TAG = "Helper";
|
||||
static private final String WALLET_DIR = "monerujo";
|
||||
|
||||
static public int DISPLAY_DIGITS_INFO = 5;
|
||||
static public int DISPLAY_DIGITS_SHORT = 5;
|
||||
|
||||
static public File getStorageRoot(Context context) {
|
||||
if (!isExternalStorageWritable()) {
|
||||
String msg = context.getString(R.string.message_strorage_not_writable);
|
||||
|
@ -73,7 +80,7 @@ public class Helper {
|
|||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
|
||||
if (context.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
== PackageManager.PERMISSION_DENIED) {
|
||||
Log.d(TAG, "Permission denied to WRITE_EXTERNAL_STORAGE - requesting it");
|
||||
Log.w(TAG, "Permission denied to WRITE_EXTERNAL_STORAGE - requesting it");
|
||||
String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
|
||||
context.requestPermissions(permissions, PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE);
|
||||
return false;
|
||||
|
@ -91,7 +98,7 @@ public class Helper {
|
|||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
|
||||
if (context.checkSelfPermission(Manifest.permission.CAMERA)
|
||||
== PackageManager.PERMISSION_DENIED) {
|
||||
Log.d(TAG, "Permission denied for CAMERA - requesting it");
|
||||
Log.w(TAG, "Permission denied for CAMERA - requesting it");
|
||||
String[] permissions = {Manifest.permission.CAMERA};
|
||||
context.requestPermissions(permissions, PERMISSIONS_REQUEST_CAMERA);
|
||||
return false;
|
||||
|
@ -103,13 +110,8 @@ public class Helper {
|
|||
}
|
||||
}
|
||||
|
||||
// static public String getWalletPath(Context context, String aWalletName) {
|
||||
// return getWalletFile(context, aWalletName).getAbsolutePath();
|
||||
// }
|
||||
|
||||
static public File getWalletFile(Context context, String aWalletName) {
|
||||
File walletDir = getStorageRoot(context);
|
||||
//d(TAG, "walletdir=" + walletDir.getAbsolutePath());
|
||||
File f = new File(walletDir, aWalletName);
|
||||
Log.d(TAG, "wallet = " + f.getAbsolutePath() + " size=" + f.length());
|
||||
return f;
|
||||
|
@ -127,6 +129,7 @@ public class Helper {
|
|||
}
|
||||
|
||||
static public void hideKeyboard(Activity act) {
|
||||
if (act == null) return;
|
||||
if (act.getCurrentFocus() == null) {
|
||||
act.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
|
||||
} else {
|
||||
|
@ -145,19 +148,38 @@ public class Helper {
|
|||
}
|
||||
|
||||
static public String getDisplayAmount(long amount) {
|
||||
String s = Wallet.getDisplayAmount(amount);
|
||||
return getDisplayAmount(amount, 20);
|
||||
}
|
||||
|
||||
static public String getDisplayAmount(long amount, int maxDecimals) {
|
||||
return getDisplayAmount(Wallet.getDisplayAmount(amount), maxDecimals);
|
||||
}
|
||||
|
||||
// amountString must have '.' as decimal point
|
||||
static public String getDisplayAmount(String amountString, int maxDecimals) {
|
||||
int lastZero = 0;
|
||||
int decimal = 0;
|
||||
for (int i = s.length() - 1; i >= 0; i--) {
|
||||
if ((lastZero == 0) && (s.charAt(i) != '0')) lastZero = i + 1;
|
||||
for (int i = amountString.length() - 1; i >= 0; i--) {
|
||||
if ((lastZero == 0) && (amountString.charAt(i) != '0')) lastZero = i + 1;
|
||||
// TODO i18n
|
||||
if (s.charAt(i) == '.') {
|
||||
decimal = i;
|
||||
if (amountString.charAt(i) == '.') {
|
||||
decimal = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int cutoff = Math.max(lastZero, decimal + 2);
|
||||
return s.substring(0, cutoff);
|
||||
int cutoff = Math.min(Math.max(lastZero, decimal + 2), decimal + maxDecimals);
|
||||
return amountString.substring(0, cutoff);
|
||||
}
|
||||
|
||||
static public String getFormattedAmount(double amount, boolean isXmr) {
|
||||
// at this point selection is XMR in case of error
|
||||
String displayB;
|
||||
if (isXmr) { // not XMR
|
||||
displayB = String.format(Locale.US, "%,.5f", amount);
|
||||
} else { // XMR
|
||||
displayB = String.format(Locale.US, "%,.2f", amount);
|
||||
}
|
||||
return displayB;
|
||||
}
|
||||
|
||||
static public Bitmap getBitmap(Context context, int drawableId) {
|
||||
|
@ -180,11 +202,15 @@ public class Helper {
|
|||
return bitmap;
|
||||
}
|
||||
|
||||
static final int HTTP_TIMEOUT = 5000;
|
||||
|
||||
static public String getUrl(String httpsUrl) {
|
||||
HttpsURLConnection urlConnection = null;
|
||||
try {
|
||||
URL url = new URL(httpsUrl);
|
||||
urlConnection = (HttpsURLConnection) url.openConnection();
|
||||
urlConnection.setConnectTimeout(HTTP_TIMEOUT);
|
||||
urlConnection.setReadTimeout(HTTP_TIMEOUT);
|
||||
InputStreamReader in = new InputStreamReader(urlConnection.getInputStream());
|
||||
StringBuffer sb = new StringBuffer();
|
||||
final int BUFFER_SIZE = 512;
|
||||
|
@ -195,6 +221,8 @@ public class Helper {
|
|||
length = in.read(buffer, 0, BUFFER_SIZE);
|
||||
}
|
||||
return sb.toString();
|
||||
} catch (SocketTimeoutException ex) {
|
||||
Log.w(TAG, "C " + ex.getLocalizedMessage());
|
||||
} catch (MalformedURLException ex) {
|
||||
Log.e(TAG, "A " + ex.getLocalizedMessage());
|
||||
} catch (IOException ex) {
|
||||
|
@ -206,4 +234,10 @@ public class Helper {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static public void clipBoardCopy(Context context, String label, String text) {
|
||||
ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
ClipData clip = ClipData.newPlainText(label, text);
|
||||
clipboardManager.setPrimaryClip(clip);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
|
||||
package com.m2049r.xmrwallet.util;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:fillAfter="true">
|
||||
<scale
|
||||
android:duration="300"
|
||||
android:fromXScale="1.0"
|
||||
android:fromYScale="1.0"
|
||||
android:interpolator="@android:anim/linear_interpolator"
|
||||
android:pivotX="50%"
|
||||
android:pivotY="50%"
|
||||
android:toXScale="0.0"
|
||||
android:toYScale="0.0" />
|
||||
<alpha
|
||||
android:duration="300"
|
||||
android:fromAlpha="1.0"
|
||||
android:interpolator="@android:anim/accelerate_interpolator"
|
||||
android:toAlpha="0.0" />
|
||||
</set>
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:fillAfter="false">
|
||||
<alpha
|
||||
android:duration="300"
|
||||
android:fromAlpha="1.0"
|
||||
android:interpolator="@android:anim/accelerate_interpolator"
|
||||
android:toAlpha="0.0" />
|
||||
</set>
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:fillAfter="true">
|
||||
<scale
|
||||
android:duration="300"
|
||||
android:fromXScale="0.0"
|
||||
android:fromYScale="0.0"
|
||||
android:interpolator="@android:anim/linear_interpolator"
|
||||
android:pivotX="50%"
|
||||
android:pivotY="50%"
|
||||
android:toXScale="1.0"
|
||||
android:toYScale="1.0" />
|
||||
<alpha
|
||||
android:duration="300"
|
||||
android:fromAlpha="0.0"
|
||||
android:interpolator="@android:anim/accelerate_interpolator"
|
||||
android:toAlpha="1.0" />
|
||||
</set>
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:fillAfter="true">
|
||||
<alpha
|
||||
android:duration="300"
|
||||
android:fromAlpha="0.0"
|
||||
android:interpolator="@android:anim/accelerate_interpolator"
|
||||
android:toAlpha="1.0" />
|
||||
</set>
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:fillAfter="true">
|
||||
<rotate
|
||||
android:duration="300"
|
||||
android:fromDegrees="315"
|
||||
android:interpolator="@android:anim/linear_interpolator"
|
||||
android:pivotX="50%"
|
||||
android:pivotY="50%"
|
||||
android:toDegrees="0" />
|
||||
</set>
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:fillAfter="true">
|
||||
<rotate
|
||||
android:duration="300"
|
||||
android:fromDegrees="0"
|
||||
android:interpolator="@android:anim/linear_interpolator"
|
||||
android:pivotX="50%"
|
||||
android:pivotY="50%"
|
||||
android:toDegrees="315" />
|
||||
</set>
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="@color/moneroGray" android:state_enabled="false" />
|
||||
<item android:color="@color/moneroText" android:state_enabled="false" />
|
||||
<item android:color="@color/moneroWhite" />
|
||||
</selector>
|
|
@ -0,0 +1,352 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="1080dp"
|
||||
android:height="1920dp"
|
||||
android:viewportWidth="1080"
|
||||
android:viewportHeight="1920">
|
||||
|
||||
<group>
|
||||
<path
|
||||
android:fillColor="#F6F5F5"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 134.4 -393.2 L 215.2 -363 L 231.2 -273.1 L 109.9 -318.4 L 134.4 -393.2 Z" />
|
||||
<path
|
||||
android:fillColor="#F6F5F5"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 457.7 -272.4 L 538.5 -242.2 L 408.8 -122.7 L 424.8 -32.7 L 263.1 -93.1 L 457.7 -272.4 Z" />
|
||||
<path
|
||||
android:fillColor="#F0F0F0"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 1023.6 -61 L 1266.1 29.6 L 1071.5 208.9 L 1023.6 -61 Z" />
|
||||
<path
|
||||
android:fillColor="#F6F5F5"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 1266.1 29.6 L 1589.5 150.4 L 1524.6 210.1 L 1363 149.7 L 1233.2 269.3 L 1071.5 208.9 L 1266.1 29.6 Z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 215.2 -363 L 457.7 -272.4 L 263.1 -93.1 L 215.2 -363 Z" />
|
||||
<path
|
||||
android:fillColor="#F0F0F0"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 1363 149.7 L 1524.6 210.1 L 1394.9 329.6 L 1363 149.7 Z" />
|
||||
<path
|
||||
android:fillColor="#F0F0F0"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 109.9 -318.4 L 231.2 -273.1 L 263.1 -93.1 L 424.8 -32.7 L 440.7 57.3 L 36.5 -93.7 L 109.9 -318.4 Z" />
|
||||
<path
|
||||
android:fillColor="#F6F5F5"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 36.5 -93.7 L 440.7 57.3 L 456.7 147.2 L 52.5 -3.8 L -12.4 56 L 36.5 -93.7 Z" />
|
||||
<path
|
||||
android:fillColor="#F0F0F0"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 619.5 -212 L 1023.6 -61 L 1071.5 208.9 L 1233.2 269.3 L 1281.1 539.2 L 634.4 297.6 L 602.4 117.7 L 683.3 147.9 L 619.5 -212 Z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 1589.5 150.4 L 1670.4 180.5 L 1572.5 480 L 1377.9 659.3 L 1362 569.4 L 1297 629.1 L 1233.2 269.3 L 1363 149.7 L 1394.9 329.6 L 1589.5 150.4 Z" />
|
||||
<path
|
||||
android:fillColor="#F0F0F0"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 52.5 -3.8 L 456.7 147.2 L 472.7 237.2 L 278.1 416.5 L 230.1 146.6 L 100.4 266.1 L 52.5 -3.8 Z" />
|
||||
<path
|
||||
android:fillColor="#F6F5F5"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 1474.7 779.4 L 1232.2 688.9 L 1167.3 748.7 L 1183.3 838.6 L 1021.6 778.1 L 891.8 897.7 L 568.5 777 L 503.6 836.8 L 180.2 716 L 634.4 297.6 L 1281.1 539.2 L 1297 629.1 L 1362 569.4 L 1377.9 659.3 L 1572.5 480 L 1474.7 779.4 Z" />
|
||||
<path
|
||||
android:fillColor="#F0F0F0"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 1232.2 688.9 L 1474.7 779.4 L 1345 898.9 L 1264.2 868.8 L 1232.2 688.9 Z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 538.5 -242.2 L 619.5 -212 L 683.3 147.9 L 602.4 117.7 L 634.4 297.6 L 180.2 716 L 341.9 776.4 L 357.9 866.3 L 163.3 1045.6 L 51.5 415.8 L -78.3 535.4 L 2.6 565.6 L -127.2 685.1 L -208 654.9 L -12.4 56 L 52.5 -3.8 L 100.4 266.1 L 230.1 146.6 L 278.1 416.5 L 472.7 237.2 L 408.8 -122.7 Z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 1232.2 688.9 L 1264.2 868.8 L 1199.2 928.5 L 1167.3 748.7 L 1232.2 688.9 Z" />
|
||||
<path
|
||||
android:fillColor="#F6F5F5"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 1264.2 868.8 L 1345 898.9 L 1360.9 988.9 L 1199.2 928.5 L 1264.2 868.8 Z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 1474.7 779.4 L 1376.9 1078.9 L 1345 898.9 L 1474.7 779.4 Z" />
|
||||
<path
|
||||
android:fillColor="#F6F5F5"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 51.5 415.8 L 115.3 775.7 L -127.2 685.1 L 2.6 565.6 L -78.3 535.4 L 51.5 415.8 Z" />
|
||||
<path
|
||||
android:fillColor="#F0F0F0"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 341.9 776.4 L 503.6 836.8 L 438.7 896.5 L 357.9 866.3 Z" />
|
||||
<path
|
||||
android:fillColor="#F0F0F0"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 811 867.6 L 891.8 897.7 L 923.7 1077.6 L 842.9 1047.5 L 811 867.6 Z" />
|
||||
<path
|
||||
android:fillColor="#F0F0F0"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M -208 654.9 L 115.3 775.7 L 147.3 955.6 L -176.1 834.8 Z" />
|
||||
<path
|
||||
android:fillColor="#F6F5F5"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 357.9 866.3 L 438.7 896.5 L 373.8 956.3 L 405.8 1136.2 L 421.7 1226.1 L -225 984.6 L -354.7 1104.1 L -305.8 954.4 L -176.1 834.8 L 147.3 955.6 L 163.3 1045.6 Z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 811 867.5 L 842.9 1047.4 L 778.1 1107.3 L 746.2 927.4 L 811 867.5 Z" />
|
||||
<path
|
||||
android:fillColor="#F6F5F5"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 842.9 1047.5 L 923.7 1077.6 L 939.7 1167.6 L 778.1 1107.3 L 842.9 1047.5 Z" />
|
||||
<path
|
||||
android:fillColor="#F0F0F0"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 568.5 777 L 811 867.6 L 746.1 927.4 L 778.1 1107.3 L 939.7 1167.6 L 874.8 1227.3 L 632.4 1136.8 L 568.5 777 Z" />
|
||||
<path
|
||||
android:fillColor="#F6F5F5"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 405.8 1136.2 L 421.7 1226.2 L 421.7 1226.1 Z" />
|
||||
<path
|
||||
android:fillColor="#F0F0F0"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 1021.6 778.1 L 1183.3 838.6 L 1199.2 928.5 L 1360.9 988.9 L 1376.9 1078.9 L 1254.6 1453.2 L 1214.2 1438.1 L 1134.4 988.4 L 1069.5 1048.1 L 1021.6 778.1 Z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M -208 654.9 L -176.1 834.8 L -305.8 954.4 Z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 476.8 1536.3 L 485.6 1586 L 485.6 1586 Z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 485.7 1586 L 728.1 1676.6 L 533.5 1855.9 Z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 728.1 1676.6 L 889.8 1737 L 760 1856.5 Z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 729.2 1256.9 L 745.1 1346.9 L 664.3 1316.7 Z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 1069.5 1048.1 L 1134.4 988.3 L 1214.2 1438.1 L 1149.2 1497.9 L 745.1 1346.9 L 810 1287.1 L 874.8 1227.3 L 939.7 1167.6 L 923.7 1077.6 L 891.8 897.7 L 1021.6 778.1 Z" />
|
||||
<path
|
||||
android:fillColor="#F0F0F0"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 729.2 1257 L 810 1287.2 L 745.1 1346.9 L 729.2 1257 Z" />
|
||||
<path
|
||||
android:fillColor="#F0F0F0"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M -144.2 1014.8 L 421.7 1226.1 L 437.6 1316.1 L 518.6 1346.3 L 453.6 1406.1 L 469.6 1496 L 65.4 1345 L 49.4 1255 L -15.4 1314.9 L -96.3 1284.7 Z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 568.5 777 L 632.4 1136.8 L 437.7 1316.1 L 421.7 1226.2 L 421.7 1226.1 L 405.8 1136.2 L 373.8 956.3 L 438.7 896.5 L 503.6 836.8 Z" />
|
||||
<path
|
||||
android:fillColor="#F6F5F5"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 874.8 1227.3 L 810 1287.1 L 729.2 1256.9 L 664.3 1316.7 L 583.5 1286.6 L 518.6 1346.3 L 437.6 1316.1 L 632.3 1136.7 L 874.8 1227.3 " />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M -225 984.6 L -144.2 1014.8 L -96.2 1284.7 L -355.7 1523.8 L -194.1 1584.2 L -178.1 1674.1 L -420.6 1583.5 L -452.6 1403.6 L -354.7 1104.1 Z" />
|
||||
<path
|
||||
android:fillColor="#F6F5F5"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M -145.2 1434.4 L -129.2 1524.3 L 65.4 1345 L 469.6 1496 L 476.8 1536.3 L 485.6 1586 L 243.1 1495.4 L 113.3 1614.9 L 48.4 1674.7 L -355.8 1523.8 L -96.3 1284.7 L -15.5 1314.8 Z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 1132.3 1827.6 L 1083.4 1977.3 L 888.8 2156.6 L 872.9 2066.6 L 937.7 2006.9 Z" />
|
||||
<path
|
||||
android:fillColor="#F6F5F5"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M -15.5 1314.8 L -15.4 1314.9 L -145.1 1434.4 Z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 49.4 1255.1 L 65.4 1345.1 L -129.2 1524.4 L -145.1 1434.4 L -15.5 1314.8 L -15.4 1314.9 Z" />
|
||||
<path
|
||||
android:fillColor="#F6F5F5"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 1214.2 1438.1 L 1254.6 1453.2 L 1230.1 1528.1 L 1149.2 1497.9 Z" />
|
||||
<path
|
||||
android:fillColor="#F6F5F5"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M -452.6 1403.6 L -420.6 1583.5 L -501.5 1553.3 L -452.6 1403.6 Z" />
|
||||
<path
|
||||
android:fillColor="#F0F0F0"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M -194.1 1584.2 L 48.4 1674.7 L -16.4 1734.5 L 47.5 2094.3 L -195.1 2003.7 L -243 1733.9 L -307.9 1793.6 L -509.9 1718.1 L -525.9 1628.2 L -501.5 1553.3 L -178.1 1674.1 Z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 306.9 1855.2 L 436.7 1735.7 L 468.6 1915.6 L 274 2094.9 L 258 2004.9 L 128.3 2124.5 L 47.4 2094.3 L -16.4 1734.5 L 48.4 1674.7 L 113.3 1614.9 L 243.1 1495.4 Z" />
|
||||
<path
|
||||
android:fillColor="#F0F0F0"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 243.1 1495.4 L 485.6 1586 L 533.5 1855.9 L 695.2 1916.3 L 630.3 1976 L 468.6 1915.6 L 436.7 1735.7 L 306.9 1855.2 Z" />
|
||||
<path
|
||||
android:fillColor="#F0F0F0"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 695.2 1916.3 L 937.7 2006.9 L 872.9 2066.6 L 888.8 2156.6 L 1010.1 2201.9 L 936.7 2426.5 L 775 2366.1 Z" />
|
||||
<path
|
||||
android:fillColor="#F6F5F5"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 1083.5 1977.3 L 1010.1 2201.9 L 888.8 2156.6 L 1083.5 1977.3 Z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M -243 1733.9 L -195.1 2003.7 L -437.6 1913.2 L -243 1733.9 Z" />
|
||||
<path
|
||||
android:fillColor="#F6F5F5"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 468.6 1915.6 L 630.3 1976 L 435.7 2155.3 L 370.8 2215.1 L 128.3 2124.5 L 258 2004.9 L 274 2094.9 Z" />
|
||||
<path
|
||||
android:fillColor="#F6F5F5"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M -509.9 1718.1 L -307.9 1793.6 L -437.6 1913.2 L -599.3 1852.8 L -574.8 1777.8 L -509.9 1718.1 Z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M -525.9 1628.2 L -509.9 1718.1 L -574.8 1777.8 L -525.9 1628.2 Z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 695.2 1916.3 L 775 2366.1 L 370.8 2215.1 L 435.7 2155.3 L 630.3 1976 Z" />
|
||||
<path
|
||||
android:fillColor="#F0F0F0"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 583.5 1286.6 L 1230.2 1528.1 L 1181.3 1677.8 L 615.4 1466.5 Z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 583.5 1286.6 L 615.4 1466.5 L 485.7 1586 L 453.7 1406.1 Z" />
|
||||
<path
|
||||
android:fillColor="#F6F5F5"
|
||||
android:fillAlpha="0.62"
|
||||
android:strokeAlpha="0.62"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M 615.4 1466.5 L 1181.3 1677.8 L 1132.3 1827.6 L 937.7 2006.9 L 533.5 1855.9 L 728.1 1676.6 L 760 1856.5 L 889.8 1737 L 485.7 1586 Z" />
|
||||
</group>
|
||||
</vector>
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@color/white" />
|
||||
<padding
|
||||
android:bottom="8dp"
|
||||
android:left="8dp"
|
||||
android:right="8dp"
|
||||
android:top="8dp" />
|
||||
</shape>
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<padding
|
||||
android:bottom="8dp"
|
||||
android:left="8dp"
|
||||
android:right="8dp"
|
||||
android:top="8dp" />
|
||||
<corners android:radius="3dp" />
|
||||
<stroke
|
||||
android:width="2dp"
|
||||
android:color="@color/gradientOrange"
|
||||
android:dashGap="16dp"
|
||||
android:dashWidth="16dp" />
|
||||
</shape>
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@color/white" />
|
||||
<padding
|
||||
android:bottom="8dp"
|
||||
android:left="8dp"
|
||||
android:right="8dp"
|
||||
android:top="8dp" />
|
||||
<stroke
|
||||
android:width="2dp"
|
||||
android:color="#FF979797"
|
||||
android:dashGap="8dp"
|
||||
android:dashWidth="8dp" />
|
||||
</shape>
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<padding
|
||||
android:bottom="8dp"
|
||||
android:left="8dp"
|
||||
android:right="8dp"
|
||||
android:top="8dp" />
|
||||
<stroke
|
||||
android:width="2dp"
|
||||
android:color="@color/gradientOrange" />
|
||||
</shape>
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/gradient_all" />
|
||||
<item
|
||||
android:height="?attr/actionBarSize"
|
||||
android:drawable="@drawable/texture_cash" />
|
||||
</layer-list>
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/gradientOrange" />
|
||||
</shape>
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/moneroGray" />
|
||||
</shape>
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/button_disabled" android:state_enabled="false" />
|
||||
<item android:drawable="@drawable/button_default" android:state_enabled="true" />
|
||||
<item android:drawable="@drawable/button_default" android:state_pressed="false" />
|
||||
</selector>
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<gradient
|
||||
android:angle="45"
|
||||
android:endColor="@color/gradientOrange"
|
||||
android:startColor="@color/gradientPink"
|
||||
android:type="linear" />
|
||||
</shape>
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<gradient
|
||||
android:angle="45"
|
||||
android:endColor="@color/gradientOrange"
|
||||
android:startColor="@color/gradientPink"
|
||||
android:type="linear" />
|
||||
</shape>
|
|
@ -0,0 +1,73 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:oneshot="true">
|
||||
<item
|
||||
android:drawable="@drawable/gunther_wallets_00"
|
||||
android:duration="500" />
|
||||
<item
|
||||
android:drawable="@drawable/gunther_wallets_01"
|
||||
android:duration="200" />
|
||||
<item
|
||||
android:drawable="@drawable/gunther_wallets_02"
|
||||
android:duration="2000" />
|
||||
<item
|
||||
android:drawable="@drawable/gunther_wallets_03"
|
||||
android:duration="1000" />
|
||||
<item
|
||||
android:drawable="@drawable/gunther_wallets_04"
|
||||
android:duration="100" />
|
||||
<item
|
||||
android:drawable="@drawable/gunther_wallets_05"
|
||||
android:duration="1000" />
|
||||
<item
|
||||
android:drawable="@drawable/gunther_wallets_06"
|
||||
android:duration="0" />
|
||||
<item
|
||||
android:drawable="@drawable/gunther_wallets_07"
|
||||
android:duration="0" />
|
||||
<item
|
||||
android:drawable="@drawable/gunther_wallets_08"
|
||||
android:duration="0" />
|
||||
<item
|
||||
android:drawable="@drawable/gunther_wallets_09"
|
||||
android:duration="0" />
|
||||
<item
|
||||
android:drawable="@drawable/gunther_wallets_10"
|
||||
android:duration="0" />
|
||||
<item
|
||||
android:drawable="@drawable/gunther_wallets_11"
|
||||
android:duration="0" />
|
||||
<item
|
||||
android:drawable="@drawable/gunther_wallets_12"
|
||||
android:duration="0" />
|
||||
<item
|
||||
android:drawable="@drawable/gunther_wallets_13"
|
||||
android:duration="0" />
|
||||
<item
|
||||
android:drawable="@drawable/gunther_wallets_14"
|
||||
android:duration="0" />
|
||||
<item
|
||||
android:drawable="@drawable/gunther_wallets_15"
|
||||
android:duration="0" />
|
||||
<item
|
||||
android:drawable="@drawable/gunther_wallets_16"
|
||||
android:duration="0" />
|
||||
<item
|
||||
android:drawable="@drawable/gunther_wallets_17"
|
||||
android:duration="0" />
|
||||
<item
|
||||
android:drawable="@drawable/gunther_wallets_18"
|
||||
android:duration="5000" />
|
||||
<item
|
||||
android:drawable="@drawable/gunther_wallets_19"
|
||||
android:duration="0" />
|
||||
<item
|
||||
android:drawable="@drawable/gunther_wallets_20"
|
||||
android:duration="0" />
|
||||
<item
|
||||
android:drawable="@drawable/gunther_wallets_21"
|
||||
android:duration="100" />
|
||||
<item
|
||||
android:drawable="@drawable/gunther_wallets_22"
|
||||
android:duration="200" />
|
||||
</animation-list>
|
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="20.0"
|
||||
android:viewportWidth="20.0">
|
||||
<path
|
||||
android:fillColor="@color/moneroFab"
|
||||
android:pathData="M11,5L9,5L9,9L5,9L5,11L9,11L9,15L11,15L11,11L15,11L15,9L11,9L11,5L11,5ZM10,0C4.5,0 0,4.5 0,10C0,15.5 4.5,20 10,20C15.5,20 20,15.5 20,10C20,4.5 15.5,0 10,0L10,0ZM10,18C5.6,18 2,14.4 2,10C2,5.6 5.6,2 10,2C14.4,2 18,5.6 18,10C18,14.4 14.4,18 10,18L10,18Z" />
|
||||
</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="#FFffffff"
|
||||
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" />
|
||||
</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="#FFffffff"
|
||||
android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z" />
|
||||
</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="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
|
||||
</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="@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"/>
|
||||
</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="@color/moneroGray"
|
||||
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,13 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<group
|
||||
android:translateX="0.000000"
|
||||
android:translateY="+7.000000">
|
||||
<path
|
||||
android:fillColor="#417505"
|
||||
android:pathData="M17.6,1.4L16.2,0L9.9,6.3L11.3,7.7L17.6,1.4L17.6,1.4ZM21.8,0L11.3,10.6L7.1,6.4L5.7,7.8L11.3,13.4L23.3,1.4L21.8,0L21.8,0ZM0,7.8L5.6,13.4L7,12L1.4,6.4L0,7.8L0,7.8Z" />
|
||||
</group>
|
||||
</vector>
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="29dp"
|
||||
android:height="17dp"
|
||||
android:viewportHeight="17"
|
||||
android:viewportWidth="29">
|
||||
|
||||
<group
|
||||
android:translateX="-219.000000"
|
||||
android:translateY="-74.000000">
|
||||
<group
|
||||
android:translateX="219.000000"
|
||||
android:translateY="74.000000">
|
||||
<path
|
||||
android:fillColor="#FEFEFE"
|
||||
android:pathData="M14.4474298,13.6840973 C11.5770468,13.6840973 9.24995106,11.3571559
|
||||
9.24995106,8.48677287 C9.24995106,5.61623564 11.5770468,3.28929415
|
||||
14.4474298,3.28929415 C17.3178128,3.28929415 19.6449085,5.61623564
|
||||
19.6449085,8.48677287 C19.6449085,11.3571559 17.3178128,13.6840973
|
||||
14.4474298,13.6840973 M14.4474298,-4.62765957e-05 C8.23695638,-4.62765957e-05
|
||||
2.82706809,3.42395904 3.08510638e-05,8.48692713 C2.82706809,13.5494324
|
||||
8.23695638,16.9734378 14.4474298,16.9734378 C20.6579032,16.9734378
|
||||
26.0676372,13.5494324 28.8948287,8.48692713 C26.0676372,3.42395904
|
||||
20.6579032,-4.62765957e-05 14.4474298,-4.62765957e-05"
|
||||
android:strokeWidth="1" />
|
||||
</group>
|
||||
</group>
|
||||
</vector>
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="14dp"
|
||||
android:height="14dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="#FFffffff"
|
||||
android:pathData="M12,21.35l-1.45,-1.32C5.4,15.36 2,12.28 2,8.5 2,5.42 4.42,3 7.5,3c1.74,0 3.41,0.81 4.5,2.09C13.09,3.81 14.76,3 16.5,3 19.58,3 22,5.42 22,8.5c0,3.78 -3.4,6.86 -8.55,11.54L12,21.35z" />
|
||||
</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="#FFffffff"
|
||||
android:pathData="M12,21.35l-1.45,-1.32C5.4,15.36 2,12.28 2,8.5 2,5.42 4.42,3 7.5,3c1.74,0 3.41,0.81 4.5,2.09C13.09,3.81 14.76,3 16.5,3 19.58,3 22,5.42 22,8.5c0,3.78 -3.4,6.86 -8.55,11.54L12,21.35z" />
|
||||
</vector>
|
|
@ -0,0 +1,21 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="22.0"
|
||||
android:viewportWidth="22.0">
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M13.985,8.648C14.245,8.798 14.478,8.873 14.684,8.873C14.817,8.873 14.925,8.842 15.008,8.777C15.093,8.713 15.135,8.63 15.135,8.527C15.135,8.418 15.089,8.333 14.998,8.272C14.907,8.212 14.778,8.181 14.611,8.181C14.43,8.181 14.24,8.219 14.04,8.295L14.293,6.397L15.913,6.397L15.913,7.177L14.985,7.177L14.915,7.502C14.976,7.498 15.025,7.496 15.063,7.496C15.33,7.496 15.556,7.592 15.74,7.782C15.923,7.971 16.014,8.207 16.014,8.49C16.014,8.822 15.896,9.099 15.66,9.321C15.426,9.543 15.132,9.654 14.776,9.654C14.472,9.654 14.175,9.572 13.882,9.407L13.985,8.648ZM15,11C16.657,11 18,9.657 18,8C18,6.343 16.657,5 15,5C13.343,5 12,6.343 12,8C12,9.657 13.343,11 15,11L15,11Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeWidth="1" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M21.344,12.691C20.503,12.122 19.588,12.527 19.168,12.769L14.417,16.615L10.807,16.616L10.035,15.847L12.871,15.847C13.724,15.847 14.679,15.293 14.679,14.308C14.679,13.262 13.724,12.769 12.871,12.769L11.808,12.769C11.019,12.769 10.096,12.839 9.446,12.492C8.828,12.179 8.116,12.001 7.356,12.001C6.081,12.001 4.939,12.507 4.157,13.307L-0,17.385L4.631,22L6.175,19.692L13.993,19.692C14.771,19.692 15.522,19.408 16.103,18.893L21.397,13.745C21.72,13.459 21.702,12.933 21.344,12.691"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeWidth="1" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M10.115,1.099L11.102,1.099L11.102,3.926L10.397,3.926L10.397,1.776L10.115,1.776L10.115,1.099ZM10.692,5C11.967,5 13,3.881 13,2.5C13,1.119 11.967,-0 10.692,-0C9.418,-0 8.384,1.119 8.384,2.5C8.384,3.881 9.418,5 10.692,5L10.692,5Z"
|
||||
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="#FF000000"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,19h-2v-2h2v2zM15.07,11.25l-0.9,0.92C13.45,12.9 13,13.5 13,15h-2v-0.5c0,-1.1 0.45,-2.1 1.17,-2.83l1.24,-1.26c0.37,-0.36 0.59,-0.86 0.59,-1.41 0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2L8,9c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,0.88 -0.36,1.68 -0.93,2.25z"/>
|
||||
android:fillColor="#FFffffff"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,19h-2v-2h2v2zM15.07,11.25l-0.9,0.92C13.45,12.9 13,13.5 13,15h-2v-0.5c0,-1.1 0.45,-2.1 1.17,-2.83l1.24,-1.26c0.37,-0.36 0.59,-0.86 0.59,-1.41 0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2L8,9c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,0.88 -0.36,1.68 -0.93,2.25z" />
|
||||
</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="@color/moneroFab"
|
||||
android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/>
|
||||
</vector>
|
|
@ -4,6 +4,6 @@
|
|||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:fillColor="#FFffffff"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zm1,15h-2v-6h2v6zm0,-8h-2V7h2v2z" />
|
||||
</vector>
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="29dp"
|
||||
android:height="13dp"
|
||||
android:viewportHeight="13"
|
||||
android:viewportWidth="29">
|
||||
|
||||
<group
|
||||
android:translateX="-219.000000"
|
||||
android:translateY="-136.000000">
|
||||
<group
|
||||
android:translateX="219.000000"
|
||||
android:translateY="136.000000">
|
||||
<path
|
||||
android:fillColor="#FEFEFE"
|
||||
android:pathData="M6.29687258,9.00290326 C4.95784407,9.00290326 3.87228646,7.88216454
|
||||
3.87228646,6.49992511 C3.87228646,5.11783546 4.95784407,3.99709674
|
||||
6.29687258,3.99709674 C7.63604617,3.99709674 8.72160379,5.11783546
|
||||
8.72160379,6.49992511 C8.72160379,7.88216454 7.63604617,9.00290326
|
||||
6.29687258,9.00290326 L6.29687258,9.00290326 Z M19.5790661,4.89647346
|
||||
L12.4001961,4.89647346 C11.7082656,2.08212076 9.23841162,0 6.29687258,0
|
||||
C2.81922883,0 0,2.9099068 0,6.49992511 C0,10.0899434 2.81922883,13 6.29687258,13
|
||||
C9.23841162,13 11.7082656,10.9178792 12.4001961,8.10352654
|
||||
L19.5790661,8.10352654 L19.5790661,13 L21.3018556,13 L21.3018556,9.33689328
|
||||
L23.3905602,9.33689328 L23.3905602,13 L25.3240193,13 L25.3240193,10.81259
|
||||
L27.3216078,10.81259 L27.3216078,13 L29,13 L29,8.10352654 L29,4.89647346
|
||||
L19.5790661,4.89647346 Z"
|
||||
android:strokeWidth="1" />
|
||||
</group>
|
||||
</group>
|
||||
</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="#FF000000"
|
||||
android:pathData="M8.59,16.34l4.58,-4.59 -4.58,-4.59L10,5.75l6,6 -6,6z"/>
|
||||
</vector>
|
|
@ -0,0 +1,36 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="135dp"
|
||||
android:height="48dp"
|
||||
android:viewportHeight="108.0"
|
||||
android:viewportWidth="304.0">
|
||||
<path
|
||||
android:fillColor="#FFffffff"
|
||||
android:pathData="M74.4,65.14q-4.73,-4.88 -4.73,-12.84t4.95,-12.87A16.88,16.88 0,0 1,87 34.52a16.88,16.88 0,0 1,12.4 4.92q4.95,4.92 4.95,12.84A16.91,16.91 0,0 1,99.2 65.11,17.62 17.62,0 0,1 86.58,70 16.2,16.2 0,0 1,74.4 65.14ZM86.58,65.33a11.53,11.53 0,0 0,8.36 -3.48q3.54,-3.48 3.54,-9.61T95.1,42.66a11.11,11.11 0,0 0,-8.24 -3.44,10.7 10.7,0 0,0 -8.11,3.44q-3.26,3.45 -3.26,9.61t3.13,9.61A10.27,10.27 0,0 0,86.58 65.33Z" />
|
||||
<path
|
||||
android:fillColor="#FFffffff"
|
||||
android:pathData="M117.21,35.08v5.57q3.51,-6.14 11.21,-6.14a13,13 0,0 1,9.52 3.79q3.82,3.79 3.82,10.8V69.46h-5.64V50.05q0,-5.2 -2.5,-7.89a9,9 0,0 0,-6.92 -2.69,9.09 9.09,0 0,0 -7,2.69q-2.54,2.69 -2.54,7.89V69.46h-5.7V35.08Z" />
|
||||
<path
|
||||
android:fillColor="#FFffffff"
|
||||
android:pathData="M165.24,70a15.82,15.82 0,0 1,-12 -4.88q-4.63,-4.88 -4.63,-12.9t4.7,-12.87a16.2,16.2 0,0 1,12.18 -4.85q7.48,0 12,4.6A16,16 0,0 1,182 50.87a21.51,21.51 0,0 1,-0.25 3.38L154.4,54.25a11.81,11.81 0,0 0,3.22 8.11,10.3 10.3,0 0,0 7.61,3 10.63,10.63 0,0 0,5.92 -1.57,9.3 9.3,0 0,0 3.54,-4.13h6.14a15.79,15.79 0,0 1,-5.61 7.45A16.33,16.33 0,0 1,165.24 70ZM172.94,42.16a11.23,11.23 0,0 0,-15.16 -0.06,11.65 11.65,0 0,0 -3.32,8h21.61A10.73,10.73 0,0 0,172.94 42.19Z" />
|
||||
<path
|
||||
android:fillColor="#FFffffff"
|
||||
android:pathData="M194.8,35.08v5.82q3.07,-6.39 10.46,-6.39v5.95h-1.5q-4.38,0 -6.67,2.29t-2.29,7.92V69.46h-5.7V35.08Z" />
|
||||
<path
|
||||
android:fillColor="#FFffffff"
|
||||
android:pathData="M236.38,35.08h5.7V69.46h-5.7V64Q232.93,70 225.17,70a13,13 0,0 1,-9.52 -3.79q-3.82,-3.79 -3.82,-10.74V35.08h5.64V54.56q0,5.14 2.54,7.86a10.15,10.15 0,0 0,13.84 0q2.54,-2.72 2.54,-7.86Z" />
|
||||
<path
|
||||
android:fillColor="#FFffffff"
|
||||
android:pathData="M254.35,29.57a3.9,3.9 0,0 0,2.76 -6.64,3.85 3.85,0 0,0 -6.58,2.76 3.8,3.8 0,0 0,1.1 2.75A3.64,3.64 0,0 0,254.35 29.57Z" />
|
||||
<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" />
|
||||
<path
|
||||
android:fillColor="#FFffffff"
|
||||
android:pathData="M269,65.14q-4.73,-4.88 -4.73,-12.84t4.95,-12.87a18.09,18.09 0,0 1,24.8 0Q299,44.35 299,52.28a16.91,16.91 0,0 1,-5.17 12.84A17.62,17.62 0,0 1,281.21 70,16.2 16.2,0 0,1 269,65.14ZM281.18,65.33a11.53,11.53 0,0 0,8.36 -3.48q3.54,-3.48 3.54,-9.61t-3.38,-9.58a11.11,11.11 0,0 0,-8.24 -3.44,10.7 10.7,0 0,0 -8.11,3.44q-3.26,3.45 -3.26,9.61t3.13,9.61A10.27,10.27 0,0 0,281.21 65.33Z" />
|
||||
</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="#FF000000"
|
||||
android:pathData="M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6z"/>
|
||||
</vector>
|
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="29dp"
|
||||
android:height="29dp"
|
||||
android:viewportHeight="29"
|
||||
android:viewportWidth="29">
|
||||
|
||||
<group
|
||||
android:translateX="-219.000000"
|
||||
android:translateY="-7.000000">
|
||||
<group
|
||||
android:translateX="219.000000"
|
||||
android:translateY="7.000000">
|
||||
<path
|
||||
android:fillColor="#FEFEFE"
|
||||
android:pathData="M11.0476403,8.86547314 C10.1626979,9.41441547 9.41459398,10.1624996
|
||||
8.86563718,11.047619 L3.4524022,5.63432651 L5.63440531,3.45238095
|
||||
L11.0476403,8.86547314 Z M14.8450352,7.41694052 C14.2508096,7.41694052
|
||||
13.6733955,7.47975215 13.1190689,7.5952381 L13.1190689,0 L16.5714498,0
|
||||
L16.5714498,7.5952381 C16.0168991,7.47995092 15.4394849,7.41694052
|
||||
14.8450352,7.41694052 Z M7.92772894,14.8624137 C7.92772894,15.4344301
|
||||
7.99486447,15.9902634 8.11830037,16.5240878 L0,16.5240878 L0,13.2007396
|
||||
L8.11830037,13.2007396 C7.99486447,13.734564 7.92772894,14.2903973
|
||||
7.92772894,14.8624137 Z M20.1343478,11.047619 C19.5854054,10.1627
|
||||
18.8375216,9.41461581 17.9524022,8.86547314 L23.3654944,3.45238095
|
||||
L25.5476403,5.63432651 L20.1343478,11.047619 Z M21.4047832,13.1190476
|
||||
L29.0000212,13.1190476 L29.0000212,16.5714286 L21.4047832,16.5714286
|
||||
C21.5202661,16.0168778 21.5830761,15.4394636 21.5830761,14.8452381
|
||||
C21.5830761,14.2510125 21.5202661,13.6735984 21.4047832,13.1190476 Z
|
||||
M8.86557962,17.952381 C9.4145509,18.8373234 10.1626745,19.5854273
|
||||
11.0476403,20.1345844 L5.63446287,25.547619 L3.4524022,23.3656159
|
||||
L8.86557962,17.952381 Z M17.9524022,20.1345269 C18.8373679,19.5855845
|
||||
19.5854916,18.8375004 20.1344629,17.952381 L25.5476403,23.3654731
|
||||
L23.36578,25.547619 L17.9524022,20.1345269 Z M14.8450352,21.5830595
|
||||
C15.4394849,21.5830595 16.0168991,21.5200491 16.5714498,21.4047619
|
||||
L16.5714498,29 L13.1190689,29 L13.1190689,21.4047619 C13.6733955,21.5200491
|
||||
14.2508096,21.5830595 14.8450352,21.5830595 Z"
|
||||
android:strokeWidth="1" />
|
||||
</group>
|
||||
</group>
|
||||
</vector>
|
|
@ -0,0 +1,13 @@
|
|||
<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="30.0"
|
||||
android:viewportWidth="30.0">
|
||||
<path
|
||||
android:fillColor="#FF640C"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M26.667,27.996L27.991,26.667L27.991,20L30,20L30,26.667C30,28.5 28.5,30 26.667,30L20,30L20,27.996L26.667,27.996ZM3.333,27.996L10,27.996L10,30L3.333,30C1.5,30 0,28.5 0,26.667L0,20L2.009,20L2.009,26.667L3.333,27.996ZM26.667,2.004L20,2.004L20,0L26.667,0C28.5,0 30,1.5 30,3.333L30,10L27.991,10L27.991,3.333L26.667,2.004ZM3.333,2.004L2.009,3.333L2.009,10L0,10L0,3.333C0,1.5 1.5,0 3.333,0L10,0L10,2.004L3.333,2.004Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeWidth="1" />
|
||||
</vector>
|
|
@ -0,0 +1,21 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="6.35"
|
||||
android:viewportHeight="6.3500004">
|
||||
<path
|
||||
android:pathData="m4.518,3.147c0.341,-0.341 0.45,-0.827 0.327,-1.26 -0.433,-0.123 -0.919,-0.014 -1.26,0.327 -0.341,0.341 -0.45,0.827 -0.327,1.26 0.433,0.123 0.919,0.014 1.26,-0.328"
|
||||
android:fillColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="m2.731,2.214c-0.341,-0.341 -0.826,-0.45 -1.26,-0.327 -0.123,0.433 -0.014,0.919 0.327,1.26 0.341,0.341 0.827,0.45 1.26,0.328 0.123,-0.433 0.014,-0.919 -0.327,-1.26"
|
||||
android:fillColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="M3.064,2.185l0.206,0l0,3.126l-0.206,0z"
|
||||
android:fillColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="m4.18,5.357c0,-0.549 -0.445,-0.994 -0.994,-0.994 -0.549,0 -0.994,0.445 -0.994,0.994 0,0.549 0.445,0.994 0.994,0.994 0.549,0 0.994,-0.445 0.994,-0.994"
|
||||
android:fillColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="m3.834,1.123c0,-0.482 -0.266,-0.903 -0.659,-1.123 -0.393,0.22 -0.659,0.64 -0.659,1.123 -0,0.483 0.266,0.903 0.659,1.123 0.393,-0.22 0.659,-0.64 0.659,-1.123"
|
||||
android:fillColor="#ffffff"/>
|
||||
</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="#FFFFFFFF"
|
||||
android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z" />
|
||||
</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="@color/gradientOrange"
|
||||
android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98s-0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.12,-0.22 -0.39,-0.3 -0.61,-0.22l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.23,-0.09 -0.49,0 -0.61,0.22l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98s0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.12,0.22 0.39,0.3 0.61,0.22l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.23,0.09 0.49,0 0.61,-0.22l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM12,15.5c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5 3.5,1.57 3.5,3.5 -1.57,3.5 -3.5,3.5z"/>
|
||||
</vector>
|
|
@ -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/moneroWhite"
|
||||
android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z" />
|
||||
</vector>
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="16.0"
|
||||
android:viewportWidth="13.0">
|
||||
<path
|
||||
android:fillColor="@color/trafficGray"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M8.401,0.431L8.401,1.741C8.401,2.064 8.163,2.326 7.87,2.326L0.569,2.326C0.255,2.326 0,2.605 0,2.951L0,5.031C0,5.376 0.255,5.657 0.569,5.657L7.87,5.657C8.163,5.657 8.401,5.918 8.401,6.24L8.401,7.569C8.401,7.934 8.788,8.133 9.042,7.899L12.809,4.447C13.064,4.215 13.064,3.785 12.809,3.553L9.042,0.101C8.788,-0.133 8.401,0.066 8.401,0.431L8.401,0.431L8.401,0.431ZM4.599,8.431L4.599,9.742C4.599,10.065 4.837,10.326 5.131,10.326L12.431,10.326C12.746,10.326 13,10.606 13,10.952L13,13.03C13,13.376 12.746,13.656 12.431,13.656L5.131,13.656C4.837,13.656 4.599,13.917 4.599,14.24L4.599,15.569C4.599,15.934 4.212,16.133 3.957,15.9L0.19,12.447C-0.063,12.215 -0.063,11.786 0.19,11.553L3.957,8.101C4.212,7.867 4.599,8.066 4.599,8.431L4.599,8.431L4.599,8.431Z" />
|
||||
</vector>
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true">
|
||||
<shape>
|
||||
<solid android:color="@color/colorAccent" />
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
<item android:state_pressed="false">
|
||||
<shape>
|
||||
<solid android:color="@android:color/transparent" />
|
||||
</shape>
|
||||
</item>
|
||||
</selector>
|
After Width: | Height: | Size: 48 KiB |
|
@ -2,11 +2,17 @@
|
|||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/backgound_all"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include
|
||||
layout="@layout/toolbar" />
|
||||
<com.m2049r.xmrwallet.layout.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
style="@style/ToolBarStyle.Event"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/backgound_toolbar_mainnet"
|
||||
android:minHeight="?attr/actionBarSize" />
|
||||
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/fragment_container"
|
|
@ -2,12 +2,17 @@
|
|||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/backgound_all"
|
||||
android:gravity="center_horizontal"
|
||||
android:background="@color/moneroBlack"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include
|
||||
layout="@layout/toolbar" />
|
||||
<com.m2049r.xmrwallet.layout.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
style="@style/ToolBarStyle.Event"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/backgound_toolbar_mainnet"
|
||||
android:minHeight="?attr/actionBarSize" />
|
||||
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/fragment_container"
|
|
@ -0,0 +1,160 @@
|
|||
<?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"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="8sp">
|
||||
|
||||
<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:orientation="horizontal"
|
||||
android:weightSum="2">
|
||||
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:id="@+id/etWalletName"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
app:counterEnabled="true"
|
||||
app:counterMaxLength="20"
|
||||
app:errorEnabled="true">
|
||||
|
||||
<android.support.design.widget.TextInputEditText
|
||||
style="@style/MoneroEdit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/generate_name_hint"
|
||||
android:imeOptions="actionNext"
|
||||
android:inputType="text"
|
||||
android:maxLines="1"
|
||||
android:textAlignment="textStart" />
|
||||
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:id="@+id/etWalletPassword"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1">
|
||||
|
||||
<android.support.design.widget.TextInputEditText
|
||||
style="@style/MoneroEdit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:hint="@string/generate_password_hint"
|
||||
android:imeOptions="actionNext"
|
||||
android:inputType="text"
|
||||
android:textAlignment="textStart" />
|
||||
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:id="@+id/etWalletMnemonic"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:errorEnabled="true">
|
||||
|
||||
<android.support.design.widget.TextInputEditText
|
||||
style="@style/MoneroEdit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/generate_mnemonic_hint"
|
||||
android:imeOptions="actionNext"
|
||||
android:inputType="textMultiLine"
|
||||
android:textAlignment="center" />
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:id="@+id/etWalletAddress"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
|
||||
app:counterEnabled="true"
|
||||
app:counterMaxLength="95"
|
||||
app:errorEnabled="true">
|
||||
|
||||
<android.support.design.widget.TextInputEditText
|
||||
style="@style/MoneroEdit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/generate_address_hint"
|
||||
android:imeOptions="actionNext"
|
||||
android:inputType="textMultiLine"
|
||||
android:textAlignment="center" />
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:id="@+id/etWalletViewKey"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:counterEnabled="true"
|
||||
app:counterMaxLength="64"
|
||||
app:errorEnabled="true">
|
||||
|
||||
<android.support.design.widget.TextInputEditText
|
||||
android:id="@+id/textInputEditText"
|
||||
style="@style/MoneroEdit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/generate_viewkey_hint"
|
||||
android:imeOptions="actionNext"
|
||||
android:inputType="textMultiLine"
|
||||
android:textAlignment="center" />
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:id="@+id/etWalletSpendKey"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:counterEnabled="true"
|
||||
app:counterMaxLength="64"
|
||||
app:errorEnabled="true">
|
||||
|
||||
<android.support.design.widget.TextInputEditText
|
||||
style="@style/MoneroEdit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/generate_spendkey_hint"
|
||||
android:imeOptions="actionNext"
|
||||
android:inputType="textMultiLine"
|
||||
android:textAlignment="center" />
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:id="@+id/etWalletRestoreHeight"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:errorEnabled="true">
|
||||
|
||||
<android.support.design.widget.TextInputEditText
|
||||
style="@style/MoneroEdit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/generate_restoreheight_hint"
|
||||
android:imeOptions="actionDone"
|
||||
android:inputType="number"
|
||||
android:textAlignment="center" />
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/bGenerate"
|
||||
style="@style/MoneroButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:text="@string/generate_buttonGenerate" />
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
|
@ -0,0 +1,71 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout 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:layout_margin="8sp">
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etDummy"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp" />
|
||||
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:hint="@string/label_daemon">
|
||||
|
||||
<com.m2049r.xmrwallet.layout.DropDownEditText
|
||||
android:id="@+id/etDaemonAddress"
|
||||
style="@style/MoneroEdit.Small"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="start"
|
||||
android:hint="@string/prompt_daemon"
|
||||
android:imeOptions="actionDone"
|
||||
android:inputType="textWebEmailAddress|textNoSuggestions"
|
||||
android:maxLines="1"
|
||||
android:textIsSelectable="true" />
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
|
||||
<TextView
|
||||
style="@style/MoneroLabel.Heading"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:padding="8sp"
|
||||
android:text="@string/label_login_wallets" />
|
||||
|
||||
<FrameLayout 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">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivGuntherWallets"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/gunther_wallets_00" />
|
||||
|
||||
<android.support.v7.widget.RecyclerView xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:paddingBottom="72dp"
|
||||
app:layoutManager="LinearLayoutManager"
|
||||
tools:listitem="@layout/item_wallet" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<include layout="@layout/layout_fabmenu" />
|
||||
|
||||
</FrameLayout>
|