mirror of
https://github.com/m2049r/xmrwallet
synced 2025-09-06 19:00:30 +02:00
Compare commits
43 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0776b7b6a3 | ||
![]() |
c2eed85a83 | ||
![]() |
d7c2b4a727 | ||
![]() |
085e41f5da | ||
![]() |
6c6b3061a8 | ||
![]() |
5fc15779b7 | ||
![]() |
520d151f3c | ||
![]() |
7aad941dab | ||
![]() |
01e7693425 | ||
![]() |
091538752b | ||
![]() |
d5b95dd976 | ||
![]() |
008f06959c | ||
![]() |
817816cd34 | ||
![]() |
9d41d5da52 | ||
![]() |
ad76a7ffc1 | ||
![]() |
475542c4f3 | ||
![]() |
b5d0659ca9 | ||
![]() |
781bfbc78b | ||
![]() |
8985511209 | ||
![]() |
3c8a4ce967 | ||
![]() |
fcfedbcfae | ||
![]() |
74279b135a | ||
![]() |
d6d2de8312 | ||
![]() |
af0ecb2894 | ||
![]() |
975cc4f43c | ||
![]() |
74ba36de26 | ||
![]() |
7627e15a48 | ||
![]() |
37244cb9e0 | ||
![]() |
843566b820 | ||
![]() |
0bcf156929 | ||
![]() |
b1d91e2671 | ||
![]() |
271cd2d4a8 | ||
![]() |
22c5a543db | ||
![]() |
cd986860c5 | ||
![]() |
0cf5981eae | ||
![]() |
e109df34f0 | ||
![]() |
5a7aa6cc77 | ||
![]() |
f50629ff81 | ||
![]() |
cb12d64e5f | ||
![]() |
a8f08fb9b9 | ||
![]() |
3e9be418a8 | ||
![]() |
fa5dc9988d | ||
![]() |
857cf8d6d8 |
@@ -7,8 +7,8 @@ android {
|
|||||||
applicationId "com.m2049r.xmrwallet"
|
applicationId "com.m2049r.xmrwallet"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 25
|
targetSdkVersion 25
|
||||||
versionCode 91
|
versionCode 99
|
||||||
versionName "1.5.1 'CrAzY Nacho'"
|
versionName "1.5.9 'Maximum Nacho'"
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -60,7 +60,15 @@ enum {
|
|||||||
HASH_DATA_AREA = 136
|
HASH_DATA_AREA = 136
|
||||||
};
|
};
|
||||||
|
|
||||||
void cn_slow_hash(const void *data, size_t length, char *hash);
|
void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed);
|
||||||
|
|
||||||
|
inline void slow_hash(const void *data, const size_t length, char *hash) {
|
||||||
|
cn_slow_hash(data, length, hash, 0 /* variant */, 0/*prehashed*/);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void slow_hash_broken(const void *data, char *hash, int variant) {
|
||||||
|
cn_slow_hash(data, 200 /*sizeof(union hash_state)*/, hash, variant, 1 /*prehashed*/);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@@ -53,7 +53,6 @@ import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
|
|||||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.security.KeyStoreException;
|
|
||||||
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
@@ -62,27 +61,26 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
static final public String VIEW_TYPE_ACCEPT = "accept";
|
static final public String VIEW_TYPE_ACCEPT = "accept";
|
||||||
static final public String VIEW_TYPE_WALLET = "wallet";
|
static final public String VIEW_TYPE_WALLET = "wallet";
|
||||||
|
|
||||||
ScrollView scrollview;
|
public static final String REQUEST_TYPE = "type";
|
||||||
|
public static final String REQUEST_PATH = "path";
|
||||||
|
public static final String REQUEST_PASSWORD = "password";
|
||||||
|
|
||||||
ProgressBar pbProgress;
|
private ScrollView scrollview;
|
||||||
TextView tvWalletPassword;
|
|
||||||
TextView tvWalletAddress;
|
|
||||||
TextView tvWalletMnemonic;
|
|
||||||
TextView tvWalletViewKey;
|
|
||||||
TextView tvWalletSpendKey;
|
|
||||||
ImageButton bCopyAddress;
|
|
||||||
LinearLayout llAdvancedInfo;
|
|
||||||
LinearLayout llPassword;
|
|
||||||
Button bAdvancedInfo;
|
|
||||||
Button bAccept;
|
|
||||||
|
|
||||||
// TODO fix visibility of variables
|
private ProgressBar pbProgress;
|
||||||
String walletPath;
|
private TextView tvWalletPassword;
|
||||||
String walletName;
|
private TextView tvWalletAddress;
|
||||||
// we need to keep the password so the user is not asked again if they want to change it
|
private TextView tvWalletMnemonic;
|
||||||
// note they can only enter this fragment immediately after entering the password
|
private TextView tvWalletViewKey;
|
||||||
// so asking them to enter it a couple of seconds later seems silly
|
private TextView tvWalletSpendKey;
|
||||||
String walletPassword = null;
|
private ImageButton bCopyAddress;
|
||||||
|
private LinearLayout llAdvancedInfo;
|
||||||
|
private LinearLayout llPassword;
|
||||||
|
private Button bAdvancedInfo;
|
||||||
|
private Button bAccept;
|
||||||
|
|
||||||
|
private String walletPath;
|
||||||
|
private String walletName;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
@@ -104,10 +102,10 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
|
|
||||||
bAccept = (Button) view.findViewById(R.id.bAccept);
|
bAccept = (Button) view.findViewById(R.id.bAccept);
|
||||||
|
|
||||||
boolean testnet = WalletManager.getInstance().getNetworkType() != NetworkType.NetworkType_Mainnet;
|
boolean allowCopy = WalletManager.getInstance().getNetworkType() != NetworkType.NetworkType_Mainnet;
|
||||||
tvWalletMnemonic.setTextIsSelectable(testnet);
|
tvWalletMnemonic.setTextIsSelectable(allowCopy);
|
||||||
tvWalletSpendKey.setTextIsSelectable(testnet);
|
tvWalletSpendKey.setTextIsSelectable(allowCopy);
|
||||||
tvWalletPassword.setTextIsSelectable(testnet);
|
tvWalletPassword.setTextIsSelectable(allowCopy);
|
||||||
|
|
||||||
bAccept.setOnClickListener(new View.OnClickListener() {
|
bAccept.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
@@ -136,14 +134,14 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Bundle args = getArguments();
|
Bundle args = getArguments();
|
||||||
type = args.getString("type");
|
type = args.getString(REQUEST_TYPE);
|
||||||
walletPath = args.getString("path");
|
walletPath = args.getString(REQUEST_PATH);
|
||||||
showDetails(args.getString("password"));
|
localPassword = args.getString(REQUEST_PASSWORD);
|
||||||
|
showDetails();
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
void showDetails(String password) {
|
void showDetails() {
|
||||||
walletPassword = password;
|
|
||||||
showProgress();
|
showProgress();
|
||||||
tvWalletPassword.setText(null);
|
tvWalletPassword.setText(null);
|
||||||
new AsyncShow().executeOnExecutor(MoneroThreadPoolExecutor.MONERO_THREAD_POOL_EXECUTOR, walletPath);
|
new AsyncShow().executeOnExecutor(MoneroThreadPoolExecutor.MONERO_THREAD_POOL_EXECUTOR, walletPath);
|
||||||
@@ -178,7 +176,7 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
|
|
||||||
private void acceptWallet() {
|
private void acceptWallet() {
|
||||||
bAccept.setEnabled(false);
|
bAccept.setEnabled(false);
|
||||||
acceptCallback.onAccept(walletName, walletPassword);
|
acceptCallback.onAccept(walletName, getPassword());
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AsyncShow extends AsyncTask<String, Void, Boolean> {
|
private class AsyncShow extends AsyncTask<String, Void, Boolean> {
|
||||||
@@ -201,7 +199,7 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
wallet = GenerateReviewFragment.this.walletCallback.getWallet();
|
wallet = GenerateReviewFragment.this.walletCallback.getWallet();
|
||||||
closeWallet = false;
|
closeWallet = false;
|
||||||
} else {
|
} else {
|
||||||
wallet = WalletManager.getInstance().openWallet(walletPath, walletPassword);
|
wallet = WalletManager.getInstance().openWallet(walletPath, getPassword());
|
||||||
closeWallet = true;
|
closeWallet = true;
|
||||||
}
|
}
|
||||||
name = wallet.getName();
|
name = wallet.getName();
|
||||||
@@ -231,10 +229,8 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
bAccept.setVisibility(View.VISIBLE);
|
bAccept.setVisibility(View.VISIBLE);
|
||||||
bAccept.setEnabled(true);
|
bAccept.setEnabled(true);
|
||||||
}
|
}
|
||||||
if (walletPassword != null) {
|
llPassword.setVisibility(View.VISIBLE);
|
||||||
llPassword.setVisibility(View.VISIBLE);
|
tvWalletPassword.setText(getPassword());
|
||||||
tvWalletPassword.setText(walletPassword);
|
|
||||||
}
|
|
||||||
tvWalletAddress.setText(address);
|
tvWalletAddress.setText(address);
|
||||||
tvWalletMnemonic.setText(seed);
|
tvWalletMnemonic.setText(seed);
|
||||||
tvWalletViewKey.setText(viewKey);
|
tvWalletViewKey.setText(viewKey);
|
||||||
@@ -260,6 +256,7 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
ProgressListener progressCallback = null;
|
ProgressListener progressCallback = null;
|
||||||
AcceptListener acceptCallback = null;
|
AcceptListener acceptCallback = null;
|
||||||
ListenerWithWallet walletCallback = null;
|
ListenerWithWallet walletCallback = null;
|
||||||
|
PasswordChangedListener passwordCallback = null;
|
||||||
|
|
||||||
public interface Listener {
|
public interface Listener {
|
||||||
void setTitle(String title, String subtitle);
|
void setTitle(String title, String subtitle);
|
||||||
@@ -282,6 +279,24 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
Wallet getWallet();
|
Wallet getWallet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface PasswordChangedListener {
|
||||||
|
void onPasswordChanged(String newPassword);
|
||||||
|
|
||||||
|
String getPassword();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String localPassword = null;
|
||||||
|
|
||||||
|
private String getPassword() {
|
||||||
|
if (passwordCallback != null) return passwordCallback.getPassword();
|
||||||
|
return localPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setPassword(String password) {
|
||||||
|
if (passwordCallback != null) passwordCallback.onPasswordChanged(password);
|
||||||
|
else localPassword = password;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(Context context) {
|
public void onAttach(Context context) {
|
||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
@@ -297,6 +312,9 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
if (context instanceof ListenerWithWallet) {
|
if (context instanceof ListenerWithWallet) {
|
||||||
this.walletCallback = (ListenerWithWallet) context;
|
this.walletCallback = (ListenerWithWallet) context;
|
||||||
}
|
}
|
||||||
|
if (context instanceof PasswordChangedListener) {
|
||||||
|
this.passwordCallback = (PasswordChangedListener) context;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -328,7 +346,7 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||||
String type = getArguments().getString("type");
|
String type = getArguments().getString(REQUEST_TYPE); // intance variable <type> not set yet
|
||||||
if (GenerateReviewFragment.VIEW_TYPE_ACCEPT.equals(type)) {
|
if (GenerateReviewFragment.VIEW_TYPE_ACCEPT.equals(type)) {
|
||||||
inflater.inflate(R.menu.wallet_details_help_menu, menu);
|
inflater.inflate(R.menu.wallet_details_help_menu, menu);
|
||||||
super.onCreateOptionsMenu(menu, inflater);
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
@@ -345,7 +363,7 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
wallet = GenerateReviewFragment.this.walletCallback.getWallet();
|
wallet = GenerateReviewFragment.this.walletCallback.getWallet();
|
||||||
closeWallet = false;
|
closeWallet = false;
|
||||||
} else {
|
} else {
|
||||||
wallet = WalletManager.getInstance().openWallet(walletPath, walletPassword);
|
wallet = WalletManager.getInstance().openWallet(walletPath, getPassword());
|
||||||
closeWallet = true;
|
closeWallet = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,19 +391,19 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Boolean doInBackground(String... params) {
|
protected Boolean doInBackground(String... params) {
|
||||||
if (params.length != 4) return false;
|
if (params.length != 2) return false;
|
||||||
File walletFile = Helper.getWalletFile(getActivity(), params[0]);
|
final String userPassword = params[0];
|
||||||
String oldPassword = params[1];
|
final boolean fingerPassValid = Boolean.valueOf(params[1]);
|
||||||
String userPassword = params[2];
|
|
||||||
boolean fingerprintAuthAllowed = Boolean.valueOf(params[3]);
|
|
||||||
newPassword = KeyStoreHelper.getCrazyPass(getActivity(), userPassword);
|
newPassword = KeyStoreHelper.getCrazyPass(getActivity(), userPassword);
|
||||||
boolean success = changeWalletPassword(newPassword);
|
final boolean success = changeWalletPassword(newPassword);
|
||||||
if (success) {
|
if (success) {
|
||||||
if (fingerprintAuthAllowed) {
|
Context ctx = getActivity();
|
||||||
KeyStoreHelper.saveWalletUserPass(getActivity(), walletName, userPassword);
|
if (ctx != null)
|
||||||
} else {
|
if (fingerPassValid) {
|
||||||
KeyStoreHelper.removeWalletUserPass(getActivity(), walletName);
|
KeyStoreHelper.saveWalletUserPass(ctx, walletName, userPassword);
|
||||||
}
|
} else {
|
||||||
|
KeyStoreHelper.removeWalletUserPass(ctx, walletName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
@@ -393,14 +411,15 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(Boolean result) {
|
protected void onPostExecute(Boolean result) {
|
||||||
super.onPostExecute(result);
|
super.onPostExecute(result);
|
||||||
if (getActivity().isDestroyed()) {
|
if ((getActivity() == null) || getActivity().isDestroyed()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (progressCallback != null)
|
if (progressCallback != null)
|
||||||
progressCallback.dismissProgressDialog();
|
progressCallback.dismissProgressDialog();
|
||||||
if (result) {
|
if (result) {
|
||||||
Toast.makeText(getActivity(), getString(R.string.changepw_success), Toast.LENGTH_SHORT).show();
|
Toast.makeText(getActivity(), getString(R.string.changepw_success), Toast.LENGTH_SHORT).show();
|
||||||
showDetails(newPassword);
|
setPassword(newPassword);
|
||||||
|
showDetails();
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(getActivity(), getString(R.string.changepw_failed), Toast.LENGTH_LONG).show();
|
Toast.makeText(getActivity(), getString(R.string.changepw_failed), Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
@@ -447,11 +466,7 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
swFingerprintAllowed.setChecked(FingerprintHelper.isFingerPassValid(getActivity(), walletName));
|
||||||
swFingerprintAllowed.setChecked(FingerprintHelper.isFingerprintAuthAllowed(walletName));
|
|
||||||
} catch (KeyStoreException ex) {
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
etPasswordA.getEditText().addTextChangedListener(new TextWatcher() {
|
etPasswordA.getEditText().addTextChangedListener(new TextWatcher() {
|
||||||
@@ -527,7 +542,7 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
} else if (!newPasswordA.equals(newPasswordB)) {
|
} else if (!newPasswordA.equals(newPasswordB)) {
|
||||||
etPasswordB.setError(getString(R.string.generate_bad_passwordB));
|
etPasswordB.setError(getString(R.string.generate_bad_passwordB));
|
||||||
} else if (newPasswordA.equals(newPasswordB)) {
|
} else if (newPasswordA.equals(newPasswordB)) {
|
||||||
new AsyncChangePassword().execute(walletName, walletPassword, newPasswordA, Boolean.toString(swFingerprintAllowed.isChecked()));
|
new AsyncChangePassword().execute(newPasswordA, Boolean.toString(swFingerprintAllowed.isChecked()));
|
||||||
Helper.hideKeyboardAlways(getActivity());
|
Helper.hideKeyboardAlways(getActivity());
|
||||||
openDialog.dismiss();
|
openDialog.dismiss();
|
||||||
openDialog = null;
|
openDialog = null;
|
||||||
@@ -549,7 +564,7 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
} else if (!newPasswordA.equals(newPasswordB)) {
|
} else if (!newPasswordA.equals(newPasswordB)) {
|
||||||
etPasswordB.setError(getString(R.string.generate_bad_passwordB));
|
etPasswordB.setError(getString(R.string.generate_bad_passwordB));
|
||||||
} else if (newPasswordA.equals(newPasswordB)) {
|
} else if (newPasswordA.equals(newPasswordB)) {
|
||||||
new AsyncChangePassword().execute(walletName, walletPassword, newPasswordA, Boolean.toString(swFingerprintAllowed.isChecked()));
|
new AsyncChangePassword().execute(newPasswordA, Boolean.toString(swFingerprintAllowed.isChecked()));
|
||||||
Helper.hideKeyboardAlways(getActivity());
|
Helper.hideKeyboardAlways(getActivity());
|
||||||
openDialog.dismiss();
|
openDialog.dismiss();
|
||||||
openDialog = null;
|
openDialog = null;
|
||||||
|
@@ -50,7 +50,6 @@ import com.m2049r.xmrwallet.model.NetworkType;
|
|||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
import com.m2049r.xmrwallet.model.WalletManager;
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
import com.m2049r.xmrwallet.service.WalletService;
|
import com.m2049r.xmrwallet.service.WalletService;
|
||||||
import com.m2049r.xmrwallet.util.FingerprintHelper;
|
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
import com.m2049r.xmrwallet.util.KeyStoreHelper;
|
import com.m2049r.xmrwallet.util.KeyStoreHelper;
|
||||||
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
|
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
|
||||||
@@ -63,7 +62,6 @@ import java.io.IOException;
|
|||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.nio.channels.FileChannel;
|
import java.nio.channels.FileChannel;
|
||||||
import java.security.KeyStoreException;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
@@ -229,17 +227,20 @@ public class LoginActivity extends SecureActivity
|
|||||||
@Override
|
@Override
|
||||||
protected Boolean doInBackground(String... params) {
|
protected Boolean doInBackground(String... params) {
|
||||||
if (params.length != 2) return false;
|
if (params.length != 2) return false;
|
||||||
File walletFile = Helper.getWalletFile(LoginActivity.this, params[0]);
|
String oldName = params[0];
|
||||||
String newName = params[1];
|
String newName = params[1];
|
||||||
|
File walletFile = Helper.getWalletFile(LoginActivity.this, oldName);
|
||||||
boolean success = renameWallet(walletFile, newName);
|
boolean success = renameWallet(walletFile, newName);
|
||||||
try {
|
try {
|
||||||
if (success && FingerprintHelper.isFingerprintAuthAllowed(params[0])) {
|
if (success) {
|
||||||
String savedPass = KeyStoreHelper.loadWalletUserPass(LoginActivity.this, params[0]);
|
String savedPass = KeyStoreHelper.loadWalletUserPass(LoginActivity.this, oldName);
|
||||||
KeyStoreHelper.saveWalletUserPass(LoginActivity.this, newName, savedPass);
|
KeyStoreHelper.saveWalletUserPass(LoginActivity.this, newName, savedPass);
|
||||||
KeyStoreHelper.removeWalletUserPass(LoginActivity.this, params[0]);
|
|
||||||
}
|
}
|
||||||
} catch (KeyStoreException ex) {
|
} catch (KeyStoreHelper.BrokenPasswordStoreException ex) {
|
||||||
ex.printStackTrace();
|
Timber.w(ex);
|
||||||
|
} finally {
|
||||||
|
// we have either set a new password or it is broken - kill the old one either way
|
||||||
|
KeyStoreHelper.removeWalletUserPass(LoginActivity.this, oldName);
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
@@ -1006,11 +1007,11 @@ public class LoginActivity extends SecureActivity
|
|||||||
case R.id.action_privacy_policy:
|
case R.id.action_privacy_policy:
|
||||||
PrivacyFragment.display(getSupportFragmentManager());
|
PrivacyFragment.display(getSupportFragmentManager());
|
||||||
return true;
|
return true;
|
||||||
case R.id.action_testnet:
|
case R.id.action_stagenet:
|
||||||
try {
|
try {
|
||||||
LoginFragment loginFragment = (LoginFragment)
|
LoginFragment loginFragment = (LoginFragment)
|
||||||
getSupportFragmentManager().findFragmentById(R.id.fragment_container);
|
getSupportFragmentManager().findFragmentById(R.id.fragment_container);
|
||||||
item.setChecked(loginFragment.onTestnetMenuItem());
|
item.setChecked(loginFragment.onStagenetMenuItem());
|
||||||
} catch (ClassCastException ex) {
|
} catch (ClassCastException ex) {
|
||||||
// never mind then
|
// never mind then
|
||||||
}
|
}
|
||||||
|
@@ -18,15 +18,12 @@ package com.m2049r.xmrwallet;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.res.ColorStateList;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.design.widget.FloatingActionButton;
|
import android.support.design.widget.FloatingActionButton;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
import android.support.v4.content.ContextCompat;
|
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.view.Gravity;
|
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
@@ -41,14 +38,11 @@ import android.widget.AdapterView;
|
|||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.ImageButton;
|
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.RelativeLayout;
|
import android.widget.RelativeLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.dialog.HelpFragment;
|
|
||||||
import com.m2049r.xmrwallet.layout.WalletInfoAdapter;
|
import com.m2049r.xmrwallet.layout.WalletInfoAdapter;
|
||||||
import com.m2049r.xmrwallet.model.NetworkType;
|
import com.m2049r.xmrwallet.model.NetworkType;
|
||||||
import com.m2049r.xmrwallet.model.WalletManager;
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
@@ -343,69 +337,65 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
|||||||
@Override
|
@Override
|
||||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||||
inflater.inflate(R.menu.list_menu, menu);
|
inflater.inflate(R.menu.list_menu, menu);
|
||||||
menu.findItem(R.id.action_testnet).setChecked(testnetCheckMenu);
|
menu.findItem(R.id.action_stagenet).setChecked(stagenetCheckMenu);
|
||||||
super.onCreateOptionsMenu(menu, inflater);
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean testnetCheckMenu = BuildConfig.DEBUG;
|
private boolean stagenetCheckMenu = BuildConfig.DEBUG;
|
||||||
|
|
||||||
//boolean isTestnet() {
|
public boolean onStagenetMenuItem() {
|
||||||
// return testnet;
|
boolean lastState = stagenetCheckMenu;
|
||||||
//}
|
|
||||||
|
|
||||||
public boolean onTestnetMenuItem() {
|
|
||||||
boolean lastState = testnetCheckMenu;
|
|
||||||
setNet(!lastState, true); // set and save
|
setNet(!lastState, true); // set and save
|
||||||
return !lastState;
|
return !lastState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNet(boolean testnetChecked, boolean save) {
|
public void setNet(boolean stagenetChecked, boolean save) {
|
||||||
this.testnetCheckMenu = testnetChecked;
|
this.stagenetCheckMenu = stagenetChecked;
|
||||||
NetworkType net = testnetChecked ? NetworkType.NetworkType_Testnet : NetworkType.NetworkType_Mainnet;
|
NetworkType net = stagenetChecked ? NetworkType.NetworkType_Stagenet : NetworkType.NetworkType_Mainnet;
|
||||||
activityCallback.setNetworkType(net);
|
activityCallback.setNetworkType(net);
|
||||||
activityCallback.showNet();
|
activityCallback.showNet();
|
||||||
if (save) {
|
if (save) {
|
||||||
savePrefs(true); // use previous state as we just clicked it
|
savePrefs(true); // use previous state as we just clicked it
|
||||||
}
|
}
|
||||||
if (testnetChecked) {
|
if (stagenetChecked) {
|
||||||
setDaemon(daemonTestNet);
|
setDaemon(daemonStageNet);
|
||||||
} else {
|
} else {
|
||||||
setDaemon(daemonMainNet);
|
setDaemon(daemonMainNet);
|
||||||
}
|
}
|
||||||
loadList();
|
loadList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String PREF_DAEMON_TESTNET = "daemon_testnet";
|
private static final String PREF_DAEMON_STAGENET = "daemon_stagenet";
|
||||||
private static final String PREF_DAEMON_MAINNET = "daemon_mainnet";
|
private static final String PREF_DAEMON_MAINNET = "daemon_mainnet";
|
||||||
|
|
||||||
private static final String PREF_DAEMONLIST_MAINNET =
|
private static final String PREF_DAEMONLIST_MAINNET =
|
||||||
"node.moneroworld.com:18089;node.xmrbackb.one;node.xmr.be";
|
"node.moneroworld.com:18089;node.xmrbackb.one;node.xmr.be";
|
||||||
|
|
||||||
private static final String PREF_DAEMONLIST_TESTNET =
|
private static final String PREF_DAEMONLIST_STAGENET =
|
||||||
"testnet.xmrchain.net";
|
"stagenet.monerujo.io;stagenet.xmr-tw.org";
|
||||||
|
|
||||||
private NodeList daemonTestNet;
|
private NodeList daemonStageNet;
|
||||||
private NodeList daemonMainNet;
|
private NodeList daemonMainNet;
|
||||||
|
|
||||||
void loadPrefs() {
|
void loadPrefs() {
|
||||||
SharedPreferences sharedPref = activityCallback.getPrefs();
|
SharedPreferences sharedPref = activityCallback.getPrefs();
|
||||||
|
|
||||||
daemonMainNet = new NodeList(sharedPref.getString(PREF_DAEMON_MAINNET, PREF_DAEMONLIST_MAINNET));
|
daemonMainNet = new NodeList(sharedPref.getString(PREF_DAEMON_MAINNET, PREF_DAEMONLIST_MAINNET));
|
||||||
daemonTestNet = new NodeList(sharedPref.getString(PREF_DAEMON_TESTNET, PREF_DAEMONLIST_TESTNET));
|
daemonStageNet = new NodeList(sharedPref.getString(PREF_DAEMON_STAGENET, PREF_DAEMONLIST_STAGENET));
|
||||||
setNet(testnetCheckMenu, false);
|
setNet(stagenetCheckMenu, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void savePrefs() {
|
void savePrefs() {
|
||||||
savePrefs(false);
|
savePrefs(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void savePrefs(boolean usePreviousTestnetState) {
|
void savePrefs(boolean usePreviousNetState) {
|
||||||
Timber.d("SAVE / %s", usePreviousTestnetState);
|
Timber.d("SAVE / %s", usePreviousNetState);
|
||||||
// save the daemon address for the net
|
// save the daemon address for the net
|
||||||
boolean testnet = testnetCheckMenu ^ usePreviousTestnetState;
|
boolean stagenet = stagenetCheckMenu ^ usePreviousNetState;
|
||||||
String daemon = getDaemon();
|
String daemon = getDaemon();
|
||||||
if (testnet) {
|
if (stagenet) {
|
||||||
daemonTestNet.setRecent(daemon);
|
daemonStageNet.setRecent(daemon);
|
||||||
} else {
|
} else {
|
||||||
daemonMainNet.setRecent(daemon);
|
daemonMainNet.setRecent(daemon);
|
||||||
}
|
}
|
||||||
@@ -413,7 +403,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
|||||||
SharedPreferences sharedPref = activityCallback.getPrefs();
|
SharedPreferences sharedPref = activityCallback.getPrefs();
|
||||||
SharedPreferences.Editor editor = sharedPref.edit();
|
SharedPreferences.Editor editor = sharedPref.edit();
|
||||||
editor.putString(PREF_DAEMON_MAINNET, daemonMainNet.toString());
|
editor.putString(PREF_DAEMON_MAINNET, daemonMainNet.toString());
|
||||||
editor.putString(PREF_DAEMON_TESTNET, daemonTestNet.toString());
|
editor.putString(PREF_DAEMON_STAGENET, daemonStageNet.toString());
|
||||||
editor.apply();
|
editor.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -62,6 +62,8 @@ import timber.log.Timber;
|
|||||||
public class ReceiveFragment extends Fragment {
|
public class ReceiveFragment extends Fragment {
|
||||||
|
|
||||||
private ProgressBar pbProgress;
|
private ProgressBar pbProgress;
|
||||||
|
private View llAddress;
|
||||||
|
private TextView tvAddressLabel;
|
||||||
private TextView tvAddress;
|
private TextView tvAddress;
|
||||||
private TextInputLayout etPaymentId;
|
private TextInputLayout etPaymentId;
|
||||||
private ExchangeView evAmount;
|
private ExchangeView evAmount;
|
||||||
@@ -71,6 +73,10 @@ public class ReceiveFragment extends Fragment {
|
|||||||
private ImageView qrCodeFull;
|
private ImageView qrCodeFull;
|
||||||
private EditText etDummy;
|
private EditText etDummy;
|
||||||
private ImageButton bCopyAddress;
|
private ImageButton bCopyAddress;
|
||||||
|
private Button bSubaddress;
|
||||||
|
|
||||||
|
private Wallet wallet = null;
|
||||||
|
private boolean isMyWallet = false;
|
||||||
|
|
||||||
public interface Listener {
|
public interface Listener {
|
||||||
void setToolbarButton(int type);
|
void setToolbarButton(int type);
|
||||||
@@ -87,6 +93,8 @@ public class ReceiveFragment extends Fragment {
|
|||||||
View view = inflater.inflate(R.layout.fragment_receive, container, false);
|
View view = inflater.inflate(R.layout.fragment_receive, container, false);
|
||||||
|
|
||||||
pbProgress = (ProgressBar) view.findViewById(R.id.pbProgress);
|
pbProgress = (ProgressBar) view.findViewById(R.id.pbProgress);
|
||||||
|
llAddress = view.findViewById(R.id.llAddress);
|
||||||
|
tvAddressLabel = (TextView) view.findViewById(R.id.tvAddressLabel);
|
||||||
tvAddress = (TextView) view.findViewById(R.id.tvAddress);
|
tvAddress = (TextView) view.findViewById(R.id.tvAddress);
|
||||||
etPaymentId = (TextInputLayout) view.findViewById(R.id.etPaymentId);
|
etPaymentId = (TextInputLayout) view.findViewById(R.id.etPaymentId);
|
||||||
evAmount = (ExchangeView) view.findViewById(R.id.evAmount);
|
evAmount = (ExchangeView) view.findViewById(R.id.evAmount);
|
||||||
@@ -96,6 +104,7 @@ public class ReceiveFragment extends Fragment {
|
|||||||
qrCodeFull = (ImageView) view.findViewById(R.id.qrCodeFull);
|
qrCodeFull = (ImageView) view.findViewById(R.id.qrCodeFull);
|
||||||
etDummy = (EditText) view.findViewById(R.id.etDummy);
|
etDummy = (EditText) view.findViewById(R.id.etDummy);
|
||||||
bCopyAddress = (ImageButton) view.findViewById(R.id.bCopyAddress);
|
bCopyAddress = (ImageButton) view.findViewById(R.id.bCopyAddress);
|
||||||
|
bSubaddress = (Button) view.findViewById(R.id.bSubaddress);
|
||||||
|
|
||||||
etPaymentId.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
etPaymentId.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||||
etDummy.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
etDummy.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||||
@@ -106,7 +115,7 @@ public class ReceiveFragment extends Fragment {
|
|||||||
copyAddress();
|
copyAddress();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
bCopyAddress.setClickable(false);
|
enableCopyAddress(false);
|
||||||
|
|
||||||
evAmount.setOnNewAmountListener(new ExchangeView.OnNewAmountListener() {
|
evAmount.setOnNewAmountListener(new ExchangeView.OnNewAmountListener() {
|
||||||
@Override
|
@Override
|
||||||
@@ -162,6 +171,37 @@ public class ReceiveFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
bSubaddress.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
enableSubaddressButton(false);
|
||||||
|
enableCopyAddress(false);
|
||||||
|
|
||||||
|
final Runnable resetSize = new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
tvAddress.animate().setDuration(125).scaleX(1).scaleY(1).start();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
final Runnable newAddress = new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
tvAddressLabel.setText(getString(R.string.generate_address_label_sub,
|
||||||
|
wallet.getNumSubaddresses() - 1));
|
||||||
|
tvAddress.setText(wallet.getNewSubaddress());
|
||||||
|
storeWallet();
|
||||||
|
generateQr();
|
||||||
|
enableCopyAddress(true);
|
||||||
|
tvAddress.animate().alpha(1).setDuration(125)
|
||||||
|
.scaleX(1.2f).scaleY(1.2f)
|
||||||
|
.withEndAction(resetSize).start();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
tvAddress.animate().alpha(0).setDuration(250)
|
||||||
|
.withEndAction(newAddress).start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
qrCode.setOnClickListener(new View.OnClickListener() {
|
qrCode.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
@@ -194,11 +234,25 @@ public class ReceiveFragment extends Fragment {
|
|||||||
String password = b.getString("password");
|
String password = b.getString("password");
|
||||||
loadAndShow(path, password);
|
loadAndShow(path, password);
|
||||||
} else {
|
} else {
|
||||||
show(walletName, address);
|
if (getActivity() instanceof GenerateReviewFragment.ListenerWithWallet) {
|
||||||
|
wallet = ((GenerateReviewFragment.ListenerWithWallet) getActivity()).getWallet();
|
||||||
|
show();
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("no wallet info");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void enableSubaddressButton(boolean enable) {
|
||||||
|
bSubaddress.setEnabled(enable);
|
||||||
|
if (enable) {
|
||||||
|
bSubaddress.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.ic_settings_orange_24dp, 0, 0);
|
||||||
|
} else {
|
||||||
|
bSubaddress.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.ic_settings_gray_24dp, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void copyAddress() {
|
void copyAddress() {
|
||||||
Helper.clipBoardCopy(getActivity(), getString(R.string.label_copy_address), tvAddress.getText().toString());
|
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();
|
Toast.makeText(getActivity(), getString(R.string.message_copy_address), Toast.LENGTH_SHORT).show();
|
||||||
@@ -228,25 +282,38 @@ public class ReceiveFragment extends Fragment {
|
|||||||
super.onResume();
|
super.onResume();
|
||||||
Timber.d("onResume()");
|
Timber.d("onResume()");
|
||||||
listenerCallback.setToolbarButton(Toolbar.BUTTON_BACK);
|
listenerCallback.setToolbarButton(Toolbar.BUTTON_BACK);
|
||||||
listenerCallback.setSubtitle(getString(R.string.receive_title));
|
if (wallet != null) {
|
||||||
generateQr();
|
listenerCallback.setSubtitle(wallet.getAccountLabel());
|
||||||
|
generateQr();
|
||||||
|
} else {
|
||||||
|
listenerCallback.setSubtitle(getString(R.string.status_wallet_loading));
|
||||||
|
clearQR();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isLoaded = false;
|
private boolean isLoaded = false;
|
||||||
|
|
||||||
private void show(String name, String address) {
|
private void show() {
|
||||||
Timber.d("name=%s", name);
|
Timber.d("name=%s", wallet.getName());
|
||||||
isLoaded = true;
|
isLoaded = true;
|
||||||
listenerCallback.setTitle(name);
|
listenerCallback.setTitle(wallet.getName());
|
||||||
tvAddress.setText(address);
|
listenerCallback.setSubtitle(wallet.getAccountLabel());
|
||||||
|
tvAddress.setText(wallet.getAddress());
|
||||||
etPaymentId.setEnabled(true);
|
etPaymentId.setEnabled(true);
|
||||||
bPaymentId.setEnabled(true);
|
bPaymentId.setEnabled(true);
|
||||||
bCopyAddress.setClickable(true);
|
enableCopyAddress(true);
|
||||||
bCopyAddress.setImageResource(R.drawable.ic_content_copy_black_24dp);
|
|
||||||
hideProgress();
|
hideProgress();
|
||||||
generateQr();
|
generateQr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void enableCopyAddress(boolean enable) {
|
||||||
|
bCopyAddress.setClickable(enable);
|
||||||
|
if (enable)
|
||||||
|
bCopyAddress.setImageResource(R.drawable.ic_content_copy_black_24dp);
|
||||||
|
else
|
||||||
|
bCopyAddress.setImageResource(R.drawable.ic_content_nocopy_black_24dp);
|
||||||
|
}
|
||||||
|
|
||||||
private void loadAndShow(String walletPath, String password) {
|
private void loadAndShow(String walletPath, String password) {
|
||||||
new AsyncShow().executeOnExecutor(MoneroThreadPoolExecutor.MONERO_THREAD_POOL_EXECUTOR,
|
new AsyncShow().executeOnExecutor(MoneroThreadPoolExecutor.MONERO_THREAD_POOL_EXECUTOR,
|
||||||
walletPath, password);
|
walletPath, password);
|
||||||
@@ -254,18 +321,14 @@ public class ReceiveFragment extends Fragment {
|
|||||||
|
|
||||||
private class AsyncShow extends AsyncTask<String, Void, Boolean> {
|
private class AsyncShow extends AsyncTask<String, Void, Boolean> {
|
||||||
String password;
|
String password;
|
||||||
String address;
|
|
||||||
String name;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Boolean doInBackground(String... params) {
|
protected Boolean doInBackground(String... params) {
|
||||||
if (params.length != 2) return false;
|
if (params.length != 2) return false;
|
||||||
String walletPath = params[0];
|
String walletPath = params[0];
|
||||||
password = params[1];
|
password = params[1];
|
||||||
Wallet wallet = WalletManager.getInstance().openWallet(walletPath, password);
|
wallet = WalletManager.getInstance().openWallet(walletPath, password);
|
||||||
address = wallet.getAddress();
|
isMyWallet = true;
|
||||||
name = wallet.getName();
|
|
||||||
wallet.close();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,7 +337,7 @@ public class ReceiveFragment extends Fragment {
|
|||||||
super.onPostExecute(result);
|
super.onPostExecute(result);
|
||||||
if (!isAdded()) return; // never mind
|
if (!isAdded()) return; // never mind
|
||||||
if (result) {
|
if (result) {
|
||||||
show(name, address);
|
show();
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(getActivity(), getString(R.string.receive_cannot_open), Toast.LENGTH_LONG).show();
|
Toast.makeText(getActivity(), getString(R.string.receive_cannot_open), Toast.LENGTH_LONG).show();
|
||||||
hideProgress();
|
hideProgress();
|
||||||
@@ -282,6 +345,27 @@ public class ReceiveFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void storeWallet() {
|
||||||
|
new AsyncStore().executeOnExecutor(MoneroThreadPoolExecutor.MONERO_THREAD_POOL_EXECUTOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AsyncStore extends AsyncTask<String, Void, Boolean> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Boolean doInBackground(String... params) {
|
||||||
|
if (params.length != 0) return false;
|
||||||
|
if (wallet != null) wallet.store();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Boolean result) {
|
||||||
|
enableSubaddressButton(true);
|
||||||
|
super.onPostExecute(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private boolean checkPaymentId() {
|
private boolean checkPaymentId() {
|
||||||
String paymentId = etPaymentId.getEditText().getText().toString();
|
String paymentId = etPaymentId.getEditText().getText().toString();
|
||||||
boolean ok = paymentId.isEmpty() || Wallet.isPaymentIdValid(paymentId);
|
boolean ok = paymentId.isEmpty() || Wallet.isPaymentIdValid(paymentId);
|
||||||
@@ -418,4 +502,15 @@ public class ReceiveFragment extends Fragment {
|
|||||||
Timber.d("onPause()");
|
Timber.d("onPause()");
|
||||||
super.onPause();
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDetach() {
|
||||||
|
Timber.d("onDetach()");
|
||||||
|
if ((wallet != null) && (isMyWallet)) {
|
||||||
|
wallet.close();
|
||||||
|
wallet = null;
|
||||||
|
isMyWallet = false;
|
||||||
|
}
|
||||||
|
super.onDetach();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -59,6 +59,7 @@ public class TxFragment extends Fragment {
|
|||||||
TS_FORMATTER.setTimeZone(tz);
|
TS_FORMATTER.setTimeZone(tz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TextView tvAccount;
|
||||||
private TextView tvTxTimestamp;
|
private TextView tvTxTimestamp;
|
||||||
private TextView tvTxId;
|
private TextView tvTxId;
|
||||||
private TextView tvTxKey;
|
private TextView tvTxKey;
|
||||||
@@ -88,6 +89,7 @@ public class TxFragment extends Fragment {
|
|||||||
tvDestinationBtc = (TextView) view.findViewById(R.id.tvDestinationBtc);
|
tvDestinationBtc = (TextView) view.findViewById(R.id.tvDestinationBtc);
|
||||||
tvTxAmountBtc = (TextView) view.findViewById(R.id.tvTxAmountBtc);
|
tvTxAmountBtc = (TextView) view.findViewById(R.id.tvTxAmountBtc);
|
||||||
|
|
||||||
|
tvAccount = (TextView) view.findViewById(R.id.tvAccount);
|
||||||
tvTxTimestamp = (TextView) view.findViewById(R.id.tvTxTimestamp);
|
tvTxTimestamp = (TextView) view.findViewById(R.id.tvTxTimestamp);
|
||||||
tvTxId = (TextView) view.findViewById(R.id.tvTxId);
|
tvTxId = (TextView) view.findViewById(R.id.tvTxId);
|
||||||
tvTxKey = (TextView) view.findViewById(R.id.tvTxKey);
|
tvTxKey = (TextView) view.findViewById(R.id.tvTxKey);
|
||||||
@@ -222,6 +224,8 @@ public class TxFragment extends Fragment {
|
|||||||
activityCallback.setSubtitle(getString(R.string.tx_title));
|
activityCallback.setSubtitle(getString(R.string.tx_title));
|
||||||
activityCallback.setToolbarButton(Toolbar.BUTTON_BACK);
|
activityCallback.setToolbarButton(Toolbar.BUTTON_BACK);
|
||||||
|
|
||||||
|
tvAccount.setText(getString(R.string.tx_account_formatted, info.account, info.subaddress));
|
||||||
|
|
||||||
tvTxTimestamp.setText(TS_FORMATTER.format(new Date(info.timestamp * 1000)));
|
tvTxTimestamp.setText(TS_FORMATTER.format(new Date(info.timestamp * 1000)));
|
||||||
tvTxId.setText(info.hash);
|
tvTxId.setText(info.hash);
|
||||||
tvTxKey.setText(info.txKey.isEmpty() ? "-" : info.txKey);
|
tvTxKey.setText(info.txKey.isEmpty() ? "-" : info.txKey);
|
||||||
@@ -236,9 +240,6 @@ public class TxFragment extends Fragment {
|
|||||||
String sign = (info.direction == TransactionInfo.Direction.Direction_In ? "+" : "-");
|
String sign = (info.direction == TransactionInfo.Direction.Direction_In ? "+" : "-");
|
||||||
|
|
||||||
long realAmount = info.amount;
|
long realAmount = info.amount;
|
||||||
if (info.isPending) {
|
|
||||||
realAmount = realAmount - info.fee;
|
|
||||||
}
|
|
||||||
tvTxAmount.setText(sign + Wallet.getDisplayAmount(realAmount));
|
tvTxAmount.setText(sign + Wallet.getDisplayAmount(realAmount));
|
||||||
|
|
||||||
if ((info.fee > 0)) {
|
if ((info.fee > 0)) {
|
||||||
@@ -286,7 +287,10 @@ public class TxFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sb.append("-");
|
sb.append("-");
|
||||||
dstSb.append(info.direction == TransactionInfo.Direction.Direction_In ? activityCallback.getWalletAddress() : "-");
|
dstSb.append(info.direction ==
|
||||||
|
TransactionInfo.Direction.Direction_In ?
|
||||||
|
activityCallback.getWalletSubaddress(info.account, info.subaddress) :
|
||||||
|
"-");
|
||||||
}
|
}
|
||||||
tvTxTransfers.setText(sb.toString());
|
tvTxTransfers.setText(sb.toString());
|
||||||
tvDestination.setText(dstSb.toString());
|
tvDestination.setText(dstSb.toString());
|
||||||
@@ -321,7 +325,7 @@ public class TxFragment extends Fragment {
|
|||||||
Listener activityCallback;
|
Listener activityCallback;
|
||||||
|
|
||||||
public interface Listener {
|
public interface Listener {
|
||||||
String getWalletAddress();
|
String getWalletSubaddress(int accountIndex, int subaddressIndex);
|
||||||
|
|
||||||
String getTxKey(String hash);
|
String getTxKey(String hash);
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -43,9 +43,7 @@ import com.m2049r.xmrwallet.model.Wallet;
|
|||||||
import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi;
|
import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi;
|
||||||
import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback;
|
import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback;
|
||||||
import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate;
|
import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate;
|
||||||
import com.m2049r.xmrwallet.service.exchange.kraken.ExchangeApiImpl;
|
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
import com.m2049r.xmrwallet.util.OkHttpClientSingleton;
|
|
||||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||||
|
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
@@ -101,7 +99,9 @@ public class WalletFragment extends Fragment
|
|||||||
ivSynced = (ImageView) view.findViewById(R.id.ivSynced);
|
ivSynced = (ImageView) view.findViewById(R.id.ivSynced);
|
||||||
|
|
||||||
sCurrency = (Spinner) view.findViewById(R.id.sCurrency);
|
sCurrency = (Spinner) view.findViewById(R.id.sCurrency);
|
||||||
sCurrency.setAdapter(ArrayAdapter.createFromResource(getContext(), R.array.currency, R.layout.item_spinner_balance));
|
ArrayAdapter currencyAdapter = ArrayAdapter.createFromResource(getContext(), R.array.currency, R.layout.item_spinner_balance);
|
||||||
|
currencyAdapter.setDropDownViewResource(R.layout.item_spinner_dropdown_item);
|
||||||
|
sCurrency.setAdapter(currencyAdapter);
|
||||||
|
|
||||||
bSend = (Button) view.findViewById(R.id.bSend);
|
bSend = (Button) view.findViewById(R.id.bSend);
|
||||||
bReceive = (Button) view.findViewById(R.id.bReceive);
|
bReceive = (Button) view.findViewById(R.id.bReceive);
|
||||||
@@ -150,7 +150,7 @@ public class WalletFragment extends Fragment
|
|||||||
// at this point selection is XMR in case of error
|
// at this point selection is XMR in case of error
|
||||||
String displayB;
|
String displayB;
|
||||||
double amountA = Double.parseDouble(Wallet.getDisplayAmount(unlockedBalance)); // crash if this fails!
|
double amountA = Double.parseDouble(Wallet.getDisplayAmount(unlockedBalance)); // crash if this fails!
|
||||||
if (!"XMR".equals(balanceCurrency)) { // not XMR
|
if (!Helper.CRYPTO.equals(balanceCurrency)) { // not XMR
|
||||||
double amountB = amountA * balanceRate;
|
double amountB = amountA * balanceRate;
|
||||||
displayB = Helper.getFormattedAmount(amountB, false);
|
displayB = Helper.getFormattedAmount(amountB, false);
|
||||||
} else { // XMR
|
} else { // XMR
|
||||||
@@ -159,10 +159,10 @@ public class WalletFragment extends Fragment
|
|||||||
tvBalance.setText(displayB);
|
tvBalance.setText(displayB);
|
||||||
}
|
}
|
||||||
|
|
||||||
String balanceCurrency = "XMR";
|
String balanceCurrency = Helper.CRYPTO;
|
||||||
double balanceRate = 1.0;
|
double balanceRate = 1.0;
|
||||||
|
|
||||||
private final ExchangeApi exchangeApi = new ExchangeApiImpl(OkHttpClientSingleton.getOkHttpClient());
|
private final ExchangeApi exchangeApi = Helper.getExchangeApi();
|
||||||
|
|
||||||
void refreshBalance() {
|
void refreshBalance() {
|
||||||
if (sCurrency.getSelectedItemPosition() == 0) { // XMR
|
if (sCurrency.getSelectedItemPosition() == 0) { // XMR
|
||||||
@@ -170,9 +170,10 @@ public class WalletFragment extends Fragment
|
|||||||
tvBalance.setText(Helper.getFormattedAmount(amountXmr, true));
|
tvBalance.setText(Helper.getFormattedAmount(amountXmr, true));
|
||||||
} else { // not XMR
|
} else { // not XMR
|
||||||
String currency = (String) sCurrency.getSelectedItem();
|
String currency = (String) sCurrency.getSelectedItem();
|
||||||
|
Timber.d(currency);
|
||||||
if (!currency.equals(balanceCurrency) || (balanceRate <= 0)) {
|
if (!currency.equals(balanceCurrency) || (balanceRate <= 0)) {
|
||||||
showExchanging();
|
showExchanging();
|
||||||
exchangeApi.queryExchangeRate("XMR", currency,
|
exchangeApi.queryExchangeRate(Helper.CRYPTO, currency,
|
||||||
new ExchangeCallback() {
|
new ExchangeCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(final ExchangeRate exchangeRate) {
|
public void onSuccess(final ExchangeRate exchangeRate) {
|
||||||
@@ -228,10 +229,10 @@ public class WalletFragment extends Fragment
|
|||||||
|
|
||||||
public void exchange(final ExchangeRate exchangeRate) {
|
public void exchange(final ExchangeRate exchangeRate) {
|
||||||
hideExchanging();
|
hideExchanging();
|
||||||
if (!"XMR".equals(exchangeRate.getBaseCurrency())) {
|
if (!Helper.CRYPTO.equals(exchangeRate.getBaseCurrency())) {
|
||||||
Timber.e("Not XMR");
|
Timber.e("Not XMR");
|
||||||
sCurrency.setSelection(0, true);
|
sCurrency.setSelection(0, true);
|
||||||
balanceCurrency = "XMR";
|
balanceCurrency = Helper.CRYPTO;
|
||||||
balanceRate = 1.0;
|
balanceRate = 1.0;
|
||||||
} else {
|
} else {
|
||||||
int spinnerPosition = ((ArrayAdapter) sCurrency.getAdapter()).getPosition(exchangeRate.getQuoteCurrency());
|
int spinnerPosition = ((ArrayAdapter) sCurrency.getAdapter()).getPosition(exchangeRate.getQuoteCurrency());
|
||||||
@@ -256,7 +257,7 @@ public class WalletFragment extends Fragment
|
|||||||
// called from activity
|
// called from activity
|
||||||
|
|
||||||
public void onRefreshed(final Wallet wallet, final boolean full) {
|
public void onRefreshed(final Wallet wallet, final boolean full) {
|
||||||
Timber.d("onRefreshed()");
|
Timber.d("onRefreshed(%b)", full);
|
||||||
if (full) {
|
if (full) {
|
||||||
List<TransactionInfo> list = wallet.getHistory().getAll();
|
List<TransactionInfo> list = wallet.getHistory().getAll();
|
||||||
adapter.setInfos(list);
|
adapter.setInfos(list);
|
||||||
@@ -270,6 +271,7 @@ public class WalletFragment extends Fragment
|
|||||||
bSend.setVisibility(View.VISIBLE);
|
bSend.setVisibility(View.VISIBLE);
|
||||||
bSend.setEnabled(true);
|
bSend.setEnabled(true);
|
||||||
}
|
}
|
||||||
|
enableAccountsList(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean walletLoaded = false;
|
boolean walletLoaded = false;
|
||||||
@@ -313,7 +315,7 @@ public class WalletFragment extends Fragment
|
|||||||
if (wallet == null) return;
|
if (wallet == null) return;
|
||||||
walletTitle = wallet.getName();
|
walletTitle = wallet.getName();
|
||||||
String watchOnly = (wallet.isWatchOnly() ? getString(R.string.label_watchonly) : "");
|
String watchOnly = (wallet.isWatchOnly() ? getString(R.string.label_watchonly) : "");
|
||||||
walletSubtitle = wallet.getAddress().substring(0, 10) + "…" + watchOnly;
|
walletSubtitle = wallet.getAccountLabel();
|
||||||
activityCallback.setTitle(walletTitle, walletSubtitle);
|
activityCallback.setTitle(walletTitle, walletSubtitle);
|
||||||
Timber.d("wallet title is %s", walletTitle);
|
Timber.d("wallet title is %s", walletTitle);
|
||||||
}
|
}
|
||||||
@@ -323,10 +325,13 @@ public class WalletFragment extends Fragment
|
|||||||
private String walletSubtitle = null;
|
private String walletSubtitle = null;
|
||||||
private long unlockedBalance = 0;
|
private long unlockedBalance = 0;
|
||||||
|
|
||||||
|
private int accountIdx = -1;
|
||||||
|
|
||||||
private void updateStatus(Wallet wallet) {
|
private void updateStatus(Wallet wallet) {
|
||||||
if (!isAdded()) return;
|
if (!isAdded()) return;
|
||||||
Timber.d("updateStatus()");
|
Timber.d("updateStatus()");
|
||||||
if (walletTitle == null) {
|
if ((walletTitle == null) || (accountIdx != wallet.getAccountIndex())) {
|
||||||
|
accountIdx = wallet.getAccountIndex();
|
||||||
setActivityTitle(wallet);
|
setActivityTitle(wallet);
|
||||||
}
|
}
|
||||||
long balance = wallet.getBalance();
|
long balance = wallet.getBalance();
|
||||||
@@ -412,9 +417,28 @@ public class WalletFragment extends Fragment
|
|||||||
super.onResume();
|
super.onResume();
|
||||||
Timber.d("onResume()");
|
Timber.d("onResume()");
|
||||||
activityCallback.setTitle(walletTitle, walletSubtitle);
|
activityCallback.setTitle(walletTitle, walletSubtitle);
|
||||||
activityCallback.setToolbarButton(Toolbar.BUTTON_CLOSE);
|
//activityCallback.setToolbarButton(Toolbar.BUTTON_CLOSE); // TODO: Close button somewhere else
|
||||||
|
activityCallback.setToolbarButton(Toolbar.BUTTON_NONE);
|
||||||
setProgress(syncProgress);
|
setProgress(syncProgress);
|
||||||
setProgress(syncText);
|
setProgress(syncText);
|
||||||
showReceive();
|
showReceive();
|
||||||
|
if (activityCallback.isSynced()) enableAccountsList(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
enableAccountsList(false);
|
||||||
|
super.onPause();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface DrawerLocker {
|
||||||
|
void setDrawerEnabled(boolean enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void enableAccountsList(boolean enable) {
|
||||||
|
if (activityCallback instanceof DrawerLocker) {
|
||||||
|
((DrawerLocker) activityCallback).setDrawerEnabled(enable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -233,7 +233,7 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||||||
|
|
||||||
private boolean isBitcoinAddress() {
|
private boolean isBitcoinAddress() {
|
||||||
String address = etAddress.getEditText().getText().toString();
|
String address = etAddress.getEditText().getText().toString();
|
||||||
if ((address.length() >= 27) && (address.length() <= 34))
|
if ((address.length() >= 27) && (address.length() <= 35))
|
||||||
return BitcoinAddressValidator.validate(address);
|
return BitcoinAddressValidator.validate(address);
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
|
@@ -20,6 +20,9 @@ import android.os.Bundle;
|
|||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.R;
|
import com.m2049r.xmrwallet.R;
|
||||||
@@ -57,8 +60,9 @@ public class SendAmountWizardFragment extends SendWizardFragment {
|
|||||||
|
|
||||||
private TextView tvFunds;
|
private TextView tvFunds;
|
||||||
private ExchangeTextView evAmount;
|
private ExchangeTextView evAmount;
|
||||||
//private Button bSendAll;
|
private View llAmount;
|
||||||
private NumberPadView numberPad;
|
private View rlSweep;
|
||||||
|
private ImageButton ibSweep;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
@@ -73,37 +77,64 @@ public class SendAmountWizardFragment extends SendWizardFragment {
|
|||||||
tvFunds = (TextView) view.findViewById(R.id.tvFunds);
|
tvFunds = (TextView) view.findViewById(R.id.tvFunds);
|
||||||
|
|
||||||
evAmount = (ExchangeTextView) view.findViewById(R.id.evAmount);
|
evAmount = (ExchangeTextView) view.findViewById(R.id.evAmount);
|
||||||
numberPad = (NumberPadView) view.findViewById(R.id.numberPad);
|
((NumberPadView) view.findViewById(R.id.numberPad)).setListener(evAmount);
|
||||||
numberPad.setListener(evAmount);
|
|
||||||
|
|
||||||
/*
|
rlSweep = view.findViewById(R.id.rlSweep);
|
||||||
bSendAll = (Button) view.findViewById(R.id.bSendAll);
|
llAmount = view.findViewById(R.id.llAmount);
|
||||||
bSendAll.setOnClickListener(new View.OnClickListener() {
|
view.findViewById(R.id.ivSweep).setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
// TODO: send all - figure out how to display this
|
sweepAll(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ibSweep = (ImageButton) view.findViewById(R.id.ibSweep);
|
||||||
|
|
||||||
|
ibSweep.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
sweepAll(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
*/
|
|
||||||
|
|
||||||
Helper.hideKeyboard(getActivity());
|
Helper.hideKeyboard(getActivity());
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean spendAllMode = false;
|
||||||
|
|
||||||
|
private void sweepAll(boolean spendAllMode) {
|
||||||
|
if (spendAllMode) {
|
||||||
|
ibSweep.setVisibility(View.INVISIBLE);
|
||||||
|
llAmount.setVisibility(View.GONE);
|
||||||
|
rlSweep.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
ibSweep.setVisibility(View.VISIBLE);
|
||||||
|
llAmount.setVisibility(View.VISIBLE);
|
||||||
|
rlSweep.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
this.spendAllMode = spendAllMode;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onValidateFields() {
|
public boolean onValidateFields() {
|
||||||
if (!evAmount.validate(maxFunds)) {
|
if (spendAllMode) {
|
||||||
return false;
|
if (sendListener != null) {
|
||||||
}
|
sendListener.getTxData().setAmount(Wallet.SWEEP_ALL);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!evAmount.validate(maxFunds)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (sendListener != null) {
|
if (sendListener != null) {
|
||||||
String xmr = evAmount.getAmount();
|
String xmr = evAmount.getAmount();
|
||||||
if (xmr != null) {
|
if (xmr != null) {
|
||||||
sendListener.getTxData().setAmount(Wallet.getAmountFromString(xmr));
|
sendListener.getTxData().setAmount(Wallet.getAmountFromString(xmr));
|
||||||
} else {
|
} else {
|
||||||
sendListener.getTxData().setAmount(0L);
|
sendListener.getTxData().setAmount(0L);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@@ -247,7 +247,7 @@ public class SendBtcAmountWizardFragment extends SendWizardFragment {
|
|||||||
|
|
||||||
private XmrToApi xmrToApi = null;
|
private XmrToApi xmrToApi = null;
|
||||||
|
|
||||||
private final XmrToApi getXmrToApi() {
|
private XmrToApi getXmrToApi() {
|
||||||
if (xmrToApi == null) {
|
if (xmrToApi == null) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (xmrToApi == null) {
|
if (xmrToApi == null) {
|
||||||
|
@@ -36,6 +36,7 @@ import com.m2049r.xmrwallet.util.UserNotes;
|
|||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
public class SendSettingsWizardFragment extends SendWizardFragment {
|
public class SendSettingsWizardFragment extends SendWizardFragment {
|
||||||
|
final static public int MIXIN = 6;
|
||||||
|
|
||||||
public static SendSettingsWizardFragment newInstance(Listener listener) {
|
public static SendSettingsWizardFragment newInstance(Listener listener) {
|
||||||
SendSettingsWizardFragment instance = new SendSettingsWizardFragment();
|
SendSettingsWizardFragment instance = new SendSettingsWizardFragment();
|
||||||
@@ -54,15 +55,12 @@ public class SendSettingsWizardFragment extends SendWizardFragment {
|
|||||||
TxData getTxData();
|
TxData getTxData();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mixin = Ringsize - 1
|
|
||||||
final static int Mixins[] = {6, 9, 12, 25}; // must match the layout XML / "@array/mixin"
|
|
||||||
final static PendingTransaction.Priority Priorities[] =
|
final static PendingTransaction.Priority Priorities[] =
|
||||||
{PendingTransaction.Priority.Priority_Default,
|
{PendingTransaction.Priority.Priority_Default,
|
||||||
PendingTransaction.Priority.Priority_Low,
|
PendingTransaction.Priority.Priority_Low,
|
||||||
PendingTransaction.Priority.Priority_Medium,
|
PendingTransaction.Priority.Priority_Medium,
|
||||||
PendingTransaction.Priority.Priority_High}; // must match the layout XML
|
PendingTransaction.Priority.Priority_High}; // must match the layout XML
|
||||||
|
|
||||||
private Spinner sMixin;
|
|
||||||
private Spinner sPriority;
|
private Spinner sPriority;
|
||||||
private EditText etNotes;
|
private EditText etNotes;
|
||||||
private EditText etDummy;
|
private EditText etDummy;
|
||||||
@@ -77,7 +75,6 @@ public class SendSettingsWizardFragment extends SendWizardFragment {
|
|||||||
View view = inflater.inflate(
|
View view = inflater.inflate(
|
||||||
R.layout.fragment_send_settings, container, false);
|
R.layout.fragment_send_settings, container, false);
|
||||||
|
|
||||||
sMixin = (Spinner) view.findViewById(R.id.sMixin);
|
|
||||||
sPriority = (Spinner) view.findViewById(R.id.sPriority);
|
sPriority = (Spinner) view.findViewById(R.id.sPriority);
|
||||||
|
|
||||||
etNotes = (EditText) view.findViewById(R.id.etNotes);
|
etNotes = (EditText) view.findViewById(R.id.etNotes);
|
||||||
@@ -104,7 +101,7 @@ public class SendSettingsWizardFragment extends SendWizardFragment {
|
|||||||
if (sendListener != null) {
|
if (sendListener != null) {
|
||||||
TxData txData = sendListener.getTxData();
|
TxData txData = sendListener.getTxData();
|
||||||
txData.setPriority(Priorities[sPriority.getSelectedItemPosition()]);
|
txData.setPriority(Priorities[sPriority.getSelectedItemPosition()]);
|
||||||
txData.setMixin(Mixins[sMixin.getSelectedItemPosition()]);
|
txData.setMixin(MIXIN);
|
||||||
txData.setUserNotes(new UserNotes(etNotes.getText().toString()));
|
txData.setUserNotes(new UserNotes(etNotes.getText().toString()));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@@ -166,7 +166,11 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((userNotes.note.isEmpty())) {
|
if ((userNotes.note.isEmpty())) {
|
||||||
this.tvPaymentId.setText(infoItem.paymentId.equals("0000000000000000") ? "" : infoItem.paymentId);
|
this.tvPaymentId.setText(infoItem.paymentId.equals("0000000000000000") ?
|
||||||
|
(infoItem.subaddress != 0 ?
|
||||||
|
(context.getString(R.string.tx_subaddress, infoItem.subaddress)) :
|
||||||
|
"") :
|
||||||
|
infoItem.paymentId);
|
||||||
} else {
|
} else {
|
||||||
this.tvPaymentId.setText(userNotes.note);
|
this.tvPaymentId.setText(userNotes.note);
|
||||||
}
|
}
|
||||||
|
@@ -17,8 +17,11 @@
|
|||||||
package com.m2049r.xmrwallet.model;
|
package com.m2049r.xmrwallet.model;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
public class TransactionHistory {
|
public class TransactionHistory {
|
||||||
static {
|
static {
|
||||||
System.loadLibrary("monerujo");
|
System.loadLibrary("monerujo");
|
||||||
@@ -26,8 +29,18 @@ public class TransactionHistory {
|
|||||||
|
|
||||||
private long handle;
|
private long handle;
|
||||||
|
|
||||||
public TransactionHistory(long handle) {
|
int accountIndex;
|
||||||
|
|
||||||
|
public void setAccountFor(Wallet wallet) {
|
||||||
|
if (accountIndex != wallet.getAccountIndex()) {
|
||||||
|
this.accountIndex = wallet.getAccountIndex();
|
||||||
|
refreshWithNotes(wallet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TransactionHistory(long handle, int accountIndex) {
|
||||||
this.handle = handle;
|
this.handle = handle;
|
||||||
|
this.accountIndex = accountIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadNotes(Wallet wallet) {
|
public void loadNotes(Wallet wallet) {
|
||||||
@@ -36,7 +49,7 @@ public class TransactionHistory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public native int getCount();
|
public native int getCount(); // over all accounts/subaddresses
|
||||||
|
|
||||||
//private native long getTransactionByIndexJ(int i);
|
//private native long getTransactionByIndexJ(int i);
|
||||||
|
|
||||||
@@ -53,8 +66,23 @@ public class TransactionHistory {
|
|||||||
loadNotes(wallet);
|
loadNotes(wallet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// public void refresh() {
|
||||||
|
// transactions = refreshJ();
|
||||||
|
// }
|
||||||
|
|
||||||
public void refresh() {
|
public void refresh() {
|
||||||
transactions = refreshJ();
|
List<TransactionInfo> t = refreshJ();
|
||||||
|
Timber.d("refreshed %d", t.size());
|
||||||
|
for (Iterator<TransactionInfo> iterator = t.iterator(); iterator.hasNext(); ) {
|
||||||
|
TransactionInfo info = iterator.next();
|
||||||
|
if (info.account != accountIndex) {
|
||||||
|
iterator.remove();
|
||||||
|
Timber.d("removed %s", info.hash);
|
||||||
|
} else {
|
||||||
|
Timber.d("kept %s", info.hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
transactions = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
private native List<TransactionInfo> refreshJ();
|
private native List<TransactionInfo> refreshJ();
|
||||||
|
@@ -53,6 +53,11 @@ public class TransactionInfo implements Parcelable, Comparable<TransactionInfo>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// virtual std::set<uint32_t> subaddrIndex() const = 0;
|
||||||
|
// virtual uint32_t subaddrAccount() const = 0;
|
||||||
|
// virtual std::string label() const = 0;
|
||||||
|
// virtual uint64_t confirmations() const = 0;
|
||||||
|
|
||||||
public Direction direction;
|
public Direction direction;
|
||||||
public boolean isPending;
|
public boolean isPending;
|
||||||
public boolean isFailed;
|
public boolean isFailed;
|
||||||
@@ -62,6 +67,8 @@ public class TransactionInfo implements Parcelable, Comparable<TransactionInfo>
|
|||||||
public String hash;
|
public String hash;
|
||||||
public long timestamp;
|
public long timestamp;
|
||||||
public String paymentId;
|
public String paymentId;
|
||||||
|
public int account;
|
||||||
|
public int subaddress;
|
||||||
public long confirmations;
|
public long confirmations;
|
||||||
public List<Transfer> transfers;
|
public List<Transfer> transfers;
|
||||||
|
|
||||||
@@ -78,6 +85,8 @@ public class TransactionInfo implements Parcelable, Comparable<TransactionInfo>
|
|||||||
String hash,
|
String hash,
|
||||||
long timestamp,
|
long timestamp,
|
||||||
String paymentId,
|
String paymentId,
|
||||||
|
int account,
|
||||||
|
int subaddress,
|
||||||
long confirmations,
|
long confirmations,
|
||||||
List<Transfer> transfers) {
|
List<Transfer> transfers) {
|
||||||
this.direction = Direction.values()[direction];
|
this.direction = Direction.values()[direction];
|
||||||
@@ -89,6 +98,8 @@ public class TransactionInfo implements Parcelable, Comparable<TransactionInfo>
|
|||||||
this.hash = hash;
|
this.hash = hash;
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
this.paymentId = paymentId;
|
this.paymentId = paymentId;
|
||||||
|
this.account = account;
|
||||||
|
this.subaddress = subaddress;
|
||||||
this.confirmations = confirmations;
|
this.confirmations = confirmations;
|
||||||
this.transfers = transfers;
|
this.transfers = transfers;
|
||||||
}
|
}
|
||||||
@@ -108,6 +119,8 @@ public class TransactionInfo implements Parcelable, Comparable<TransactionInfo>
|
|||||||
out.writeString(hash);
|
out.writeString(hash);
|
||||||
out.writeLong(timestamp);
|
out.writeLong(timestamp);
|
||||||
out.writeString(paymentId);
|
out.writeString(paymentId);
|
||||||
|
out.writeInt(account);
|
||||||
|
out.writeInt(subaddress);
|
||||||
out.writeLong(confirmations);
|
out.writeLong(confirmations);
|
||||||
out.writeList(transfers);
|
out.writeList(transfers);
|
||||||
out.writeString(txKey);
|
out.writeString(txKey);
|
||||||
@@ -134,6 +147,8 @@ public class TransactionInfo implements Parcelable, Comparable<TransactionInfo>
|
|||||||
hash = in.readString();
|
hash = in.readString();
|
||||||
timestamp = in.readLong();
|
timestamp = in.readLong();
|
||||||
paymentId = in.readString();
|
paymentId = in.readString();
|
||||||
|
account = in.readInt();
|
||||||
|
subaddress = in.readInt();
|
||||||
confirmations = in.readLong();
|
confirmations = in.readLong();
|
||||||
transfers = in.readArrayList(Transfer.class.getClassLoader());
|
transfers = in.readArrayList(Transfer.class.getClassLoader());
|
||||||
txKey = in.readString();
|
txKey = in.readString();
|
||||||
|
@@ -19,13 +19,30 @@ package com.m2049r.xmrwallet.model;
|
|||||||
import com.m2049r.xmrwallet.data.TxData;
|
import com.m2049r.xmrwallet.data.TxData;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
public class Wallet {
|
public class Wallet {
|
||||||
|
final static public long SWEEP_ALL = Long.MAX_VALUE;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
System.loadLibrary("monerujo");
|
System.loadLibrary("monerujo");
|
||||||
}
|
}
|
||||||
|
|
||||||
static final String TAG = "Wallet";
|
private int accountIndex = 0;
|
||||||
|
|
||||||
|
public int getAccountIndex() {
|
||||||
|
return accountIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAccountIndex(int accountIndex) {
|
||||||
|
Timber.d("setAccountIndex(%d)", accountIndex);
|
||||||
|
this.accountIndex = accountIndex;
|
||||||
|
getHistory().setAccountFor(this);
|
||||||
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return new File(getPath()).getName();
|
return new File(getPath()).getName();
|
||||||
@@ -38,6 +55,11 @@ public class Wallet {
|
|||||||
this.handle = handle;
|
this.handle = handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Wallet(long handle, int accountIndex) {
|
||||||
|
this.handle = handle;
|
||||||
|
this.accountIndex = accountIndex;
|
||||||
|
}
|
||||||
|
|
||||||
public enum Status {
|
public enum Status {
|
||||||
Status_Ok,
|
Status_Ok,
|
||||||
Status_Error,
|
Status_Error,
|
||||||
@@ -66,16 +88,23 @@ public class Wallet {
|
|||||||
|
|
||||||
public native boolean setPassword(String password);
|
public native boolean setPassword(String password);
|
||||||
|
|
||||||
private String address = null;
|
|
||||||
|
|
||||||
public String getAddress() {
|
public String getAddress() {
|
||||||
if (address == null) {
|
return getAddress(accountIndex);
|
||||||
address = getAddressJ();
|
|
||||||
}
|
|
||||||
return address;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private native String getAddressJ();
|
public String getAddress(int accountIndex) {
|
||||||
|
return getAddressJ(accountIndex, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSubaddress(int addressIndex) {
|
||||||
|
return getAddressJ(accountIndex, addressIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSubaddress(int accountIndex, int addressIndex) {
|
||||||
|
return getAddressJ(accountIndex, addressIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private native String getAddressJ(int accountIndex, int addressIndex);
|
||||||
|
|
||||||
public native String getPath();
|
public native String getPath();
|
||||||
|
|
||||||
@@ -95,7 +124,9 @@ public class Wallet {
|
|||||||
public native String getSecretSpendKey();
|
public native String getSecretSpendKey();
|
||||||
|
|
||||||
public boolean store() {
|
public boolean store() {
|
||||||
return store("");
|
final boolean ok = store("");
|
||||||
|
Timber.d("stored");
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
public native boolean store(String path);
|
public native boolean store(String path);
|
||||||
@@ -132,9 +163,21 @@ public class Wallet {
|
|||||||
//TODO virtual void setTrustedDaemon(bool arg) = 0;
|
//TODO virtual void setTrustedDaemon(bool arg) = 0;
|
||||||
//TODO virtual bool trustedDaemon() const = 0;
|
//TODO virtual bool trustedDaemon() const = 0;
|
||||||
|
|
||||||
public native long getBalance();
|
public long getBalance() {
|
||||||
|
return getBalance(accountIndex);
|
||||||
|
}
|
||||||
|
|
||||||
public native long getUnlockedBalance();
|
public native long getBalance(int accountIndex);
|
||||||
|
|
||||||
|
public native long getBalanceAll();
|
||||||
|
|
||||||
|
public long getUnlockedBalance() {
|
||||||
|
return getUnlockedBalance(accountIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public native long getUnlockedBalanceAll();
|
||||||
|
|
||||||
|
public native long getUnlockedBalance(int accountIndex);
|
||||||
|
|
||||||
public native boolean isWatchOnly();
|
public native boolean isWatchOnly();
|
||||||
|
|
||||||
@@ -164,9 +207,7 @@ public class Wallet {
|
|||||||
|
|
||||||
public static native boolean isAddressValid(String address, int networkType);
|
public static native boolean isAddressValid(String address, int networkType);
|
||||||
|
|
||||||
//TODO static static bool keyValid(const std::string &secret_key_string, const std::string &address_string, bool isViewKey, bool testnet, std::string &error);
|
public static native String getPaymentIdFromAddress(String address, int networkType);
|
||||||
|
|
||||||
public static native String getPaymentIdFromAddress(String address, boolean isTestNet);
|
|
||||||
|
|
||||||
public static native long getMaximumAllowedAmount();
|
public static native long getMaximumAllowedAmount();
|
||||||
|
|
||||||
@@ -209,14 +250,23 @@ public class Wallet {
|
|||||||
PendingTransaction.Priority priority) {
|
PendingTransaction.Priority priority) {
|
||||||
disposePendingTransaction();
|
disposePendingTransaction();
|
||||||
int _priority = priority.getValue();
|
int _priority = priority.getValue();
|
||||||
long txHandle = createTransactionJ(dst_addr, payment_id, amount, mixin_count, _priority);
|
long txHandle =
|
||||||
|
(amount == SWEEP_ALL ?
|
||||||
|
createSweepTransaction(dst_addr, payment_id, mixin_count, _priority,
|
||||||
|
accountIndex) :
|
||||||
|
createTransactionJ(dst_addr, payment_id, amount, mixin_count, _priority,
|
||||||
|
accountIndex));
|
||||||
pendingTransaction = new PendingTransaction(txHandle);
|
pendingTransaction = new PendingTransaction(txHandle);
|
||||||
return pendingTransaction;
|
return pendingTransaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
private native long createTransactionJ(String dst_addr, String payment_id,
|
private native long createTransactionJ(String dst_addr, String payment_id,
|
||||||
long amount, int mixin_count,
|
long amount, int mixin_count,
|
||||||
int priority);
|
int priority, int accountIndex);
|
||||||
|
|
||||||
|
private native long createSweepTransaction(String dst_addr, String payment_id,
|
||||||
|
int mixin_count,
|
||||||
|
int priority, int accountIndex);
|
||||||
|
|
||||||
|
|
||||||
public PendingTransaction createSweepUnmixableTransaction() {
|
public PendingTransaction createSweepUnmixableTransaction() {
|
||||||
@@ -243,7 +293,7 @@ public class Wallet {
|
|||||||
|
|
||||||
public TransactionHistory getHistory() {
|
public TransactionHistory getHistory() {
|
||||||
if (history == null) {
|
if (history == null) {
|
||||||
history = new TransactionHistory(getHistoryJ());
|
history = new TransactionHistory(getHistoryJ(), accountIndex);
|
||||||
}
|
}
|
||||||
return history;
|
return history;
|
||||||
}
|
}
|
||||||
@@ -275,4 +325,68 @@ public class Wallet {
|
|||||||
//virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &tvAmount, std::string &tx_description, std::string &recipient_name, std::vector<std::string> &unknown_parameters, std::string &error) = 0;
|
//virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &tvAmount, std::string &tx_description, std::string &recipient_name, std::vector<std::string> &unknown_parameters, std::string &error) = 0;
|
||||||
//virtual bool rescanSpent() = 0;
|
//virtual bool rescanSpent() = 0;
|
||||||
|
|
||||||
|
private static final String NEW_ACCOUNT_NAME = "Untitled account"; // src/wallet/wallet2.cpp:941
|
||||||
|
|
||||||
|
public void addAccount() {
|
||||||
|
addAccount(NEW_ACCOUNT_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
public native void addAccount(String label);
|
||||||
|
|
||||||
|
public String getAccountLabel() {
|
||||||
|
return getAccountLabel(accountIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAccountLabel(int accountIndex) {
|
||||||
|
String label = getSubaddressLabel(accountIndex, 0);
|
||||||
|
if (label.equals(NEW_ACCOUNT_NAME)) {
|
||||||
|
String address = getAddress(accountIndex);
|
||||||
|
int len = address.length();
|
||||||
|
return address.substring(0, 6) +
|
||||||
|
"\u2026" + address.substring(len - 6, len);
|
||||||
|
} else return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSubaddressLabel(int addressIndex) {
|
||||||
|
return getSubaddressLabel(accountIndex, addressIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public native String getSubaddressLabel(int accountIndex, int addressIndex);
|
||||||
|
|
||||||
|
public void setAccountLabel(String label) {
|
||||||
|
setAccountLabel(accountIndex, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAccountLabel(int accountIndex, String label) {
|
||||||
|
setSubaddressLabel(accountIndex, 0, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
public native void setSubaddressLabel(int accountIndex, int addressIndex, String label);
|
||||||
|
|
||||||
|
public native int getNumAccounts();
|
||||||
|
|
||||||
|
public int getNumSubaddresses() {
|
||||||
|
return getNumSubaddresses(accountIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public native int getNumSubaddresses(int accountIndex);
|
||||||
|
|
||||||
|
public String getNewSubaddress() {
|
||||||
|
return getNewSubaddress(accountIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNewSubaddress(int accountIndex) {
|
||||||
|
String timeStamp = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss", Locale.US).format(new Date());
|
||||||
|
addSubaddress(accountIndex, timeStamp);
|
||||||
|
String subaddress = getLastSubaddress(accountIndex);
|
||||||
|
Timber.d("%d: %s", getNumSubaddresses(accountIndex) - 1, subaddress);
|
||||||
|
return subaddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public native void addSubaddress(int accountIndex, String label);
|
||||||
|
|
||||||
|
public String getLastSubaddress(int accountIndex) {
|
||||||
|
return getSubaddress(accountIndex, getNumSubaddresses(accountIndex) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -80,6 +80,13 @@ public class WalletManager {
|
|||||||
|
|
||||||
private native long createWalletJ(String path, String password, String language, int networkType);
|
private native long createWalletJ(String path, String password, String language, int networkType);
|
||||||
|
|
||||||
|
public Wallet openAccount(String path, int accountIndex, String password) {
|
||||||
|
long walletHandle = openWalletJ(path, password, getNetworkType().getValue());
|
||||||
|
Wallet wallet = new Wallet(walletHandle, accountIndex);
|
||||||
|
manageWallet(wallet);
|
||||||
|
return wallet;
|
||||||
|
}
|
||||||
|
|
||||||
public Wallet openWallet(String path, String password) {
|
public Wallet openWallet(String path, String password) {
|
||||||
long walletHandle = openWalletJ(path, password, getNetworkType().getValue());
|
long walletHandle = openWalletJ(path, password, getNetworkType().getValue());
|
||||||
Wallet wallet = new Wallet(walletHandle);
|
Wallet wallet = new Wallet(walletHandle);
|
||||||
@@ -228,7 +235,6 @@ public class WalletManager {
|
|||||||
|
|
||||||
public String getDaemonAddress() {
|
public String getDaemonAddress() {
|
||||||
if (daemonAddress == null) {
|
if (daemonAddress == null) {
|
||||||
// assume testnet not explicitly initialised
|
|
||||||
throw new IllegalStateException("use setDaemon() to initialise daemon and net first!");
|
throw new IllegalStateException("use setDaemon() to initialise daemon and net first!");
|
||||||
}
|
}
|
||||||
return this.daemonAddress;
|
return this.daemonAddress;
|
||||||
@@ -236,13 +242,13 @@ public class WalletManager {
|
|||||||
|
|
||||||
private native void setDaemonAddressJ(String address);
|
private native void setDaemonAddressJ(String address);
|
||||||
|
|
||||||
String daemonUsername = "";
|
private String daemonUsername = "";
|
||||||
|
|
||||||
public String getDaemonUsername() {
|
public String getDaemonUsername() {
|
||||||
return daemonUsername;
|
return daemonUsername;
|
||||||
}
|
}
|
||||||
|
|
||||||
String daemonPassword = "";
|
private String daemonPassword = "";
|
||||||
|
|
||||||
public String getDaemonPassword() {
|
public String getDaemonPassword() {
|
||||||
return daemonPassword;
|
return daemonPassword;
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2017 m2049r et al.
|
* Copyright (c) 2017-2018 m2049r et al.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.m2049r.xmrwallet.service.exchange.kraken;
|
package com.m2049r.xmrwallet.service.exchange.coinmarketcap;
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.VisibleForTesting;
|
import android.support.annotation.VisibleForTesting;
|
||||||
@@ -23,6 +23,7 @@ import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi;
|
|||||||
import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback;
|
import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback;
|
||||||
import com.m2049r.xmrwallet.service.exchange.api.ExchangeException;
|
import com.m2049r.xmrwallet.service.exchange.api.ExchangeException;
|
||||||
import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate;
|
import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate;
|
||||||
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
@@ -37,6 +38,7 @@ import okhttp3.Request;
|
|||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
|
|
||||||
public class ExchangeApiImpl implements ExchangeApi {
|
public class ExchangeApiImpl implements ExchangeApi {
|
||||||
|
static final String CRYPTO_ID = "328";
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private final OkHttpClient okHttpClient;
|
private final OkHttpClient okHttpClient;
|
||||||
@@ -52,7 +54,7 @@ public class ExchangeApiImpl implements ExchangeApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ExchangeApiImpl(@NonNull final OkHttpClient okHttpClient) {
|
public ExchangeApiImpl(@NonNull final OkHttpClient okHttpClient) {
|
||||||
this(okHttpClient, HttpUrl.parse("https://api.kraken.com/0/public/Ticker"));
|
this(okHttpClient, HttpUrl.parse("https://api.coinmarketcap.com/v2/ticker/"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -67,12 +69,12 @@ public class ExchangeApiImpl implements ExchangeApi {
|
|||||||
boolean inverse = false;
|
boolean inverse = false;
|
||||||
String fiat = null;
|
String fiat = null;
|
||||||
|
|
||||||
if (baseCurrency.equals("XMR")) {
|
if (baseCurrency.equals(Helper.CRYPTO)) {
|
||||||
fiat = quoteCurrency;
|
fiat = quoteCurrency;
|
||||||
inverse = false;
|
inverse = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (quoteCurrency.equals("XMR")) {
|
if (quoteCurrency.equals(Helper.CRYPTO)) {
|
||||||
fiat = baseCurrency;
|
fiat = baseCurrency;
|
||||||
inverse = true;
|
inverse = true;
|
||||||
}
|
}
|
||||||
@@ -85,7 +87,8 @@ public class ExchangeApiImpl implements ExchangeApi {
|
|||||||
final boolean swapAssets = inverse;
|
final boolean swapAssets = inverse;
|
||||||
|
|
||||||
final HttpUrl url = baseUrl.newBuilder()
|
final HttpUrl url = baseUrl.newBuilder()
|
||||||
.addQueryParameter("pair", "XMR" + fiat)
|
.addEncodedPathSegments(CRYPTO_ID + "/")
|
||||||
|
.addQueryParameter("convert", fiat)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final Request httpRequest = createHttpRequest(url);
|
final Request httpRequest = createHttpRequest(url);
|
||||||
@@ -101,12 +104,12 @@ public class ExchangeApiImpl implements ExchangeApi {
|
|||||||
if (response.isSuccessful()) {
|
if (response.isSuccessful()) {
|
||||||
try {
|
try {
|
||||||
final JSONObject json = new JSONObject(response.body().string());
|
final JSONObject json = new JSONObject(response.body().string());
|
||||||
final JSONArray jsonError = json.getJSONArray("error");
|
final JSONObject metadata = json.getJSONObject("metadata");
|
||||||
if (jsonError.length() > 0) {
|
if (!metadata.isNull("error")) {
|
||||||
final String errorMsg = jsonError.getString(0);
|
final String errorMsg = metadata.getString("error");
|
||||||
callback.onError(new ExchangeException(response.code(), errorMsg));
|
callback.onError(new ExchangeException(response.code(), (String) errorMsg));
|
||||||
} else {
|
} else {
|
||||||
final JSONObject jsonResult = json.getJSONObject("result");
|
final JSONObject jsonResult = json.getJSONObject("data");
|
||||||
reportSuccess(jsonResult, swapAssets, callback);
|
reportSuccess(jsonResult, swapAssets, callback);
|
||||||
}
|
}
|
||||||
} catch (JSONException ex) {
|
} catch (JSONException ex) {
|
||||||
@@ -130,7 +133,6 @@ public class ExchangeApiImpl implements ExchangeApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Request createHttpRequest(final HttpUrl url) {
|
private Request createHttpRequest(final HttpUrl url) {
|
||||||
return new Request.Builder()
|
return new Request.Builder()
|
||||||
.url(url)
|
.url(url)
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2017 m2049r et al.
|
* Copyright (c) 2017-2018 m2049r et al.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.m2049r.xmrwallet.service.exchange.kraken;
|
package com.m2049r.xmrwallet.service.exchange.coinmarketcap;
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
@@ -25,6 +25,7 @@ import org.json.JSONArray;
|
|||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@@ -37,7 +38,7 @@ class ExchangeRateImpl implements ExchangeRate {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getServiceName() {
|
public String getServiceName() {
|
||||||
return "kraken.com";
|
return "coinmarketcap.com";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -64,29 +65,21 @@ class ExchangeRateImpl implements ExchangeRate {
|
|||||||
|
|
||||||
ExchangeRateImpl(final JSONObject jsonObject, final boolean swapAssets) throws JSONException, ExchangeException {
|
ExchangeRateImpl(final JSONObject jsonObject, final boolean swapAssets) throws JSONException, ExchangeException {
|
||||||
try {
|
try {
|
||||||
final String key = jsonObject.keys().next(); // we expect only one
|
final String baseC = jsonObject.getString("symbol");
|
||||||
Pattern pattern = Pattern.compile("^X(.*?)Z(.*?)$");
|
final JSONObject quotes = jsonObject.getJSONObject("quotes");
|
||||||
Matcher matcher = pattern.matcher(key);
|
final Iterator<String> keys = quotes.keys();
|
||||||
if (matcher.find()) {
|
String key = null;
|
||||||
this.baseCurrency = swapAssets ? matcher.group(2) : matcher.group(1);
|
// get key which is not USD unless it is the only one
|
||||||
this.quoteCurrency = swapAssets ? matcher.group(1) : matcher.group(2);
|
while (keys.hasNext()) {
|
||||||
} else {
|
key = keys.next();
|
||||||
throw new ExchangeException("no pair returned!");
|
if (!key.equals("USD")) break;
|
||||||
}
|
|
||||||
|
|
||||||
JSONObject pair = jsonObject.getJSONObject(key);
|
|
||||||
JSONArray close = pair.getJSONArray("c");
|
|
||||||
String closePrice = close.getString(0);
|
|
||||||
if (closePrice != null) {
|
|
||||||
try {
|
|
||||||
double rate = Double.parseDouble(closePrice);
|
|
||||||
this.rate = swapAssets ? (1 / rate) : rate;
|
|
||||||
} catch (NumberFormatException ex) {
|
|
||||||
throw new ExchangeException(ex.getLocalizedMessage());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new ExchangeException("no close price returned!");
|
|
||||||
}
|
}
|
||||||
|
final String quoteC = key;
|
||||||
|
baseCurrency = swapAssets ? quoteC : baseC;
|
||||||
|
quoteCurrency = swapAssets ? baseC : quoteC;
|
||||||
|
JSONObject quote = quotes.getJSONObject(key);
|
||||||
|
double price = quote.getDouble("price");
|
||||||
|
this.rate = swapAssets ? (1d / price) : price;
|
||||||
} catch (NoSuchElementException ex) {
|
} catch (NoSuchElementException ex) {
|
||||||
throw new ExchangeException(ex.getLocalizedMessage());
|
throw new ExchangeException(ex.getLocalizedMessage());
|
||||||
}
|
}
|
@@ -66,6 +66,8 @@ public class BitcoinAddressValidator {
|
|||||||
|
|
||||||
byte[] result = new byte[25];
|
byte[] result = new byte[25];
|
||||||
byte[] numBytes = num.toByteArray();
|
byte[] numBytes = num.toByteArray();
|
||||||
|
if (num.bitLength() > 200) return null;
|
||||||
|
|
||||||
if (num.bitLength() == 200) {
|
if (num.bitLength() == 200) {
|
||||||
System.arraycopy(numBytes, 1, result, 0, 25);
|
System.arraycopy(numBytes, 1, result, 0, 25);
|
||||||
} else {
|
} else {
|
||||||
|
@@ -2,39 +2,44 @@ package com.m2049r.xmrwallet.util;
|
|||||||
|
|
||||||
import android.app.KeyguardManager;
|
import android.app.KeyguardManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.v4.hardware.fingerprint.FingerprintManagerCompat;
|
import android.hardware.fingerprint.FingerprintManager;
|
||||||
import android.support.v4.os.CancellationSignal;
|
import android.os.Build;
|
||||||
|
import android.os.CancellationSignal;
|
||||||
import java.security.KeyStore;
|
|
||||||
import java.security.KeyStoreException;
|
|
||||||
|
|
||||||
public class FingerprintHelper {
|
public class FingerprintHelper {
|
||||||
|
|
||||||
public static boolean isDeviceSupported(Context context) {
|
public static boolean isDeviceSupported(Context context) {
|
||||||
FingerprintManagerCompat fingerprintManager = FingerprintManagerCompat.from(context);
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||||
KeyguardManager keyguardManager = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return keyguardManager != null &&
|
FingerprintManager fingerprintManager = context.getSystemService(FingerprintManager.class);
|
||||||
|
KeyguardManager keyguardManager = context.getSystemService(KeyguardManager.class);
|
||||||
|
|
||||||
|
return (keyguardManager != null) && (fingerprintManager != null) &&
|
||||||
keyguardManager.isKeyguardSecure() &&
|
keyguardManager.isKeyguardSecure() &&
|
||||||
fingerprintManager.isHardwareDetected() &&
|
fingerprintManager.isHardwareDetected() &&
|
||||||
fingerprintManager.hasEnrolledFingerprints();
|
fingerprintManager.hasEnrolledFingerprints();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isFingerprintAuthAllowed(String wallet) throws KeyStoreException {
|
public static boolean isFingerPassValid(Context context, String wallet) {
|
||||||
KeyStore keyStore = KeyStore.getInstance(KeyStoreHelper.SecurityConstants.KEYSTORE_PROVIDER_ANDROID_KEYSTORE);
|
|
||||||
try {
|
try {
|
||||||
keyStore.load(null);
|
KeyStoreHelper.loadWalletUserPass(context, wallet);
|
||||||
} catch (Exception ex) {
|
return true;
|
||||||
throw new IllegalStateException("Could not load KeyStore", ex);
|
} catch (KeyStoreHelper.BrokenPasswordStoreException ex) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return keyStore.containsAlias(KeyStoreHelper.SecurityConstants.WALLET_PASS_KEY_PREFIX + wallet);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void authenticate(Context context, CancellationSignal cancelSignal,
|
public static void authenticate(Context context, CancellationSignal cancelSignal,
|
||||||
FingerprintManagerCompat.AuthenticationCallback callback) {
|
FingerprintManager.AuthenticationCallback callback) {
|
||||||
FingerprintManagerCompat manager = FingerprintManagerCompat.from(context);
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||||
manager.authenticate(null, 0, cancelSignal, callback, null);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FingerprintManager manager = context.getSystemService(FingerprintManager.class);
|
||||||
|
if (manager != null) {
|
||||||
|
manager.authenticate(null, cancelSignal, 0, callback, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -25,6 +25,7 @@ import android.util.AttributeSet;
|
|||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
@@ -36,9 +37,7 @@ import com.m2049r.xmrwallet.model.Wallet;
|
|||||||
import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi;
|
import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi;
|
||||||
import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback;
|
import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback;
|
||||||
import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate;
|
import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate;
|
||||||
import com.m2049r.xmrwallet.service.exchange.kraken.ExchangeApiImpl;
|
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
import com.m2049r.xmrwallet.util.OkHttpClientSingleton;
|
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
@@ -47,6 +46,8 @@ import timber.log.Timber;
|
|||||||
public class ExchangeTextView extends LinearLayout
|
public class ExchangeTextView extends LinearLayout
|
||||||
implements NumberPadView.NumberPadListener {
|
implements NumberPadView.NumberPadListener {
|
||||||
|
|
||||||
|
private static String MAX = "\u221E";
|
||||||
|
|
||||||
String xmrAmount = null;
|
String xmrAmount = null;
|
||||||
String notXmrAmount = null;
|
String notXmrAmount = null;
|
||||||
|
|
||||||
@@ -70,7 +71,7 @@ public class ExchangeTextView extends LinearLayout
|
|||||||
if (amount > max) {
|
if (amount > max) {
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
if (amount <= 0) {
|
if (amount <= 0) { /////////////////////////////
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
} catch (NumberFormatException ex) {
|
} catch (NumberFormatException ex) {
|
||||||
@@ -250,7 +251,7 @@ public class ExchangeTextView extends LinearLayout
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final ExchangeApi exchangeApi = new ExchangeApiImpl(OkHttpClientSingleton.getOkHttpClient());
|
private final ExchangeApi exchangeApi = Helper.getExchangeApi();
|
||||||
|
|
||||||
void startExchange() {
|
void startExchange() {
|
||||||
showProgress();
|
showProgress();
|
||||||
@@ -458,4 +459,4 @@ public class ExchangeTextView extends LinearLayout
|
|||||||
tvAmountA.setText(null);
|
tvAmountA.setText(null);
|
||||||
doExchange();
|
doExchange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -30,6 +30,7 @@ import android.view.LayoutInflater;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
@@ -41,9 +42,7 @@ import com.m2049r.xmrwallet.model.Wallet;
|
|||||||
import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi;
|
import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi;
|
||||||
import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback;
|
import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback;
|
||||||
import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate;
|
import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate;
|
||||||
import com.m2049r.xmrwallet.service.exchange.kraken.ExchangeApiImpl;
|
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
import com.m2049r.xmrwallet.util.OkHttpClientSingleton;
|
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
@@ -166,7 +165,11 @@ public class ExchangeView extends LinearLayout
|
|||||||
etAmount = (TextInputLayout) findViewById(R.id.etAmount);
|
etAmount = (TextInputLayout) findViewById(R.id.etAmount);
|
||||||
tvAmountB = (TextView) findViewById(R.id.tvAmountB);
|
tvAmountB = (TextView) findViewById(R.id.tvAmountB);
|
||||||
sCurrencyA = (Spinner) findViewById(R.id.sCurrencyA);
|
sCurrencyA = (Spinner) findViewById(R.id.sCurrencyA);
|
||||||
|
ArrayAdapter adapter = ArrayAdapter.createFromResource(getContext(), R.array.currency, R.layout.item_spinner);
|
||||||
|
adapter.setDropDownViewResource(R.layout.item_spinner_dropdown_item);
|
||||||
|
sCurrencyA.setAdapter(adapter);
|
||||||
sCurrencyB = (Spinner) findViewById(R.id.sCurrencyB);
|
sCurrencyB = (Spinner) findViewById(R.id.sCurrencyB);
|
||||||
|
sCurrencyB.setAdapter(adapter);
|
||||||
evExchange = (ImageView) findViewById(R.id.evExchange);
|
evExchange = (ImageView) findViewById(R.id.evExchange);
|
||||||
pbExchange = (ProgressBar) findViewById(R.id.pbExchange);
|
pbExchange = (ProgressBar) findViewById(R.id.pbExchange);
|
||||||
|
|
||||||
@@ -310,12 +313,13 @@ public class ExchangeView extends LinearLayout
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final ExchangeApi exchangeApi = new ExchangeApiImpl(OkHttpClientSingleton.getOkHttpClient());
|
private final ExchangeApi exchangeApi = Helper.getExchangeApi();
|
||||||
|
|
||||||
void startExchange() {
|
void startExchange() {
|
||||||
showProgress();
|
showProgress();
|
||||||
String currencyA = (String) sCurrencyA.getSelectedItem();
|
String currencyA = (String) sCurrencyA.getSelectedItem();
|
||||||
String currencyB = (String) sCurrencyB.getSelectedItem();
|
String currencyB = (String) sCurrencyB.getSelectedItem();
|
||||||
|
|
||||||
exchangeApi.queryExchangeRate(currencyA, currencyB,
|
exchangeApi.queryExchangeRate(currencyA, currencyB,
|
||||||
new ExchangeCallback() {
|
new ExchangeCallback() {
|
||||||
@Override
|
@Override
|
||||||
|
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M21,18v1c0,1.1 -0.9,2 -2,2L5,21c-1.11,0 -2,-0.9 -2,-2L3,5c0,-1.1 0.89,-2 2,-2h14c1.1,0 2,0.9 2,2v1h-9c-1.11,0 -2,0.9 -2,2v8c0,1.1 0.89,2 2,2h9zM12,16h10L22,8L12,8v8zM16,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5z"/>
|
||||||
|
</vector>
|
9
app/src/main/res/drawable/ic_add_circle_white.xml
Normal file
9
app/src/main/res/drawable/ic_add_circle_white.xml
Normal file
@@ -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/moneroWhite"
|
||||||
|
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>
|
9
app/src/main/res/drawable/ic_all_inclusive_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_all_inclusive_24dp.xml
Normal file
File diff suppressed because one or more lines are too long
5
app/src/main/res/drawable/ic_edit_white_24dp.xml
Normal file
5
app/src/main/res/drawable/ic_edit_white_24dp.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
|
||||||
|
</vector>
|
27
app/src/main/res/drawable/ic_error_red_36dp.xml
Normal file
27
app/src/main/res/drawable/ic_error_red_36dp.xml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<!--
|
||||||
|
~ Copyright (C) 2015 The Android Open Source Project
|
||||||
|
~
|
||||||
|
~ 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
|
||||||
|
-->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="36dp"
|
||||||
|
android:height="36dp"
|
||||||
|
android:viewportWidth="36"
|
||||||
|
android:viewportHeight="36" >
|
||||||
|
<path
|
||||||
|
android:fillColor="#f4511e"
|
||||||
|
android:pathData="M18,18m -18, 0a 18, 18 0 1, 0 36, 0a 18, 18 0 1, 0 -36, 0" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#ffffffff"
|
||||||
|
android:pathData="m16.665,24.915001l2.67,0l0,2.67l-2.67,0l0,-2.67zm0,-16.5l2.67,0l0,12.67l-2.67,0l0,-12.67z" />
|
||||||
|
</vector>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user