1
mirror of https://github.com/m2049r/xmrwallet synced 2025-09-04 00:53:36 +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.
### 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)
- works on the testnet & mainnet
- sync is slow due to 32-bit architecture
- use your own daemon - it's easy
- 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/
### TODO
- more sensible error dialogs
- see taiga.getmonero.org & issues on github
### Issues / Pitfalls
- The backups folder is now called "backups" and not ".backups" - which in most file explorers was a hidden folder
- 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.
- You should backup your wallet files in the "monerujo" folder periodically.
- 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
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:
- openssl-1.0.2l
- monero-v0.11.0.0 + pull requests #2289
- monero-v0.11.1.0
- boost_1_64_0
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"
minSdkVersion 21
targetSdkVersion 25
versionCode 51
versionName "1.2.11"
versionCode 70
versionName "1.3.10 'Satoshis Dream'"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
@@ -27,6 +27,9 @@ android {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
applicationIdSuffix ".debug"
}
}
externalNativeBuild {
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
Java_com_m2049r_xmrwallet_model_WalletManager_recoveryWalletJ(JNIEnv *env, jobject instance,
jstring path, jstring mnemonic,
jstring path, jstring password,
jstring mnemonic,
jboolean isTestNet,
jlong restoreHeight) {
const char *_path = env->GetStringUTFChars(path, NULL);
const char *_password = env->GetStringUTFChars(password, NULL);
const char *_mnemonic = env->GetStringUTFChars(mnemonic, NULL);
Bitmonero::Wallet *wallet =
Bitmonero::WalletManagerFactory::getWalletManager()->recoveryWallet(
std::string(_path),
std::string(_password),
std::string(_mnemonic),
isTestNet,
restoreHeight);
env->ReleaseStringUTFChars(path, _path);
env->ReleaseStringUTFChars(password, _password);
env->ReleaseStringUTFChars(mnemonic, _mnemonic);
return reinterpret_cast<jlong>(wallet);
}
JNIEXPORT jlong JNICALL
Java_com_m2049r_xmrwallet_model_WalletManager_createWalletFromKeysJ(JNIEnv *env, jobject instance,
jstring path, jstring language,
Java_com_m2049r_xmrwallet_model_WalletManager_createWalletWithKeysJ(JNIEnv *env, jobject instance,
jstring path, jstring password,
jstring language,
jboolean isTestNet,
jlong restoreHeight,
jstring addressString,
jstring viewKeyString,
jstring spendKeyString) {
const char *_path = env->GetStringUTFChars(path, NULL);
const char *_password = env->GetStringUTFChars(password, NULL);
const char *_language = env->GetStringUTFChars(language, NULL);
const char *_addressString = env->GetStringUTFChars(addressString, NULL);
const char *_viewKeyString = env->GetStringUTFChars(viewKeyString, NULL);
const char *_spendKeyString = env->GetStringUTFChars(spendKeyString, NULL);
Bitmonero::Wallet *wallet =
Bitmonero::WalletManagerFactory::getWalletManager()->createWalletFromKeys(
Bitmonero::WalletManagerFactory::getWalletManager()->createWalletWithKeys(
std::string(_path),
std::string(_password),
std::string(_language),
isTestNet,
restoreHeight,
@@ -334,6 +341,7 @@ Java_com_m2049r_xmrwallet_model_WalletManager_createWalletFromKeysJ(JNIEnv *env,
std::string(_spendKeyString));
env->ReleaseStringUTFChars(path, _path);
env->ReleaseStringUTFChars(password, _password);
env->ReleaseStringUTFChars(language, _language);
env->ReleaseStringUTFChars(addressString, _addressString);
env->ReleaseStringUTFChars(viewKeyString, _viewKeyString);

View File

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

View File

@@ -278,7 +278,7 @@ public class LoginActivity extends SecureActivity
// set dialog message
alertDialogBuilder
.setCancelable(false)
.setPositiveButton("OK",
.setPositiveButton(getString(R.string.label_ok),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Helper.hideKeyboardAlways(LoginActivity.this);
@@ -286,7 +286,7 @@ public class LoginActivity extends SecureActivity
new AsyncRename().execute(walletName, newName);
}
})
.setNegativeButton("Cancel",
.setNegativeButton(getString(R.string.label_cancel),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Helper.hideKeyboardAlways(LoginActivity.this);
@@ -482,8 +482,8 @@ public class LoginActivity extends SecureActivity
// set dialog message
alertDialogBuilder
.setCancelable(false)
.setPositiveButton("OK", null)
.setNegativeButton("Cancel",
.setPositiveButton(getString(R.string.label_ok), null)
.setNegativeButton(getString(R.string.label_cancel),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
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
private class AsyncCreateWallet extends AsyncTask<Void, Void, Boolean> {
String walletName;
String walletPassword;
WalletCreator walletCreator;
final String walletName;
final String walletPassword;
final WalletCreator walletCreator;
File newWalletFile;
public AsyncCreateWallet(String name, String password, WalletCreator walletCreator) {
public AsyncCreateWallet(final String name, final String password,
final WalletCreator walletCreator) {
super();
this.walletName = name;
this.walletPassword = password;
@@ -814,12 +815,7 @@ public class LoginActivity extends SecureActivity
return false;
}
File newWalletFolder = Helper.getNewWalletDir(getApplicationContext());
if (!newWalletFolder.isDirectory()) {
Timber.e("New Wallet dir " + newWalletFolder.getAbsolutePath() + "is not a directory");
return false;
}
newWalletFile = new File(newWalletFolder, walletName);
newWalletFile = new File(walletFolder, walletName);
boolean success = walletCreator.createWallet(newWalletFile, walletPassword);
if (success) {
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)
.executeOnExecutor(MoneroThreadPoolExecutor.MONERO_THREAD_POOL_EXECUTOR);
}
@@ -865,7 +862,7 @@ public class LoginActivity extends SecureActivity
}
@Override
public void onGenerate(String name, String password) {
public void onGenerate(final String name, final String password) {
createWallet(name, password,
new WalletCreator() {
public boolean createWallet(File aFile, String password) {
@@ -883,16 +880,15 @@ public class LoginActivity extends SecureActivity
}
@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,
new WalletCreator() {
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);
if (success) {
newWallet.setPassword(password);
success = success && newWallet.store();
} else {
if (!success) {
Timber.e(newWallet.getErrorString());
toast(newWallet.getErrorString());
}
@@ -903,19 +899,17 @@ public class LoginActivity extends SecureActivity
}
@Override
public void onGenerate(String name, String password,
final String address, final String viewKey, final String spendKey, final long restoreHeight) {
public void onGenerate(final String name, final String password,
final String address, final String viewKey, final String spendKey,
final long restoreHeight) {
createWallet(name, password,
new WalletCreator() {
public boolean createWallet(File aFile, String password) {
Wallet newWallet = WalletManager.getInstance()
.createWalletFromKeys(aFile, MNEMONIC_LANGUAGE, restoreHeight,
.createWalletWithKeys(aFile, password, MNEMONIC_LANGUAGE, restoreHeight,
address, viewKey, spendKey);
boolean success = (newWallet.getStatus() == Wallet.Status.Status_Ok);
if (success) {
newWallet.setPassword(password);
success = success && newWallet.store();
} else {
if (!success) {
Timber.e(newWallet.getErrorString());
toast(newWallet.getErrorString());
}
@@ -936,16 +930,10 @@ public class LoginActivity extends SecureActivity
@Override
public void onAccept(final String name, final String password) {
File newWalletFile = new File(Helper.getNewWalletDir(getApplicationContext()), name);
Timber.d("New Wallet %s", newWalletFile.getAbsolutePath());
newWalletFile.delete(); // when recovering wallets, the cache seems corrupt
// TODO: figure out why this is so? Only for a private testnet?
// 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)
File walletFolder = getStorageRoot();
File walletFile = new File(walletFolder, name);
Timber.d("New Wallet %s", walletFile.getAbsolutePath());
walletFile.delete(); // when recovering wallets, the cache seems corrupt
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.Toast;
import com.m2049r.xmrwallet.dialog.HelpFragment;
import com.m2049r.xmrwallet.layout.WalletInfoAdapter;
import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.util.Helper;
@@ -61,15 +62,18 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
private WalletInfoAdapter adapter;
List<WalletManager.WalletInfo> walletList = new ArrayList<>();
List<WalletManager.WalletInfo> displayedList = new ArrayList<>();
private List<WalletManager.WalletInfo> walletList = new ArrayList<>();
private List<WalletManager.WalletInfo> displayedList = new ArrayList<>();
EditText etDummy;
ImageView ivGunther;
DropDownEditText etDaemonAddress;
ArrayAdapter<String> nodeAdapter;
private EditText etDummy;
private ImageView ivGunther;
private DropDownEditText etDaemonAddress;
private ArrayAdapter<String> nodeAdapter;
Listener activityCallback;
private View llXmrToEnabled;
private View ibXmrToInfoClose;
private Listener activityCallback;
// Container Activity must implement this interface
public interface Listener {
@@ -165,6 +169,25 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
recyclerView.setAdapter(adapter);
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);
nodeAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_dropdown_item_1line);
etDaemonAddress.setAdapter(nodeAdapter);
@@ -211,6 +234,9 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
});
loadPrefs();
if (!showXmrtoEnabled) {
llXmrToEnabled.setVisibility(View.GONE);
}
return view;
}
@@ -290,9 +316,8 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
activityCallback.onWalletDetails(name, isTestnet());
}
private boolean showReceive(@NonNull String name) {
private void showReceive(@NonNull String name) {
activityCallback.onWalletReceive(name, isTestnet());
return true;
}
@Override
@@ -308,7 +333,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
super.onCreateOptionsMenu(menu, inflater);
}
boolean testnet = false;
private boolean testnet = BuildConfig.DEBUG;
boolean isTestnet() {
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_MAINNET = "daemon_mainnet";
private static final String PREF_SHOW_XMRTO_ENABLED = "info_xmrto_enabled_login";
private static final String PREF_DAEMONLIST_MAINNET =
"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 daemonMainNet;
boolean showXmrtoEnabled = true;
void loadPrefs() {
SharedPreferences sharedPref = activityCallback.getPrefs();
daemonMainNet = new NodeList(sharedPref.getString(PREF_DAEMON_MAINNET, PREF_DAEMONLIST_MAINNET));
daemonTestNet = new NodeList(sharedPref.getString(PREF_DAEMON_TESTNET, PREF_DAEMONLIST_TESTNET));
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() {
savePrefs(false);
}
void savePrefs(boolean usePreviousState) {
Timber.d("SAVE / %s", usePreviousState);
void savePrefs(boolean usePreviousTestnetState) {
Timber.d("SAVE / %s", usePreviousTestnetState);
// save the daemon address for the net
boolean testnet = isTestnet() ^ usePreviousState;
boolean testnet = isTestnet() ^ usePreviousTestnetState;
String daemon = getDaemon();
if (testnet) {
daemonTestNet.setRecent(daemon);
@@ -373,6 +410,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString(PREF_DAEMON_MAINNET, daemonMainNet.toString());
editor.putString(PREF_DAEMON_TESTNET, daemonTestNet.toString());
editor.putBoolean(PREF_SHOW_XMRTO_ENABLED, showXmrtoEnabled);
editor.apply();
}

View File

@@ -46,6 +46,7 @@ import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.m2049r.xmrwallet.data.BarcodeData;
import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.util.Helper;
@@ -105,6 +106,7 @@ public class ReceiveFragment extends Fragment {
copyAddress();
}
});
bCopyAddress.setClickable(false);
evAmount.setOnNewAmountListener(new ExchangeView.OnNewAmountListener() {
@Override
@@ -239,7 +241,7 @@ public class ReceiveFragment extends Fragment {
tvAddress.setText(address);
etPaymentId.setEnabled(true);
bPaymentId.setEnabled(true);
bCopyAddress.setEnabled(true);
bCopyAddress.setClickable(true);
bCopyAddress.setImageResource(R.drawable.ic_content_copy_black_24dp);
hideProgress();
generateQr();
@@ -304,14 +306,14 @@ public class ReceiveFragment extends Fragment {
return;
}
StringBuffer sb = new StringBuffer();
sb.append(ScannerFragment.QR_SCHEME).append(address);
sb.append(BarcodeData.XMR_SCHEME).append(address);
boolean first = true;
if (!paymentId.isEmpty()) {
if (first) {
sb.append("?");
first = false;
}
sb.append(ScannerFragment.QR_PAYMENTID).append('=').append(paymentId);
sb.append(BarcodeData.XMR_PAYMENTID).append('=').append(paymentId);
}
if (!xmrAmount.isEmpty()) {
if (first) {
@@ -319,7 +321,7 @@ public class ReceiveFragment extends Fragment {
} else {
sb.append("&");
}
sb.append(ScannerFragment.QR_AMOUNT).append('=').append(xmrAmount);
sb.append(BarcodeData.XMR_AMOUNT).append('=').append(xmrAmount);
}
String text = sb.toString();
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;
public interface OnScannedListener {
boolean onScanned(String uri);
boolean onScanned(String qrCode);
}
private ZXingScannerView mScannerView;
@@ -56,10 +56,6 @@ public class ScannerFragment extends Fragment implements ZXingScannerView.Result
mScannerView.startCamera();
}
static final String QR_SCHEME = "monero:";
static final String QR_PAYMENTID = "tx_payment_id";
static final String QR_AMOUNT = "tx_amount";
@Override
public void handleResult(Result rawResult) {
if ((rawResult.getBarcodeFormat() == BarcodeFormat.QR_CODE)) {

View File

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

View File

@@ -30,10 +30,13 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.m2049r.xmrwallet.model.TransactionInfo;
import com.m2049r.xmrwallet.model.Transfer;
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 java.text.SimpleDateFormat;
@@ -68,12 +71,23 @@ public class TxFragment extends Fragment {
private TextView etTxNotes;
private Button bTxNotes;
// XMRTO stuff
private View cvXmrTo;
private TextView tvTxXmrToKey;
private TextView tvDestinationBtc;
private TextView tvTxAmountBtc;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
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);
tvTxId = (TextView) view.findViewById(R.id.tvTxId);
tvTxKey = (TextView) view.findViewById(R.id.tvTxKey);
@@ -94,7 +108,16 @@ public class TxFragment extends Fragment {
info.notes = null; // force reload on next view
bTxNotes.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;
UserNotes userNotes = null;
void loadNotes(TransactionInfo info) {
if (info.notes == null) {
if ((userNotes == null) || (info.notes == null)) {
info.notes = activityCallback.getTxNotes(info.hash);
}
etTxNotes.setText(info.notes);
userNotes = new UserNotes(info.notes);
etTxNotes.setText(userNotes.note);
}
private void setTxColour(int clr) {
@@ -266,8 +291,21 @@ public class TxFragment extends Fragment {
tvTxTransfers.setText(sb.toString());
tvDestination.setText(dstSb.toString());
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
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

View File

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

View File

@@ -19,6 +19,8 @@ package com.m2049r.xmrwallet.data;
import android.net.Uri;
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.Map;
@@ -34,7 +36,7 @@ public class BarcodeData {
static final String BTC_AMOUNT = "amount";
public enum Asset {
XMR
XMR, BTC
}
public Asset asset = null;
@@ -67,6 +69,14 @@ public class BarcodeData {
if (bcData == null) {
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;
}
@@ -134,4 +144,57 @@ public class BarcodeData {
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 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
public class TxData implements Parcelable {
public TxData() {
}
public TxData(TxData txData) {
this.dst_addr = txData.dst_addr;
this.dstAddr = txData.dstAddr;
this.paymentId = txData.paymentId;
this.amount = txData.amount;
this.mixin = txData.mixin;
this.priority = txData.priority;
}
public TxData(String dst_addr,
public TxData(String dstAddr,
String paymentId,
long amount,
int mixin,
PendingTransaction.Priority priority) {
this.dst_addr = dst_addr;
this.dstAddr = dstAddr;
this.paymentId = paymentId;
this.amount = amount;
this.mixin = mixin;
this.priority = priority;
}
public long getFee() {
return 0L;
}
public String getDestinationAddress() {
return dst_addr;
return dstAddr;
}
public String getPaymentId() {
@@ -68,15 +70,45 @@ public class TxData implements Parcelable {
return priority;
}
final private String dst_addr;
final private String paymentId;
final private long amount;
final private int mixin;
final private PendingTransaction.Priority priority;
public void setDestinationAddress(String dstAddr) {
this.dstAddr = dstAddr;
}
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
public void writeToParcel(Parcel out, int flags) {
out.writeString(dst_addr);
out.writeString(dstAddr);
out.writeString(paymentId);
out.writeLong(amount);
out.writeInt(mixin);
@@ -94,8 +126,8 @@ public class TxData implements Parcelable {
}
};
private TxData(Parcel in) {
dst_addr = in.readString();
protected TxData(Parcel in) {
dstAddr = in.readString();
paymentId = in.readString();
amount = in.readLong();
mixin = in.readInt();
@@ -111,8 +143,8 @@ public class TxData implements Parcelable {
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("dst_addr:");
sb.append(dst_addr);
sb.append("dstAddr:");
sb.append(dstAddr);
sb.append(",paymentId:");
sb.append(paymentId);
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.
*/
package com.m2049r.xmrwallet;
package com.m2049r.xmrwallet.fragment.send;
import android.content.Context;
import android.os.Bundle;
import android.support.design.widget.TextInputLayout;
import android.support.v7.widget.CardView;
import android.text.Editable;
import android.text.Html;
import android.text.InputType;
import android.text.TextWatcher;
import android.view.KeyEvent;
@@ -32,9 +33,13 @@ import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import com.m2049r.xmrwallet.R;
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.WalletManager;
import com.m2049r.xmrwallet.util.BitcoinAddressValidator;
import com.m2049r.xmrwallet.util.Helper;
import timber.log.Timber;
@@ -56,12 +61,12 @@ public class SendAddressWizardFragment extends SendWizardFragment {
return this;
}
interface Listener {
void setAddress(final String address);
void setPaymentId(final String paymentId);
public interface Listener {
void setBarcodeData(BarcodeData data);
void setMode(SendFragment.Mode mode);
TxData getTxData();
}
private EditText etDummy;
@@ -71,6 +76,8 @@ public class SendAddressWizardFragment extends SendWizardFragment {
private CardView cvScan;
private View tvPaymentIdIntegrated;
private View llPaymentId;
private TextView tvXmrTo;
private View llXmrTo;
OnScanListener onScanListener;
@@ -89,6 +96,9 @@ public class SendAddressWizardFragment extends SendWizardFragment {
tvPaymentIdIntegrated = view.findViewById(R.id.tvPaymentIdIntegrated);
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.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
@@ -113,12 +123,25 @@ public class SendAddressWizardFragment extends SendWizardFragment {
public void afterTextChanged(Editable editable) {
etAddress.setError(null);
if (isIntegratedAddress()) {
Timber.d("isIntegratedAddress");
etPaymentId.getEditText().getText().clear();
llPaymentId.setVisibility(View.GONE);
llPaymentId.setVisibility(View.INVISIBLE);
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);
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() {
String address = etAddress.getEditText().getText().toString();
return Wallet.isAddressValid(address);
return Wallet.isAddressValid(address)
|| BitcoinAddressValidator.validate(address, WalletManager.getInstance().isTestNet());
}
private boolean checkAddress() {
boolean ok = checkAddressNoError();
if (!ok) {
etAddress.setError(getString(R.string.send_qr_address_invalid));
etAddress.setError(getString(R.string.send_address_invalid));
} else {
etAddress.setError(null);
}
@@ -203,7 +227,16 @@ public class SendAddressWizardFragment extends SendWizardFragment {
private boolean isIntegratedAddress() {
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() {
@@ -235,8 +268,15 @@ public class SendAddressWizardFragment extends SendWizardFragment {
}
if (!ok) return false;
if (sendListener != null) {
sendListener.setAddress(etAddress.getEditText().getText().toString());
sendListener.setPaymentId(etPaymentId.getEditText().getText().toString());
TxData txData = sendListener.getTxData();
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;
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.m2049r.xmrwallet;
package com.m2049r.xmrwallet.fragment.send;
import android.os.Bundle;
import android.view.LayoutInflater;
@@ -22,10 +22,12 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.m2049r.xmrwallet.R;
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.util.Helper;
import com.m2049r.xmrwallet.widget.ExchangeTextView;
import com.m2049r.xmrwallet.widget.NumberPadView;
import timber.log.Timber;
@@ -48,7 +50,7 @@ public class SendAmountWizardFragment extends SendWizardFragment {
interface Listener {
SendFragment.Listener getActivityCallback();
void setAmount(final long amount);
TxData getTxData();
BarcodeData popBarcodeData();
}
@@ -99,9 +101,9 @@ public class SendAmountWizardFragment extends SendWizardFragment {
if (sendListener != null) {
String xmr = evAmount.getAmount();
if (xmr != null) {
sendListener.setAmount(Wallet.getAmountFromString(xmr));
sendListener.getTxData().setAmount(Wallet.getAmountFromString(xmr));
} else {
sendListener.setAmount(0L);
sendListener.getTxData().setAmount(0L);
}
}
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.
*/
package com.m2049r.xmrwallet;
package com.m2049r.xmrwallet.fragment.send;
import android.app.Activity;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AlertDialog;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.KeyEvent;
@@ -30,14 +31,16 @@ import android.view.inputmethod.EditorInfo;
import android.widget.Button;
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.Wallet;
import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.UserNotes;
import timber.log.Timber;
public class SendConfirmWizardFragment extends SendWizardFragment {
public class SendConfirmWizardFragment extends SendWizardFragment implements SendConfirm {
public static SendConfirmWizardFragment newInstance(Listener listener) {
SendConfirmWizardFragment instance = new SendConfirmWizardFragment();
@@ -57,11 +60,11 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
TxData getTxData();
String getNotes();
void commitTransaction();
void disposeTransaction();
SendFragment.Mode getMode();
}
private TextView tvTxAddress;
@@ -122,8 +125,11 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
PendingTransaction pendingTransaction = null;
@Override
// 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();
if (isResumed) {
this.pendingTransaction = pendingTransaction;
@@ -138,10 +144,22 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
pbProgressSend.setVisibility(View.VISIBLE);
}
void sendFailed() {
@Override
public void sendFailed() {
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
public boolean onValidateFields() {
return true;
@@ -173,9 +191,9 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
} else {
tvTxPaymentId.setText("-");
}
String notes = sendListener.getNotes();
if ((notes != null) && (!notes.isEmpty())) {
tvTxNotes.setText(sendListener.getNotes());
UserNotes notes = sendListener.getTxData().getUserNotes();
if ((notes != null) && (!notes.note.isEmpty())) {
tvTxNotes.setText(notes.note);
} else {
tvTxNotes.setText("-");
}
@@ -232,7 +250,7 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
alertDialogBuilder
.setCancelable(false)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
.setPositiveButton(getString(R.string.label_ok), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
String pass = etPassword.getEditText().getText().toString();
if (getActivityCallback().verifyWalletPassword(pass)) {
@@ -244,7 +262,7 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
}
}
})
.setNegativeButton("Cancel",
.setNegativeButton(getString(R.string.label_cancel),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Helper.hideKeyboardAlways(activity);
@@ -296,8 +314,10 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
passwordDialog.show();
}
// creates a pending transaction and calls us back with transactionCreated()
// or createTransactionFailed()
void prepareSend(TxData txData) {
getActivityCallback().onPrepareSend(txData);
getActivityCallback().onPrepareSend(null, txData);
}
SendFragment.Listener getActivityCallback() {

View File

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

View File

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

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