1
mirror of https://github.com/m2049r/xmrwallet synced 2025-09-06 19:00:30 +02:00

Compare commits

...

25 Commits

Author SHA1 Message Date
m2049r
c9927edbd1 save on exit only with connected wallet (#186) 2018-01-18 17:23:35 +01:00
m2049r
f0a3c05a9a v1.3.8 (#185) 2018-01-18 00:16:02 +01:00
m2049r
d6eb82c457 new wallet password fix (#184)
* revert to old (in-place) wallet creation method

* recover with password
2018-01-18 00:14:07 +01:00
m2049r
7f47307307 Revert "APK Split" (#183) 2018-01-16 22:23:10 +01:00
m2049r
165dd3dfd1 more spanish (#182) 2018-01-16 22:09:35 +01:00
m2049r
171727c9db new debug icon (#181) 2018-01-16 19:29:42 +01:00
m2049r
1492814ec9 new version 1.3.7 2018-01-16 19:28:30 +01:00
Stephan Hagios
9b1225fe4b Added an application suffix to distinguish between release and debug ver (#177)
* Added an application suffix to distinguish between release and debug ver

* Added icon for debug version.

* Added icon from mattermost assets channel.
2018-01-16 18:55:36 +01:00
m2049r
595d88e42e fixes & touchups (#178) 2018-01-15 23:31:14 +01:00
Stephan Hagios
0e207d7401 Merge pull request #174 from m2049r/feature/apk-split
APK Split
2018-01-04 17:07:52 +01:00
Stephan
5920d6c9e8 added apk split for different abis 2018-01-03 15:18:34 +01:00
m2049r
44fd3c10fa added info about xmr..to 2017-12-24 14:48:04 +01:00
anhdres
91ab8a681c Update spanish help.xml (#166)
* Update help.xml
2017-12-24 14:33:58 +01:00
m2049r
d843bdb451 Tweaks (#167)
* update privacy policy

* fix height

* send confirm scrollable

* use clickable instead of enabled

* rename
2017-12-24 14:18:32 +01:00
m2049r
2884fc711c UI Tweaks & spend help (#165)
* green send

* add xmrto to send help
2017-12-23 15:41:52 +01:00
m2049r
8ea2081270 Update README.md 2017-12-22 22:37:02 +01:00
m2049r
2296329962 Merge branch 'master' of https://github.com/m2049r/xmrwallet 2017-12-22 21:45:35 +01:00
Miguel Botón
fc1bff2160 Remove the gap at the bottom in the wallet fragment. (#162) 2017-12-22 21:43:46 +01:00
m2049r
e61c2b616e new version 2017-12-22 21:43:24 +01:00
m2049r
ea1e8ac2c3 UI tweaks, fix crash (#164) 2017-12-22 21:41:47 +01:00
m2049r
1082175089 spanish tweaked (#163) 2017-12-22 08:47:12 +01:00
m2049r
90d64089a6 new version id 2017-12-21 08:00:09 +01:00
m2049r
b689628975 fix some strings and remove debugging code (#160) 2017-12-21 07:58:50 +01:00
m2049r
f8e701aa07 Satoshis Dream (#159)
xmr.to integration
2017-12-21 00:46:34 +01:00
Miguel Botón
d855328c52 Translate strings and privacy policy to Spanish. (#155)
* Translate strings and privacy policy to Spanish.

* Translate help to Spanish.

* Improved translation of a couple of strings.

* The pirates are back.
2017-12-17 10:43:38 +01:00
123 changed files with 6462 additions and 1062 deletions

View File

@@ -11,22 +11,19 @@ Another Android Monero Wallet
You may lose all your Moneroj if you use this App. Be cautious when spending on the mainnet. You may lose all your Moneroj if you use this App. Be cautious when spending on the mainnet.
### Random Notes ### Random Notes
- Based off monero v0.11.0.0 with PR #2289 applied - Based off monero v0.11.1.0
- currently only android32 (runs on 64-bit as well) - currently only android32 (runs on 64-bit as well)
- works on the testnet & mainnet - works on the testnet & mainnet
- sync is slow due to 32-bit architecture - sync is slow due to 32-bit architecture
- use your own daemon - it's easy - use your own daemon - it's easy
- screen stays on until first sync is complete - screen stays on until first sync is complete
- saves wallet only on first sync and when sending transactions or editing notes
- Monerujo means "Monero Wallet" according to https://www.reddit.com/r/Monero/comments/3exy7t/esperanto_corner/ - Monerujo means "Monero Wallet" according to https://www.reddit.com/r/Monero/comments/3exy7t/esperanto_corner/
### TODO ### TODO
- more sensible error dialogs - see taiga.getmonero.org & issues on github
### Issues / Pitfalls ### Issues / Pitfalls
- The backups folder is now called "backups" and not ".backups" - which in most file explorers was a hidden folder - You should backup your wallet files in the "monerujo" folder periodically.
- Wallets are now created directly in the "monerujo" folder, and not in the ".new" folder as before
- You may want to check the old folders with a file browsing app and delete the ".new" and ".backups" folders AFTER moving neccessary wallet files to the new locations. Or simply make new backups from within Monerujo.
- Also note, that on some devices the backups will only be visible on a PC over USB after a reboot of the device (it's an Android bug/feature) - Also note, that on some devices the backups will only be visible on a PC over USB after a reboot of the device (it's an Android bug/feature)
- Created wallets on a private testnet are unusable because the restore height is set to that - Created wallets on a private testnet are unusable because the restore height is set to that
of the "real" testnet. After creating a new wallet, make a **new** one by recovering from the seed. of the "real" testnet. After creating a new wallet, make a **new** one by recovering from the seed.
@@ -36,7 +33,7 @@ The official monero client shows the same behaviour.
No need to build. Binaries are included: No need to build. Binaries are included:
- openssl-1.0.2l - openssl-1.0.2l
- monero-v0.11.0.0 + pull requests #2289 - monero-v0.11.1.0
- boost_1_64_0 - boost_1_64_0
If you want to build them yourself (recommended) check out [the instructions](doc/BUILDING-external-libs.md) If you want to build them yourself (recommended) check out [the instructions](doc/BUILDING-external-libs.md)

View File

@@ -8,8 +8,8 @@ android {
applicationId "com.m2049r.xmrwallet" applicationId "com.m2049r.xmrwallet"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 25 targetSdkVersion 25
versionCode 51 versionCode 70
versionName "1.2.11" versionName "1.3.10 'Satoshis Dream'"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild { externalNativeBuild {
cmake { cmake {
@@ -27,6 +27,9 @@ android {
minifyEnabled false minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
} }
debug {
applicationIdSuffix ".debug"
}
} }
externalNativeBuild { externalNativeBuild {
cmake { cmake {

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name" translatable="false">monerujo - Debug</string>
</resources>

View File

@@ -291,41 +291,48 @@ Java_com_m2049r_xmrwallet_model_WalletManager_openWalletJ(JNIEnv *env, jobject i
JNIEXPORT jlong JNICALL JNIEXPORT jlong JNICALL
Java_com_m2049r_xmrwallet_model_WalletManager_recoveryWalletJ(JNIEnv *env, jobject instance, Java_com_m2049r_xmrwallet_model_WalletManager_recoveryWalletJ(JNIEnv *env, jobject instance,
jstring path, jstring mnemonic, jstring path, jstring password,
jstring mnemonic,
jboolean isTestNet, jboolean isTestNet,
jlong restoreHeight) { jlong restoreHeight) {
const char *_path = env->GetStringUTFChars(path, NULL); const char *_path = env->GetStringUTFChars(path, NULL);
const char *_password = env->GetStringUTFChars(password, NULL);
const char *_mnemonic = env->GetStringUTFChars(mnemonic, NULL); const char *_mnemonic = env->GetStringUTFChars(mnemonic, NULL);
Bitmonero::Wallet *wallet = Bitmonero::Wallet *wallet =
Bitmonero::WalletManagerFactory::getWalletManager()->recoveryWallet( Bitmonero::WalletManagerFactory::getWalletManager()->recoveryWallet(
std::string(_path), std::string(_path),
std::string(_password),
std::string(_mnemonic), std::string(_mnemonic),
isTestNet, isTestNet,
restoreHeight); restoreHeight);
env->ReleaseStringUTFChars(path, _path); env->ReleaseStringUTFChars(path, _path);
env->ReleaseStringUTFChars(password, _password);
env->ReleaseStringUTFChars(mnemonic, _mnemonic); env->ReleaseStringUTFChars(mnemonic, _mnemonic);
return reinterpret_cast<jlong>(wallet); return reinterpret_cast<jlong>(wallet);
} }
JNIEXPORT jlong JNICALL JNIEXPORT jlong JNICALL
Java_com_m2049r_xmrwallet_model_WalletManager_createWalletFromKeysJ(JNIEnv *env, jobject instance, Java_com_m2049r_xmrwallet_model_WalletManager_createWalletWithKeysJ(JNIEnv *env, jobject instance,
jstring path, jstring language, jstring path, jstring password,
jstring language,
jboolean isTestNet, jboolean isTestNet,
jlong restoreHeight, jlong restoreHeight,
jstring addressString, jstring addressString,
jstring viewKeyString, jstring viewKeyString,
jstring spendKeyString) { jstring spendKeyString) {
const char *_path = env->GetStringUTFChars(path, NULL); const char *_path = env->GetStringUTFChars(path, NULL);
const char *_password = env->GetStringUTFChars(password, NULL);
const char *_language = env->GetStringUTFChars(language, NULL); const char *_language = env->GetStringUTFChars(language, NULL);
const char *_addressString = env->GetStringUTFChars(addressString, NULL); const char *_addressString = env->GetStringUTFChars(addressString, NULL);
const char *_viewKeyString = env->GetStringUTFChars(viewKeyString, NULL); const char *_viewKeyString = env->GetStringUTFChars(viewKeyString, NULL);
const char *_spendKeyString = env->GetStringUTFChars(spendKeyString, NULL); const char *_spendKeyString = env->GetStringUTFChars(spendKeyString, NULL);
Bitmonero::Wallet *wallet = Bitmonero::Wallet *wallet =
Bitmonero::WalletManagerFactory::getWalletManager()->createWalletFromKeys( Bitmonero::WalletManagerFactory::getWalletManager()->createWalletWithKeys(
std::string(_path), std::string(_path),
std::string(_password),
std::string(_language), std::string(_language),
isTestNet, isTestNet,
restoreHeight, restoreHeight,
@@ -334,6 +341,7 @@ Java_com_m2049r_xmrwallet_model_WalletManager_createWalletFromKeysJ(JNIEnv *env,
std::string(_spendKeyString)); std::string(_spendKeyString));
env->ReleaseStringUTFChars(path, _path); env->ReleaseStringUTFChars(path, _path);
env->ReleaseStringUTFChars(password, _password);
env->ReleaseStringUTFChars(language, _language); env->ReleaseStringUTFChars(language, _language);
env->ReleaseStringUTFChars(addressString, _addressString); env->ReleaseStringUTFChars(addressString, _addressString);
env->ReleaseStringUTFChars(viewKeyString, _viewKeyString); env->ReleaseStringUTFChars(viewKeyString, _viewKeyString);

View File

@@ -103,6 +103,7 @@ public class GenerateReviewFragment extends Fragment {
copyAddress(); copyAddress();
} }
}); });
bCopyAddress.setClickable(false);
view.findViewById(R.id.bAdvancedInfo).setOnClickListener(new View.OnClickListener() { view.findViewById(R.id.bAdvancedInfo).setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
@@ -213,7 +214,7 @@ public class GenerateReviewFragment extends Fragment {
tvWalletViewKey.setText(viewKey); tvWalletViewKey.setText(viewKey);
tvWalletSpendKey.setText(spendKey); tvWalletSpendKey.setText(spendKey);
bAdvancedInfo.setVisibility(View.VISIBLE); bAdvancedInfo.setVisibility(View.VISIBLE);
bCopyAddress.setEnabled(true); bCopyAddress.setClickable(true);
bCopyAddress.setImageResource(R.drawable.ic_content_copy_black_24dp); bCopyAddress.setImageResource(R.drawable.ic_content_copy_black_24dp);
activityCallback.setTitle(name, getString(R.string.details_title)); activityCallback.setTitle(name, getString(R.string.details_title));
activityCallback.setToolbarButton( activityCallback.setToolbarButton(

View File

@@ -278,7 +278,7 @@ public class LoginActivity extends SecureActivity
// set dialog message // set dialog message
alertDialogBuilder alertDialogBuilder
.setCancelable(false) .setCancelable(false)
.setPositiveButton("OK", .setPositiveButton(getString(R.string.label_ok),
new DialogInterface.OnClickListener() { new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) { public void onClick(DialogInterface dialog, int id) {
Helper.hideKeyboardAlways(LoginActivity.this); Helper.hideKeyboardAlways(LoginActivity.this);
@@ -286,7 +286,7 @@ public class LoginActivity extends SecureActivity
new AsyncRename().execute(walletName, newName); new AsyncRename().execute(walletName, newName);
} }
}) })
.setNegativeButton("Cancel", .setNegativeButton(getString(R.string.label_cancel),
new DialogInterface.OnClickListener() { new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) { public void onClick(DialogInterface dialog, int id) {
Helper.hideKeyboardAlways(LoginActivity.this); Helper.hideKeyboardAlways(LoginActivity.this);
@@ -482,8 +482,8 @@ public class LoginActivity extends SecureActivity
// set dialog message // set dialog message
alertDialogBuilder alertDialogBuilder
.setCancelable(false) .setCancelable(false)
.setPositiveButton("OK", null) .setPositiveButton(getString(R.string.label_ok), null)
.setNegativeButton("Cancel", .setNegativeButton(getString(R.string.label_cancel),
new DialogInterface.OnClickListener() { new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) { public void onClick(DialogInterface dialog, int id) {
Helper.hideKeyboardAlways(LoginActivity.this); Helper.hideKeyboardAlways(LoginActivity.this);
@@ -778,13 +778,14 @@ public class LoginActivity extends SecureActivity
static final String MNEMONIC_LANGUAGE = "English"; // see mnemonics/electrum-words.cpp for more static final String MNEMONIC_LANGUAGE = "English"; // see mnemonics/electrum-words.cpp for more
private class AsyncCreateWallet extends AsyncTask<Void, Void, Boolean> { private class AsyncCreateWallet extends AsyncTask<Void, Void, Boolean> {
String walletName; final String walletName;
String walletPassword; final String walletPassword;
WalletCreator walletCreator; final WalletCreator walletCreator;
File newWalletFile; File newWalletFile;
public AsyncCreateWallet(String name, String password, WalletCreator walletCreator) { public AsyncCreateWallet(final String name, final String password,
final WalletCreator walletCreator) {
super(); super();
this.walletName = name; this.walletName = name;
this.walletPassword = password; this.walletPassword = password;
@@ -814,12 +815,7 @@ public class LoginActivity extends SecureActivity
return false; return false;
} }
File newWalletFolder = Helper.getNewWalletDir(getApplicationContext()); newWalletFile = new File(walletFolder, walletName);
if (!newWalletFolder.isDirectory()) {
Timber.e("New Wallet dir " + newWalletFolder.getAbsolutePath() + "is not a directory");
return false;
}
newWalletFile = new File(newWalletFolder, walletName);
boolean success = walletCreator.createWallet(newWalletFile, walletPassword); boolean success = walletCreator.createWallet(newWalletFile, walletPassword);
if (success) { if (success) {
return true; return true;
@@ -844,7 +840,8 @@ public class LoginActivity extends SecureActivity
} }
} }
public void createWallet(String name, String password, WalletCreator walletCreator) { public void createWallet(final String name, final String password,
final WalletCreator walletCreator) {
new AsyncCreateWallet(name, password, walletCreator) new AsyncCreateWallet(name, password, walletCreator)
.executeOnExecutor(MoneroThreadPoolExecutor.MONERO_THREAD_POOL_EXECUTOR); .executeOnExecutor(MoneroThreadPoolExecutor.MONERO_THREAD_POOL_EXECUTOR);
} }
@@ -865,7 +862,7 @@ public class LoginActivity extends SecureActivity
} }
@Override @Override
public void onGenerate(String name, String password) { public void onGenerate(final String name, final String password) {
createWallet(name, password, createWallet(name, password,
new WalletCreator() { new WalletCreator() {
public boolean createWallet(File aFile, String password) { public boolean createWallet(File aFile, String password) {
@@ -883,16 +880,15 @@ public class LoginActivity extends SecureActivity
} }
@Override @Override
public void onGenerate(String name, String password, final String seed, final long restoreHeight) { public void onGenerate(final String name, final String password, final String seed,
final long restoreHeight) {
createWallet(name, password, createWallet(name, password,
new WalletCreator() { new WalletCreator() {
public boolean createWallet(File aFile, String password) { public boolean createWallet(File aFile, String password) {
Wallet newWallet = WalletManager.getInstance().recoveryWallet(aFile, seed, restoreHeight); Wallet newWallet = WalletManager.getInstance().
recoveryWallet(aFile, password, seed, restoreHeight);
boolean success = (newWallet.getStatus() == Wallet.Status.Status_Ok); boolean success = (newWallet.getStatus() == Wallet.Status.Status_Ok);
if (success) { if (!success) {
newWallet.setPassword(password);
success = success && newWallet.store();
} else {
Timber.e(newWallet.getErrorString()); Timber.e(newWallet.getErrorString());
toast(newWallet.getErrorString()); toast(newWallet.getErrorString());
} }
@@ -903,19 +899,17 @@ public class LoginActivity extends SecureActivity
} }
@Override @Override
public void onGenerate(String name, String password, public void onGenerate(final String name, final String password,
final String address, final String viewKey, final String spendKey, final long restoreHeight) { final String address, final String viewKey, final String spendKey,
final long restoreHeight) {
createWallet(name, password, createWallet(name, password,
new WalletCreator() { new WalletCreator() {
public boolean createWallet(File aFile, String password) { public boolean createWallet(File aFile, String password) {
Wallet newWallet = WalletManager.getInstance() Wallet newWallet = WalletManager.getInstance()
.createWalletFromKeys(aFile, MNEMONIC_LANGUAGE, restoreHeight, .createWalletWithKeys(aFile, password, MNEMONIC_LANGUAGE, restoreHeight,
address, viewKey, spendKey); address, viewKey, spendKey);
boolean success = (newWallet.getStatus() == Wallet.Status.Status_Ok); boolean success = (newWallet.getStatus() == Wallet.Status.Status_Ok);
if (success) { if (!success) {
newWallet.setPassword(password);
success = success && newWallet.store();
} else {
Timber.e(newWallet.getErrorString()); Timber.e(newWallet.getErrorString());
toast(newWallet.getErrorString()); toast(newWallet.getErrorString());
} }
@@ -936,16 +930,10 @@ public class LoginActivity extends SecureActivity
@Override @Override
public void onAccept(final String name, final String password) { public void onAccept(final String name, final String password) {
File newWalletFile = new File(Helper.getNewWalletDir(getApplicationContext()), name); File walletFolder = getStorageRoot();
Timber.d("New Wallet %s", newWalletFile.getAbsolutePath()); File walletFile = new File(walletFolder, name);
newWalletFile.delete(); // when recovering wallets, the cache seems corrupt Timber.d("New Wallet %s", walletFile.getAbsolutePath());
// TODO: figure out why this is so? Only for a private testnet? walletFile.delete(); // when recovering wallets, the cache seems corrupt
// now copy the new wallet to the wallet folder
File walletFile = new File(getStorageRoot(), name);
Timber.d("Wallet %s", walletFile.getAbsolutePath());
copyWallet(newWalletFile, walletFile, false, true);
deleteWallet(newWalletFile); // delete it no matter what (can't recover from this anyway)
boolean rc = testWallet(walletFile.getAbsolutePath(), password) == Wallet.Status.Status_Ok; boolean rc = testWallet(walletFile.getAbsolutePath(), password) == Wallet.Status.Status_Ok;

View File

@@ -43,6 +43,7 @@ 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.WalletManager; import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.util.Helper; import com.m2049r.xmrwallet.util.Helper;
@@ -61,15 +62,18 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
private WalletInfoAdapter adapter; private WalletInfoAdapter adapter;
List<WalletManager.WalletInfo> walletList = new ArrayList<>(); private List<WalletManager.WalletInfo> walletList = new ArrayList<>();
List<WalletManager.WalletInfo> displayedList = new ArrayList<>(); private List<WalletManager.WalletInfo> displayedList = new ArrayList<>();
EditText etDummy; private EditText etDummy;
ImageView ivGunther; private ImageView ivGunther;
DropDownEditText etDaemonAddress; private DropDownEditText etDaemonAddress;
ArrayAdapter<String> nodeAdapter; private ArrayAdapter<String> nodeAdapter;
Listener activityCallback; private View llXmrToEnabled;
private View ibXmrToInfoClose;
private Listener activityCallback;
// Container Activity must implement this interface // Container Activity must implement this interface
public interface Listener { public interface Listener {
@@ -165,6 +169,25 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
recyclerView.setAdapter(adapter); recyclerView.setAdapter(adapter);
etDummy = (EditText) view.findViewById(R.id.etDummy); etDummy = (EditText) view.findViewById(R.id.etDummy);
llXmrToEnabled = view.findViewById(R.id.llXmrToEnabled);
llXmrToEnabled.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
HelpFragment.display(getChildFragmentManager(), R.string.help_xmrto);
}
});
ibXmrToInfoClose = view.findViewById(R.id.ibXmrToInfoClose);
ibXmrToInfoClose.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
llXmrToEnabled.setVisibility(View.GONE);
showXmrtoEnabled = false;
saveXmrToPrefs();
}
});
etDaemonAddress = (DropDownEditText) view.findViewById(R.id.etDaemonAddress); etDaemonAddress = (DropDownEditText) view.findViewById(R.id.etDaemonAddress);
nodeAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_dropdown_item_1line); nodeAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_dropdown_item_1line);
etDaemonAddress.setAdapter(nodeAdapter); etDaemonAddress.setAdapter(nodeAdapter);
@@ -211,6 +234,9 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
}); });
loadPrefs(); loadPrefs();
if (!showXmrtoEnabled) {
llXmrToEnabled.setVisibility(View.GONE);
}
return view; return view;
} }
@@ -290,9 +316,8 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
activityCallback.onWalletDetails(name, isTestnet()); activityCallback.onWalletDetails(name, isTestnet());
} }
private boolean showReceive(@NonNull String name) { private void showReceive(@NonNull String name) {
activityCallback.onWalletReceive(name, isTestnet()); activityCallback.onWalletReceive(name, isTestnet());
return true;
} }
@Override @Override
@@ -308,7 +333,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
super.onCreateOptionsMenu(menu, inflater); super.onCreateOptionsMenu(menu, inflater);
} }
boolean testnet = false; private boolean testnet = BuildConfig.DEBUG;
boolean isTestnet() { boolean isTestnet() {
return testnet; return testnet;
@@ -336,6 +361,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
private static final String PREF_DAEMON_TESTNET = "daemon_testnet"; private static final String PREF_DAEMON_TESTNET = "daemon_testnet";
private static final String PREF_DAEMON_MAINNET = "daemon_mainnet"; private static final String PREF_DAEMON_MAINNET = "daemon_mainnet";
private static final String PREF_SHOW_XMRTO_ENABLED = "info_xmrto_enabled_login";
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";
@@ -346,22 +372,33 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
private NodeList daemonTestNet; private NodeList daemonTestNet;
private NodeList daemonMainNet; private NodeList daemonMainNet;
boolean showXmrtoEnabled = true;
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)); daemonTestNet = new NodeList(sharedPref.getString(PREF_DAEMON_TESTNET, PREF_DAEMONLIST_TESTNET));
setNet(isTestnet(), false); setNet(isTestnet(), false);
showXmrtoEnabled = sharedPref.getBoolean(PREF_SHOW_XMRTO_ENABLED, true);
}
void saveXmrToPrefs() {
SharedPreferences sharedPref = activityCallback.getPrefs();
SharedPreferences.Editor editor = sharedPref.edit();
editor.putBoolean(PREF_SHOW_XMRTO_ENABLED, showXmrtoEnabled);
editor.apply();
} }
void savePrefs() { void savePrefs() {
savePrefs(false); savePrefs(false);
} }
void savePrefs(boolean usePreviousState) { void savePrefs(boolean usePreviousTestnetState) {
Timber.d("SAVE / %s", usePreviousState); Timber.d("SAVE / %s", usePreviousTestnetState);
// save the daemon address for the net // save the daemon address for the net
boolean testnet = isTestnet() ^ usePreviousState; boolean testnet = isTestnet() ^ usePreviousTestnetState;
String daemon = getDaemon(); String daemon = getDaemon();
if (testnet) { if (testnet) {
daemonTestNet.setRecent(daemon); daemonTestNet.setRecent(daemon);
@@ -373,6 +410,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
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_TESTNET, daemonTestNet.toString());
editor.putBoolean(PREF_SHOW_XMRTO_ENABLED, showXmrtoEnabled);
editor.apply(); editor.apply();
} }

View File

@@ -46,6 +46,7 @@ import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix; import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter; import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.m2049r.xmrwallet.data.BarcodeData;
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.util.Helper; import com.m2049r.xmrwallet.util.Helper;
@@ -105,6 +106,7 @@ public class ReceiveFragment extends Fragment {
copyAddress(); copyAddress();
} }
}); });
bCopyAddress.setClickable(false);
evAmount.setOnNewAmountListener(new ExchangeView.OnNewAmountListener() { evAmount.setOnNewAmountListener(new ExchangeView.OnNewAmountListener() {
@Override @Override
@@ -239,7 +241,7 @@ public class ReceiveFragment extends Fragment {
tvAddress.setText(address); tvAddress.setText(address);
etPaymentId.setEnabled(true); etPaymentId.setEnabled(true);
bPaymentId.setEnabled(true); bPaymentId.setEnabled(true);
bCopyAddress.setEnabled(true); bCopyAddress.setClickable(true);
bCopyAddress.setImageResource(R.drawable.ic_content_copy_black_24dp); bCopyAddress.setImageResource(R.drawable.ic_content_copy_black_24dp);
hideProgress(); hideProgress();
generateQr(); generateQr();
@@ -304,14 +306,14 @@ public class ReceiveFragment extends Fragment {
return; return;
} }
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
sb.append(ScannerFragment.QR_SCHEME).append(address); sb.append(BarcodeData.XMR_SCHEME).append(address);
boolean first = true; boolean first = true;
if (!paymentId.isEmpty()) { if (!paymentId.isEmpty()) {
if (first) { if (first) {
sb.append("?"); sb.append("?");
first = false; first = false;
} }
sb.append(ScannerFragment.QR_PAYMENTID).append('=').append(paymentId); sb.append(BarcodeData.XMR_PAYMENTID).append('=').append(paymentId);
} }
if (!xmrAmount.isEmpty()) { if (!xmrAmount.isEmpty()) {
if (first) { if (first) {
@@ -319,7 +321,7 @@ public class ReceiveFragment extends Fragment {
} else { } else {
sb.append("&"); sb.append("&");
} }
sb.append(ScannerFragment.QR_AMOUNT).append('=').append(xmrAmount); sb.append(BarcodeData.XMR_AMOUNT).append('=').append(xmrAmount);
} }
String text = sb.toString(); String text = sb.toString();
int size = Math.min(qrCode.getHeight(), qrCode.getWidth()); int size = Math.min(qrCode.getHeight(), qrCode.getWidth());

View File

@@ -36,7 +36,7 @@ public class ScannerFragment extends Fragment implements ZXingScannerView.Result
private OnScannedListener onScannedListener; private OnScannedListener onScannedListener;
public interface OnScannedListener { public interface OnScannedListener {
boolean onScanned(String uri); boolean onScanned(String qrCode);
} }
private ZXingScannerView mScannerView; private ZXingScannerView mScannerView;
@@ -56,10 +56,6 @@ public class ScannerFragment extends Fragment implements ZXingScannerView.Result
mScannerView.startCamera(); mScannerView.startCamera();
} }
static final String QR_SCHEME = "monero:";
static final String QR_PAYMENTID = "tx_payment_id";
static final String QR_AMOUNT = "tx_amount";
@Override @Override
public void handleResult(Result rawResult) { public void handleResult(Result rawResult) {
if ((rawResult.getBarcodeFormat() == BarcodeFormat.QR_CODE)) { if ((rawResult.getBarcodeFormat() == BarcodeFormat.QR_CODE)) {

View File

@@ -20,6 +20,10 @@ import android.os.Bundle;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import com.m2049r.xmrwallet.util.Helper;
import java.io.File;
import static android.view.WindowManager.LayoutParams; import static android.view.WindowManager.LayoutParams;
public abstract class SecureActivity extends AppCompatActivity { public abstract class SecureActivity extends AppCompatActivity {

View File

@@ -30,10 +30,13 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast;
import com.m2049r.xmrwallet.model.TransactionInfo; import com.m2049r.xmrwallet.model.TransactionInfo;
import com.m2049r.xmrwallet.model.Transfer; import com.m2049r.xmrwallet.model.Transfer;
import com.m2049r.xmrwallet.model.Wallet; import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.UserNotes;
import com.m2049r.xmrwallet.widget.Toolbar; import com.m2049r.xmrwallet.widget.Toolbar;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
@@ -68,12 +71,23 @@ public class TxFragment extends Fragment {
private TextView etTxNotes; private TextView etTxNotes;
private Button bTxNotes; private Button bTxNotes;
// XMRTO stuff
private View cvXmrTo;
private TextView tvTxXmrToKey;
private TextView tvDestinationBtc;
private TextView tvTxAmountBtc;
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_tx_info, container, false); View view = inflater.inflate(R.layout.fragment_tx_info, container, false);
cvXmrTo = view.findViewById(R.id.cvXmrTo);
tvTxXmrToKey = (TextView) view.findViewById(R.id.tvTxXmrToKey);
tvDestinationBtc = (TextView) view.findViewById(R.id.tvDestinationBtc);
tvTxAmountBtc = (TextView) view.findViewById(R.id.tvTxAmountBtc);
tvTxTimestamp = (TextView) view.findViewById(R.id.tvTxTimestamp); 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);
@@ -94,7 +108,16 @@ public class TxFragment extends Fragment {
info.notes = null; // force reload on next view info.notes = null; // force reload on next view
bTxNotes.setEnabled(false); bTxNotes.setEnabled(false);
etTxNotes.setEnabled(false); etTxNotes.setEnabled(false);
activityCallback.onSetNote(info.hash, etTxNotes.getText().toString()); userNotes.setNote(etTxNotes.getText().toString());
activityCallback.onSetNote(info.hash, userNotes.txNotes);
}
});
tvTxXmrToKey.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Helper.clipBoardCopy(getActivity(), getString(R.string.label_copy_xmrtokey), tvTxXmrToKey.getText().toString());
Toast.makeText(getActivity(), getString(R.string.message_copy_xmrtokey), Toast.LENGTH_SHORT).show();
} }
}); });
@@ -175,12 +198,14 @@ public class TxFragment extends Fragment {
} }
TransactionInfo info = null; TransactionInfo info = null;
UserNotes userNotes = null;
void loadNotes(TransactionInfo info) { void loadNotes(TransactionInfo info) {
if (info.notes == null) { if ((userNotes == null) || (info.notes == null)) {
info.notes = activityCallback.getTxNotes(info.hash); info.notes = activityCallback.getTxNotes(info.hash);
} }
etTxNotes.setText(info.notes); userNotes = new UserNotes(info.notes);
etTxNotes.setText(userNotes.note);
} }
private void setTxColour(int clr) { private void setTxColour(int clr) {
@@ -266,8 +291,21 @@ public class TxFragment extends Fragment {
tvTxTransfers.setText(sb.toString()); tvTxTransfers.setText(sb.toString());
tvDestination.setText(dstSb.toString()); tvDestination.setText(dstSb.toString());
this.info = info; this.info = info;
showBtcInfo();
} }
void showBtcInfo() {
if (userNotes.xmrtoKey != null) {
cvXmrTo.setVisibility(View.VISIBLE);
tvTxXmrToKey.setText(userNotes.xmrtoKey);
tvDestinationBtc.setText(userNotes.xmrtoDestination);
tvTxAmountBtc.setText(userNotes.xmrtoAmount + " BTC");
} else {
cvXmrTo.setVisibility(View.GONE);
}
}
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);

View File

@@ -22,8 +22,8 @@ import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import android.os.PowerManager; import android.os.PowerManager;
@@ -38,17 +38,18 @@ import com.m2049r.xmrwallet.data.BarcodeData;
import com.m2049r.xmrwallet.data.TxData; import com.m2049r.xmrwallet.data.TxData;
import com.m2049r.xmrwallet.dialog.DonationFragment; import com.m2049r.xmrwallet.dialog.DonationFragment;
import com.m2049r.xmrwallet.dialog.HelpFragment; import com.m2049r.xmrwallet.dialog.HelpFragment;
import com.m2049r.xmrwallet.fragment.send.SendAddressWizardFragment;
import com.m2049r.xmrwallet.fragment.send.SendFragment;
import com.m2049r.xmrwallet.model.PendingTransaction; import com.m2049r.xmrwallet.model.PendingTransaction;
import com.m2049r.xmrwallet.model.TransactionInfo; import com.m2049r.xmrwallet.model.TransactionInfo;
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.Helper; import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.UserNotes;
import com.m2049r.xmrwallet.widget.Toolbar; import com.m2049r.xmrwallet.widget.Toolbar;
import java.io.File; import java.io.File;
import java.util.HashMap;
import java.util.Map;
import timber.log.Timber; import timber.log.Timber;
@@ -140,6 +141,9 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
@Override @Override
protected void onDestroy() { protected void onDestroy() {
Timber.d("onDestroy()"); Timber.d("onDestroy()");
if ((mBoundService != null) && !isSynced() && (getWallet() != null)) {
saveWallet();
}
stopWalletService(); stopWalletService();
super.onDestroy(); super.onDestroy();
} }
@@ -465,7 +469,7 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
} }
@Override @Override
public void onTransactionCreated(final PendingTransaction pendingTransaction) { public void onTransactionCreated(final String txTag, final PendingTransaction pendingTransaction) {
try { try {
final SendFragment sendFragment = (SendFragment) final SendFragment sendFragment = (SendFragment)
getSupportFragmentManager().findFragmentById(R.id.fragment_container); getSupportFragmentManager().findFragmentById(R.id.fragment_container);
@@ -477,7 +481,7 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
getWallet().disposePendingTransaction(); getWallet().disposePendingTransaction();
sendFragment.onCreateTransactionFailed(errorText); sendFragment.onCreateTransactionFailed(errorText);
} else { } else {
sendFragment.onTransactionCreated(pendingTransaction); sendFragment.onTransactionCreated(txTag, pendingTransaction);
} }
} }
}); });
@@ -560,19 +564,20 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
@Override @Override
public void onProgress(final int n) { public void onProgress(final int n) {
try { runOnUiThread(new Runnable() {
final WalletFragment walletFragment = (WalletFragment) public void run() {
getSupportFragmentManager().findFragmentByTag(WalletFragment.class.getName()); try {
runOnUiThread(new Runnable() { WalletFragment walletFragment = (WalletFragment)
public void run() { getSupportFragmentManager().findFragmentByTag(WalletFragment.class.getName());
walletFragment.setProgress(n); if (walletFragment != null)
walletFragment.setProgress(n);
} catch (ClassCastException ex) {
// not in wallet fragment (probably send monero)
Timber.d(ex.getLocalizedMessage());
// keep calm and carry on
} }
}); }
} catch (ClassCastException ex) { });
// not in wallet fragment (probably send monero)
Timber.d(ex.getLocalizedMessage());
// keep calm and carry on
}
} }
private void updateProgress() { private void updateProgress() {
@@ -588,11 +593,11 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
/////////////////////////// ///////////////////////////
@Override @Override
public void onSend(String notes) { public void onSend(UserNotes notes) {
if (mIsBound) { // no point in talking to unbound service if (mIsBound) { // no point in talking to unbound service
Intent intent = new Intent(getApplicationContext(), WalletService.class); Intent intent = new Intent(getApplicationContext(), WalletService.class);
intent.putExtra(WalletService.REQUEST, WalletService.REQUEST_CMD_SEND); intent.putExtra(WalletService.REQUEST, WalletService.REQUEST_CMD_SEND);
intent.putExtra(WalletService.REQUEST_CMD_SEND_NOTES, notes); intent.putExtra(WalletService.REQUEST_CMD_SEND_NOTES, notes.txNotes);
startService(intent); startService(intent);
Timber.d("SEND TX request sent"); Timber.d("SEND TX request sent");
} else { } else {
@@ -617,11 +622,12 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
} }
@Override @Override
public void onPrepareSend(TxData txData) { public void onPrepareSend(final String tag, final TxData txData) {
if (mIsBound) { // no point in talking to unbound service if (mIsBound) { // no point in talking to unbound service
Intent intent = new Intent(getApplicationContext(), WalletService.class); Intent intent = new Intent(getApplicationContext(), WalletService.class);
intent.putExtra(WalletService.REQUEST, WalletService.REQUEST_CMD_TX); intent.putExtra(WalletService.REQUEST, WalletService.REQUEST_CMD_TX);
intent.putExtra(WalletService.REQUEST_CMD_TX_DATA, txData); intent.putExtra(WalletService.REQUEST_CMD_TX_DATA, txData);
intent.putExtra(WalletService.REQUEST_CMD_TX_TAG, tag);
startService(intent); startService(intent);
Timber.d("CREATE TX request sent"); Timber.d("CREATE TX request sent");
} else { } else {
@@ -694,6 +700,7 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
@Override @Override
public void onDisposeRequest() { public void onDisposeRequest() {
//TODO consider doing this through the WalletService to avoid concurrency issues
getWallet().disposePendingTransaction(); getWallet().disposePendingTransaction();
} }
@@ -804,9 +811,6 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
super.onBackPressed(); super.onBackPressed();
} }
} else { } else {
if (!isSynced()) {
saveWallet();
}
super.onBackPressed(); super.onBackPressed();
} }
} }
@@ -815,4 +819,10 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
public void onFragmentDone() { public void onFragmentDone() {
popFragmentStack(null); popFragmentStack(null);
} }
@Override
public SharedPreferences getPrefs() {
return getPreferences(Context.MODE_PRIVATE);
}
} }

View File

@@ -313,7 +313,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, 16) + "…" + watchOnly; walletSubtitle = wallet.getAddress().substring(0, 10) + "…" + watchOnly;
activityCallback.setTitle(walletTitle, walletSubtitle); activityCallback.setTitle(walletTitle, walletSubtitle);
Timber.d("wallet title is %s", walletTitle); Timber.d("wallet title is %s", walletTitle);
} }

View File

@@ -19,6 +19,8 @@ package com.m2049r.xmrwallet.data;
import android.net.Uri; import android.net.Uri;
import com.m2049r.xmrwallet.model.Wallet; import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.util.BitcoinAddressValidator;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@@ -34,7 +36,7 @@ public class BarcodeData {
static final String BTC_AMOUNT = "amount"; static final String BTC_AMOUNT = "amount";
public enum Asset { public enum Asset {
XMR XMR, BTC
} }
public Asset asset = null; public Asset asset = null;
@@ -67,6 +69,14 @@ public class BarcodeData {
if (bcData == null) { if (bcData == null) {
bcData = parseMoneroNaked(qrCode); bcData = parseMoneroNaked(qrCode);
} }
// check for btc uri
if (bcData == null) {
bcData = parseBitcoinUri(qrCode);
}
// check for naked btc addres
if (bcData == null) {
bcData = parseBitcoinNaked(qrCode);
}
return bcData; return bcData;
} }
@@ -134,4 +144,57 @@ public class BarcodeData {
return new BarcodeData(Asset.XMR, address); return new BarcodeData(Asset.XMR, address);
} }
// bitcoin:mpQ84J43EURZHkCnXbyQ4PpNDLLBqdsMW2?amount=0.01
static public BarcodeData parseBitcoinUri(String uri) {
Timber.d("parseBitcoinUri=%s", uri);
if (uri == null) return null;
if (!uri.startsWith(BTC_SCHEME)) return null;
String noScheme = uri.substring(BTC_SCHEME.length());
Uri bitcoin = Uri.parse(noScheme);
Map<String, String> parms = new HashMap<>();
String query = bitcoin.getQuery();
if (query != null) {
String[] args = query.split("&");
for (String arg : args) {
String[] namevalue = arg.split("=");
if (namevalue.length == 0) {
continue;
}
parms.put(Uri.decode(namevalue[0]).toLowerCase(),
namevalue.length > 1 ? Uri.decode(namevalue[1]) : "");
}
}
String address = bitcoin.getPath();
String amount = parms.get(BTC_AMOUNT);
if (amount != null) {
try {
Double.parseDouble(amount);
} catch (NumberFormatException ex) {
Timber.d(ex.getLocalizedMessage());
return null; // we have an amount but its not a number!
}
}
if (!BitcoinAddressValidator.validate(address, WalletManager.getInstance().isTestNet())) {
Timber.d("address invalid");
return null;
}
return new BarcodeData(BarcodeData.Asset.BTC, address, amount);
}
static public BarcodeData parseBitcoinNaked(String address) {
Timber.d("parseBitcoinNaked=%s", address);
if (address == null) return null;
if (!BitcoinAddressValidator.validate(address, WalletManager.getInstance().isTestNet())) {
Timber.d("address invalid");
return null;
}
return new BarcodeData(BarcodeData.Asset.BTC, address);
}
} }

View File

@@ -20,36 +20,38 @@ import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import com.m2049r.xmrwallet.model.PendingTransaction; import com.m2049r.xmrwallet.model.PendingTransaction;
import com.m2049r.xmrwallet.util.UserNotes;
import timber.log.Timber;
// https://stackoverflow.com/questions/2139134/how-to-send-an-object-from-one-android-activity-to-another-using-intents // https://stackoverflow.com/questions/2139134/how-to-send-an-object-from-one-android-activity-to-another-using-intents
public class TxData implements Parcelable { public class TxData implements Parcelable {
public TxData() {
}
public TxData(TxData txData) { public TxData(TxData txData) {
this.dst_addr = txData.dst_addr; this.dstAddr = txData.dstAddr;
this.paymentId = txData.paymentId; this.paymentId = txData.paymentId;
this.amount = txData.amount; this.amount = txData.amount;
this.mixin = txData.mixin; this.mixin = txData.mixin;
this.priority = txData.priority; this.priority = txData.priority;
} }
public TxData(String dst_addr, public TxData(String dstAddr,
String paymentId, String paymentId,
long amount, long amount,
int mixin, int mixin,
PendingTransaction.Priority priority) { PendingTransaction.Priority priority) {
this.dst_addr = dst_addr; this.dstAddr = dstAddr;
this.paymentId = paymentId; this.paymentId = paymentId;
this.amount = amount; this.amount = amount;
this.mixin = mixin; this.mixin = mixin;
this.priority = priority; this.priority = priority;
} }
public long getFee() {
return 0L;
}
public String getDestinationAddress() { public String getDestinationAddress() {
return dst_addr; return dstAddr;
} }
public String getPaymentId() { public String getPaymentId() {
@@ -68,15 +70,45 @@ public class TxData implements Parcelable {
return priority; return priority;
} }
final private String dst_addr; public void setDestinationAddress(String dstAddr) {
final private String paymentId; this.dstAddr = dstAddr;
final private long amount; }
final private int mixin;
final private PendingTransaction.Priority priority; public void setPaymentId(String paymentId) {
this.paymentId = paymentId;
}
public void setAmount(long amount) {
this.amount = amount;
}
public void setMixin(int mixin) {
this.mixin = mixin;
}
public void setPriority(PendingTransaction.Priority priority) {
this.priority = priority;
}
public UserNotes getUserNotes() {
return userNotes;
}
public void setUserNotes(UserNotes userNotes) {
this.userNotes = userNotes;
}
private String dstAddr;
private String paymentId;
private long amount;
private int mixin;
private PendingTransaction.Priority priority;
private UserNotes userNotes;
@Override @Override
public void writeToParcel(Parcel out, int flags) { public void writeToParcel(Parcel out, int flags) {
out.writeString(dst_addr); out.writeString(dstAddr);
out.writeString(paymentId); out.writeString(paymentId);
out.writeLong(amount); out.writeLong(amount);
out.writeInt(mixin); out.writeInt(mixin);
@@ -94,8 +126,8 @@ public class TxData implements Parcelable {
} }
}; };
private TxData(Parcel in) { protected TxData(Parcel in) {
dst_addr = in.readString(); dstAddr = in.readString();
paymentId = in.readString(); paymentId = in.readString();
amount = in.readLong(); amount = in.readLong();
mixin = in.readInt(); mixin = in.readInt();
@@ -111,8 +143,8 @@ public class TxData implements Parcelable {
@Override @Override
public String toString() { public String toString() {
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
sb.append("dst_addr:"); sb.append("dstAddr:");
sb.append(dst_addr); sb.append(dstAddr);
sb.append(",paymentId:"); sb.append(",paymentId:");
sb.append(paymentId); sb.append(paymentId);
sb.append(",amount:"); sb.append(",amount:");

View File

@@ -0,0 +1,98 @@
/*
* Copyright (c) 2017 m2049r
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.m2049r.xmrwallet.data;
import android.os.Parcel;
import com.m2049r.xmrwallet.model.PendingTransaction;
public class TxDataBtc extends TxData {
private String xmrtoUuid;
private String btcAddress;
private double btcAmount;
public TxDataBtc() {
super();
}
public TxDataBtc(TxDataBtc txDataBtc) {
super(txDataBtc);
}
public String getXmrtoUuid() {
return xmrtoUuid;
}
public void setXmrtoUuid(String xmrtoUuid) {
this.xmrtoUuid = xmrtoUuid;
}
public String getBtcAddress() {
return btcAddress;
}
public void setBtcAddress(String btcAddress) {
this.btcAddress = btcAddress;
}
public double getBtcAmount() {
return btcAmount;
}
public void setBtcAmount(double btcAmount) {
this.btcAmount = btcAmount;
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeString(xmrtoUuid);
out.writeString(btcAddress);
out.writeDouble(btcAmount);
}
// this is used to regenerate your object. All Parcelables must have a CREATOR that implements these two methods
public static final Creator<TxDataBtc> CREATOR = new Creator<TxDataBtc>() {
public TxDataBtc createFromParcel(Parcel in) {
return new TxDataBtc(in);
}
public TxDataBtc[] newArray(int size) {
return new TxDataBtc[size];
}
};
protected TxDataBtc(Parcel in) {
super(in);
xmrtoUuid = in.readString();
btcAddress = in.readString();
btcAmount = in.readDouble();
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append(",xmrtoUuid:");
sb.append(xmrtoUuid);
sb.append(",btcAddress:");
sb.append(btcAddress);
sb.append(",btcAmount:");
sb.append(btcAmount);
return sb.toString();
}
}

View File

@@ -14,13 +14,14 @@
* limitations under the License. * limitations under the License.
*/ */
package com.m2049r.xmrwallet; package com.m2049r.xmrwallet.fragment.send;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.support.design.widget.TextInputLayout; import android.support.design.widget.TextInputLayout;
import android.support.v7.widget.CardView; import android.support.v7.widget.CardView;
import android.text.Editable; import android.text.Editable;
import android.text.Html;
import android.text.InputType; import android.text.InputType;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.view.KeyEvent; import android.view.KeyEvent;
@@ -32,9 +33,13 @@ import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import android.widget.TextView; import android.widget.TextView;
import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.data.BarcodeData; import com.m2049r.xmrwallet.data.BarcodeData;
import com.m2049r.xmrwallet.data.TxData;
import com.m2049r.xmrwallet.data.TxDataBtc;
import com.m2049r.xmrwallet.model.Wallet; import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.model.WalletManager; import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.util.BitcoinAddressValidator;
import com.m2049r.xmrwallet.util.Helper; import com.m2049r.xmrwallet.util.Helper;
import timber.log.Timber; import timber.log.Timber;
@@ -56,12 +61,12 @@ public class SendAddressWizardFragment extends SendWizardFragment {
return this; return this;
} }
interface Listener { public interface Listener {
void setAddress(final String address);
void setPaymentId(final String paymentId);
void setBarcodeData(BarcodeData data); void setBarcodeData(BarcodeData data);
void setMode(SendFragment.Mode mode);
TxData getTxData();
} }
private EditText etDummy; private EditText etDummy;
@@ -71,6 +76,8 @@ public class SendAddressWizardFragment extends SendWizardFragment {
private CardView cvScan; private CardView cvScan;
private View tvPaymentIdIntegrated; private View tvPaymentIdIntegrated;
private View llPaymentId; private View llPaymentId;
private TextView tvXmrTo;
private View llXmrTo;
OnScanListener onScanListener; OnScanListener onScanListener;
@@ -89,6 +96,9 @@ public class SendAddressWizardFragment extends SendWizardFragment {
tvPaymentIdIntegrated = view.findViewById(R.id.tvPaymentIdIntegrated); tvPaymentIdIntegrated = view.findViewById(R.id.tvPaymentIdIntegrated);
llPaymentId = view.findViewById(R.id.llPaymentId); llPaymentId = view.findViewById(R.id.llPaymentId);
llXmrTo = view.findViewById(R.id.llXmrTo);
tvXmrTo = (TextView) view.findViewById(R.id.tvXmrTo);
tvXmrTo.setText(Html.fromHtml(getString(R.string.info_xmrto)));
etAddress = (TextInputLayout) view.findViewById(R.id.etAddress); etAddress = (TextInputLayout) view.findViewById(R.id.etAddress);
etAddress.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); etAddress.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
@@ -113,12 +123,25 @@ public class SendAddressWizardFragment extends SendWizardFragment {
public void afterTextChanged(Editable editable) { public void afterTextChanged(Editable editable) {
etAddress.setError(null); etAddress.setError(null);
if (isIntegratedAddress()) { if (isIntegratedAddress()) {
Timber.d("isIntegratedAddress");
etPaymentId.getEditText().getText().clear(); etPaymentId.getEditText().getText().clear();
llPaymentId.setVisibility(View.GONE); llPaymentId.setVisibility(View.INVISIBLE);
tvPaymentIdIntegrated.setVisibility(View.VISIBLE); tvPaymentIdIntegrated.setVisibility(View.VISIBLE);
} else { // we don't llXmrTo.setVisibility(View.INVISIBLE);
sendListener.setMode(SendFragment.Mode.XMR);
} else if (isBitcoinAddress()) {
Timber.d("isBitcoinAddress");
etPaymentId.getEditText().getText().clear();
llPaymentId.setVisibility(View.INVISIBLE);
tvPaymentIdIntegrated.setVisibility(View.INVISIBLE);
llXmrTo.setVisibility(View.VISIBLE);
sendListener.setMode(SendFragment.Mode.BTC);
} else {
Timber.d("isStandardAddress");
llPaymentId.setVisibility(View.VISIBLE); llPaymentId.setVisibility(View.VISIBLE);
tvPaymentIdIntegrated.setVisibility(View.GONE); tvPaymentIdIntegrated.setVisibility(View.INVISIBLE);
llXmrTo.setVisibility(View.INVISIBLE);
sendListener.setMode(SendFragment.Mode.XMR);
} }
} }
@@ -188,13 +211,14 @@ public class SendAddressWizardFragment extends SendWizardFragment {
private boolean checkAddressNoError() { private boolean checkAddressNoError() {
String address = etAddress.getEditText().getText().toString(); String address = etAddress.getEditText().getText().toString();
return Wallet.isAddressValid(address); return Wallet.isAddressValid(address)
|| BitcoinAddressValidator.validate(address, WalletManager.getInstance().isTestNet());
} }
private boolean checkAddress() { private boolean checkAddress() {
boolean ok = checkAddressNoError(); boolean ok = checkAddressNoError();
if (!ok) { if (!ok) {
etAddress.setError(getString(R.string.send_qr_address_invalid)); etAddress.setError(getString(R.string.send_address_invalid));
} else { } else {
etAddress.setError(null); etAddress.setError(null);
} }
@@ -203,7 +227,16 @@ public class SendAddressWizardFragment extends SendWizardFragment {
private boolean isIntegratedAddress() { private boolean isIntegratedAddress() {
String address = etAddress.getEditText().getText().toString(); String address = etAddress.getEditText().getText().toString();
return (address.length() == INTEGRATED_ADDRESS_LENGTH) && Wallet.isAddressValid(address); return (address.length() == INTEGRATED_ADDRESS_LENGTH)
&& Wallet.isAddressValid(address, WalletManager.getInstance().isTestNet());
}
private boolean isBitcoinAddress() {
String address = etAddress.getEditText().getText().toString();
if ((address.length() >= 27) && (address.length() <= 34))
return BitcoinAddressValidator.validate(address, WalletManager.getInstance().isTestNet());
else
return false;
} }
private boolean checkPaymentId() { private boolean checkPaymentId() {
@@ -235,8 +268,15 @@ public class SendAddressWizardFragment extends SendWizardFragment {
} }
if (!ok) return false; if (!ok) return false;
if (sendListener != null) { if (sendListener != null) {
sendListener.setAddress(etAddress.getEditText().getText().toString()); TxData txData = sendListener.getTxData();
sendListener.setPaymentId(etPaymentId.getEditText().getText().toString()); if (isBitcoinAddress()) {
((TxDataBtc) txData).setBtcAddress(etAddress.getEditText().getText().toString());
txData.setDestinationAddress(null);
txData.setPaymentId("");
} else {
txData.setDestinationAddress(etAddress.getEditText().getText().toString());
txData.setPaymentId(etPaymentId.getEditText().getText().toString());
}
} }
return true; return true;
} }

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.m2049r.xmrwallet; package com.m2049r.xmrwallet.fragment.send;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@@ -22,10 +22,12 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.data.BarcodeData; import com.m2049r.xmrwallet.data.BarcodeData;
import com.m2049r.xmrwallet.widget.ExchangeTextView; import com.m2049r.xmrwallet.data.TxData;
import com.m2049r.xmrwallet.model.Wallet; import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.util.Helper; import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.widget.ExchangeTextView;
import com.m2049r.xmrwallet.widget.NumberPadView; import com.m2049r.xmrwallet.widget.NumberPadView;
import timber.log.Timber; import timber.log.Timber;
@@ -48,7 +50,7 @@ public class SendAmountWizardFragment extends SendWizardFragment {
interface Listener { interface Listener {
SendFragment.Listener getActivityCallback(); SendFragment.Listener getActivityCallback();
void setAmount(final long amount); TxData getTxData();
BarcodeData popBarcodeData(); BarcodeData popBarcodeData();
} }
@@ -99,9 +101,9 @@ public class SendAmountWizardFragment extends SendWizardFragment {
if (sendListener != null) { if (sendListener != null) {
String xmr = evAmount.getAmount(); String xmr = evAmount.getAmount();
if (xmr != null) { if (xmr != null) {
sendListener.setAmount(Wallet.getAmountFromString(xmr)); sendListener.getTxData().setAmount(Wallet.getAmountFromString(xmr));
} else { } else {
sendListener.setAmount(0L); sendListener.getTxData().setAmount(0L);
} }
} }
return true; return true;

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) 2017 m2049r
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.m2049r.xmrwallet.fragment.send;
import com.m2049r.xmrwallet.model.PendingTransaction;
interface SendConfirm {
void sendFailed();
void createTransactionFailed(String errorText);
void transactionCreated(String txTag, PendingTransaction pendingTransaction);
}

View File

@@ -14,12 +14,13 @@
* limitations under the License. * limitations under the License.
*/ */
package com.m2049r.xmrwallet; package com.m2049r.xmrwallet.fragment.send;
import android.app.Activity; import android.app.Activity;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.os.Bundle; import android.os.Bundle;
import android.support.design.widget.TextInputLayout; import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AlertDialog;
import android.text.Editable; import android.text.Editable;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.view.KeyEvent; import android.view.KeyEvent;
@@ -30,14 +31,16 @@ import android.view.inputmethod.EditorInfo;
import android.widget.Button; import android.widget.Button;
import android.widget.TextView; import android.widget.TextView;
import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.data.TxData; import com.m2049r.xmrwallet.data.TxData;
import com.m2049r.xmrwallet.model.PendingTransaction; import com.m2049r.xmrwallet.model.PendingTransaction;
import com.m2049r.xmrwallet.model.Wallet; import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.util.Helper; import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.UserNotes;
import timber.log.Timber; import timber.log.Timber;
public class SendConfirmWizardFragment extends SendWizardFragment { public class SendConfirmWizardFragment extends SendWizardFragment implements SendConfirm {
public static SendConfirmWizardFragment newInstance(Listener listener) { public static SendConfirmWizardFragment newInstance(Listener listener) {
SendConfirmWizardFragment instance = new SendConfirmWizardFragment(); SendConfirmWizardFragment instance = new SendConfirmWizardFragment();
@@ -57,11 +60,11 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
TxData getTxData(); TxData getTxData();
String getNotes();
void commitTransaction(); void commitTransaction();
void disposeTransaction(); void disposeTransaction();
SendFragment.Mode getMode();
} }
private TextView tvTxAddress; private TextView tvTxAddress;
@@ -122,8 +125,11 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
PendingTransaction pendingTransaction = null; PendingTransaction pendingTransaction = null;
@Override
// callback from wallet when PendingTransaction created // callback from wallet when PendingTransaction created
void transactionCreated(PendingTransaction pendingTransaction) { public void transactionCreated(String txTag, PendingTransaction pendingTransaction) {
// ignore txTag - the app flow ensures this is the correct tx
// TODO: use the txTag
hideProgress(); hideProgress();
if (isResumed) { if (isResumed) {
this.pendingTransaction = pendingTransaction; this.pendingTransaction = pendingTransaction;
@@ -138,10 +144,22 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
pbProgressSend.setVisibility(View.VISIBLE); pbProgressSend.setVisibility(View.VISIBLE);
} }
void sendFailed() { @Override
public void sendFailed() {
pbProgressSend.setVisibility(View.INVISIBLE); pbProgressSend.setVisibility(View.INVISIBLE);
} }
@Override
public void createTransactionFailed(String errorText) {
hideProgress();
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setCancelable(true).
setTitle(getString(R.string.send_create_tx_error_title)).
setMessage(errorText).
create().
show();
}
@Override @Override
public boolean onValidateFields() { public boolean onValidateFields() {
return true; return true;
@@ -173,9 +191,9 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
} else { } else {
tvTxPaymentId.setText("-"); tvTxPaymentId.setText("-");
} }
String notes = sendListener.getNotes(); UserNotes notes = sendListener.getTxData().getUserNotes();
if ((notes != null) && (!notes.isEmpty())) { if ((notes != null) && (!notes.note.isEmpty())) {
tvTxNotes.setText(sendListener.getNotes()); tvTxNotes.setText(notes.note);
} else { } else {
tvTxNotes.setText("-"); tvTxNotes.setText("-");
} }
@@ -232,7 +250,7 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
alertDialogBuilder alertDialogBuilder
.setCancelable(false) .setCancelable(false)
.setPositiveButton("OK", new DialogInterface.OnClickListener() { .setPositiveButton(getString(R.string.label_ok), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) { public void onClick(DialogInterface dialog, int id) {
String pass = etPassword.getEditText().getText().toString(); String pass = etPassword.getEditText().getText().toString();
if (getActivityCallback().verifyWalletPassword(pass)) { if (getActivityCallback().verifyWalletPassword(pass)) {
@@ -244,7 +262,7 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
} }
} }
}) })
.setNegativeButton("Cancel", .setNegativeButton(getString(R.string.label_cancel),
new DialogInterface.OnClickListener() { new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) { public void onClick(DialogInterface dialog, int id) {
Helper.hideKeyboardAlways(activity); Helper.hideKeyboardAlways(activity);
@@ -296,8 +314,10 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
passwordDialog.show(); passwordDialog.show();
} }
// creates a pending transaction and calls us back with transactionCreated()
// or createTransactionFailed()
void prepareSend(TxData txData) { void prepareSend(TxData txData) {
getActivityCallback().onPrepareSend(txData); getActivityCallback().onPrepareSend(null, txData);
} }
SendFragment.Listener getActivityCallback() { SendFragment.Listener getActivityCallback() {

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.m2049r.xmrwallet; package com.m2049r.xmrwallet.fragment.send;
import android.os.Bundle; import android.os.Bundle;
import android.text.InputType; import android.text.InputType;
@@ -27,8 +27,11 @@ import android.widget.EditText;
import android.widget.Spinner; import android.widget.Spinner;
import android.widget.TextView; import android.widget.TextView;
import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.data.TxData;
import com.m2049r.xmrwallet.model.PendingTransaction; import com.m2049r.xmrwallet.model.PendingTransaction;
import com.m2049r.xmrwallet.util.Helper; import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.UserNotes;
import timber.log.Timber; import timber.log.Timber;
@@ -48,12 +51,7 @@ public class SendSettingsWizardFragment extends SendWizardFragment {
} }
interface Listener { interface Listener {
TxData getTxData();
void setPriority(final PendingTransaction.Priority priority);
void setMixin(final int mixin);
void setNotes(final String notes);
} }
final static int Mixins[] = {4, 7, 12, 25}; // must match the layout XML final static int Mixins[] = {4, 7, 12, 25}; // must match the layout XML
@@ -103,13 +101,10 @@ public class SendSettingsWizardFragment extends SendWizardFragment {
@Override @Override
public boolean onValidateFields() { public boolean onValidateFields() {
if (sendListener != null) { if (sendListener != null) {
int mixin = Mixins[sMixin.getSelectedItemPosition()]; TxData txData = sendListener.getTxData();
int priorityIndex = sPriority.getSelectedItemPosition(); txData.setPriority(Priorities[sPriority.getSelectedItemPosition()]);
PendingTransaction.Priority priority = Priorities[priorityIndex]; txData.setMixin(Mixins[sMixin.getSelectedItemPosition()]);
sendListener.setPriority(priority); txData.setUserNotes(new UserNotes(etNotes.getText().toString()));
sendListener.setMixin(mixin);
String notes = etNotes.getText().toString();
sendListener.setNotes(notes);
} }
return true; return true;
} }

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.m2049r.xmrwallet; package com.m2049r.xmrwallet.fragment.send;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@@ -24,10 +24,10 @@ import android.widget.ImageButton;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.m2049r.xmrwallet.model.Wallet; import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.data.PendingTx; import com.m2049r.xmrwallet.data.PendingTx;
import com.m2049r.xmrwallet.data.TxData; import com.m2049r.xmrwallet.data.TxData;
import com.m2049r.xmrwallet.util.Helper;
import timber.log.Timber; import timber.log.Timber;
@@ -47,23 +47,21 @@ public class SendSuccessWizardFragment extends SendWizardFragment {
} }
interface Listener { interface Listener {
String getNotes();
TxData getTxData(); TxData getTxData();
PendingTx getCommittedTx(); PendingTx getCommittedTx();
void enableDone(); void enableDone();
SendFragment.Mode getMode();
} }
ImageButton bCopyAddress; ImageButton bCopyTxId;
private TextView tvTxId; private TextView tvTxId;
private TextView tvTxAddress; private TextView tvTxAddress;
private TextView tvTxPaymentId; private TextView tvTxPaymentId;
private TextView tvTxNotes;
private TextView tvTxAmount; private TextView tvTxAmount;
private TextView tvTxFee; private TextView tvTxFee;
private TextView tvTxTotal;
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container,
@@ -74,21 +72,20 @@ public class SendSuccessWizardFragment extends SendWizardFragment {
View view = inflater.inflate( View view = inflater.inflate(
R.layout.fragment_send_success, container, false); R.layout.fragment_send_success, container, false);
bCopyAddress = (ImageButton) view.findViewById(R.id.bCopyAddress); bCopyTxId = (ImageButton) view.findViewById(R.id.bCopyTxId);
bCopyAddress.setOnClickListener(new View.OnClickListener() { bCopyTxId.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
copyAddress(); Helper.clipBoardCopy(getActivity(), getString(R.string.label_send_txid), tvTxId.getText().toString());
Toast.makeText(getActivity(), getString(R.string.message_copy_address), Toast.LENGTH_SHORT).show();
} }
}); });
tvTxId = (TextView) view.findViewById(R.id.tvTxId); tvTxId = (TextView) view.findViewById(R.id.tvTxId);
tvTxAddress = (TextView) view.findViewById(R.id.tvTxAddress); tvTxAddress = (TextView) view.findViewById(R.id.tvTxAddress);
tvTxPaymentId = (TextView) view.findViewById(R.id.tvTxPaymentId); tvTxPaymentId = (TextView) view.findViewById(R.id.tvTxPaymentId);
tvTxNotes = (TextView) view.findViewById(R.id.tvTxNotes);
tvTxAmount = ((TextView) view.findViewById(R.id.tvTxAmount)); tvTxAmount = ((TextView) view.findViewById(R.id.tvTxAmount));
tvTxFee = (TextView) view.findViewById(R.id.tvTxFee); tvTxFee = (TextView) view.findViewById(R.id.tvTxFee);
tvTxTotal = (TextView) view.findViewById(R.id.tvTxTotal);
return view; return view;
} }
@@ -117,30 +114,15 @@ public class SendSuccessWizardFragment extends SendWizardFragment {
} else { } else {
tvTxPaymentId.setText("-"); tvTxPaymentId.setText("-");
} }
String notes = sendListener.getNotes();
if ((notes != null) && (!notes.isEmpty())) {
tvTxNotes.setText(sendListener.getNotes());
} else {
tvTxNotes.setText("-");
}
final PendingTx committedTx = sendListener.getCommittedTx(); final PendingTx committedTx = sendListener.getCommittedTx();
if (committedTx != null) { if (committedTx != null) {
tvTxId.setText(committedTx.txId); tvTxId.setText(committedTx.txId);
bCopyAddress.setEnabled(true); bCopyTxId.setEnabled(true);
bCopyAddress.setImageResource(R.drawable.ic_content_copy_black_24dp); bCopyTxId.setImageResource(R.drawable.ic_content_copy_black_24dp);
tvTxAmount.setText(Wallet.getDisplayAmount(committedTx.amount)); tvTxAmount.setText(getString(R.string.send_amount, Helper.getDisplayAmount(committedTx.amount)));
tvTxFee.setText(Wallet.getDisplayAmount(committedTx.fee)); tvTxFee.setText(getString(R.string.send_fee, Helper.getDisplayAmount(committedTx.fee)));
//tvTxDust.setText(Wallet.getDisplayAmount(pendingTransaction.getDust()));
tvTxTotal.setText(Wallet.getDisplayAmount(
committedTx.fee + committedTx.amount));
} }
sendListener.enableDone(); sendListener.enableDone();
} }
void copyAddress() {
Helper.clipBoardCopy(getActivity(), getString(R.string.label_send_txid), tvTxId.getText().toString());
Toast.makeText(getActivity(), getString(R.string.message_copy_address), Toast.LENGTH_SHORT).show();
}
} }

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.m2049r.xmrwallet; package com.m2049r.xmrwallet.fragment.send;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;

Some files were not shown because too many files have changed in this diff Show More