1
mirror of https://github.com/m2049r/xmrwallet synced 2025-09-04 17:28:42 +02:00

Compare commits

...

99 Commits
v0.4.0 ... v0.7

Author SHA1 Message Date
m2049r
4918f44048 Docs updated for 0.7 and bugfixes (#55)
* docs and version

* wallet failed message moved to UI thread

* display balance in pure white
2017-09-10 20:04:21 +02:00
m2049r
924c3fa260 allow back only if not accepting (#54) 2017-09-10 10:40:13 +02:00
m2049r
eb2b3b5675 use MoneroThreadPoolExecutor for wallet creation (#53) 2017-09-10 09:49:21 +02:00
Benedict
7a9bb22da7 Added more files and directories to gitignore (#47)
* added files and directories to gitignore we don't need to change and push

* correct gitignore level for .idea folder
2017-09-09 22:16:58 +02:00
m2049r
c7e745cbc3 Merge pull request #52 from m2049r/feature_kraken
Add support for USD/EUR on receive
2017-09-09 22:16:02 +02:00
m2049r
654caaed22 Merge branch 'master' into feature_kraken 2017-09-09 22:15:37 +02:00
m2049r
b8c287b763 cleanup 2017-09-09 22:02:17 +02:00
m2049r
5c1fa097a9 show alternative currency (USD/EUR) on receive
uses https://www.kraken.com/help/api#get-ticker-info
2017-09-09 19:31:37 +02:00
m2049r
80531740dd Update strings.xml 2017-09-09 12:24:01 +02:00
m2049r
08a62cabab Bugfix: Display of unconfirmed amount (#51)
* fix unconfirmed display

* fix unconfirmed display
2017-09-09 12:22:24 +02:00
m2049r
cf4d8bdbf0 fix unconfirmed display 2017-09-09 09:34:44 +02:00
m2049r
7b690a5086 fix merge conflict in gradle-witness.jar 2017-09-09 01:11:17 +02:00
m2049r
e8e5be35b3 Merge branch 'master' of https://github.com/m2049r/xmrwallet 2017-09-09 01:02:56 +02:00
Benedict
5dbf84d5d6 verify checksum from dependencies 2017-09-09 01:01:47 +02:00
m2049r
bf64f77b10 Upgrade to monero v0.11.0.0 (#50) 2017-09-09 01:01:28 +02:00
m2049r
9b82023a9f UI facelift (#49) 2017-09-09 01:01:27 +02:00
KeeJef
be54900e1f Making a few small changes to the readme
Added a link to the release page 
corrected a few small spelling and grammatical errors
2017-09-09 01:01:27 +02:00
KeeJef
033032639a Revert "Update README.md"
This reverts commit 466fd3bf26.
2017-09-09 01:01:27 +02:00
KeeJef
ab8567692f Update README.md 2017-09-09 01:01:27 +02:00
m2049r
65894664a1 Upgrade to monero v0.11.0.0 (#50) 2017-09-09 00:37:12 +02:00
m2049r
e8f53a5a2f UI facelift (#49) 2017-09-08 23:59:50 +02:00
Benedict
22e0a225b0 verify checksum from dependencies 2017-09-08 22:14:09 +02:00
m2049r
e769f1a472 Merge pull request #46 from KeeJef/master
Small changes to the readme
2017-09-07 15:44:13 +02:00
KeeJef
b447df9ef9 Making a few small changes to the readme
Added a link to the release page 
corrected a few small spelling and grammatical errors
2017-09-07 14:27:49 +10:00
KeeJef
42f4e4a0e9 Revert "Update README.md"
This reverts commit 466fd3bf26.
2017-09-07 14:17:12 +10:00
KeeJef
466fd3bf26 Update README.md 2017-09-07 14:15:07 +10:00
KeeJef
c9bbe1db3f Merge pull request #1 from m2049r/master
Merging Up to date
2017-09-07 14:08:27 +10:00
m2049r
dec67e0675 Revert "Upgrade to monero v0.11.0.0 (#44)" (#45)
This reverts commit 9cbeaa7942.
2017-09-06 21:14:38 +02:00
m2049r
9cbeaa7942 Upgrade to monero v0.11.0.0 (#44)
and minor changes
2017-09-06 21:03:31 +02:00
m2049r
093e4bda1d Doc & Version update (#43)
* added hint that amount is in XMR

* update FAQ and version
2017-09-04 23:29:48 +02:00
m2049r
4aa7000cb3 added hint that amount is in XMR (#42)
added hint that amount is in XMR when receiving
2017-09-04 23:27:04 +02:00
m2049r
62844192df Merge pull request #41 from m2049r/bugfix_logo
fixed logo svg
2017-09-04 23:21:29 +02:00
m2049r
855b35a6b7 added l in svg path 2017-09-04 22:52:10 +02:00
m2049r
88110b702f Merge pull request #40 from m2049r/bugfix_issue_37
request and respond to permissions marshmallow style
2017-09-04 22:32:30 +02:00
m2049r
0013caa05f request and respond to permissions marshmallow style 2017-09-04 22:30:37 +02:00
m2049r
5b3e92e91a Merge pull request #39 from m2049r/bugfix_issue_36
Use AsyncTask with 5MB stack in lots of places
2017-09-04 20:51:21 +02:00
m2049r
f8ea3cc77f use AsyncTask with 5MB stack in lots of places 2017-09-04 20:43:05 +02:00
m2049r
59ef2a1f8e Merge pull request #33 from KeeJef/master
Clarifying some Strings
2017-09-04 18:26:30 +02:00
m2049r
fae07ed716 Merge pull request #38 from m2049r/feature_rename_wallet
Rename/Backup/Archive Wallet FIles
2017-09-04 07:34:48 +02:00
m2049r
e662d5a9c0 wallet rename + tweaks 2017-09-04 07:26:04 +02:00
m2049r
4b2d52fbe6 wallet archive/backup progress dialogs 2017-09-03 21:29:15 +02:00
m2049r
ec7798cb34 wallet archive/backup 2017-09-03 14:09:27 +02:00
m2049r
20e7d6d065 rename option in wallet list + tweaks 2017-09-03 11:55:42 +02:00
m2049r
89ada5b294 Merge pull request #35 from m2049r/feature_info_alert
Alert before showing wallet details
2017-09-03 09:44:37 +02:00
m2049r
fe80fef36e alert before showing wallet details 2017-09-03 09:43:52 +02:00
m2049r
e8331dda7a Merge pull request #34 from m2049r/feature_qr_receive
QR Code for receiving
2017-09-02 12:56:17 +02:00
m2049r
68abaec6cb tweaks + get address from wallet (and not from file) 2017-09-02 12:51:57 +02:00
m2049r
fe84bae9ed rework options menus 2017-09-02 10:05:50 +02:00
KeeJef
1289a0ada4 Clarifying some Strings
Just for new people i think the amount when sending should indicate that the values are XMR not USD or something
2017-09-02 13:08:09 +10:00
m2049r
93025c5e1b Receive QR code 2017-09-02 00:00:54 +02:00
m2049r
e0439a1359 Merge pull request #32 from m2049r/bugfix_scanbutton
fix scan button enable/disable
2017-08-31 18:48:27 +02:00
m2049r
93ec3865da fix scan button enable/disable 2017-08-31 18:43:51 +02:00
m2049r
49e338e80d Merge pull request #31 from m2049r/doc
Update FAQ + version
2017-08-31 18:22:02 +02:00
m2049r
075ddff226 update FAQ + version 2017-08-31 18:19:59 +02:00
m2049r
7eaf17d48e Merge pull request #30 from m2049r/feature_qr_amount
QR scan of amount
2017-08-31 09:58:21 +02:00
m2049r
6822aa83d8 QR scan of amount as well
bugfix: use getSupportFragmentManager everywhere
2017-08-31 09:57:14 +02:00
m2049r
20dbaac4fa Merge pull request #29 from m2049r/bugfix_fragment_v4
use v4 fragment support library to cater for android 5.1
2017-08-31 01:00:52 +02:00
m2049r
726887af2e use v4 fragment support library to cater for android 5.1 2017-08-31 01:00:27 +02:00
m2049r
03da2880ac Merge pull request #28 from m2049r/bugfix_service_timing
make user wait for service to finish
2017-08-30 23:36:01 +02:00
m2049r
78c053f4e8 make user wait for service to finish 2017-08-30 23:35:16 +02:00
m2049r
5b38cc438c Merge pull request #27 from m2049r/docs
update docs and version
2017-08-30 22:24:49 +02:00
m2049r
1eac363102 update docs and version 2017-08-30 22:24:24 +02:00
m2049r
e51425bc2e Merge pull request #26 from m2049r/feature_qr
QR Scanning incl. payment id
2017-08-30 22:02:34 +02:00
m2049r
f5535dbefa QR Scanning incl. payment id 2017-08-30 21:36:07 +02:00
m2049r
2d42a0287d Merge pull request #25 from m2049r/docs
updated version number + docs
2017-08-29 23:41:38 +02:00
m2049r
2ebb9d0650 updated version number + docs 2017-08-29 23:40:46 +02:00
m2049r
30792c53c0 Merge pull request #24 from m2049r/feature_spend_mainnet
mainnet spending
2017-08-29 22:37:23 +02:00
m2049r
3846a0c391 mainnet spending 2017-08-29 22:22:07 +02:00
m2049r
c66ebd654a Merge pull request #23 from m2049r/cleanup
Lots of GUI tweaks
2017-08-29 22:07:17 +02:00
m2049r
186ed5cd39 second spend confirmation for mainnet 2017-08-29 22:05:51 +02:00
m2049r
e39cd1c988 lots of GUI tweaks 2017-08-29 22:05:45 +02:00
m2049r
39d9c4d0c3 Merge pull request #22 from m2049r/feature_colours
balance colour + tx ordering
2017-08-29 08:44:36 +02:00
m2049r
e4562f07a4 balance colour + tx ordering 2017-08-29 08:43:56 +02:00
m2049r
b3ea4540a1 Merge pull request #21 from m2049r/feature_toolbar
Toolbars + action & context menu
2017-08-28 23:51:36 +02:00
m2049r
ea7c7d2fdb net colour in toolbar 2017-08-28 23:46:18 +02:00
m2049r
8ff8be6f60 list context menu + tweaks 2017-08-28 23:14:53 +02:00
m2049r
b5ded700fe toolbar info action for wallet activity 2017-08-28 22:10:17 +02:00
m2049r
a5527d4efd use default daemon ports if none supplied 2017-08-28 19:38:13 +02:00
m2049r
a007810824 Merge pull request #20 from m2049r/feature_list_addfab
nicer add icon
2017-08-27 22:58:36 +02:00
m2049r
a634cf18b1 nicer fab icon 2017-08-27 22:57:35 +02:00
m2049r
0b2fa08df8 Merge pull request #19 from m2049r/feature_list_addfab
Create wallet by action button
2017-08-27 09:14:52 +02:00
m2049r
191aa6ac22 action button for create wallet + setting activity title in LoginActivity 2017-08-27 09:12:53 +02:00
m2049r
a82a90575d deamon prompt show syntax 2017-08-26 00:34:17 +02:00
m2049r
2e04046f50 Merge pull request #18 from m2049r/feature_layout
simple layout
2017-08-26 00:29:41 +02:00
m2049r
c11d577c5f simple layout
minimum number of decimal places
progress at top
2017-08-26 00:27:27 +02:00
m2049r
74b2dd209c Merge pull request #17 from m2049r/feature_daemon_userpassword
Username/Password for daemon
2017-08-24 00:06:18 +02:00
m2049r
cb1d541474 Username/Password for daemon 2017-08-24 00:03:23 +02:00
m2049r
807d217aac Merge pull request #16 from m2049r/feature_txrecipient
show destinations in tx view
2017-08-22 13:10:14 +02:00
m2049r
0421bcfac3 show destination in tx view 2017-08-22 13:02:31 +02:00
m2049r
b6c4e06fda Merge pull request #15 from m2049r/feature_spend_redo
enable dispose of prepared transaction
2017-08-22 11:10:19 +02:00
m2049r
3ee8343074 enable dispose of prepared transaction 2017-08-22 11:05:43 +02:00
m2049r
110621824a Merge pull request #14 from m2049r/hotfix_priority
passing of transaction priority fixed
2017-08-22 10:56:07 +02:00
m2049r
7194580fbe passing of transaction priority fixed 2017-08-22 10:54:16 +02:00
m2049r
48dcd37740 Update build.gradle 2017-08-22 00:19:53 +02:00
m2049r
8e619756b9 Merge pull request #13 from m2049r/feature_service_notification
start WalletService as foreground service
2017-08-21 17:33:08 +02:00
m2049r
6c6b47db7d Merge pull request #12 from m2049r/bugfix
don't show Send Button on mainnet (instead of crashing when clicked)
2017-08-21 17:31:45 +02:00
m2049r
a126844272 start WalletService as foreground service preventing it from being killed by the system 2017-08-21 15:58:22 +02:00
m2049r
9b3086ff2e don't show Send Button on mainnet (instead of crashing when clicked) 2017-08-21 10:14:19 +02:00
m2049r
89d1842d59 Update README.md 2017-08-21 00:22:57 +02:00
100 changed files with 3505 additions and 1236 deletions

9
.gitignore vendored
View File

@@ -1,2 +1,9 @@
.gradle
build
/build
*.iml
/.idea/libraries
/.idea/workspace.xml
/local.properties
/captures
.externalNativeBuild
.DS_Store

2
.idea/.gitignore generated vendored
View File

@@ -1,2 +1,2 @@
workspace.xml
markdown-navigator*
markdown-*

10
.idea/libraries/core_1_9_8.xml generated Normal file
View File

@@ -0,0 +1,10 @@
<component name="libraryTable">
<library name="core-1.9.8">
<CLASSES>
<root url="jar://$USER_HOME$/.android/build-cache/db7eb580bfa6467818ef12c5f1fa42273b50aa3a/output/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.android/build-cache/db7eb580bfa6467818ef12c5f1fa42273b50aa3a/output/res" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

View File

@@ -1,11 +1,11 @@
<component name="libraryTable">
<library name="junit-4.12">
<library name="core-3.3.0">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/junit/junit/4.12/2973d150c0dc1fefe998f834810d68f278ea58ec/junit-4.12.jar!/" />
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.google.zxing/core/3.3.0/73c49077166faa4c3c0059c5f583d1d7bd1475fe/core-3.3.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/junit/junit/4.12/a6c32b40bf3d76eca54e3c601e5d1470c86fcdfa/junit-4.12-sources.jar!/" />
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.google.zxing/core/3.3.0/39d966e052e28fc7d83793b02e0af97ccf955745/core-3.3.0-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@@ -1,12 +0,0 @@
<component name="libraryTable">
<library name="espresso-core-2.2.2">
<CLASSES>
<root url="file://$USER_HOME$/.android/build-cache/d505abdc89cc7d1b938ec3f95e87d4323360fa14/output/res" />
<root url="jar://$USER_HOME$/.android/build-cache/d505abdc89cc7d1b938ec3f95e87d4323360fa14/output/jars/classes.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/AppData/Local/Android/Sdk/extras/android/m2repository/com/android/support/test/espresso/espresso-core/2.2.2/espresso-core-2.2.2-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@@ -1,12 +0,0 @@
<component name="libraryTable">
<library name="espresso-idling-resource-2.2.2">
<CLASSES>
<root url="jar://$USER_HOME$/.android/build-cache/0dcbbeb3c862ffabe5d9f3c1f70b25bfdf6c739e/output/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.android/build-cache/0dcbbeb3c862ffabe5d9f3c1f70b25bfdf6c739e/output/res" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/AppData/Local/Android/Sdk/extras/android/m2repository/com/android/support/test/espresso/espresso-idling-resource/2.2.2/espresso-idling-resource-2.2.2-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@@ -1,12 +0,0 @@
<component name="libraryTable">
<library name="exposed-instrumentation-api-publish-0.5">
<CLASSES>
<root url="jar://$USER_HOME$/.android/build-cache/c11e9f250159df473b4fbff8b80f455f0be2e5b5/output/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.android/build-cache/c11e9f250159df473b4fbff8b80f455f0be2e5b5/output/res" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/AppData/Local/Android/Sdk/extras/android/m2repository/com/android/support/test/exposed-instrumentation-api-publish/0.5/exposed-instrumentation-api-publish-0.5-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@@ -1,11 +0,0 @@
<component name="libraryTable">
<library name="hamcrest-core-1.3">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.hamcrest/hamcrest-core/1.3/42a25dc3219429f0e5d060061f71acb49bf010a0/hamcrest-core-1.3.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.hamcrest/hamcrest-core/1.3/1dc37250fbc78e23a65a67fbbaf71d2e9cbc3c0b/hamcrest-core-1.3-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@@ -1,9 +0,0 @@
<component name="libraryTable">
<library name="hamcrest-integration-1.3">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.hamcrest/hamcrest-integration/1.3/5de0c73fef18917cd85d0ab70bb23818685e4dfd/hamcrest-integration-1.3.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

View File

@@ -1,9 +0,0 @@
<component name="libraryTable">
<library name="hamcrest-library-1.3">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.hamcrest/hamcrest-library/1.3/4785a3c21320980282f9f33d0d1264a69040538f/hamcrest-library-1.3.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

View File

@@ -1,9 +0,0 @@
<component name="libraryTable">
<library name="javawriter-2.1.1">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.squareup/javawriter/2.1.1/67ff45d9ae02e583d0f9b3432a5ebbe05c30c966/javawriter-2.1.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

View File

@@ -1,9 +0,0 @@
<component name="libraryTable">
<library name="javax.annotation-api-1.2">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/javax.annotation/javax.annotation-api/1.2/479c1e06db31c432330183f5cae684163f186146/javax.annotation-api-1.2.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

View File

@@ -1,9 +0,0 @@
<component name="libraryTable">
<library name="javax.inject-1">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/javax.inject/javax.inject/1/6975da39a7040257bd51d21a231b76c915872d38/javax.inject-1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

View File

@@ -1,9 +0,0 @@
<component name="libraryTable">
<library name="jsr305-2.0.1">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.google.code.findbugs/jsr305/2.0.1/516c03b21d50a644d538de0f0369c620989cd8f0/jsr305-2.0.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

View File

@@ -1,12 +0,0 @@
<component name="libraryTable">
<library name="rules-0.5">
<CLASSES>
<root url="jar://$USER_HOME$/.android/build-cache/8f8d46a3318b85241b55e25415619e9017c0aef1/output/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.android/build-cache/8f8d46a3318b85241b55e25415619e9017c0aef1/output/res" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/AppData/Local/Android/Sdk/extras/android/m2repository/com/android/support/test/rules/0.5/rules-0.5-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@@ -1,12 +0,0 @@
<component name="libraryTable">
<library name="runner-0.5">
<CLASSES>
<root url="jar://$USER_HOME$/.android/build-cache/a3a29c4e90c979d7576a0a7d8450261e0065a0a8/output/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.android/build-cache/a3a29c4e90c979d7576a0a7d8450261e0065a0a8/output/res" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/AppData/Local/Android/Sdk/extras/android/m2repository/com/android/support/test/runner/0.5/runner-0.5-sources.jar!/" />
</SOURCES>
</library>
</component>

10
.idea/libraries/zxing_1_9_8.xml generated Normal file
View File

@@ -0,0 +1,10 @@
<component name="libraryTable">
<library name="zxing-1.9.8">
<CLASSES>
<root url="jar://$USER_HOME$/.android/build-cache/8d8f2e0e10c7af73321454f6fa481e8e5438e654/output/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.android/build-cache/8d8f2e0e10c7af73321454f6fa481e8e5438e654/output/res" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

View File

@@ -2,19 +2,18 @@
Another Android Monero Wallet
### QUICKSTART
- Download APK (Release) and install it
- Download the APK for the most current release [here](https://github.com/m2049r/xmrwallet/releases) and install it
- Run the App and select "Generate Wallet" to create a new wallet or recover a wallet
- Advanced users could copy over synced wallet files (all files) onto sdcard in directory Monerujo (created first time App is started)
- see the [FAQ](doc/FAQ.md)
- Advanced users can copy over synced wallet files (all files) onto sdcard in directory Monerujo (created first time App is started)
- See the [FAQ](doc/FAQ.md)
### Disclaimer
You may loose all your Moneroj if you use this App.
You may lose all your Moneroj if you use this App. Be cautious when spending on the mainnet.
### Random Notes
- Based off monero v0.10.3.1 with pull requests #2238, #2239 and #2289 applied => so can be used in mainnet!
- currently only android32
- ~~currently only use is checking incoming/outgoing transactions~~
- works in testnet & mainnet
- Based off monero v0.11.0.0 with PR #2289 applied
- currently only android32 (runs on 64-bit as well)
- works on the testnet & mainnet
- takes forever to sync due to 32-bit architecture
- use your own daemon - it's easy
- screen stays on until first sync is complete
@@ -22,16 +21,14 @@ You may loose all your Moneroj if you use this App.
- Monerujo means "Monero Wallet" according to https://www.reddit.com/r/Monero/comments/3exy7t/esperanto_corner/
### TODO
- wallet backup functions
- adjust layout so we can use bigger font sizes (maybe show only 5 decimal places instead of 12 in main view)
- review visibility of methods/classes
- more sensible error dialogs ~~(e.g. when no write permissions granted) instead of just crashing on purpose~~
- more sensible error dialogs
- check licenses of included libraries; License Dialog
- ~~make it pretty~~ (decided to go with "form follows function")
- ~~spend monero - not so difficult with wallet api~~
### Issues
- Pending incoming transactions disappear after reload
### Issues / Pitfalls
- 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.
The official monero client shows the same behaviour.
### HOW TO BUILD
No need to build. Binaries are included:
@@ -43,3 +40,7 @@ No need to build. Binaries are included:
If you want to build them yourself (recommended) check out [the instructions](doc/BUILDING-external-libs.md)
Then, fire up Android Studio and build the APK.
### Donations
- Address: 4AdkPJoxn7JCvAby9szgnt93MSEwdnxdhaASxbTBm6x5dCwmsDep2UYN4FhStDn5i11nsJbpU7oj59ahg8gXb1Mg3viqCuk
- Viewkey: b1aff2a12191723da0afbe75516f94dd8b068215f6e847d8da57aca5f1f98e0c

View File

@@ -147,7 +147,7 @@ target_link_libraries( monerujo
blockchain_db
lmdb
#easylogging # not for 0.10.3.1
easylogging
unbound
p2p

View File

@@ -1,4 +1,5 @@
apply plugin: 'com.android.application'
apply plugin: 'witness'
android {
compileSdkVersion 25
@@ -7,8 +8,8 @@ android {
applicationId "com.m2049r.xmrwallet"
minSdkVersion 21
targetSdkVersion 25
versionCode 4
versionName "0.4.0"
versionCode 12
versionName "0.7"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
@@ -35,16 +36,36 @@ android {
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support:design:25.3.1'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
compile 'com.android.support:support-v4:25.3.1'
compile 'com.android.support:recyclerview-v7:25.3.1'
compile 'com.android.support:cardview-v7:25.3.1'
testCompile 'junit:junit:4.12'
compile 'me.dm7.barcodescanner:zxing:1.9.8'
}
dependencyVerification {
verify = [
'com.android.support:design:a3e83064fe99d0a4369f9b46d8bfbe77d0c3022fffdee4be3ac3857b87cc89e3',
'com.android.support:appcompat-v7:ac1ebbc46589195dda3e0b1becfe410bafd75bdf3edd1cd9acf04850f3895830',
'com.android.support.constraint:constraint-layout:b0c688cc2b7172608f8153a689d746da40f71e52d7e2fe2bfd9df2f92db77085',
'com.android.support:transition:36c688825a8c0e6e879e18886de83dc90673322822d5b606ee302f70fb558e16',
'me.dm7.barcodescanner:zxing:d43973c9527c23fa8e6d338c6a2c458e373ce1ac6bcaa3bc41d11ae49116000d',
'me.dm7.barcodescanner:core:a5c8a704089b58029db166172ed8e55d756877d010a85a0b1c94fdc96ffb8f9a',
'com.android.support:support-v4:07d389154bcf73b47e514964df1578136b26cba78257b8a577a3ccb54beff0ae',
'com.android.support:recyclerview-v7:375974a8724e359d97d77fa8522c614f813a3ac4583c1807f154a3f9a054b0a1',
'com.android.support:cardview-v7:defc17032ffa600a82e1c7d96bb574aa5ed64e2b57e28414a245da7d6db0c666',
'com.android.support:animated-vector-drawable:4bc46edf1946b32d518b41416d1734e915e0cbb28021de3b340527419b070691',
'com.android.support:support-vector-drawable:13728f337f36d1c02d52198a6c20724edb447a0875454d829f95cb9eb4aa293b',
'com.android.support:support-fragment:541d6393c1e024453aca2a14f31bea0c7270ff4e2a02783f3528aa426367444d',
'com.android.support:support-media-compat:cbed07d07e0e84fdb4b75712f5fd946229a8af155933c9a92e41db64d00791e0',
'com.android.support:support-core-utils:32fac02eb2c20a77fa3e3bc3ede62392a19613f72b8f8e10f5dfa84bb4c89ea1',
'com.android.support:support-core-ui:6182278a6653e6c111c888963626cbb16f2d0022571cb239760475119e0b92a8',
'com.android.support:support-compat:e02d781268dc60aab6638d8dc20156ea11ca20b962d294b85e6f1e8418cabfa7',
'com.android.support:support-annotations:aedf76962584adfaed2bd3fcaa22406461c4310237fc27e301128edaa2dba2fa',
'com.android.support.constraint:constraint-layout-solver:8c62525a9bc5cff5633a96cb9b32fffeccaf41b8841aa87fc22607070dea9b8d',
'com.google.zxing:core:bba7724e02a997cec38213af77133ee8e24b0d5cf5fa7ecbc16a4fa93f11ee0d',
]
}

View File

@@ -7,18 +7,20 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.CAMERA" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:icon="@drawable/ic_monero_32dp"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
android:theme="@style/MyMaterialTheme">
<activity
android:name=".WalletActivity"
android:configChanges="orientation|keyboardHidden"
android:label="@string/wallet_activity_name"
android:launchMode="singleTask"
android:screenOrientation="portrait" />
<activity

View File

@@ -461,12 +461,11 @@ Java_com_m2049r_xmrwallet_model_WalletManager_resolveOpenAlias(JNIEnv *env, jobj
//TODO static std::tuple<bool, std::string, std::string, std::string, std::string> checkUpdates(const std::string &software, const std::string &subdir);
// actually a WalletManager function, but logically in onWalletSelected
JNIEXPORT jboolean JNICALL
Java_com_m2049r_xmrwallet_model_WalletManager_closeJ(JNIEnv *env, jobject instance,
jobject walletInstance) {
Bitmonero::Wallet *wallet = getHandle<Bitmonero::Wallet>(env, walletInstance);
bool closeSuccess = Bitmonero::WalletManagerFactory::getWalletManager()->closeWallet(wallet);
bool closeSuccess = Bitmonero::WalletManagerFactory::getWalletManager()->closeWallet(wallet, false);
if (closeSuccess) {
MyWalletListener *walletListener = getHandle<MyWalletListener>(env, walletInstance,
"listenerHandle");
@@ -564,8 +563,13 @@ Java_com_m2049r_xmrwallet_model_Wallet_getIntegratedAddress(JNIEnv *env, jobject
JNIEXPORT jstring JNICALL
Java_com_m2049r_xmrwallet_model_Wallet_getSecretViewKey(JNIEnv *env, jobject instance) {
Bitmonero::Wallet *wallet = getHandle<Bitmonero::Wallet>(env, instance);
//return env->NewStringUTF(wallet->secretViewKey().c_str()); // changed in head
return env->NewStringUTF(wallet->privateViewKey().c_str());
return env->NewStringUTF(wallet->secretViewKey().c_str());
}
JNIEXPORT jstring JNICALL
Java_com_m2049r_xmrwallet_model_Wallet_getSecretSpendKey(JNIEnv *env, jobject instance) {
Bitmonero::Wallet *wallet = getHandle<Bitmonero::Wallet>(env, instance);
return env->NewStringUTF(wallet->secretSpendKey().c_str());
}
JNIEXPORT jboolean JNICALL
@@ -592,12 +596,16 @@ Java_com_m2049r_xmrwallet_model_Wallet_getFilename(JNIEnv *env, jobject instance
JNIEXPORT jboolean JNICALL
Java_com_m2049r_xmrwallet_model_Wallet_initJ(JNIEnv *env, jobject instance,
jstring daemon_address,
jlong upper_transaction_size_limit) {
// const std::string &daemon_username = "", const std::string &daemon_password = "") = 0;
jlong upper_transaction_size_limit,
jstring daemon_username, jstring daemon_password) {
const char *_daemon_address = env->GetStringUTFChars(daemon_address, JNI_FALSE);
const char *_daemon_username = env->GetStringUTFChars(daemon_username, JNI_FALSE);
const char *_daemon_password = env->GetStringUTFChars(daemon_password, JNI_FALSE);
Bitmonero::Wallet *wallet = getHandle<Bitmonero::Wallet>(env, instance);
bool status = wallet->init(_daemon_address, upper_transaction_size_limit);
bool status = wallet->init(_daemon_address, upper_transaction_size_limit, _daemon_username, _daemon_password);
env->ReleaseStringUTFChars(daemon_address, _daemon_address);
env->ReleaseStringUTFChars(daemon_username, _daemon_username);
env->ReleaseStringUTFChars(daemon_password, _daemon_password);
return status;
}

View File

@@ -16,12 +16,13 @@
package com.m2049r.xmrwallet;
import android.app.Fragment;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
@@ -68,12 +69,9 @@ public class GenerateFragment extends Fragment {
bGenerate = (Button) view.findViewById(R.id.bGenerate);
etWalletMnemonic.setRawInputType(InputType.TYPE_CLASS_TEXT);
etWalletAddress.setRawInputType(InputType.TYPE_CLASS_TEXT);
etWalletViewKey.setRawInputType(InputType.TYPE_CLASS_TEXT);
etWalletSpendKey.setRawInputType(InputType.TYPE_CLASS_TEXT);
boolean testnet = WalletManager.getInstance().isTestNet();
//etWalletMnemonic.setTextIsSelectable(testnet);
etWalletAddress.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
etWalletViewKey.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
etWalletSpendKey.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
Helper.showKeyboard(getActivity());
etWalletName.addTextChangedListener(new TextWatcher() {
@@ -297,8 +295,12 @@ public class GenerateFragment extends Fragment {
private void generateWallet() {
String name = etWalletName.getText().toString();
if (name.length() == 0) return;
String walletPath = Helper.getWalletPath(getActivity(), name);
if (WalletManager.getInstance().walletExists(walletPath)) {
if (name.charAt(0)=='.') {
Toast.makeText(getActivity(), getString(R.string.generate_wallet_dot), Toast.LENGTH_LONG).show();
etWalletName.requestFocus();
}
File walletFile = Helper.getWalletFile(getActivity(), name);
if (WalletManager.getInstance().walletExists(walletFile)) {
Toast.makeText(getActivity(), getString(R.string.generate_wallet_exists), Toast.LENGTH_LONG).show();
etWalletName.requestFocus();
return;
@@ -344,6 +346,13 @@ public class GenerateFragment extends Fragment {
bGenerate.setVisibility(View.VISIBLE);
}
@Override
public void onResume() {
super.onResume();
Log.d(TAG, "onResume()");
activityCallback.setTitle(getString(R.string.generate_title));
}
GenerateFragment.Listener activityCallback;
public interface Listener {
@@ -354,6 +363,9 @@ public class GenerateFragment extends Fragment {
void onGenerate(String name, String password, String address, String viewKey, String spendKey, long height);
File getStorageRoot();
void setTitle(String title);
}
@Override

View File

@@ -16,9 +16,11 @@
package com.m2049r.xmrwallet;
import android.app.Fragment;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -28,15 +30,13 @@ import android.widget.TextView;
import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.service.MoneroHandlerThread;
import java.io.File;
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
public class GenerateReviewFragment extends Fragment {
static final String TAG = "GenerateReviewFragment";
static final public String VIEW_DETAILS = "details";
static final public String VIEW_ACCEPT = "accept";
static final public String VIEW_WALLET = "wallet";
static final public String VIEW_TYPE_DETAILS = "details";
static final public String VIEW_TYPE_ACCEPT = "accept";
static final public String VIEW_TYPE_WALLET = "wallet";
ProgressBar pbProgress;
TextView tvWalletName;
@@ -65,6 +65,7 @@ public class GenerateReviewFragment extends Fragment {
boolean testnet = WalletManager.getInstance().isTestNet();
tvWalletMnemonic.setTextIsSelectable(testnet);
tvWalletSpendKey.setTextIsSelectable(testnet);
bAccept.setOnClickListener(new View.OnClickListener() {
@Override
@@ -75,19 +76,17 @@ public class GenerateReviewFragment extends Fragment {
showProgress();
Bundle b = getArguments();
String type = b.getString("type");
if (!type.equals(VIEW_WALLET)) {
String name = b.getString("name");
String password = b.getString("password");
tvWalletName.setText(new File(name).getName());
show(name, password, type);
} else {
show(walletCallback.getWallet(), null, type);
}
Bundle args = getArguments();
String path = args.getString("path");
String password = args.getString("password");
this.type = args.getString("type");
new AsyncShow().executeOnExecutor(MoneroThreadPoolExecutor.MONERO_THREAD_POOL_EXECUTOR,
path, password);
return view;
}
String type;
private void acceptWallet() {
String name = tvWalletName.getText().toString();
String password = tvWalletPassword.getText().toString();
@@ -95,40 +94,72 @@ public class GenerateReviewFragment extends Fragment {
acceptCallback.onAccept(name, password);
}
private void show(final String walletPath, final String password, final String type) {
new Thread(null,
new Runnable() {
@Override
public void run() {
final Wallet wallet = WalletManager.getInstance().openWallet(walletPath, password);
getActivity().runOnUiThread(new Runnable() {
public void run() {
show(wallet, password, type);
wallet.close();
}
});
}
}
, "DetailsReview", MoneroHandlerThread.THREAD_STACK_SIZE).start();
}
private class AsyncShow extends AsyncTask<String, Void, Boolean> {
String password;
private void show(final Wallet wallet, final String password, final String type) {
if (type.equals(GenerateReviewFragment.VIEW_ACCEPT)) {
tvWalletPassword.setText(password);
bAccept.setVisibility(View.VISIBLE);
bAccept.setEnabled(true);
String name;
String address;
String seed;
String viewKey;
String spendKey;
boolean isWatchOnly;
Wallet.Status status;
@Override
protected Boolean doInBackground(String... params) {
if (params.length != 2) return false;
String walletPath = params[0];
password = params[1];
Wallet wallet;
boolean closeWallet;
if (type.equals(GenerateReviewFragment.VIEW_TYPE_WALLET)) {
wallet = GenerateReviewFragment.this.walletCallback.getWallet();
closeWallet = false;
} else {
wallet = WalletManager.getInstance().openWallet(walletPath, password);
closeWallet = true;
}
name = wallet.getName();
status = wallet.getStatus();
if (status != Wallet.Status.Status_Ok) {
if (closeWallet) wallet.close();
return false;
}
address = wallet.getAddress();
seed = wallet.getSeed();
viewKey = wallet.getSecretViewKey();
spendKey = isWatchOnly ? getActivity().getString(R.string.watchonly_label) : wallet.getSecretSpendKey();
isWatchOnly = wallet.isWatchOnly();
if (closeWallet) wallet.close();
return true;
}
tvWalletName.setText(wallet.getName());
tvWalletAddress.setText(wallet.getAddress());
tvWalletMnemonic.setText(wallet.getSeed());
tvWalletViewKey.setText(wallet.getSecretViewKey());
String spend = wallet.isWatchOnly() ? "" : "not available - use seed for recovery";
if (spend.length() > 0) { //TODO should be == 64, but spendkey is not in the API yet
tvWalletSpendKey.setText(spend);
} else {
tvWalletSpendKey.setText(getString(R.string.generate_wallet_watchonly));
@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
tvWalletName.setText(name);
if (result) {
if (type.equals(GenerateReviewFragment.VIEW_TYPE_ACCEPT)) {
tvWalletPassword.setText(password);
bAccept.setVisibility(View.VISIBLE);
bAccept.setEnabled(true);
}
tvWalletAddress.setText(address);
tvWalletMnemonic.setText(seed);
tvWalletViewKey.setText(viewKey);
tvWalletSpendKey.setText(spendKey);
} else {
// TODO show proper error message
// TODO end the fragment
tvWalletAddress.setText(status.toString());
tvWalletMnemonic.setText(status.toString());
tvWalletViewKey.setText(status.toString());
tvWalletSpendKey.setText(status.toString());
}
hideProgress();
}
hideProgress();
}
GenerateReviewFragment.Listener acceptCallback = null;
@@ -140,6 +171,7 @@ public class GenerateReviewFragment extends Fragment {
public interface ListenerWithWallet {
Wallet getWallet();
}
@Override
@@ -163,4 +195,8 @@ public class GenerateReviewFragment extends Fragment {
public void hideProgress() {
pbProgress.setVisibility(View.INVISIBLE);
}
boolean backOk() {
return !type.equals(GenerateReviewFragment.VIEW_TYPE_ACCEPT);
}
}

File diff suppressed because it is too large Load Diff

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,112 @@
/*
* Copyright (c) 2017 dm77, 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.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.Result;
import com.m2049r.xmrwallet.util.BarcodeData;
import me.dm7.barcodescanner.zxing.ZXingScannerView;
public class ScannerFragment extends Fragment implements ZXingScannerView.ResultHandler {
static final String TAG = "ScannerFragment";
Listener activityCallback;
public interface Listener {
boolean onAddressScanned(String uri);
}
private ZXingScannerView mScannerView;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.d(TAG, "onCreateView");
mScannerView = new ZXingScannerView(getActivity());
return mScannerView;
}
@Override
public void onResume() {
super.onResume();
Log.d(TAG, "onResume");
mScannerView.setResultHandler(this);
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) {
//Log.d(TAG, rawResult.getBarcodeFormat().toString() + "/" + rawResult.getText());
if ((rawResult.getBarcodeFormat() == BarcodeFormat.QR_CODE) &&
(rawResult.getText().startsWith(QR_SCHEME))) {
if (activityCallback.onAddressScanned(rawResult.getText())) {
return;
} else {
Toast.makeText(getActivity(), getString(R.string.send_qr_address_invalid), Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(getActivity(), getString(R.string.send_qr_invalid), Toast.LENGTH_SHORT).show();
}
// Note from dm77:
// * Wait 2 seconds to resume the preview.
// * On older devices continuously stopping and resuming camera preview can result in freezing the app.
// * I don't know why this is the case but I don't have the time to figure out.
Handler handler = new Handler();
handler.postDelayed(new
Runnable() {
@Override
public void run() {
mScannerView.resumeCameraPreview(ScannerFragment.this);
}
}, 2000);
}
@Override
public void onPause() {
Log.d(TAG, "onPause");
mScannerView.stopCamera();
super.onPause();
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
//Log.d(TAG, "attaching scan");
if (context instanceof Listener) {
this.activityCallback = (Listener) context;
} else {
throw new ClassCastException(context.toString()
+ " must implement Listener");
}
}
}

View File

@@ -16,12 +16,11 @@
package com.m2049r.xmrwallet;
import android.app.Fragment;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.support.v7.app.AlertDialog;
import android.text.Editable;
import android.text.InputType;
@@ -40,23 +39,24 @@ import android.widget.Spinner;
import android.widget.TextView;
import com.m2049r.xmrwallet.model.PendingTransaction;
import com.m2049r.xmrwallet.model.TransactionInfo;
import com.m2049r.xmrwallet.model.Transfer;
import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.BarcodeData;
import com.m2049r.xmrwallet.util.TxData;
public class SendFragment extends Fragment {
static final String TAG = "GenerateFragment";
static final String TAG = "SendFragment";
EditText etAddress;
EditText etPaymentId;
EditText etAmount;
Button bScan;
Button bSweep;
Spinner sMixin;
Spinner sPriority;
Button bPrepareSend;
Button bDispose;
Button bPaymentId;
LinearLayout llConfirmSend;
TextView tvTxAmount;
@@ -64,11 +64,13 @@ public class SendFragment extends Fragment {
TextView tvTxDust;
EditText etNotes;
Button bSend;
Button bReallySend;
ProgressBar pbProgress;
final static int Mixins[] = {4, 6, 8, 10, 13}; // must match the layout XML
final static int Mixins[] = {4, 7, 12, 25}; // must match the layout XML
final static PendingTransaction.Priority Priorities[] =
{PendingTransaction.Priority.Priority_Low,
{PendingTransaction.Priority.Priority_Default,
PendingTransaction.Priority.Priority_Low,
PendingTransaction.Priority.Priority_Medium,
PendingTransaction.Priority.Priority_High}; // must match the layout XML
@@ -83,9 +85,11 @@ public class SendFragment extends Fragment {
etAddress = (EditText) view.findViewById(R.id.etAddress);
etPaymentId = (EditText) view.findViewById(R.id.etPaymentId);
etAmount = (EditText) view.findViewById(R.id.etAmount);
bScan = (Button) view.findViewById(R.id.bScan);
bSweep = (Button) view.findViewById(R.id.bSweep);
bPrepareSend = (Button) view.findViewById(R.id.bPrepareSend);
bPaymentId = (Button) view.findViewById(R.id.bPaymentId);
bDispose = (Button) view.findViewById(R.id.bDispose);
llConfirmSend = (LinearLayout) view.findViewById(R.id.llConfirmSend);
tvTxAmount = (TextView) view.findViewById(R.id.tvTxAmount);
@@ -93,17 +97,14 @@ public class SendFragment extends Fragment {
tvTxDust = (TextView) view.findViewById(R.id.tvTxDust);
etNotes = (EditText) view.findViewById(R.id.etNotes);
bSend = (Button) view.findViewById(R.id.bSend);
bReallySend = (Button) view.findViewById(R.id.bReallySend);
pbProgress = (ProgressBar) view.findViewById(R.id.pbProgress);
etAddress.setRawInputType(InputType.TYPE_CLASS_TEXT);
etPaymentId.setRawInputType(InputType.TYPE_CLASS_TEXT);
etAddress.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
etPaymentId.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
etNotes.setRawInputType(InputType.TYPE_CLASS_TEXT);
// etAddress.setText("9tDC52GsMjTNt4dpnRCwAF7ekVBkbkgkXGaMKTcSTpBhGpqkPX56jCNRydLq9oGjbbAQBsZhLfgmTKsntmxRd3TaJFYM2f8");
boolean testnet = WalletManager.getInstance().isTestNet();
if (!testnet) throw new IllegalStateException("Sending TX only on testnet. sorry.");
Helper.showKeyboard(getActivity());
etAddress.requestFocus();
etAddress.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@@ -191,10 +192,26 @@ public class SendFragment extends Fragment {
}
});
bDispose.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
activityCallback.onDisposeRequest();
enableEdit();
}
});
bScan.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
activityCallback.onScanAddress();
}
});
bPaymentId.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
etPaymentId.setText((activityCallback.generatePaymentId()));
etPaymentId.setText((Wallet.generatePaymentId()));
etPaymentId.setSelection(etPaymentId.getText().length());
}
});
@@ -224,6 +241,26 @@ public class SendFragment extends Fragment {
@Override
public void onClick(View v) {
bSend.setEnabled(false);
boolean testnet = WalletManager.getInstance().isTestNet();
if (testnet) {
send();
} else {
etNotes.setEnabled(false);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
bReallySend.setVisibility(View.VISIBLE);
}
}, 1000);
}
}
});
bReallySend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bReallySend.setEnabled(false);
send();
}
});
@@ -240,11 +277,7 @@ public class SendFragment extends Fragment {
private boolean addressOk() {
String address = etAddress.getText().toString();
if (WalletManager.getInstance().isTestNet()) {
return ((address.length() == 95) && ("9A".indexOf(address.charAt(0)) >= 0));
} else {
return ((address.length() == 95) && ("4".indexOf(address.charAt(0)) >= 0));
}
return Helper.isAddressOk(address, WalletManager.getInstance().isTestNet());
}
private boolean amountOk() {
@@ -254,7 +287,7 @@ public class SendFragment extends Fragment {
private boolean paymentIdOk() {
String paymentId = etPaymentId.getText().toString();
return paymentId.isEmpty() || activityCallback.isPaymentIdValid(paymentId);
return paymentId.isEmpty() || Wallet.isPaymentIdValid(paymentId);
}
private void prepareSend() {
@@ -290,6 +323,7 @@ public class SendFragment extends Fragment {
etAddress.setEnabled(false);
etPaymentId.setEnabled(false);
etAmount.setEnabled(false);
bScan.setEnabled(false);
bPaymentId.setEnabled(false);
bSweep.setEnabled(false);
bPrepareSend.setEnabled(false);
@@ -301,9 +335,14 @@ public class SendFragment extends Fragment {
etAddress.setEnabled(true);
etPaymentId.setEnabled(true);
etAmount.setEnabled(true);
bScan.setEnabled(true);
bPaymentId.setEnabled(true);
bSweep.setEnabled(true);
bPrepareSend.setEnabled(true);
llConfirmSend.setVisibility(View.GONE);
bSend.setEnabled(true);
etNotes.setEnabled(true);
bReallySend.setVisibility(View.GONE);
}
private void send() {
@@ -321,12 +360,53 @@ public class SendFragment extends Fragment {
void onSend(String notes);
String generatePaymentId();
boolean isPaymentIdValid(String paymentId);
String getWalletAddress();
void onDisposeRequest();
void onScanAddress();
BarcodeData getScannedData();
}
@Override
public void onResume() {
super.onResume();
Log.d(TAG, "onResume");
BarcodeData data = activityCallback.getScannedData();
if (data != null) {
String scannedAddress = data.address;
if (scannedAddress != null) {
etAddress.setText(scannedAddress);
} else {
etAddress.getText().clear();
}
String scannedPaymenId = data.paymentId;
if (scannedPaymenId != null) {
etPaymentId.setText(scannedPaymenId);
} else {
etPaymentId.getText().clear();
}
if (data.amount >= 0) {
String scannedAmount = Helper.getDisplayAmount(data.amount);
etAmount.setText(scannedAmount);
} else {
etAmount.getText().clear();
}
etAmount.requestFocus();
etAmount.setSelection(etAmount.getText().length());
} else { // no scan data
// jump to first empty field
if (etAddress.getText().toString().isEmpty()) {
etAddress.requestFocus();
} else if (etPaymentId.getText().toString().isEmpty()) {
etPaymentId.requestFocus();
} else {
etAmount.requestFocus();
etAmount.setSelection(etAmount.getText().length());
}
}
}
@Override
@@ -350,7 +430,6 @@ public class SendFragment extends Fragment {
tvTxAmount.setText(Wallet.getDisplayAmount(pendingTransaction.getAmount()));
tvTxFee.setText(Wallet.getDisplayAmount(pendingTransaction.getFee()));
tvTxDust.setText(Wallet.getDisplayAmount(pendingTransaction.getDust()));
bSend.setEnabled(true);
}
public void onCreatedTransactionFailed(String errorText) {
@@ -365,6 +444,7 @@ public class SendFragment extends Fragment {
}
});
builder.setMessage(errorText);
builder.setCancelable(false);
builder.create().show();
}

View File

@@ -16,31 +16,28 @@
package com.m2049r.xmrwallet;
import android.app.Fragment;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.text.InputType;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ProgressBar;
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.model.WalletManager;
import com.m2049r.xmrwallet.service.MoneroHandlerThread;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.TimeZone;
public class TxFragment extends Fragment {
@@ -48,7 +45,7 @@ public class TxFragment extends Fragment {
static public final String ARG_INFO = "info";
private final SimpleDateFormat TS_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private final SimpleDateFormat TS_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
public TxFragment() {
super();
@@ -60,6 +57,7 @@ public class TxFragment extends Fragment {
TextView tvTxTimestamp;
TextView tvTxId;
TextView tvTxKey;
TextView tvDestination;
TextView tvTxPaymentId;
TextView tvTxBlockheight;
TextView tvTxAmount;
@@ -78,6 +76,7 @@ public class TxFragment extends Fragment {
tvTxTimestamp = (TextView) view.findViewById(R.id.tvTxTimestamp);
tvTxId = (TextView) view.findViewById(R.id.tvTxId);
tvTxKey = (TextView) view.findViewById(R.id.tvTxKey);
tvDestination = (TextView) view.findViewById(R.id.tvDestination);
tvTxPaymentId = (TextView) view.findViewById(R.id.tvTxPaymentId);
tvTxBlockheight = (TextView) view.findViewById(R.id.tvTxBlockheight);
tvTxAmount = (TextView) view.findViewById(R.id.tvTxAmount);
@@ -142,10 +141,10 @@ public class TxFragment extends Fragment {
sb.append(getString(R.string.tx_timestamp)).append(": ");
sb.append(TS_FORMATTER.format(new Date(info.timestamp * 1000))).append("\n");
sb.append(getString(R.string.tx_blockheight)).append(": ");
if (info.isPending) {
sb.append(getString(R.string.tx_pending)).append("\n");
} else if (info.isFailed) {
if (info.isFailed) {
sb.append(getString(R.string.tx_failed)).append("\n");
} else if (info.isPending) {
sb.append(getString(R.string.tx_pending)).append("\n");
} else {
sb.append(info.blockheight).append("\n");
}
@@ -154,11 +153,11 @@ public class TxFragment extends Fragment {
boolean comma = false;
for (Transfer transfer : info.transfers) {
if (comma) {
sb.append(",");
sb.append(", ");
} else {
comma = true;
}
sb.append("[").append(transfer.address.substring(0, 6)).append("] ");
sb.append(transfer.address).append(": ");
sb.append(Wallet.getDisplayAmount(transfer.amount));
}
} else {
@@ -192,20 +191,23 @@ public class TxFragment extends Fragment {
tvTxId.setText(info.hash);
tvTxKey.setText(info.txKey.isEmpty() ? "-" : info.txKey);
tvTxPaymentId.setText(info.paymentId);
if (info.isPending) {
tvTxBlockheight.setText(getString(R.string.tx_pending));
} else if (info.isFailed) {
if (info.isFailed) {
tvTxBlockheight.setText(getString(R.string.tx_failed));
} else if (info.isPending) {
tvTxBlockheight.setText(getString(R.string.tx_pending));
} else {
tvTxBlockheight.setText("" + info.blockheight);
}
String sign = (info.direction == TransactionInfo.Direction.Direction_In ? "+" : "-");
tvTxAmount.setText(sign + Wallet.getDisplayAmount(info.amount));
tvTxFee.setText(Wallet.getDisplayAmount(info.fee));
Set<String> destinations = new HashSet<>();
StringBuffer sb = new StringBuffer();
StringBuffer dstSb = new StringBuffer();
if (info.transfers != null) {
boolean newline = false;
for (Transfer transfer : info.transfers) {
destinations.add(transfer.address);
if (newline) {
sb.append("\n");
} else {
@@ -214,10 +216,21 @@ public class TxFragment extends Fragment {
sb.append("[").append(transfer.address.substring(0, 6)).append("] ");
sb.append(Wallet.getDisplayAmount(transfer.amount));
}
newline = false;
for (String dst : destinations) {
if (newline) {
dstSb.append("\n");
} else {
newline = true;
}
dstSb.append(dst);
}
} else {
sb.append("-");
dstSb.append(info.direction == TransactionInfo.Direction.Direction_In ? activityCallback.getWalletAddress() : "-");
}
tvTxTransfers.setText(sb.toString());
tvDestination.setText(dstSb.toString());
this.info = info;
bCopy.setEnabled(true);
}

File diff suppressed because it is too large Load Diff

View File

@@ -16,17 +16,18 @@
package com.m2049r.xmrwallet;
import android.app.Fragment;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.support.annotation.Nullable;
import android.support.constraint.ConstraintLayout;
import android.support.v4.app.Fragment;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
@@ -36,8 +37,8 @@ import android.widget.TextView;
import com.m2049r.xmrwallet.layout.TransactionInfoAdapter;
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 java.text.NumberFormat;
import java.util.List;
@@ -48,14 +49,26 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
private NumberFormat formatter = NumberFormat.getInstance();
TextView tvBalance;
TextView tvUnlockedBalance;
TextView tvUnconfirmedAmount;
TextView tvBlockHeightProgress;
TextView tvConnectionStatus;
LinearLayout llProgress;
ConstraintLayout clProgress;
TextView tvProgress;
ProgressBar pbProgress;
Button bSend;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if (activityCallback.hasWallet())
inflater.inflate(R.menu.wallet_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
@@ -63,20 +76,18 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
tvProgress = (TextView) view.findViewById(R.id.tvProgress);
pbProgress = (ProgressBar) view.findViewById(R.id.pbProgress);
llProgress = (LinearLayout) view.findViewById(R.id.llProgress);
clProgress = (ConstraintLayout) view.findViewById(R.id.clProgress);
tvBalance = (TextView) view.findViewById(R.id.tvBalance);
tvUnlockedBalance = (TextView) view.findViewById(R.id.tvUnlockedBalance);
tvBalance.setText(getResources().getString(R.string.xmr_balance, Helper.getDisplayAmount(0)));
tvUnconfirmedAmount = (TextView) view.findViewById(R.id.tvUnconfirmedAmount);
tvUnconfirmedAmount.setText(getResources().getString(R.string.xmr_unconfirmed_amount, Helper.getDisplayAmount(0)));
tvBlockHeightProgress = (TextView) view.findViewById(R.id.tvBlockHeightProgress);
tvConnectionStatus = (TextView) view.findViewById(R.id.tvConnectionStatus);
bSend = (Button) view.findViewById(R.id.bSend);
RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.list);
RecyclerView.ItemDecoration itemDecoration = new
DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL);
recyclerView.addItemDecoration(itemDecoration);
this.adapter = new TransactionInfoAdapter(this);
this.adapter = new TransactionInfoAdapter(getActivity(), this);
recyclerView.setAdapter(adapter);
bSend.setOnClickListener(new View.OnClickListener()
@@ -144,11 +155,13 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
}
public void showProgress() {
llProgress.setVisibility(View.VISIBLE);
clProgress.setVisibility(View.VISIBLE);
tvBlockHeightProgress.setVisibility(View.GONE);
}
public void hideProgress() {
llProgress.setVisibility(View.GONE);
clProgress.setVisibility(View.GONE);
tvBlockHeightProgress.setVisibility(View.VISIBLE);
}
String setActivityTitle(Wallet wallet) {
@@ -157,10 +170,14 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
if (shortName.length() > 16) {
shortName = shortName.substring(0, 14) + "...";
}
String title = "[" + wallet.getAddress().substring(0, 6) + "] "
+ shortName
+ (wallet.isWatchOnly() ? " " + getString(R.string.watchonly_label) : "");
// TODO very very rarely this craches because getAddress returns "" or so ...
// maybe because this runs in the ui thread and not in a 5MB thread
String title = "[" + wallet.getAddress().substring(0, 6) + "] " + shortName;
activityCallback.setTitle(title);
String watchOnly = (wallet.isWatchOnly() ? " " + getString(R.string.watchonly_label) : "");
String net = (wallet.isTestNet() ? getString(R.string.connect_testnet) : getString(R.string.connect_mainnet));
activityCallback.setSubtitle(net + " " + watchOnly);
Log.d(TAG, "wallet title is " + title);
return title;
}
@@ -174,8 +191,10 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
walletTitle = setActivityTitle(wallet);
onProgress(100); // of loading
}
tvBalance.setText(Wallet.getDisplayAmount(wallet.getBalance()));
tvUnlockedBalance.setText(Wallet.getDisplayAmount(wallet.getUnlockedBalance()));
long balance = wallet.getBalance();
long unlockedBalance = wallet.getUnlockedBalance();
tvBalance.setText(getResources().getString(R.string.xmr_balance, Helper.getDisplayAmount(unlockedBalance)));
tvUnconfirmedAmount.setText(getResources().getString(R.string.xmr_unconfirmed_amount, Helper.getDisplayAmount(balance - unlockedBalance)));
String sync = "";
if (!activityCallback.hasBoundService())
throw new IllegalStateException("WalletService not bound.");
@@ -196,9 +215,10 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
sync = getString(R.string.status_synced) + ": " + formatter.format(wallet.getBlockChainHeight());
}
}
String net = (wallet.isTestNet() ? getString(R.string.connect_testnet) : getString(R.string.connect_mainnet));
tvBlockHeightProgress.setText(sync);
tvConnectionStatus.setText(net + " " + daemonConnected.toString().substring(17));
//String net = (wallet.isTestNet() ? getString(R.string.connect_testnet) : getString(R.string.connect_mainnet));
//activityCallback.setSubtitle(net + " " + daemonConnected.toString().substring(17));
// TODO show connected status somewhere
}
Listener activityCallback;
@@ -215,6 +235,8 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
void setTitle(String title);
void setSubtitle(String subtitle);
void onSendRequest();
void onTxDetailsRequest(TransactionInfo info);
@@ -224,6 +246,10 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
boolean isWatchOnly();
String getTxKey(String txId);
void onWalletReceive();
boolean hasWallet();
}
@Override

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