1
mirror of https://github.com/m2049r/xmrwallet synced 2025-09-07 11:35:59 +02:00

Compare commits

..

55 Commits

Author SHA1 Message Date
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
m2049r
bafe05117b Update FAQ.md 2017-12-11 16:15:35 +01:00
m2049r
4b7c181040 drawable fix for < v24 2017-12-11 16:00:45 +01:00
m2049r
a3721ae784 new version number 2017-12-09 20:43:23 +01:00
m2049r
ae62c528aa Tweaks & Fixes (#153)
* clear error

* isAddressValid refactoring

* better numpad layout

* receive qr code as card

* scan integrated address
2017-12-09 20:38:01 +01:00
m2049r
e6522769d0 rename version 2017-12-07 20:39:50 +01:00
m2049r
cab93e8c5e store on exit wallet if not synced (#152) 2017-12-07 20:04:04 +01:00
m2049r
ac78ecb298 Create new wallets in app-private storage (#151)
* new version

* create new wallet in app-private storage
2017-12-07 19:55:01 +01:00
m2049r
51876f788f Bugfixes & UI tweaks (#149)
* cancel button + avoid crash if exchanging

* max check fix
2017-12-05 21:26:38 +01:00
m2049r
82c32d4442 support integrated address (excl. qr code) (#147)
UI & code tweaks
2017-12-05 07:48:59 +01:00
m2049r
22b4905828 new alpha version 2017-12-03 22:19:57 +01:00
m2049r
0cb8ece336 Rework of Send flow + refactoring (#146) 2017-12-03 22:17:28 +01:00
Stephan Hagios
d2429da044 Feature/timber logging (#143)
* Added Timber for logging

* Replaced Log calls with timber

* added timber to licenses list

* PR suggestions
2017-11-25 15:49:07 +01:00
Stephan Hagios
92d867fbaa Added okhttp to the license string (#142) 2017-11-23 22:05:44 +01:00
Stephan Hagios
a5e3986eb9 Merge pull request #141 from m2049r/refactor_okhttp
Use OkHttp to get exchange rates
2017-11-23 20:25:45 +01:00
m2049r
8f7f4ee9f9 changes based on review 2017-11-23 08:23:23 +01:00
m2049r
c23597066a use OkHttpClient to get exchange rates
test cases
2017-11-22 18:34:28 +01:00
m2049r
dab5e08910 use textVisiblePassword for password field (#139) 2017-11-19 20:25:20 +01:00
m2049r
c35deab283 zoom into qr code on touch (#140) 2017-11-19 20:25:02 +01:00
Stephan Hagios
7c36ccfd9c Merge pull request #137 from m2049r/layout-tweaks
Layout tweaks
2017-11-18 16:02:47 +01:00
Stephan Hagios
402d51ec6e Merge pull request #138 from m2049r/screenshot-tweak
Don't prevent screenshots in debug mode
2017-11-18 15:55:37 +01:00
m2049r
ca58211676 dont prevent screenshots in debug mode 2017-11-18 13:11:54 +01:00
m2049r
97c6ba5334 full width amount fields 2017-11-18 13:10:34 +01:00
m2049r
f1f2f250be qr code is now a button 2017-11-18 11:04:34 +01:00
m2049r
7b19e9a2bd wider amount field with % left/right padding 2017-11-18 10:19:16 +01:00
mattcode55
ed8010c92c Set FLAG_SECURE to disable screenshots (#134)
mattermost: https://taiga.getmonero.org/project/m2049r-monerujo/us/38

Sets FLAG_SECURE on all activities to prevent users accidentally
screenshotting sensitive information.
2017-11-16 19:14:53 +01:00
m2049r
41580e5519 upgrade m2049r/monero to monerujo-v0.11.1.0 (#127) 2017-11-11 15:39:42 +01:00
m2049r
1875e2df62 Bugfixes (#126)
* new domain

* InetSocketAddress.IllegalArgumentException

* white text for buttons

* tweak credit dialog

* prevent multiple popups
2017-11-11 08:02:13 +01:00
m2049r
347123d961 UI bugfixes (#120)
* better wallet load progress

new version

* dont start LoginFragment if is already started
2017-11-08 23:04:01 +01:00
m2049r
f5ad07c2b0 some bugfixes (#119)
* avoid IllegalStateException in rare cases

* clear error state on edit

* new version

* ignore error if fragment unloaded
2017-11-07 23:22:09 +01:00
m2049r
62695af9c6 layout correction + new version code 2017-11-05 01:01:36 +01:00
Stephan Hagios
3b1c3d564b Adjusted Layout files (#118)
* Adjusted layout files with correct sizes.

* Added password visibility toggle
2017-11-05 00:25:26 +01:00
Jonathan Cross
b28a140b48 FAQ improvements (#116) 2017-11-04 23:55:26 +01:00
m2049r
75bba4a091 remove e-notaion for android 5.0! (#117)
and new version
2017-11-04 23:54:49 +01:00
m2049r
cfb3c23003 hide receive button before wallet is loaded (#115) 2017-11-04 15:31:34 +01:00
m2049r
2cb87bab8e nodes help 2017-11-04 14:07:54 +01:00
m2049r
1ddc3d6b58 normal font for receiver 2017-11-04 13:45:21 +01:00
m2049r
2fa48d7441 more help & restyle reallysend button (#114) 2017-11-04 13:23:56 +01:00
m2049r
545367db90 Changes from Alpha Feedback (#113)
* fab covers whole screen

* avoid potential NPE

* bugfix - spinners crashed after scan

* Gunther only if no wallets

* clearQR on failed exchange, tweaks, gray

* refactor info dialogs

* added default testnet node

* FAQ: my testnet wallet is broken

* version code 36, version name 1.1.7
2017-11-04 10:17:20 +01:00
m2049r
d67e02cbcb Mostly Help "System" (#112)
* help & new exchange icon

* layout tweaks + removed nocopy icons

* sync help

* hide keyboard on spend

* QR Recieve => Receive

* menu tweaking

* use png logo for android < nougat

* gray generate

* position tweak in toolbar

* new exchange icon for wallet balance

* new About Dialog

* enable sending on mainnet

* new version 1.1.6

* dispose transaction on back

* remove unused onExchange method

* gray stuff + some tweaks

* new logo for qr
2017-11-04 00:43:24 +01:00
m2049r
d3beb7ca3f exchange & toolbar layout (#111) 2017-11-03 10:14:19 +01:00
m2049r
f951e1a621 abort exchange if amount is invalid 2017-11-03 01:20:59 +01:00
203 changed files with 12141 additions and 3165 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 31 versionCode 65
versionName "1.1.3-alpha" versionName "1.3.5 'Satoshis Dream'"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild { externalNativeBuild {
cmake { cmake {
@@ -43,28 +43,39 @@ dependencies {
compile 'com.android.support:cardview-v7:25.4.0' compile 'com.android.support:cardview-v7:25.4.0'
compile 'com.android.support.constraint:constraint-layout:1.0.2' compile 'com.android.support.constraint:constraint-layout:1.0.2'
compile 'me.dm7.barcodescanner:zxing:1.9.8' compile 'me.dm7.barcodescanner:zxing:1.9.8'
compile "com.squareup.okhttp3:okhttp:$rootProject.ext.okHttpVersion"
compile "com.jakewharton.timber:timber:$rootProject.ext.timberVersion"
testCompile "junit:junit:$rootProject.ext.junitVersion"
testCompile "org.mockito:mockito-all:$rootProject.ext.mockitoVersion"
testCompile "com.squareup.okhttp3:mockwebserver:$rootProject.ext.okHttpVersion"
testCompile 'org.json:json:20140107'
testCompile 'net.jodah:concurrentunit:0.4.2'
} }
dependencyVerification { dependencyVerification {
verify = [ verify = [
'com.android.support:appcompat-v7:70551e62660db15b790c5275f56b9de4dd9407d1494d07c8f3dd5698f3638677',
'com.android.support:design:3f409bf2019967ffc344cfaf11e52131fac982468a1707aaeb25bf3c52838966', 'com.android.support:design:3f409bf2019967ffc344cfaf11e52131fac982468a1707aaeb25bf3c52838966',
'com.android.support:appcompat-v7:70551e62660db15b790c5275f56b9de4dd9407d1494d07c8f3dd5698f3638677',
'com.android.support:transition:848270144fb180efd2bf928a00ed176dbbc5290badfd638390ffba90088df8b3',
'me.dm7.barcodescanner:zxing:d43973c9527c23fa8e6d338c6a2c458e373ce1ac6bcaa3bc41d11ae49116000d',
'me.dm7.barcodescanner:core:a5c8a704089b58029db166172ed8e55d756877d010a85a0b1c94fdc96ffb8f9a',
'com.android.support:support-v4:ee44c481a1f4d6978568e223e8125379b52b2ececdd53450e09ebae144bd377d', 'com.android.support:support-v4:ee44c481a1f4d6978568e223e8125379b52b2ececdd53450e09ebae144bd377d',
'com.android.support:recyclerview-v7:a2fe121f9d01ed8980e97095b4a3fe9700a0aa0a7d4b0f8c594f765ad8455a0d', 'com.android.support:recyclerview-v7:a2fe121f9d01ed8980e97095b4a3fe9700a0aa0a7d4b0f8c594f765ad8455a0d',
'com.android.support:cardview-v7:f3fbbe1fcfdbec7333c6a2c516c5fd511a909d1975271818e268d6fe297d8c70', 'com.android.support:cardview-v7:f3fbbe1fcfdbec7333c6a2c516c5fd511a909d1975271818e268d6fe297d8c70',
'com.android.support.constraint:constraint-layout:b0c688cc2b7172608f8153a689d746da40f71e52d7e2fe2bfd9df2f92db77085', 'com.android.support.constraint:constraint-layout:b0c688cc2b7172608f8153a689d746da40f71e52d7e2fe2bfd9df2f92db77085',
'me.dm7.barcodescanner:zxing:d43973c9527c23fa8e6d338c6a2c458e373ce1ac6bcaa3bc41d11ae49116000d',
'com.android.support:support-annotations:a774272036941b4e912eb426d70c848bde7f06a3bf5fb491f75a427dc6595270',
'com.android.support:support-vector-drawable:077009d13882ee96f061e4bc2dbe7cce7ae1762d8297592a787ff741afbfb1f2',
'com.android.support:animated-vector-drawable:628ab1d56a6ee4cbedf32617af8b2a1fe02964ed0628e8f898cc09ddba6e1835', 'com.android.support:animated-vector-drawable:628ab1d56a6ee4cbedf32617af8b2a1fe02964ed0628e8f898cc09ddba6e1835',
'com.android.support:transition:848270144fb180efd2bf928a00ed176dbbc5290badfd638390ffba90088df8b3', 'com.android.support:support-vector-drawable:077009d13882ee96f061e4bc2dbe7cce7ae1762d8297592a787ff741afbfb1f2',
'com.android.support:support-compat:54019c63614ce08b02d7b9605490cd2b29ba5b2505f394a9517450b5f72b30ca', 'com.android.support:support-fragment:316d35d4d2d2902057efad104a73e4bdb50bee260a7075678185b8cd71170945',
'com.android.support:support-core-ui:e72ae29b823889686cff6fcb948d6745c2baf6d4c2af4fdffa1ec1e42e3833a3',
'com.android.support:support-media-compat:566a161d9cb0083ef62a53e46b71ce5b3d455b8635b1a0a4ae28d96d4b583de8', 'com.android.support:support-media-compat:566a161d9cb0083ef62a53e46b71ce5b3d455b8635b1a0a4ae28d96d4b583de8',
'com.android.support:support-core-utils:34b8437dfa95ff28d29cf57ffa3b1354a9fa9bfe4059f0fd5ce2f5e4326a1748', 'com.android.support:support-core-utils:34b8437dfa95ff28d29cf57ffa3b1354a9fa9bfe4059f0fd5ce2f5e4326a1748',
'com.android.support:support-core-ui:e72ae29b823889686cff6fcb948d6745c2baf6d4c2af4fdffa1ec1e42e3833a3', 'com.android.support:support-compat:54019c63614ce08b02d7b9605490cd2b29ba5b2505f394a9517450b5f72b30ca',
'com.android.support:support-fragment:316d35d4d2d2902057efad104a73e4bdb50bee260a7075678185b8cd71170945', 'com.android.support:support-annotations:a774272036941b4e912eb426d70c848bde7f06a3bf5fb491f75a427dc6595270',
'com.android.support.constraint:constraint-layout-solver:8c62525a9bc5cff5633a96cb9b32fffeccaf41b8841aa87fc22607070dea9b8d', 'com.android.support.constraint:constraint-layout-solver:8c62525a9bc5cff5633a96cb9b32fffeccaf41b8841aa87fc22607070dea9b8d',
'me.dm7.barcodescanner:core:a5c8a704089b58029db166172ed8e55d756877d010a85a0b1c94fdc96ffb8f9a',
'com.google.zxing:core:bba7724e02a997cec38213af77133ee8e24b0d5cf5fa7ecbc16a4fa93f11ee0d', 'com.google.zxing:core:bba7724e02a997cec38213af77133ee8e24b0d5cf5fa7ecbc16a4fa93f11ee0d',
'com.squareup.okio:okio:734269c3ebc5090e3b23566db558f421f0b4027277c79ad5d176b8ec168bb850',
'com.squareup.okhttp3:okhttp:7265adbd6f028aade307f58569d814835cd02bc9beffb70c25f72c9de50d61c4',
] ]
} }

View File

@@ -13,6 +13,7 @@
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:supportsRtl="true" android:supportsRtl="true"
android:name=".XmrWalletApplication"
android:theme="@style/MyMaterialTheme"> android:theme="@style/MyMaterialTheme">
<activity <activity

View File

@@ -22,7 +22,6 @@ import android.support.annotation.Nullable;
import android.support.design.widget.TextInputLayout; import android.support.design.widget.TextInputLayout;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.text.InputType; import android.text.InputType;
import android.util.Log;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
@@ -33,15 +32,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.layout.Toolbar; import com.m2049r.xmrwallet.widget.Toolbar;
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;
import java.io.File; import java.io.File;
import timber.log.Timber;
public class GenerateFragment extends Fragment { public class GenerateFragment extends Fragment {
static final String TAG = "GenerateFragment";
static final String TYPE = "type"; static final String TYPE = "type";
static final String TYPE_NEW = "new"; static final String TYPE_NEW = "new";
@@ -366,7 +366,7 @@ public class GenerateFragment extends Fragment {
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
Log.d(TAG, "onResume()"); Timber.d("onResume()");
activityCallback.setTitle(getString(R.string.generate_title) + " - " + getType()); activityCallback.setTitle(getString(R.string.generate_title) + " - " + getType());
activityCallback.setToolbarButton(Toolbar.BUTTON_BACK); activityCallback.setToolbarButton(Toolbar.BUTTON_BACK);
@@ -383,7 +383,7 @@ public class GenerateFragment extends Fragment {
case TYPE_VIEWONLY: case TYPE_VIEWONLY:
return getString(R.string.generate_wallet_type_view); return getString(R.string.generate_wallet_type_view);
default: default:
Log.e(TAG, "unknown type " + type); Timber.e("unknown type %s", type);
return "?"; return "?";
} }
} }
@@ -422,7 +422,21 @@ public class GenerateFragment extends Fragment {
@Override @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.create_wallet_menu, menu); switch (type) {
case TYPE_KEY:
inflater.inflate(R.menu.create_wallet_keys, menu);
break;
case TYPE_NEW:
inflater.inflate(R.menu.create_wallet_new, menu);
break;
case TYPE_SEED:
inflater.inflate(R.menu.create_wallet_seed, menu);
break;
case TYPE_VIEWONLY:
inflater.inflate(R.menu.create_wallet_view, menu);
break;
default:
}
super.onCreateOptionsMenu(menu, inflater); super.onCreateOptionsMenu(menu, inflater);
} }
} }

View File

@@ -21,7 +21,6 @@ import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
@@ -35,14 +34,15 @@ import android.widget.ScrollView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.m2049r.xmrwallet.layout.Toolbar; import com.m2049r.xmrwallet.widget.Toolbar;
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;
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor; import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
import timber.log.Timber;
public class GenerateReviewFragment extends Fragment { public class GenerateReviewFragment extends Fragment {
static final String TAG = "GenerateReviewFragment";
static final public String VIEW_TYPE_DETAILS = "details"; static final public String VIEW_TYPE_DETAILS = "details";
static final public String VIEW_TYPE_ACCEPT = "accept"; static final public String VIEW_TYPE_ACCEPT = "accept";
static final public String VIEW_TYPE_WALLET = "wallet"; static final public String VIEW_TYPE_WALLET = "wallet";
@@ -103,18 +103,7 @@ public class GenerateReviewFragment extends Fragment {
copyAddress(); copyAddress();
} }
}); });
view.findViewById(R.id.bCopySeed).setOnClickListener(new View.OnClickListener() { bCopyAddress.setClickable(false);
@Override
public void onClick(View v) {
nocopy();
}
});
view.findViewById(R.id.bCopySepndKey).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
nocopy();
}
});
view.findViewById(R.id.bAdvancedInfo).setOnClickListener(new View.OnClickListener() { view.findViewById(R.id.bAdvancedInfo).setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
@@ -225,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(
@@ -276,7 +265,7 @@ public class GenerateReviewFragment extends Fragment {
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
Log.d(TAG, "onResume()"); Timber.d("onResume()");
String name = tvWalletName.getText().toString(); String name = tvWalletName.getText().toString();
if (name.isEmpty()) name = null; if (name.isEmpty()) name = null;
activityCallback.setTitle(name, getString(R.string.details_title)); activityCallback.setTitle(name, getString(R.string.details_title));
@@ -305,5 +294,6 @@ public class GenerateReviewFragment extends Fragment {
@Override @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.wallet_details_menu, menu); inflater.inflate(R.menu.wallet_details_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -24,7 +24,6 @@ import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton; import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
@@ -44,20 +43,21 @@ import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.m2049r.xmrwallet.layout.DropDownEditText;
import com.m2049r.xmrwallet.layout.Toolbar;
import com.m2049r.xmrwallet.layout.WalletInfoAdapter; import com.m2049r.xmrwallet.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;
import com.m2049r.xmrwallet.util.NodeList; import com.m2049r.xmrwallet.util.NodeList;
import com.m2049r.xmrwallet.widget.DropDownEditText;
import com.m2049r.xmrwallet.widget.Toolbar;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import timber.log.Timber;
public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInteractionListener, public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInteractionListener,
View.OnClickListener { View.OnClickListener {
private static final String TAG = "LoginFragment";
private WalletInfoAdapter adapter; private WalletInfoAdapter adapter;
@@ -65,6 +65,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
List<WalletManager.WalletInfo> displayedList = new ArrayList<>(); List<WalletManager.WalletInfo> displayedList = new ArrayList<>();
EditText etDummy; EditText etDummy;
ImageView ivGunther;
DropDownEditText etDaemonAddress; DropDownEditText etDaemonAddress;
ArrayAdapter<String> nodeAdapter; ArrayAdapter<String> nodeAdapter;
@@ -111,7 +112,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
@Override @Override
public void onPause() { public void onPause() {
Log.d(TAG, "onPause()"); Timber.d("onPause()");
savePrefs(); savePrefs();
super.onPause(); super.onPause();
} }
@@ -119,7 +120,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
Log.d(TAG, "onResume()"); Timber.d("onResume()");
activityCallback.setTitle(null); activityCallback.setTitle(null);
activityCallback.setToolbarButton(Toolbar.BUTTON_DONATE); activityCallback.setToolbarButton(Toolbar.BUTTON_DONATE);
activityCallback.showNet(isTestnet()); activityCallback.showNet(isTestnet());
@@ -128,9 +129,10 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
Log.d(TAG, "onCreateView"); Timber.d("onCreateView");
View view = inflater.inflate(R.layout.fragment_login, container, false); View view = inflater.inflate(R.layout.fragment_login, container, false);
ivGunther = (ImageView) view.findViewById(R.id.ivGunther);
fabScreen = (FrameLayout) view.findViewById(R.id.fabScreen); fabScreen = (FrameLayout) view.findViewById(R.id.fabScreen);
fab = (FloatingActionButton) view.findViewById(R.id.fab); fab = (FloatingActionButton) view.findViewById(R.id.fab);
fabNew = (FloatingActionButton) view.findViewById(R.id.fabNew); fabNew = (FloatingActionButton) view.findViewById(R.id.fabNew);
@@ -260,7 +262,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
} }
public void loadList() { public void loadList() {
Log.d(TAG, "loadList()"); Timber.d("loadList()");
WalletManager mgr = WalletManager.getInstance(); WalletManager mgr = WalletManager.getInstance();
List<WalletManager.WalletInfo> walletInfos = List<WalletManager.WalletInfo> walletInfos =
mgr.findWallets(activityCallback.getStorageRoot()); mgr.findWallets(activityCallback.getStorageRoot());
@@ -269,10 +271,18 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
filterList(); filterList();
adapter.setInfos(displayedList); adapter.setInfos(displayedList);
adapter.notifyDataSetChanged(); adapter.notifyDataSetChanged();
// deal with Gunther & FAB animation
if (displayedList.isEmpty()) { if (displayedList.isEmpty()) {
fab.startAnimation(fab_pulse); fab.startAnimation(fab_pulse);
if (ivGunther.getDrawable() == null) {
ivGunther.setImageResource(R.drawable.gunther_desaturated);
}
} else { } else {
fab.clearAnimation(); fab.clearAnimation();
if (ivGunther.getDrawable() != null) {
ivGunther.setImageDrawable(null);
}
} }
} }
@@ -305,7 +315,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
} }
public boolean onTestnetMenuItem() { public boolean onTestnetMenuItem() {
boolean lastState = testnet;//item.isChecked(); boolean lastState = testnet;
setNet(!lastState, true); // set and save setNet(!lastState, true); // set and save
return !lastState; return !lastState;
} }
@@ -326,10 +336,12 @@ 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_TESTNET = "testnet";
private static final String PREF_DAEMONLIST_MAINNET = private static final String PREF_DAEMONLIST_MAINNET =
"node.moneroworld.com:18089;node.xmrbackb.one:18081;node.xmr.be:18081"; "node.moneroworld.com:18089;node.xmrbackb.one;node.xmr.be";
private static final String PREF_DAEMONLIST_TESTNET =
"testnet.xmrchain.net";
private NodeList daemonTestNet; private NodeList daemonTestNet;
private NodeList daemonMainNet; private NodeList daemonMainNet;
@@ -338,7 +350,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
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, "")); daemonTestNet = new NodeList(sharedPref.getString(PREF_DAEMON_TESTNET, PREF_DAEMONLIST_TESTNET));
setNet(isTestnet(), false); setNet(isTestnet(), false);
} }
@@ -347,7 +359,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
} }
void savePrefs(boolean usePreviousState) { void savePrefs(boolean usePreviousState) {
Log.d(TAG, "SAVE / " + usePreviousState); Timber.d("SAVE / %s", usePreviousState);
// save the daemon address for the net // save the daemon address for the net
boolean testnet = isTestnet() ^ usePreviousState; boolean testnet = isTestnet() ^ usePreviousState;
String daemon = getDaemon(); String daemon = getDaemon();
@@ -359,7 +371,6 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
SharedPreferences sharedPref = activityCallback.getPrefs(); SharedPreferences sharedPref = activityCallback.getPrefs();
SharedPreferences.Editor editor = sharedPref.edit(); SharedPreferences.Editor editor = sharedPref.edit();
//editor.putBoolean(PREF_TESTNET, testnet);
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.apply(); editor.apply();
@@ -370,7 +381,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
} }
void setDaemon(NodeList nodeList) { void setDaemon(NodeList nodeList) {
Log.d(TAG, "setDaemon() " + nodeList.toString()); Timber.d("setDaemon() %s", nodeList.toString());
String[] nodes = nodeList.getNodes().toArray(new String[0]); String[] nodes = nodeList.getNodes().toArray(new String[0]);
nodeAdapter.clear(); nodeAdapter.clear();
nodeAdapter.addAll(nodes); nodeAdapter.addAll(nodes);

View File

@@ -0,0 +1,21 @@
/*
* 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;
public interface OnBackPressedListener {
boolean onBackPressed();
}

File diff suppressed because it is too large Load Diff

View File

@@ -20,7 +20,6 @@ import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@@ -30,21 +29,21 @@ import com.google.zxing.BarcodeFormat;
import com.google.zxing.Result; import com.google.zxing.Result;
import me.dm7.barcodescanner.zxing.ZXingScannerView; import me.dm7.barcodescanner.zxing.ZXingScannerView;
import timber.log.Timber;
public class ScannerFragment extends Fragment implements ZXingScannerView.ResultHandler { public class ScannerFragment extends Fragment implements ZXingScannerView.ResultHandler {
static final String TAG = "ScannerFragment";
private Listener activityCallback; private OnScannedListener onScannedListener;
public interface Listener { public interface OnScannedListener {
boolean onAddressScanned(String uri); boolean onScanned(String qrCode);
} }
private ZXingScannerView mScannerView; private ZXingScannerView mScannerView;
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.d(TAG, "onCreateView"); Timber.d("onCreateView");
mScannerView = new ZXingScannerView(getActivity()); mScannerView = new ZXingScannerView(getActivity());
return mScannerView; return mScannerView;
} }
@@ -52,20 +51,15 @@ public class ScannerFragment extends Fragment implements ZXingScannerView.Result
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
Log.d(TAG, "onResume"); Timber.d("onResume");
mScannerView.setResultHandler(this); mScannerView.setResultHandler(this);
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)) {
(rawResult.getText().startsWith(QR_SCHEME))) { if (onScannedListener.onScanned(rawResult.getText())) {
if (activityCallback.onAddressScanned(rawResult.getText())) {
return; return;
} else { } else {
Toast.makeText(getActivity(), getString(R.string.send_qr_address_invalid), Toast.LENGTH_SHORT).show(); Toast.makeText(getActivity(), getString(R.string.send_qr_address_invalid), Toast.LENGTH_SHORT).show();
@@ -91,7 +85,7 @@ public class ScannerFragment extends Fragment implements ZXingScannerView.Result
@Override @Override
public void onPause() { public void onPause() {
Log.d(TAG, "onPause"); Timber.d("onPause");
mScannerView.stopCamera(); mScannerView.stopCamera();
super.onPause(); super.onPause();
} }
@@ -99,8 +93,8 @@ public class ScannerFragment extends Fragment implements ZXingScannerView.Result
@Override @Override
public void onAttach(Context context) { public void onAttach(Context context) {
super.onAttach(context); super.onAttach(context);
if (context instanceof Listener) { if (context instanceof OnScannedListener) {
this.activityCallback = (Listener) context; this.onScannedListener = (OnScannedListener) context;
} else { } else {
throw new ClassCastException(context.toString() throw new ClassCastException(context.toString()
+ " must implement Listener"); + " must implement Listener");

View File

@@ -0,0 +1,39 @@
/*
* 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;
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 {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// set FLAG_SECURE to prevent screenshots in Release Mode
if (!BuildConfig.DEBUG) {
getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -30,11 +30,14 @@ 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.layout.Toolbar;
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 java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Calendar; import java.util.Calendar;
@@ -44,7 +47,6 @@ import java.util.Set;
import java.util.TimeZone; import java.util.TimeZone;
public class TxFragment extends Fragment { public class TxFragment extends Fragment {
static final String TAG = "TxFragment";
static public final String ARG_INFO = "info"; static public final String ARG_INFO = "info";
@@ -69,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);
@@ -95,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();
} }
}); });
@@ -167,8 +189,7 @@ public class TxFragment extends Fragment {
sb.append("-"); sb.append("-");
} }
sb.append("\n\n"); sb.append("\n\n");
//Helper.clipBoardCopy(getActivity(), getString(R.string.tx_copy_label), sb.toString());
//Toast.makeText(getActivity(), getString(R.string.tx_copy_message), Toast.LENGTH_SHORT).show();
Intent sendIntent = new Intent(); Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND); sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, sb.toString()); sendIntent.putExtra(Intent.EXTRA_TEXT, sb.toString());
@@ -177,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) {
@@ -268,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);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2017 m2049r et al.
*
* 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;
import android.app.Application;
import timber.log.Timber;
public class XmrWalletApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
if (BuildConfig.DEBUG) {
Timber.plant(new Timber.DebugTree());
}
}
}

View File

@@ -0,0 +1,200 @@
/*
* 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.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;
import timber.log.Timber;
public class BarcodeData {
public static final String XMR_SCHEME = "monero:";
public static final String XMR_PAYMENTID = "tx_payment_id";
public static final String XMR_AMOUNT = "tx_amount";
static final String BTC_SCHEME = "bitcoin:";
static final String BTC_AMOUNT = "amount";
public enum Asset {
XMR, BTC
}
public Asset asset = null;
public String address = null;
public String paymentId = null;
public String amount = null;
public BarcodeData(Asset asset, String address) {
this.asset = asset;
this.address = address;
}
public BarcodeData(Asset asset, String address, String amount) {
this.asset = asset;
this.address = address;
this.amount = amount;
}
public BarcodeData(Asset asset, String address, String paymentId, String amount) {
this.asset = asset;
this.address = address;
this.paymentId = paymentId;
this.amount = amount;
}
static public BarcodeData fromQrCode(String qrCode) {
// check for monero uri
BarcodeData bcData = parseMoneroUri(qrCode);
// check for naked monero address / integrated address
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;
}
/**
* Parse and decode a monero scheme string. It is here because it needs to validate the data.
*
* @param uri String containing a monero URL
* @return BarcodeData object or null if uri not valid
*/
static public BarcodeData parseMoneroUri(String uri) {
Timber.d("parseMoneroUri=%s", uri);
if (uri == null) return null;
if (!uri.startsWith(XMR_SCHEME)) return null;
String noScheme = uri.substring(XMR_SCHEME.length());
Uri monero = Uri.parse(noScheme);
Map<String, String> parms = new HashMap<>();
String query = monero.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 = monero.getPath();
String paymentId = parms.get(XMR_PAYMENTID);
String amount = parms.get(XMR_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 ((paymentId != null) && !Wallet.isPaymentIdValid(paymentId)) {
Timber.d("paymentId invalid");
return null;
}
if (!Wallet.isAddressValid(address)) {
Timber.d("address invalid");
return null;
}
return new BarcodeData(Asset.XMR, address, paymentId, amount);
}
static public BarcodeData parseMoneroNaked(String address) {
Timber.d("parseMoneroNaked=%s", address);
if (address == null) return null;
if (!Wallet.isAddressValid(address)) {
Timber.d("address invalid");
return null;
}
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

@@ -0,0 +1,39 @@
/*
* 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 com.m2049r.xmrwallet.model.PendingTransaction;
public class PendingTx {
final public PendingTransaction.Status status;
final public String error;
final public long amount;
final public long dust;
final public long fee;
final public String txId;
final public long txCount;
public PendingTx(PendingTransaction pendingTransaction) {
status = pendingTransaction.getStatus();
error = pendingTransaction.getErrorString();
amount = pendingTransaction.getAmount();
dust = pendingTransaction.getDust();
fee = pendingTransaction.getFee();
txId = pendingTransaction.getFirstTxId();
txCount = pendingTransaction.getTxCount();
}
}

View File

@@ -14,36 +14,101 @@
* limitations under the License. * limitations under the License.
*/ */
package com.m2049r.xmrwallet.util; package com.m2049r.xmrwallet.data;
import android.os.Parcel; 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(String dst_addr,
public TxData() {
}
public TxData(TxData txData) {
this.dstAddr = txData.dstAddr;
this.paymentId = txData.paymentId;
this.amount = txData.amount;
this.mixin = txData.mixin;
this.priority = txData.priority;
}
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 String dst_addr; public String getDestinationAddress() {
public String paymentId; return dstAddr;
public long amount; }
public int mixin;
public PendingTransaction.Priority priority; public String getPaymentId() {
return paymentId;
}
public long getAmount() {
return amount;
}
public int getMixin() {
return mixin;
}
public PendingTransaction.Priority getPriority() {
return 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 @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);
@@ -61,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();
@@ -78,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:");
@@ -87,7 +152,7 @@ public class TxData implements Parcelable {
sb.append(",mixin:"); sb.append(",mixin:");
sb.append(mixin); sb.append(mixin);
sb.append(",priority:"); sb.append(",priority:");
sb.append(priority.toString()); sb.append(String.valueOf(priority));
return sb.toString(); return sb.toString();
} }
} }

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

@@ -0,0 +1,69 @@
/*
* 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.dialog;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import com.m2049r.xmrwallet.BuildConfig;
import com.m2049r.xmrwallet.R;
public class AboutFragment extends DialogFragment {
static final String TAG = "AboutFragment";
public static AboutFragment newInstance() {
return new AboutFragment();
}
public static void display(FragmentManager fm) {
FragmentTransaction ft = fm.beginTransaction();
Fragment prev = fm.findFragmentByTag(TAG);
if (prev != null) {
ft.remove(prev);
}
AboutFragment.newInstance().show(ft, TAG);
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final View view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_about, null);
((TextView) view.findViewById(R.id.tvHelp)).setText(Html.fromHtml(getString(R.string.about_licenses)));
((TextView) view.findViewById(R.id.tvVersion)).setText(getString(R.string.about_version, BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE));
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(view);
builder.setNegativeButton(R.string.about_close,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
return builder.create();
}
}

View File

@@ -14,82 +14,49 @@
* limitations under the License. * limitations under the License.
*/ */
/**
* Based on work by Adam Speakman http://speakman.net.nz
*/
package com.m2049r.xmrwallet.dialog; package com.m2049r.xmrwallet.dialog;
import android.annotation.SuppressLint;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.DialogFragment; import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction; import android.support.v4.app.FragmentTransaction;
import android.text.Html; import android.text.Html;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.webkit.WebView;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.m2049r.xmrwallet.BuildConfig;
import com.m2049r.xmrwallet.R; import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.util.Helper; import com.m2049r.xmrwallet.util.Helper;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class DonationFragment extends DialogFragment { public class DonationFragment extends DialogFragment {
static final String TAG = "DonationFragment"; static final String TAG = "DonationFragment";
private static final String FRAGMENT_TAG = "com.m2049r.xmrwalelt.dialog.DonationFragment";
/**
* Creates a new instance of LicensesFragment with no Close button.
*
* @return A new licenses fragment.
*/
public static DonationFragment newInstance() { public static DonationFragment newInstance() {
return new DonationFragment(); return new DonationFragment();
} }
/**
* Builds and displays a licenses fragment with no Close button. Requires
* "/res/raw/licenses.html" and "/res/layout/licenses_fragment.xml" to be
* present.
*
* @param fm A fragment manager instance used to display this LicensesFragment.
*/
public static void display(FragmentManager fm) { public static void display(FragmentManager fm) {
FragmentTransaction ft = fm.beginTransaction(); FragmentTransaction ft = fm.beginTransaction();
Fragment prev = fm.findFragmentByTag(FRAGMENT_TAG); Fragment prev = fm.findFragmentByTag(TAG);
if (prev != null) { if (prev != null) {
ft.remove(prev); ft.remove(prev);
} }
ft.addToBackStack(null);
// Create and show the dialog. DonationFragment.newInstance().show(ft, TAG);
DialogFragment newFragment = DonationFragment.newInstance();
newFragment.show(ft, FRAGMENT_TAG);
} }
@SuppressLint("InflateParams")
@Override @Override
public Dialog onCreateDialog(Bundle savedInstanceState) { public Dialog onCreateDialog(Bundle savedInstanceState) {
final View view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_donation, null); final View view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_donation, null);
((TextView) view.findViewById(R.id.tvCredits)).setText(Html.fromHtml(getString(R.string.donation_credits))); ((TextView) view.findViewById(R.id.tvCredits)).setText(Html.fromHtml(getString(R.string.donation_credits)));
((ImageButton) view.findViewById(R.id.bCopyAddress)). (view.findViewById(R.id.bCopyAddress)).
setOnClickListener(new View.OnClickListener() { setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {

View File

@@ -1,12 +1,12 @@
/** /*
* Copyright 2013 Adam Speakman, m2049r * Copyright (c) 2017 m2049r
* <p> *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* <p> *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* <p> *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -16,98 +16,57 @@
package com.m2049r.xmrwallet.dialog; package com.m2049r.xmrwallet.dialog;
import android.annotation.SuppressLint;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.DialogFragment; import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction; import android.support.v4.app.FragmentTransaction;
import android.util.Log; import android.text.Html;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.webkit.WebView; import android.widget.TextView;
import android.widget.ProgressBar;
import com.m2049r.xmrwallet.R; import com.m2049r.xmrwallet.R;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* Based on LicensesFragment by Adam Speakman on 24/09/13.
* http://speakman.net.nz
*/
public class HelpFragment extends DialogFragment { public class HelpFragment extends DialogFragment {
static final String TAG = "HelpFragment"; static final String TAG = "HelpFragment";
private static final String FRAGMENT_TAG = "com.m2049r.xmrwallet.dialog.HelpFragment";
private static final String HELP_ID = "HELP_ID"; private static final String HELP_ID = "HELP_ID";
private AsyncTask<Void, Void, String> loader;
public static HelpFragment newInstance(int helpResourceId) { public static HelpFragment newInstance(int helpResourceId) {
HelpFragment fragment = new HelpFragment(); HelpFragment fragment = new HelpFragment();
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putInt(HELP_ID, helpResourceId); bundle.putInt(HELP_ID, helpResourceId);
fragment.setArguments(bundle); fragment.setArguments(bundle);
return fragment; return fragment;
} }
/** public static void display(FragmentManager fm, int helpResourceId) {
* @param fm A fragment manager instance used to display this LicensesFragment.
*/
public static void displayHelp(FragmentManager fm, int helpResourceId) {
FragmentTransaction ft = fm.beginTransaction(); FragmentTransaction ft = fm.beginTransaction();
Fragment prev = fm.findFragmentByTag(FRAGMENT_TAG); Fragment prev = fm.findFragmentByTag(TAG);
if (prev != null) { if (prev != null) {
ft.remove(prev); ft.remove(prev);
} }
// Create and show the dialog. HelpFragment.newInstance(helpResourceId).show(ft, TAG);
DialogFragment newFragment = HelpFragment.newInstance(helpResourceId);
newFragment.show(ft, FRAGMENT_TAG);
} }
@Override @Override
public void onActivityCreated(Bundle savedInstanceState) { public Dialog onCreateDialog(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); final View view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_help, null);
int helpId = 0; int helpId = 0;
Bundle arguments = getArguments(); Bundle arguments = getArguments();
if (arguments != null) { if (arguments != null) {
helpId = arguments.getInt(HELP_ID); helpId = arguments.getInt(HELP_ID);
} }
if (helpId > 0) if (helpId > 0)
loadHelp(helpId); ((TextView) view.findViewById(R.id.tvHelp)).setText(Html.fromHtml(getString(helpId)));
}
@Override
public void onDestroy() {
super.onDestroy();
if (loader != null) {
loader.cancel(true);
}
}
private WebView webView;
private ProgressBar progress;
@SuppressLint("InflateParams")
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
View content = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_help, null);
webView = (WebView) content.findViewById(R.id.helpFragmentWebView);
progress = (ProgressBar) content.findViewById(R.id.helpFragmentProgress);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(view);
builder.setView(content);
builder.setNegativeButton(R.string.about_close, builder.setNegativeButton(R.string.about_close,
new DialogInterface.OnClickListener() { new DialogInterface.OnClickListener() {
@Override @Override
@@ -115,47 +74,6 @@ public class HelpFragment extends DialogFragment {
dialog.dismiss(); dialog.dismiss();
} }
}); });
return builder.create(); return builder.create();
} }
private void loadHelp(final int helpResourceId) {
// Load asynchronously in case of a very large file.
loader = new AsyncTask<Void, Void, String>() {
@Override
protected String doInBackground(Void... params) {
InputStream rawResource = getActivity().getResources().openRawResource(helpResourceId);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(rawResource));
String line;
StringBuilder sb = new StringBuilder();
try {
while ((line = bufferedReader.readLine()) != null) {
sb.append(line);
sb.append("\n");
}
bufferedReader.close();
} catch (IOException ex) {
Log.e(TAG, ex.getLocalizedMessage());
}
return sb.toString();
}
@Override
protected void onPostExecute(String licensesBody) {
super.onPostExecute(licensesBody);
if (getActivity() == null || isCancelled()) {
return;
}
progress.setVisibility(View.INVISIBLE);
webView.setVisibility(View.VISIBLE);
webView.loadDataWithBaseURL(null, licensesBody, "text/html", "utf-8", null);
loader = null;
}
}.execute();
}
} }

View File

@@ -1,165 +0,0 @@
/**
* Copyright 2013 Adam Speakman, m2049r
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.dialog;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.webkit.WebView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.m2049r.xmrwallet.BuildConfig;
import com.m2049r.xmrwallet.R;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* Created by Adam Speakman on 24/09/13.
* http://speakman.net.nz
*/
public class LicensesFragment extends DialogFragment {
static final String TAG = "LicensesFragment";
int versionCode = BuildConfig.VERSION_CODE;
String versionName = BuildConfig.VERSION_NAME;
private AsyncTask<Void, Void, String> mLicenseLoader;
private static final String FRAGMENT_TAG = "com.m2049r.xmrwalelt.dialog.LicensesFragment";
/**
* Creates a new instance of LicensesFragment with no Close button.
*
* @return A new licenses fragment.
*/
public static LicensesFragment newInstance() {
return new LicensesFragment();
}
/**
* Builds and displays a licenses fragment with no Close button. Requires
* "/res/raw/licenses.html" and "/res/layout/licenses_fragment.xml" to be
* present.
*
* @param fm A fragment manager instance used to display this LicensesFragment.
*/
public static void displayLicensesFragment(FragmentManager fm) {
FragmentTransaction ft = fm.beginTransaction();
Fragment prev = fm.findFragmentByTag(FRAGMENT_TAG);
if (prev != null) {
ft.remove(prev);
}
ft.addToBackStack(null);
// Create and show the dialog.
DialogFragment newFragment = LicensesFragment.newInstance();
newFragment.show(ft, FRAGMENT_TAG);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
loadLicenses();
}
@Override
public void onDestroy() {
super.onDestroy();
if (mLicenseLoader != null) {
mLicenseLoader.cancel(true);
}
}
private WebView mWebView;
private ProgressBar mIndeterminateProgress;
@SuppressLint("InflateParams")
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
View content = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_licenses, null);
mWebView = (WebView) content.findViewById(R.id.licensesFragmentWebView);
mIndeterminateProgress = (ProgressBar) content.findViewById(R.id.licensesFragmentIndeterminateProgress);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
TextView text = (TextView) content.findViewById(R.id.licensesFragmentText);
text.setText(getString(R.string.about_text, versionName, versionCode));
builder.setView(content);
builder.setNegativeButton(R.string.about_close,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
return builder.create();
}
private void loadLicenses() {
// Load asynchronously in case of a very large file.
mLicenseLoader = new AsyncTask<Void, Void, String>() {
@Override
protected String doInBackground(Void... params) {
InputStream rawResource = getActivity().getResources().openRawResource(R.raw.licenses);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(rawResource));
String line;
StringBuilder sb = new StringBuilder();
try {
while ((line = bufferedReader.readLine()) != null) {
sb.append(line);
sb.append("\n");
}
bufferedReader.close();
} catch (IOException ex) {
Log.e(TAG, ex.getLocalizedMessage());
}
return sb.toString();
}
@Override
protected void onPostExecute(String licensesBody) {
super.onPostExecute(licensesBody);
if (getActivity() == null || isCancelled()) {
return;
}
mIndeterminateProgress.setVisibility(View.INVISIBLE);
mWebView.setVisibility(View.VISIBLE);
mWebView.loadDataWithBaseURL(null, licensesBody, "text/html", "utf-8", null);
mLicenseLoader = null;
}
}.execute();
}
}

View File

@@ -14,13 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
/**
* Based on work by Adam Speakman http://speakman.net.nz
*/
package com.m2049r.xmrwallet.dialog; package com.m2049r.xmrwallet.dialog;
import android.annotation.SuppressLint;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
import android.content.DialogInterface; import android.content.DialogInterface;
@@ -32,47 +27,27 @@ import android.support.v4.app.FragmentTransaction;
import android.text.Html; import android.text.Html;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.ImageButton;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast;
import com.m2049r.xmrwallet.R; import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.util.Helper;
public class PrivacyFragment extends DialogFragment { public class PrivacyFragment extends DialogFragment {
static final String TAG = "PrivacyFragment"; static final String TAG = "PrivacyFragment";
private static final String FRAGMENT_TAG = "com.m2049r.xmrwalelt.dialog.PrivacyFragment";
/**
* Creates a new instance of LicensesFragment with no Close button.
*
* @return A new licenses fragment.
*/
public static PrivacyFragment newInstance() { public static PrivacyFragment newInstance() {
return new PrivacyFragment(); return new PrivacyFragment();
} }
/**
* Builds and displays a licenses fragment with no Close button. Requires
* "/res/raw/licenses.html" and "/res/layout/licenses_fragment.xml" to be
* present.
*
* @param fm A fragment manager instance used to display this LicensesFragment.
*/
public static void display(FragmentManager fm) { public static void display(FragmentManager fm) {
FragmentTransaction ft = fm.beginTransaction(); FragmentTransaction ft = fm.beginTransaction();
Fragment prev = fm.findFragmentByTag(FRAGMENT_TAG); Fragment prev = fm.findFragmentByTag(TAG);
if (prev != null) { if (prev != null) {
ft.remove(prev); ft.remove(prev);
} }
ft.addToBackStack(null);
// Create and show the dialog. PrivacyFragment.newInstance().show(ft, TAG);
DialogFragment newFragment = PrivacyFragment.newInstance();
newFragment.show(ft, FRAGMENT_TAG);
} }
@SuppressLint("InflateParams")
@Override @Override
public Dialog onCreateDialog(Bundle savedInstanceState) { public Dialog onCreateDialog(Bundle savedInstanceState) {
final View view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_privacy_policy, null); final View view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_privacy_policy, null);

View File

@@ -0,0 +1,135 @@
/*
* 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 android.os.Bundle;
import android.view.LayoutInflater;
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.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;
public class SendAmountWizardFragment extends SendWizardFragment {
public static SendAmountWizardFragment newInstance(Listener listener) {
SendAmountWizardFragment instance = new SendAmountWizardFragment();
instance.setSendListener(listener);
return instance;
}
Listener sendListener;
public SendAmountWizardFragment setSendListener(Listener listener) {
this.sendListener = listener;
return this;
}
interface Listener {
SendFragment.Listener getActivityCallback();
TxData getTxData();
BarcodeData popBarcodeData();
}
private TextView tvFunds;
private ExchangeTextView evAmount;
//private Button bSendAll;
private NumberPadView numberPad;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Timber.d("onCreateView() %s", (String.valueOf(savedInstanceState)));
sendListener = (Listener) getParentFragment();
View view = inflater.inflate(R.layout.fragment_send_amount, container, false);
tvFunds = (TextView) view.findViewById(R.id.tvFunds);
evAmount = (ExchangeTextView) view.findViewById(R.id.evAmount);
numberPad = (NumberPadView) view.findViewById(R.id.numberPad);
numberPad.setListener(evAmount);
/*
bSendAll = (Button) view.findViewById(R.id.bSendAll);
bSendAll.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO: send all - figure out how to display this
}
});
*/
Helper.hideKeyboard(getActivity());
return view;
}
@Override
public boolean onValidateFields() {
if (!evAmount.validate(maxFunds)) {
return false;
}
if (sendListener != null) {
String xmr = evAmount.getAmount();
if (xmr != null) {
sendListener.getTxData().setAmount(Wallet.getAmountFromString(xmr));
} else {
sendListener.getTxData().setAmount(0L);
}
}
return true;
}
double maxFunds = 0;
@Override
public void onResumeFragment() {
super.onResumeFragment();
Timber.d("onResumeFragment()");
Helper.hideKeyboard(getActivity());
final long funds = getTotalFunds();
maxFunds = 1.0 * funds / 1000000000000L;
tvFunds.setText(getString(R.string.send_available,
Wallet.getDisplayAmount(funds)));
// getAmount is null if exchange is in progress
if ((evAmount.getAmount() != null) && evAmount.getAmount().isEmpty()) {
final BarcodeData data = sendListener.popBarcodeData();
if ((data != null) && (data.amount != null)) {
evAmount.setAmount(data.amount);
}
}
}
long getTotalFunds() {
return sendListener.getActivityCallback().getTotalFunds();
}
}

View File

@@ -14,16 +14,14 @@
* limitations under the License. * limitations under the License.
*/ */
package com.m2049r.xmrwallet.util; package com.m2049r.xmrwallet.fragment.send;
public class BarcodeData { import com.m2049r.xmrwallet.model.PendingTransaction;
public String address = null;
public String paymentId = null;
public long amount = -1;
public BarcodeData(String address, String paymentId, long amount) { interface SendConfirm {
this.address = address; void sendFailed();
this.paymentId = paymentId;
this.amount = amount; void createTransactionFailed(String errorText);
}
void transactionCreated(String txTag, PendingTransaction pendingTransaction);
} }

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