mirror of
https://github.com/m2049r/xmrwallet
synced 2025-09-08 20:40:51 +02:00
Compare commits
38 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
48dcd37740 | ||
![]() |
8e619756b9 | ||
![]() |
6c6b47db7d | ||
![]() |
a126844272 | ||
![]() |
9b3086ff2e | ||
![]() |
89d1842d59 | ||
![]() |
d44067e952 | ||
![]() |
0370eaa619 | ||
![]() |
35c393495a | ||
![]() |
f19618e017 | ||
![]() |
3a68802ae7 | ||
![]() |
344eeb7a3b | ||
![]() |
4ad58684b4 | ||
![]() |
30e35a895d | ||
![]() |
37414be4bf | ||
![]() |
a37ca4c0e5 | ||
![]() |
408b1a68d0 | ||
![]() |
40da44222e | ||
![]() |
b0efdca928 | ||
![]() |
d61198b47f | ||
![]() |
62433f6e10 | ||
![]() |
c9ae39508f | ||
![]() |
44836a24bb | ||
![]() |
80e60bd0c8 | ||
![]() |
9f38b957e1 | ||
![]() |
032aa24ab5 | ||
![]() |
afc45e1cbc | ||
![]() |
bd598deddd | ||
![]() |
952fb3a7f1 | ||
![]() |
fb62074d20 | ||
![]() |
56132e26ed | ||
![]() |
3239bdeb33 | ||
![]() |
142885821e | ||
![]() |
34941c599a | ||
![]() |
58c8f1896c | ||
![]() |
6611539491 | ||
![]() |
69729e5257 | ||
![]() |
535158c5e9 |
1
.idea/.gitignore
generated
vendored
1
.idea/.gitignore
generated
vendored
@@ -1 +1,2 @@
|
|||||||
workspace.xml
|
workspace.xml
|
||||||
|
markdown-navigator*
|
||||||
|
31
README.md
31
README.md
@@ -3,39 +3,35 @@ Another Android Monero Wallet
|
|||||||
|
|
||||||
### QUICKSTART
|
### QUICKSTART
|
||||||
- Download APK (Release) and install it
|
- Download APK (Release) and install it
|
||||||
- Copy over synced wallet (all three files) onto sdcard in directory Monerujo (created first time app is started)
|
- Run the App and select "Generate Wallet" to create a new wallet or recover a wallet
|
||||||
- Start app (again)
|
- 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)
|
- see the [FAQ](doc/FAQ.md)
|
||||||
|
|
||||||
### Disclaimer
|
### Disclaimer
|
||||||
This is my first serious Android App.
|
You may loose all your Moneroj if you use this App.
|
||||||
|
|
||||||
### Random Notes
|
### Random Notes
|
||||||
- Based off monero v0.10.3.1 with pull requests #2238, #2239 and #2289 applied => so can be used in mainnet!
|
- 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 android32
|
||||||
- currently only use is checking incoming/outgoing transactions
|
- ~~currently only use is checking incoming/outgoing transactions~~
|
||||||
- works in testnet & mainnet (please use your own daemons)
|
- works in testnet & mainnet
|
||||||
- takes forever to sync on mainnet (even with own daemon) - due to 32-bit architecture
|
- takes forever to sync 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
|
- 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
|
||||||
- make it pretty
|
- wallet backup functions
|
||||||
- adjust layout so we can use bigger font sizes (maybe show only 5 decimal places instead of 12 in main view)
|
- 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
|
- review visibility of methods/classes
|
||||||
- sensible error dialogs (e.g. when no write permissions granted) instead of just crashing on purpose
|
- more sensible error dialogs ~~(e.g. when no write permissions granted) instead of just crashing on purpose~~
|
||||||
- spend monero - not so difficult with wallet api
|
|
||||||
- check licenses of included libraries; License Dialog
|
- check licenses of included libraries; License Dialog
|
||||||
- ~~provide detailed build instructions for third party binaries~~
|
- ~~make it pretty~~ (decided to go with "form follows function")
|
||||||
- ~~sensible loading/saving progress bars instead of just freezing up~~
|
- ~~spend monero - not so difficult with wallet api~~
|
||||||
- ~~figure out how to make it all flow better (loading/saving takes forever and does not run in background)~~
|
|
||||||
- ~~currently loading in background thread produces segfaults in JNI~~
|
|
||||||
|
|
||||||
### Issues
|
### Issues
|
||||||
- ~~screen rotation crashes the app~~
|
- Pending incoming transactions disappear after reload
|
||||||
- ~~turning the display off/on during sync stops sync~~
|
|
||||||
|
|
||||||
### HOW TO BUILD
|
### HOW TO BUILD
|
||||||
No need to build. Binaries are included:
|
No need to build. Binaries are included:
|
||||||
@@ -47,3 +43,6 @@ No need to build. Binaries are included:
|
|||||||
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)
|
||||||
|
|
||||||
Then, fire up Android Studio and build the APK.
|
Then, fire up Android Studio and build the APK.
|
||||||
|
|
||||||
|
### Donations
|
||||||
|
4AdkPJoxn7JCvAby9szgnt93MSEwdnxdhaASxbTBm6x5dCwmsDep2UYN4FhStDn5i11nsJbpU7oj59ahg8gXb1Mg3viqCuk
|
||||||
|
1
app/.gitignore
vendored
1
app/.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
.externalNativeBuild
|
.externalNativeBuild
|
||||||
build
|
build
|
||||||
|
app.iml
|
||||||
|
147
app/app.iml
147
app/app.iml
@@ -1,147 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">
|
|
||||||
<component name="FacetManager">
|
|
||||||
<facet type="android-gradle" name="Android-Gradle">
|
|
||||||
<configuration>
|
|
||||||
<option name="GRADLE_PROJECT_PATH" value=":app" />
|
|
||||||
</configuration>
|
|
||||||
</facet>
|
|
||||||
<facet type="native-android-gradle" name="Native-Android-Gradle">
|
|
||||||
<configuration>
|
|
||||||
<option name="SELECTED_BUILD_VARIANT" value="debug" />
|
|
||||||
</configuration>
|
|
||||||
</facet>
|
|
||||||
<facet type="android" name="Android">
|
|
||||||
<configuration>
|
|
||||||
<option name="SELECTED_BUILD_VARIANT" value="debug" />
|
|
||||||
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
|
|
||||||
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
|
|
||||||
<afterSyncTasks>
|
|
||||||
<task>generateDebugSources</task>
|
|
||||||
</afterSyncTasks>
|
|
||||||
<option name="ALLOW_USER_CONFIGURATION" value="false" />
|
|
||||||
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
|
|
||||||
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
|
|
||||||
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
|
|
||||||
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
|
|
||||||
</configuration>
|
|
||||||
</facet>
|
|
||||||
</component>
|
|
||||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false">
|
|
||||||
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
|
|
||||||
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/test/debug" />
|
|
||||||
<exclude-output />
|
|
||||||
<content url="file://$MODULE_DIR$">
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/cpp" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/debug" isTestSource="false" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/androidTest/debug" isTestSource="true" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/jni" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/jni" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/cmake" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-classes" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-runtime-classes" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-safeguard" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-verifier" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant-run-resources" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant-run-support" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/reload-dex" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/restart-dex" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/split-apk" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
|
|
||||||
</content>
|
|
||||||
<orderEntry type="jdk" jdkName="Android API 25 Platform" jdkType="Android SDK" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="runner-0.5" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="espresso-idling-resource-2.2.2" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="constraint-layout-1.0.2" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="hamcrest-library-1.3" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="transition-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="hamcrest-integration-1.3" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="design-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="support-core-ui-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="cardview-v7-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="jsr305-2.0.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="support-core-utils-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="support-fragment-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="espresso-core-2.2.2" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="exposed-instrumentation-api-publish-0.5" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="rules-0.5" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="constraint-layout-solver-1.0.2" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="javax.annotation-api-1.2" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="javax.inject-1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="javawriter-2.1.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="support-v4-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="support-media-compat-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="hamcrest-core-1.3" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="junit-4.12" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="recyclerview-v7-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="support-annotations-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="appcompat-v7-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="support-vector-drawable-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="support-compat-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="animated-vector-drawable-25.3.1" level="project" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
@@ -7,8 +7,8 @@ android {
|
|||||||
applicationId "com.m2049r.xmrwallet"
|
applicationId "com.m2049r.xmrwallet"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 25
|
targetSdkVersion 25
|
||||||
versionCode 3
|
versionCode 5
|
||||||
versionName "0.3.0"
|
versionName "0.4.1"
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
|
@@ -19,14 +19,14 @@
|
|||||||
android:name=".WalletActivity"
|
android:name=".WalletActivity"
|
||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:label="@string/wallet_activity_name"
|
android:label="@string/wallet_activity_name"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTask"
|
||||||
android:screenOrientation="portrait"></activity>
|
android:screenOrientation="portrait" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".LoginActivity"
|
android:name=".LoginActivity"
|
||||||
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait">
|
||||||
android:configChanges="orientation|keyboardHidden">
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
File diff suppressed because it is too large
Load Diff
370
app/src/main/java/com/m2049r/xmrwallet/GenerateFragment.java
Normal file
370
app/src/main/java/com/m2049r/xmrwallet/GenerateFragment.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,166 @@
|
|||||||
|
/*
|
||||||
|
* 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.app.Fragment;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
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 com.m2049r.xmrwallet.model.Wallet;
|
||||||
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
|
import com.m2049r.xmrwallet.service.MoneroHandlerThread;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
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";
|
||||||
|
|
||||||
|
ProgressBar pbProgress;
|
||||||
|
TextView tvWalletName;
|
||||||
|
TextView tvWalletPassword;
|
||||||
|
TextView tvWalletAddress;
|
||||||
|
TextView tvWalletMnemonic;
|
||||||
|
TextView tvWalletViewKey;
|
||||||
|
TextView tvWalletSpendKey;
|
||||||
|
Button bAccept;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
|
||||||
|
View view = inflater.inflate(R.layout.gen_review_fragment, container, false);
|
||||||
|
|
||||||
|
pbProgress = (ProgressBar) view.findViewById(R.id.pbProgress);
|
||||||
|
tvWalletName = (TextView) view.findViewById(R.id.tvWalletName);
|
||||||
|
tvWalletPassword = (TextView) view.findViewById(R.id.tvWalletPassword);
|
||||||
|
tvWalletAddress = (TextView) view.findViewById(R.id.tvWalletAddress);
|
||||||
|
tvWalletViewKey = (TextView) view.findViewById(R.id.tvWalletViewKey);
|
||||||
|
tvWalletSpendKey = (TextView) view.findViewById(R.id.tvWalletSpendKey);
|
||||||
|
tvWalletMnemonic = (TextView) view.findViewById(R.id.tvWalletMnemonic);
|
||||||
|
|
||||||
|
bAccept = (Button) view.findViewById(R.id.bAccept);
|
||||||
|
|
||||||
|
boolean testnet = WalletManager.getInstance().isTestNet();
|
||||||
|
tvWalletMnemonic.setTextIsSelectable(testnet);
|
||||||
|
|
||||||
|
bAccept.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
acceptWallet();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void acceptWallet() {
|
||||||
|
String name = tvWalletName.getText().toString();
|
||||||
|
String password = tvWalletPassword.getText().toString();
|
||||||
|
bAccept.setEnabled(false);
|
||||||
|
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 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);
|
||||||
|
}
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
hideProgress();
|
||||||
|
}
|
||||||
|
|
||||||
|
GenerateReviewFragment.Listener acceptCallback = null;
|
||||||
|
GenerateReviewFragment.ListenerWithWallet walletCallback = null;
|
||||||
|
|
||||||
|
public interface Listener {
|
||||||
|
void onAccept(String name, String password);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ListenerWithWallet {
|
||||||
|
Wallet getWallet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Context context) {
|
||||||
|
super.onAttach(context);
|
||||||
|
if (context instanceof GenerateReviewFragment.Listener) {
|
||||||
|
this.acceptCallback = (GenerateReviewFragment.Listener) context;
|
||||||
|
} else if (context instanceof GenerateReviewFragment.ListenerWithWallet) {
|
||||||
|
this.walletCallback = (GenerateReviewFragment.ListenerWithWallet) context;
|
||||||
|
} else {
|
||||||
|
throw new ClassCastException(context.toString()
|
||||||
|
+ " must implement Listener");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showProgress() {
|
||||||
|
pbProgress.setIndeterminate(true);
|
||||||
|
pbProgress.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void hideProgress() {
|
||||||
|
pbProgress.setVisibility(View.INVISIBLE);
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
369
app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java
Normal file
369
app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java
Normal file
File diff suppressed because it is too large
Load Diff
379
app/src/main/java/com/m2049r/xmrwallet/SendFragment.java
Normal file
379
app/src/main/java/com/m2049r/xmrwallet/SendFragment.java
Normal file
File diff suppressed because it is too large
Load Diff
248
app/src/main/java/com/m2049r/xmrwallet/TxFragment.java
Normal file
248
app/src/main/java/com/m2049r/xmrwallet/TxFragment.java
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
/*
|
||||||
|
* 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.app.Fragment;
|
||||||
|
import android.content.ClipData;
|
||||||
|
import android.content.ClipboardManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
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.TimeZone;
|
||||||
|
|
||||||
|
public class TxFragment extends Fragment {
|
||||||
|
static final String TAG = "TxFragment";
|
||||||
|
|
||||||
|
static public final String ARG_INFO = "info";
|
||||||
|
|
||||||
|
private final SimpleDateFormat TS_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
|
public TxFragment() {
|
||||||
|
super();
|
||||||
|
Calendar cal = Calendar.getInstance();
|
||||||
|
TimeZone tz = cal.getTimeZone(); //get the local time zone.
|
||||||
|
TS_FORMATTER.setTimeZone(tz);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextView tvTxTimestamp;
|
||||||
|
TextView tvTxId;
|
||||||
|
TextView tvTxKey;
|
||||||
|
TextView tvTxPaymentId;
|
||||||
|
TextView tvTxBlockheight;
|
||||||
|
TextView tvTxAmount;
|
||||||
|
TextView tvTxFee;
|
||||||
|
TextView tvTxTransfers;
|
||||||
|
TextView etTxNotes;
|
||||||
|
Button bCopy;
|
||||||
|
Button bTxNotes;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
|
||||||
|
View view = inflater.inflate(R.layout.tx_fragment, container, false);
|
||||||
|
|
||||||
|
tvTxTimestamp = (TextView) view.findViewById(R.id.tvTxTimestamp);
|
||||||
|
tvTxId = (TextView) view.findViewById(R.id.tvTxId);
|
||||||
|
tvTxKey = (TextView) view.findViewById(R.id.tvTxKey);
|
||||||
|
tvTxPaymentId = (TextView) view.findViewById(R.id.tvTxPaymentId);
|
||||||
|
tvTxBlockheight = (TextView) view.findViewById(R.id.tvTxBlockheight);
|
||||||
|
tvTxAmount = (TextView) view.findViewById(R.id.tvTxAmount);
|
||||||
|
tvTxFee = (TextView) view.findViewById(R.id.tvTxFee);
|
||||||
|
tvTxTransfers = (TextView) view.findViewById(R.id.tvTxTransfers);
|
||||||
|
etTxNotes = (TextView) view.findViewById(R.id.etTxNotes);
|
||||||
|
bCopy = (Button) view.findViewById(R.id.bCopy);
|
||||||
|
bTxNotes = (Button) view.findViewById(R.id.bTxNotes);
|
||||||
|
|
||||||
|
etTxNotes.setRawInputType(InputType.TYPE_CLASS_TEXT);
|
||||||
|
|
||||||
|
bCopy.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
copyToClipboard();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bTxNotes.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
info.notes = null; // force reload on next view
|
||||||
|
bTxNotes.setEnabled(false);
|
||||||
|
etTxNotes.setEnabled(false);
|
||||||
|
activityCallback.onSetNote(info.hash, etTxNotes.getText().toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Bundle args = getArguments();
|
||||||
|
TransactionInfo info = args.getParcelable(ARG_INFO);
|
||||||
|
show(info);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onNotesSet(boolean reload) {
|
||||||
|
bTxNotes.setEnabled(true);
|
||||||
|
etTxNotes.setEnabled(true);
|
||||||
|
if (reload) {
|
||||||
|
loadNotes(this.info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void copyToClipboard() {
|
||||||
|
if (this.info == null) return;
|
||||||
|
StringBuffer sb = new StringBuffer();
|
||||||
|
sb.append(getString(R.string.tx_address)).append(": ");
|
||||||
|
sb.append(activityCallback.getWalletAddress()).append("\n");
|
||||||
|
sb.append(getString(R.string.tx_id)).append(": ");
|
||||||
|
sb.append(info.hash).append("\n");
|
||||||
|
sb.append(getString(R.string.tx_key)).append(": ");
|
||||||
|
sb.append(info.txKey.isEmpty() ? "-" : info.txKey).append("\n");
|
||||||
|
sb.append(getString(R.string.tx_paymentId)).append(": ");
|
||||||
|
sb.append(info.paymentId).append("\n");
|
||||||
|
sb.append(getString(R.string.tx_amount)).append(": ");
|
||||||
|
sb.append((info.direction == TransactionInfo.Direction.Direction_In ? "+" : "-"));
|
||||||
|
sb.append(Wallet.getDisplayAmount(info.amount)).append("\n");
|
||||||
|
sb.append(getString(R.string.tx_fee)).append(": ");
|
||||||
|
sb.append(Wallet.getDisplayAmount(info.fee)).append("\n");
|
||||||
|
sb.append(getString(R.string.tx_notes)).append(": ");
|
||||||
|
String oneLineNotes = info.notes.replace("\n", " ; ");
|
||||||
|
sb.append(oneLineNotes.isEmpty() ? "-" : oneLineNotes).append("\n");
|
||||||
|
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) {
|
||||||
|
sb.append(getString(R.string.tx_failed)).append("\n");
|
||||||
|
} else {
|
||||||
|
sb.append(info.blockheight).append("\n");
|
||||||
|
}
|
||||||
|
sb.append(getString(R.string.tx_transfers)).append(": ");
|
||||||
|
if (info.transfers != null) {
|
||||||
|
boolean comma = false;
|
||||||
|
for (Transfer transfer : info.transfers) {
|
||||||
|
if (comma) {
|
||||||
|
sb.append(",");
|
||||||
|
} else {
|
||||||
|
comma = true;
|
||||||
|
}
|
||||||
|
sb.append("[").append(transfer.address.substring(0, 6)).append("] ");
|
||||||
|
sb.append(Wallet.getDisplayAmount(transfer.amount));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sb.append("-");
|
||||||
|
}
|
||||||
|
sb.append("\n");
|
||||||
|
ClipboardManager clipboardManager = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
|
||||||
|
ClipData clip = ClipData.newPlainText(getString(R.string.tx_copy_label), sb.toString());
|
||||||
|
clipboardManager.setPrimaryClip(clip);
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.tx_copy_message), Toast.LENGTH_SHORT).show();
|
||||||
|
//Log.d(TAG, sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TransactionInfo info = null;
|
||||||
|
|
||||||
|
void loadNotes(TransactionInfo info) {
|
||||||
|
if (info.notes == null) {
|
||||||
|
info.notes = activityCallback.getTxNotes(info.hash);
|
||||||
|
//Log.d(TAG, "NOTES:" + info.notes + ":");
|
||||||
|
}
|
||||||
|
etTxNotes.setText(info.notes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void show(TransactionInfo info) {
|
||||||
|
if (info.txKey == null) {
|
||||||
|
info.txKey = activityCallback.getTxKey(info.hash);
|
||||||
|
//Log.d(TAG, "TXKEY:" + info.txKey + ":");
|
||||||
|
}
|
||||||
|
loadNotes(info);
|
||||||
|
tvTxTimestamp.setText(TS_FORMATTER.format(new Date(info.timestamp * 1000)));
|
||||||
|
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) {
|
||||||
|
tvTxBlockheight.setText(getString(R.string.tx_failed));
|
||||||
|
} 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));
|
||||||
|
StringBuffer sb = new StringBuffer();
|
||||||
|
if (info.transfers != null) {
|
||||||
|
boolean newline = false;
|
||||||
|
for (Transfer transfer : info.transfers) {
|
||||||
|
if (newline) {
|
||||||
|
sb.append("\n");
|
||||||
|
} else {
|
||||||
|
newline = true;
|
||||||
|
}
|
||||||
|
sb.append("[").append(transfer.address.substring(0, 6)).append("] ");
|
||||||
|
sb.append(Wallet.getDisplayAmount(transfer.amount));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sb.append("-");
|
||||||
|
}
|
||||||
|
tvTxTransfers.setText(sb.toString());
|
||||||
|
this.info = info;
|
||||||
|
bCopy.setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TxFragment.Listener activityCallback;
|
||||||
|
|
||||||
|
public interface Listener {
|
||||||
|
String getWalletAddress();
|
||||||
|
|
||||||
|
String getTxKey(String hash);
|
||||||
|
|
||||||
|
String getTxNotes(String hash);
|
||||||
|
|
||||||
|
void onSetNote(String txId, String notes);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Context context) {
|
||||||
|
super.onAttach(context);
|
||||||
|
if (context instanceof TxFragment.Listener) {
|
||||||
|
this.activityCallback = (TxFragment.Listener) context;
|
||||||
|
} else {
|
||||||
|
throw new ClassCastException(context.toString()
|
||||||
|
+ " must implement Listener");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
240
app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java
Normal file
240
app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
/*
|
||||||
|
* 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.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.v7.widget.DividerItemDecoration;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
|
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.model.WalletManager;
|
||||||
|
|
||||||
|
import java.text.NumberFormat;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class WalletFragment extends Fragment implements TransactionInfoAdapter.OnInteractionListener {
|
||||||
|
private static final String TAG = "WalletFragment";
|
||||||
|
private TransactionInfoAdapter adapter;
|
||||||
|
private NumberFormat formatter = NumberFormat.getInstance();
|
||||||
|
|
||||||
|
TextView tvBalance;
|
||||||
|
TextView tvUnlockedBalance;
|
||||||
|
TextView tvBlockHeightProgress;
|
||||||
|
TextView tvConnectionStatus;
|
||||||
|
LinearLayout llProgress;
|
||||||
|
TextView tvProgress;
|
||||||
|
ProgressBar pbProgress;
|
||||||
|
Button bSend;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.wallet_fragment, container, false);
|
||||||
|
|
||||||
|
tvProgress = (TextView) view.findViewById(R.id.tvProgress);
|
||||||
|
pbProgress = (ProgressBar) view.findViewById(R.id.pbProgress);
|
||||||
|
llProgress = (LinearLayout) view.findViewById(R.id.llProgress);
|
||||||
|
tvBalance = (TextView) view.findViewById(R.id.tvBalance);
|
||||||
|
tvUnlockedBalance = (TextView) view.findViewById(R.id.tvUnlockedBalance);
|
||||||
|
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);
|
||||||
|
recyclerView.setAdapter(adapter);
|
||||||
|
|
||||||
|
bSend.setOnClickListener(new View.OnClickListener()
|
||||||
|
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
activityCallback.onSendRequest();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (activityCallback.isSynced()) {
|
||||||
|
onSynced();
|
||||||
|
}
|
||||||
|
|
||||||
|
// activityCallback.setTitle(getString(R.string.status_wallet_loading));
|
||||||
|
|
||||||
|
activityCallback.forceUpdate();
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callbacks from TransactionInfoAdapter
|
||||||
|
@Override
|
||||||
|
public void onInteraction(final View view, final TransactionInfo infoItem) {
|
||||||
|
activityCallback.onTxDetailsRequest(infoItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
// called from activity
|
||||||
|
public void onRefreshed(final Wallet wallet, final boolean full) {
|
||||||
|
Log.d(TAG, "onRefreshed()");
|
||||||
|
if (full) {
|
||||||
|
List<TransactionInfo> list = wallet.getHistory().getAll();
|
||||||
|
adapter.setInfos(list);
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
updateStatus(wallet);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onSynced() {
|
||||||
|
if (!activityCallback.isWatchOnly() && WalletManager.getInstance().isTestNet()) {
|
||||||
|
bSend.setVisibility(View.VISIBLE);
|
||||||
|
bSend.setEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onProgress(final String text) {
|
||||||
|
if (text != null) {
|
||||||
|
tvProgress.setText(text);
|
||||||
|
showProgress();
|
||||||
|
} else {
|
||||||
|
hideProgress();
|
||||||
|
tvProgress.setText(getString(R.string.status_working));
|
||||||
|
onProgress(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onProgress(final int n) {
|
||||||
|
if (n >= 0) {
|
||||||
|
pbProgress.setIndeterminate(false);
|
||||||
|
pbProgress.setProgress(n);
|
||||||
|
} else {
|
||||||
|
pbProgress.setIndeterminate(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showProgress() {
|
||||||
|
llProgress.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void hideProgress() {
|
||||||
|
llProgress.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
String setActivityTitle(Wallet wallet) {
|
||||||
|
if (wallet == null) return null;
|
||||||
|
String shortName = wallet.getName();
|
||||||
|
if (shortName.length() > 16) {
|
||||||
|
shortName = shortName.substring(0, 14) + "...";
|
||||||
|
}
|
||||||
|
String title = "[" + wallet.getAddress().substring(0, 6) + "] "
|
||||||
|
+ shortName
|
||||||
|
+ (wallet.isWatchOnly() ? " " + getString(R.string.watchonly_label) : "");
|
||||||
|
activityCallback.setTitle(title);
|
||||||
|
Log.d(TAG, "wallet title is " + title);
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long firstBlock = 0;
|
||||||
|
private String walletTitle = null;
|
||||||
|
|
||||||
|
private void updateStatus(Wallet wallet) {
|
||||||
|
Log.d(TAG, "updateStatus()");
|
||||||
|
if (walletTitle == null) {
|
||||||
|
walletTitle = setActivityTitle(wallet);
|
||||||
|
onProgress(100); // of loading
|
||||||
|
}
|
||||||
|
tvBalance.setText(Wallet.getDisplayAmount(wallet.getBalance()));
|
||||||
|
tvUnlockedBalance.setText(Wallet.getDisplayAmount(wallet.getUnlockedBalance()));
|
||||||
|
String sync = "";
|
||||||
|
if (!activityCallback.hasBoundService())
|
||||||
|
throw new IllegalStateException("WalletService not bound.");
|
||||||
|
Wallet.ConnectionStatus daemonConnected = activityCallback.getConnectionStatus();
|
||||||
|
if (daemonConnected == Wallet.ConnectionStatus.ConnectionStatus_Connected) {
|
||||||
|
long daemonHeight = activityCallback.getDaemonHeight();
|
||||||
|
if (!wallet.isSynchronized()) {
|
||||||
|
long n = daemonHeight - wallet.getBlockChainHeight();
|
||||||
|
sync = formatter.format(n) + " " + getString(R.string.status_remaining);
|
||||||
|
if (firstBlock == 0) {
|
||||||
|
firstBlock = wallet.getBlockChainHeight();
|
||||||
|
}
|
||||||
|
int x = 100 - Math.round(100f * n / (1f * daemonHeight - firstBlock));
|
||||||
|
onProgress(getString(R.string.status_syncing) + " " + sync);
|
||||||
|
if (x == 0) x = -1;
|
||||||
|
onProgress(x);
|
||||||
|
} else {
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
Listener activityCallback;
|
||||||
|
|
||||||
|
// Container Activity must implement this interface
|
||||||
|
public interface Listener {
|
||||||
|
boolean hasBoundService();
|
||||||
|
|
||||||
|
void forceUpdate();
|
||||||
|
|
||||||
|
Wallet.ConnectionStatus getConnectionStatus();
|
||||||
|
|
||||||
|
long getDaemonHeight(); //mBoundService.getDaemonHeight();
|
||||||
|
|
||||||
|
void setTitle(String title);
|
||||||
|
|
||||||
|
void onSendRequest();
|
||||||
|
|
||||||
|
void onTxDetailsRequest(TransactionInfo info);
|
||||||
|
|
||||||
|
boolean isSynced();
|
||||||
|
|
||||||
|
boolean isWatchOnly();
|
||||||
|
|
||||||
|
String getTxKey(String txId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Context context) {
|
||||||
|
super.onAttach(context);
|
||||||
|
if (context instanceof Listener) {
|
||||||
|
this.activityCallback = (Listener) context;
|
||||||
|
} else {
|
||||||
|
throw new ClassCastException(context.toString()
|
||||||
|
+ " must implement Listener");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -40,11 +40,13 @@ import java.util.TimeZone;
|
|||||||
public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfoAdapter.ViewHolder> {
|
public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfoAdapter.ViewHolder> {
|
||||||
private static final String TAG = "TransactionInfoAdapter";
|
private static final String TAG = "TransactionInfoAdapter";
|
||||||
|
|
||||||
private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyy-MM-dd");
|
private final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyy-MM-dd");
|
||||||
private static final SimpleDateFormat TIME_FORMATTER = new SimpleDateFormat("HH:mm:ss");
|
private final SimpleDateFormat TIME_FORMATTER = new SimpleDateFormat("HH:mm:ss");
|
||||||
|
|
||||||
static final int TX_RED = Color.rgb(255, 79, 65);
|
static final int TX_RED = Color.rgb(255, 79, 65);
|
||||||
static final int TX_GREEN = Color.rgb(54, 176, 91);
|
static final int TX_GREEN = Color.rgb(54, 176, 91);
|
||||||
|
static final int TX_PENDING = Color.rgb(72, 53, 176);
|
||||||
|
static final int TX_FAILED = Color.rgb(208, 0, 255);
|
||||||
|
|
||||||
public interface OnInteractionListener {
|
public interface OnInteractionListener {
|
||||||
void onInteraction(View view, TransactionInfo item);
|
void onInteraction(View view, TransactionInfo item);
|
||||||
@@ -81,6 +83,7 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
|||||||
|
|
||||||
public void setInfos(List<TransactionInfo> data) {
|
public void setInfos(List<TransactionInfo> data) {
|
||||||
// TODO do stuff with data so we can really recycle elements (i.e. add only new tx)
|
// TODO do stuff with data so we can really recycle elements (i.e. add only new tx)
|
||||||
|
// as the TransactionInfo items are always recreated, we cannot recycle
|
||||||
this.infoItems.clear();
|
this.infoItems.clear();
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
Log.d(TAG, "setInfos " + data.size());
|
Log.d(TAG, "setInfos " + data.size());
|
||||||
@@ -88,8 +91,15 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
|||||||
Collections.sort(data, new Comparator<TransactionInfo>() {
|
Collections.sort(data, new Comparator<TransactionInfo>() {
|
||||||
@Override
|
@Override
|
||||||
public int compare(TransactionInfo o1, TransactionInfo o2) {
|
public int compare(TransactionInfo o1, TransactionInfo o2) {
|
||||||
long b1 = o1.getBlockHeight();
|
if ((o1.isPending) && (o2.isPending)) {
|
||||||
long b2 = o2.getBlockHeight();
|
long b1 = o1.timestamp;
|
||||||
|
long b2 = o2.timestamp;
|
||||||
|
return (b1 > b2) ? -1 : (b1 < b2) ? 1 : 0;
|
||||||
|
}
|
||||||
|
if (o1.isPending) return -1;
|
||||||
|
if (o2.isPending) return 1;
|
||||||
|
long b1 = o1.blockheight;
|
||||||
|
long b2 = o2.blockheight;
|
||||||
return (b1 > b2) ? -1 : (b1 < b2) ? 1 : 0;
|
return (b1 > b2) ? -1 : (b1 < b2) ? 1 : 0;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -134,20 +144,28 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
|||||||
|
|
||||||
void bind(int position) {
|
void bind(int position) {
|
||||||
this.infoItem = infoItems.get(position);
|
this.infoItem = infoItems.get(position);
|
||||||
String displayAmount = Wallet.getDisplayAmount(infoItem.getAmount());
|
String displayAmount = Wallet.getDisplayAmount(infoItem.amount);
|
||||||
// TODO fix this with i8n code
|
// TODO fix this with i8n code but cryptonote::print_money always uses '.' for decimal point
|
||||||
String amountParts[] = displayAmount.split("\\.");
|
String amountParts[] = displayAmount.split("\\.");
|
||||||
// TODO what if there is no decimal point?
|
|
||||||
|
|
||||||
this.tvAmount.setText(amountParts[0]);
|
this.tvAmount.setText(amountParts[0]);
|
||||||
this.tvAmountDecimal.setText(amountParts[1]);
|
this.tvAmountDecimal.setText(amountParts[1]);
|
||||||
if (infoItem.getDirection() == TransactionInfo.Direction.Direction_In) {
|
if (infoItem.isPending) {
|
||||||
|
setTxColour(TX_PENDING);
|
||||||
|
if (infoItem.direction == TransactionInfo.Direction.Direction_Out) {
|
||||||
|
this.tvAmount.setText('-' + amountParts[0]);
|
||||||
|
}
|
||||||
|
} else if (infoItem.isFailed) {
|
||||||
|
this.tvAmount.setText('(' + amountParts[0]);
|
||||||
|
this.tvAmountDecimal.setText(amountParts[1] + ')');
|
||||||
|
setTxColour(TX_FAILED);
|
||||||
|
} else if (infoItem.direction == TransactionInfo.Direction.Direction_In) {
|
||||||
setTxColour(TX_GREEN);
|
setTxColour(TX_GREEN);
|
||||||
} else {
|
} else {
|
||||||
setTxColour(TX_RED);
|
setTxColour(TX_RED);
|
||||||
}
|
}
|
||||||
this.tvDate.setText(getDate(infoItem.getTimestamp()));
|
this.tvDate.setText(getDate(infoItem.timestamp));
|
||||||
this.tvTime.setText(getTime(infoItem.getTimestamp()));
|
this.tvTime.setText(getTime(infoItem.timestamp));
|
||||||
|
|
||||||
itemView.setOnClickListener(this);
|
itemView.setOnClickListener(this);
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* 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.model;
|
||||||
|
|
||||||
|
public class PendingTransaction {
|
||||||
|
static {
|
||||||
|
System.loadLibrary("monerujo");
|
||||||
|
}
|
||||||
|
|
||||||
|
public long handle;
|
||||||
|
|
||||||
|
PendingTransaction(long handle) {
|
||||||
|
this.handle = handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Status {
|
||||||
|
Status_Ok,
|
||||||
|
Status_Error,
|
||||||
|
Status_Critical
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Priority {
|
||||||
|
Priority_Low(1),
|
||||||
|
Priority_Medium(2),
|
||||||
|
Priority_High(3),
|
||||||
|
Priority_Last(4);
|
||||||
|
|
||||||
|
public static Priority fromInteger(int n) {
|
||||||
|
switch (n) {
|
||||||
|
case 1:
|
||||||
|
return Priority_Low;
|
||||||
|
case 2:
|
||||||
|
return Priority_Medium;
|
||||||
|
case 3:
|
||||||
|
return Priority_High;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int value;
|
||||||
|
|
||||||
|
Priority(int value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Status getStatus() {
|
||||||
|
return Status.values()[getStatusJ()];
|
||||||
|
}
|
||||||
|
|
||||||
|
public native int getStatusJ();
|
||||||
|
|
||||||
|
public native String getErrorString();
|
||||||
|
|
||||||
|
// commit transaction or save to file if filename is provided.
|
||||||
|
public native boolean commit(String filename, boolean overwrite);
|
||||||
|
|
||||||
|
public native long getAmount();
|
||||||
|
|
||||||
|
public native long getDust();
|
||||||
|
|
||||||
|
public native long getFee();
|
||||||
|
|
||||||
|
public native String getFirstTxId();
|
||||||
|
|
||||||
|
public native long getTxCount();
|
||||||
|
|
||||||
|
}
|
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.m2049r.xmrwallet.model;
|
package com.m2049r.xmrwallet.model;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class TransactionHistory {
|
public class TransactionHistory {
|
||||||
@@ -29,34 +30,22 @@ public class TransactionHistory {
|
|||||||
this.handle = handle;
|
this.handle = handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TransactionInfo getTransaction(int i) {
|
|
||||||
long infoHandle = getTransactionByIndexJ(i);
|
|
||||||
return new TransactionInfo(infoHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TransactionInfo getTransaction(String id) {
|
|
||||||
long infoHandle = getTransactionByIdJ(id);
|
|
||||||
return new TransactionInfo(infoHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
public List<TransactionInfo> getAll() {
|
|
||||||
List<Long> handles = getAllJ();
|
|
||||||
List<TransactionInfo> infoList = new ArrayList<TransactionInfo>();
|
|
||||||
for (Long handle : handles) {
|
|
||||||
infoList.add(new TransactionInfo(handle.longValue()));
|
|
||||||
}
|
|
||||||
return infoList;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
public native int getCount();
|
public native int getCount();
|
||||||
|
|
||||||
private native long getTransactionByIndexJ(int i);
|
//private native long getTransactionByIndexJ(int i);
|
||||||
|
|
||||||
private native long getTransactionByIdJ(String id);
|
//private native long getTransactionByIdJ(String id);
|
||||||
|
|
||||||
public native List<TransactionInfo> getAll();
|
public List<TransactionInfo> getAll() {
|
||||||
|
return transactions;
|
||||||
|
}
|
||||||
|
|
||||||
public native void refresh();
|
private List<TransactionInfo> transactions = new ArrayList<>();
|
||||||
|
|
||||||
|
public void refresh() {
|
||||||
|
transactions = refreshJ();
|
||||||
|
}
|
||||||
|
|
||||||
|
private native List<TransactionInfo> refreshJ();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -16,79 +16,134 @@
|
|||||||
|
|
||||||
package com.m2049r.xmrwallet.model;
|
package com.m2049r.xmrwallet.model;
|
||||||
|
|
||||||
public class TransactionInfo {
|
import android.os.Parcel;
|
||||||
static {
|
import android.os.Parcelable;
|
||||||
System.loadLibrary("monerujo");
|
import android.util.Log;
|
||||||
}
|
|
||||||
|
|
||||||
public long handle;
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
TransactionInfo(long handle) {
|
// this is not the TransactionInfo from the API as that is owned by the TransactionHistory
|
||||||
this.handle = handle;
|
// this is a POJO for the TransactionInfoAdapter
|
||||||
}
|
public class TransactionInfo implements Parcelable {
|
||||||
|
static final String TAG = "TransactionInfo";
|
||||||
|
|
||||||
public enum Direction {
|
public enum Direction {
|
||||||
Direction_In,
|
Direction_In(0),
|
||||||
Direction_Out
|
Direction_Out(1);
|
||||||
}
|
|
||||||
|
|
||||||
public class Transfer {
|
public static Direction fromInteger(int n) {
|
||||||
long amount;
|
switch (n) {
|
||||||
String address;
|
case 0:
|
||||||
|
return Direction_In;
|
||||||
public Transfer(long amount, String address) {
|
case 1:
|
||||||
this.amount = amount;
|
return Direction_Out;
|
||||||
this.address = address;
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getAmount() {
|
public int getValue() {
|
||||||
return amount;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAddress() {
|
private int value;
|
||||||
return address;
|
|
||||||
|
Direction(int value) {
|
||||||
|
this.value = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Direction direction;
|
||||||
|
public boolean isPending;
|
||||||
|
public boolean isFailed;
|
||||||
|
public long amount;
|
||||||
|
public long fee;
|
||||||
|
public long blockheight;
|
||||||
|
public String hash;
|
||||||
|
public long timestamp;
|
||||||
|
public String paymentId;
|
||||||
|
public long confirmations;
|
||||||
|
public List<Transfer> transfers;
|
||||||
|
|
||||||
|
public String txKey = null;
|
||||||
|
public String notes = null;
|
||||||
|
|
||||||
|
public TransactionInfo(
|
||||||
|
int direction,
|
||||||
|
boolean isPending,
|
||||||
|
boolean isFailed,
|
||||||
|
long amount,
|
||||||
|
long fee,
|
||||||
|
long blockheight,
|
||||||
|
String hash,
|
||||||
|
long timestamp,
|
||||||
|
String paymentId,
|
||||||
|
long confirmations,
|
||||||
|
List<Transfer> transfers) {
|
||||||
|
this.direction = Direction.values()[direction];
|
||||||
|
this.isPending = isPending;
|
||||||
|
this.isFailed = isFailed;
|
||||||
|
this.amount = amount;
|
||||||
|
this.fee = fee;
|
||||||
|
this.blockheight = blockheight;
|
||||||
|
this.hash = hash;
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
this.paymentId = paymentId;
|
||||||
|
this.confirmations = confirmations;
|
||||||
|
this.transfers = transfers;
|
||||||
|
}
|
||||||
|
Random rnd = new Random();
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return getDirection() + "@" + getBlockHeight() + " " + getAmount();
|
return direction + "@" + blockheight + " " + amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Direction getDirection() {
|
@Override
|
||||||
return TransactionInfo.Direction.values()[getDirectionJ()];
|
public void writeToParcel(Parcel out, int flags) {
|
||||||
|
out.writeInt(direction.getValue());
|
||||||
|
out.writeByte((byte) (isPending ? 1 : 0));
|
||||||
|
out.writeByte((byte) (isFailed ? 1 : 0));
|
||||||
|
out.writeLong(amount);
|
||||||
|
out.writeLong(fee);
|
||||||
|
out.writeLong(blockheight);
|
||||||
|
out.writeString(hash);
|
||||||
|
out.writeLong(timestamp);
|
||||||
|
out.writeString(paymentId);
|
||||||
|
out.writeLong(confirmations);
|
||||||
|
out.writeList(transfers);
|
||||||
|
out.writeString(txKey);
|
||||||
|
out.writeString(notes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public native int getDirectionJ();
|
public static final Parcelable.Creator<TransactionInfo> CREATOR = new Parcelable.Creator<TransactionInfo>() {
|
||||||
|
public TransactionInfo createFromParcel(Parcel in) {
|
||||||
public native boolean isPending();
|
return new TransactionInfo(in);
|
||||||
|
|
||||||
public native boolean isFailed();
|
|
||||||
|
|
||||||
public native long getAmount();
|
|
||||||
|
|
||||||
public native long getFee();
|
|
||||||
|
|
||||||
public native long getBlockHeight();
|
|
||||||
|
|
||||||
public native long getConfirmations();
|
|
||||||
|
|
||||||
public native String getHash();
|
|
||||||
|
|
||||||
public native long getTimestamp();
|
|
||||||
|
|
||||||
public native String getPaymentId();
|
|
||||||
|
|
||||||
/*
|
|
||||||
private List<Transfer> transfers;
|
|
||||||
|
|
||||||
public List<Transfer> getTransfers() { // not threadsafe
|
|
||||||
if (this.transfers == null) {
|
|
||||||
this.transfers = getTransfersJ();
|
|
||||||
}
|
}
|
||||||
return this.transfers;
|
|
||||||
|
public TransactionInfo[] newArray(int size) {
|
||||||
|
return new TransactionInfo[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private TransactionInfo(Parcel in) {
|
||||||
|
direction = Direction.fromInteger(in.readInt());
|
||||||
|
isPending = in.readByte() != 0;
|
||||||
|
isFailed = in.readByte() != 0;
|
||||||
|
amount = in.readLong();
|
||||||
|
fee = in.readLong();
|
||||||
|
blockheight = in.readLong();
|
||||||
|
hash = in.readString();
|
||||||
|
timestamp = in.readLong();
|
||||||
|
paymentId = in.readString();
|
||||||
|
confirmations = in.readLong();
|
||||||
|
transfers = in.readArrayList(Transfer.class.getClassLoader());
|
||||||
|
txKey = in.readString();
|
||||||
|
notes = in.readString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private native List<Transfer> getTransfersJ();
|
@Override
|
||||||
*/
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
59
app/src/main/java/com/m2049r/xmrwallet/model/Transfer.java
Normal file
59
app/src/main/java/com/m2049r/xmrwallet/model/Transfer.java
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* 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.model;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.util.TxData;
|
||||||
|
|
||||||
|
public class Transfer implements Parcelable {
|
||||||
|
public long amount;
|
||||||
|
public String address;
|
||||||
|
|
||||||
|
public Transfer(long amount, String address) {
|
||||||
|
this.amount = amount;
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel out, int flags) {
|
||||||
|
out.writeLong(amount);
|
||||||
|
out.writeString(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Parcelable.Creator<Transfer> CREATOR = new Parcelable.Creator<Transfer>() {
|
||||||
|
public Transfer createFromParcel(Parcel in) {
|
||||||
|
return new Transfer(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Transfer[] newArray(int size) {
|
||||||
|
return new Transfer[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private Transfer(Parcel in) {
|
||||||
|
amount = in.readLong();
|
||||||
|
address = in.readString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -28,8 +28,7 @@ public class Wallet {
|
|||||||
static final String TAG = "Wallet";
|
static final String TAG = "Wallet";
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
String p = getPath();
|
return new File(getPath()).getName();
|
||||||
return new File(p).getName();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private long handle = 0;
|
private long handle = 0;
|
||||||
@@ -83,12 +82,13 @@ public class Wallet {
|
|||||||
public native String getSecretViewKey();
|
public native String getSecretViewKey();
|
||||||
|
|
||||||
public boolean store() {
|
public boolean store() {
|
||||||
return store(this.getPath());
|
return store("");
|
||||||
}
|
}
|
||||||
|
|
||||||
public native boolean store(String path);
|
public native boolean store(String path);
|
||||||
|
|
||||||
public boolean close() {
|
public boolean close() {
|
||||||
|
disposePendingTransaction();
|
||||||
return WalletManager.getInstance().close(this);
|
return WalletManager.getInstance().close(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,15 +162,47 @@ public class Wallet {
|
|||||||
//TODO virtual int autoRefreshInterval() const = 0;
|
//TODO virtual int autoRefreshInterval() const = 0;
|
||||||
|
|
||||||
|
|
||||||
//virtual PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id,
|
private PendingTransaction pendingTransaction = null;
|
||||||
// optional<uint64_t> tvAmount, uint32_t mixin_count,
|
|
||||||
// PendingTransaction::Priority = PendingTransaction::Priority_Low) = 0;
|
|
||||||
|
|
||||||
//virtual PendingTransaction * createSweepUnmixableTransaction() = 0;
|
public PendingTransaction getPendingTransaction() {
|
||||||
|
return pendingTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disposePendingTransaction() {
|
||||||
|
if (pendingTransaction != null) {
|
||||||
|
disposeTransaction(pendingTransaction);
|
||||||
|
pendingTransaction = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PendingTransaction createTransaction(String dst_addr, String payment_id,
|
||||||
|
long amount, int mixin_count,
|
||||||
|
PendingTransaction.Priority priority) {
|
||||||
|
disposePendingTransaction();
|
||||||
|
long txHandle = createTransactionJ(dst_addr, payment_id, amount, mixin_count, priority);
|
||||||
|
pendingTransaction = new PendingTransaction(txHandle);
|
||||||
|
return pendingTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
private native long createTransactionJ(String dst_addr, String payment_id,
|
||||||
|
long mount, int mixin_count,
|
||||||
|
PendingTransaction.Priority priority);
|
||||||
|
|
||||||
|
|
||||||
|
public PendingTransaction createSweepUnmixableTransaction() {
|
||||||
|
disposePendingTransaction();
|
||||||
|
long txHandle = createSweepUnmixableTransactionJ();
|
||||||
|
pendingTransaction = new PendingTransaction(txHandle);
|
||||||
|
return pendingTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
private native long createSweepUnmixableTransactionJ();
|
||||||
|
|
||||||
//virtual UnsignedTransaction * loadUnsignedTx(const std::string &unsigned_filename) = 0;
|
//virtual UnsignedTransaction * loadUnsignedTx(const std::string &unsigned_filename) = 0;
|
||||||
//virtual bool submitTransaction(const std::string &fileName) = 0;
|
//virtual bool submitTransaction(const std::string &fileName) = 0;
|
||||||
//virtual void disposeTransaction(PendingTransaction * t) = 0;
|
|
||||||
|
public native void disposeTransaction(PendingTransaction pendingTransaction);
|
||||||
|
|
||||||
//virtual bool exportKeyImages(const std::string &filename) = 0;
|
//virtual bool exportKeyImages(const std::string &filename) = 0;
|
||||||
//virtual bool importKeyImages(const std::string &filename) = 0;
|
//virtual bool importKeyImages(const std::string &filename) = 0;
|
||||||
|
|
||||||
@@ -201,9 +233,10 @@ public class Wallet {
|
|||||||
|
|
||||||
public native void setDefaultMixin(int mixin);
|
public native void setDefaultMixin(int mixin);
|
||||||
|
|
||||||
//virtual bool setUserNote(const std::string &txid, const std::string ¬e) = 0;
|
public native boolean setUserNote(String txid, String note);
|
||||||
//virtual std::string getUserNote(const std::string &txid) const = 0;
|
public native String getUserNote(String txid);
|
||||||
//virtual std::string getTxKey(const std::string &txid) const = 0;
|
|
||||||
|
public native String getTxKey(String txid);
|
||||||
|
|
||||||
//virtual std::string signMessage(const std::string &message) = 0;
|
//virtual std::string signMessage(const std::string &message) = 0;
|
||||||
//virtual bool verifySignedMessage(const std::string &message, const std::string &addres, const std::string &signature) const = 0;
|
//virtual bool verifySignedMessage(const std::string &message, const std::string &addres, const std::string &signature) const = 0;
|
||||||
|
@@ -38,7 +38,7 @@ public class WalletManager {
|
|||||||
// no need to keep a reference to the REAL WalletManager (we get it every tvTime we need it)
|
// no need to keep a reference to the REAL WalletManager (we get it every tvTime we need it)
|
||||||
private static WalletManager Instance = null;
|
private static WalletManager Instance = null;
|
||||||
|
|
||||||
public static WalletManager getInstance() { // TODO not threadsafe
|
public static synchronized WalletManager getInstance() {
|
||||||
if (WalletManager.Instance == null) {
|
if (WalletManager.Instance == null) {
|
||||||
WalletManager.Instance = new WalletManager();
|
WalletManager.Instance = new WalletManager();
|
||||||
}
|
}
|
||||||
@@ -57,7 +57,7 @@ public class WalletManager {
|
|||||||
|
|
||||||
private void manageWallet(String walletId, Wallet wallet) {
|
private void manageWallet(String walletId, Wallet wallet) {
|
||||||
if (getWallet(walletId) != null) {
|
if (getWallet(walletId) != null) {
|
||||||
throw new IllegalStateException("Wallet already under management!");
|
throw new IllegalStateException(walletId + " already under management!");
|
||||||
}
|
}
|
||||||
Log.d(TAG, "Managing " + walletId);
|
Log.d(TAG, "Managing " + walletId);
|
||||||
managedWallets.put(walletId, wallet);
|
managedWallets.put(walletId, wallet);
|
||||||
@@ -65,7 +65,7 @@ public class WalletManager {
|
|||||||
|
|
||||||
private void unmanageWallet(String walletId) {
|
private void unmanageWallet(String walletId) {
|
||||||
if (getWallet(walletId) == null) {
|
if (getWallet(walletId) == null) {
|
||||||
throw new IllegalStateException("Wallet not under management!");
|
throw new IllegalStateException(walletId + " not under management!");
|
||||||
}
|
}
|
||||||
Log.d(TAG, "Unmanaging " + walletId);
|
Log.d(TAG, "Unmanaging " + walletId);
|
||||||
managedWallets.remove(walletId);
|
managedWallets.remove(walletId);
|
||||||
@@ -78,6 +78,8 @@ public class WalletManager {
|
|||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private native long createWalletJ(String path, String password, String language, boolean isTestNet);
|
||||||
|
|
||||||
public Wallet openWallet(String path, String password) {
|
public Wallet openWallet(String path, String password) {
|
||||||
long walletHandle = openWalletJ(path, password, isTestNet());
|
long walletHandle = openWalletJ(path, password, isTestNet());
|
||||||
Wallet wallet = new Wallet(walletHandle);
|
Wallet wallet = new Wallet(walletHandle);
|
||||||
@@ -85,6 +87,8 @@ public class WalletManager {
|
|||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private native long openWalletJ(String path, String password, boolean isTestNet);
|
||||||
|
|
||||||
public Wallet recoveryWallet(String path, String mnemonic) {
|
public Wallet recoveryWallet(String path, String mnemonic) {
|
||||||
Wallet wallet = recoveryWallet(path, mnemonic, 0);
|
Wallet wallet = recoveryWallet(path, mnemonic, 0);
|
||||||
manageWallet(wallet.getName(), wallet);
|
manageWallet(wallet.getName(), wallet);
|
||||||
@@ -98,12 +102,17 @@ public class WalletManager {
|
|||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
|
|
||||||
private native long createWalletJ(String path, String password, String language, boolean isTestNet);
|
|
||||||
|
|
||||||
private native long openWalletJ(String path, String password, boolean isTestNet);
|
|
||||||
|
|
||||||
private native long recoveryWalletJ(String path, String mnemonic, boolean isTestNet, long restoreHeight);
|
private native long recoveryWalletJ(String path, String mnemonic, boolean isTestNet, long restoreHeight);
|
||||||
|
|
||||||
|
public Wallet createWalletFromKeys(String path, String language, long restoreHeight,
|
||||||
|
String addressString, String viewKeyString, String spendKeyString) {
|
||||||
|
long walletHandle = createWalletFromKeysJ(path, language, isTestNet(), restoreHeight,
|
||||||
|
addressString, viewKeyString, spendKeyString);
|
||||||
|
Wallet wallet = new Wallet(walletHandle);
|
||||||
|
manageWallet(wallet.getName(), wallet);
|
||||||
|
return wallet;
|
||||||
|
}
|
||||||
|
|
||||||
private native long createWalletFromKeysJ(String path, String language,
|
private native long createWalletFromKeysJ(String path, String language,
|
||||||
boolean isTestNet,
|
boolean isTestNet,
|
||||||
long restoreHeight,
|
long restoreHeight,
|
||||||
|
@@ -26,7 +26,7 @@ import android.os.Process;
|
|||||||
/**
|
/**
|
||||||
* Handy class for starting a new thread that has a looper. The looper can then be
|
* Handy class for starting a new thread that has a looper. The looper can then be
|
||||||
* used to create handler classes. Note that start() must still be called.
|
* used to create handler classes. Note that start() must still be called.
|
||||||
* The started Thread has a stck size of STACK_SIZE (=3MB)
|
* The started Thread has a stck size of STACK_SIZE (=5MB)
|
||||||
*/
|
*/
|
||||||
public class MoneroHandlerThread extends Thread {
|
public class MoneroHandlerThread extends Thread {
|
||||||
// from src/cryptonote_config.h
|
// from src/cryptonote_config.h
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -18,10 +18,13 @@ package com.m2049r.xmrwallet.util;
|
|||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.app.Dialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
import android.view.inputmethod.InputMethodManager;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.R;
|
import com.m2049r.xmrwallet.R;
|
||||||
|
|
||||||
@@ -43,7 +46,7 @@ public class Helper {
|
|||||||
dir.mkdirs(); // try to make it
|
dir.mkdirs(); // try to make it
|
||||||
}
|
}
|
||||||
if (!dir.isDirectory()) {
|
if (!dir.isDirectory()) {
|
||||||
String msg = "Directory " + dir.getAbsolutePath() + " does not exists.";
|
String msg = "Directory " + dir.getAbsolutePath() + " does not exist.";
|
||||||
Log.e(TAG, msg);
|
Log.e(TAG, msg);
|
||||||
throw new IllegalStateException(msg);
|
throw new IllegalStateException(msg);
|
||||||
}
|
}
|
||||||
@@ -56,7 +59,7 @@ public class Helper {
|
|||||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
|
||||||
if (context.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
if (context.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||||
== PackageManager.PERMISSION_DENIED) {
|
== PackageManager.PERMISSION_DENIED) {
|
||||||
Log.d("permission", "permission denied to WRITE_EXTERNAL_STORAGE - requesting it");
|
Log.d(TAG, "Permission denied to WRITE_EXTERNAL_STORAGE - requesting it");
|
||||||
String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
|
String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
|
||||||
context.requestPermissions(permissions, PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE);
|
context.requestPermissions(permissions, PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE);
|
||||||
return false;
|
return false;
|
||||||
@@ -82,4 +85,26 @@ public class Helper {
|
|||||||
return Environment.MEDIA_MOUNTED.equals(state);
|
return Environment.MEDIA_MOUNTED.equals(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static public void showKeyboard(Activity act) {
|
||||||
|
InputMethodManager imm = (InputMethodManager) act.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||||
|
imm.showSoftInput(act.getCurrentFocus(), InputMethodManager.SHOW_IMPLICIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static public void hideKeyboard(Activity act) {
|
||||||
|
if (act.getCurrentFocus() == null) {
|
||||||
|
act.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
|
||||||
|
} else {
|
||||||
|
InputMethodManager imm = (InputMethodManager) act.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||||
|
imm.hideSoftInputFromWindow((null == act.getCurrentFocus()) ? null : act.getCurrentFocus().getWindowToken(),
|
||||||
|
InputMethodManager.HIDE_NOT_ALWAYS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static public void showKeyboard(Dialog dialog) {
|
||||||
|
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static public void hideKeyboardAlways(Activity act) {
|
||||||
|
act.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
78
app/src/main/java/com/m2049r/xmrwallet/util/TxData.java
Normal file
78
app/src/main/java/com/m2049r/xmrwallet/util/TxData.java
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.model.PendingTransaction;
|
||||||
|
|
||||||
|
// https://stackoverflow.com/questions/2139134/how-to-send-an-object-from-one-android-activity-to-another-using-intents
|
||||||
|
public class TxData implements Parcelable {
|
||||||
|
public TxData(String dst_addr,
|
||||||
|
String paymentId,
|
||||||
|
long amount,
|
||||||
|
int mixin,
|
||||||
|
PendingTransaction.Priority priority) {
|
||||||
|
this.dst_addr = dst_addr;
|
||||||
|
this.paymentId = paymentId;
|
||||||
|
this.amount = amount;
|
||||||
|
this.mixin = mixin;
|
||||||
|
this.priority = priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String dst_addr;
|
||||||
|
public String paymentId;
|
||||||
|
public long amount;
|
||||||
|
public int mixin;
|
||||||
|
public PendingTransaction.Priority priority;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel out, int flags) {
|
||||||
|
out.writeString(dst_addr);
|
||||||
|
out.writeString(paymentId);
|
||||||
|
out.writeLong(amount);
|
||||||
|
out.writeInt(mixin);
|
||||||
|
out.writeInt(priority.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is used to regenerate your object. All Parcelables must have a CREATOR that implements these two methods
|
||||||
|
public static final Parcelable.Creator<TxData> CREATOR = new Parcelable.Creator<TxData>() {
|
||||||
|
public TxData createFromParcel(Parcel in) {
|
||||||
|
return new TxData(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TxData[] newArray(int size) {
|
||||||
|
return new TxData[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private TxData(Parcel in) {
|
||||||
|
dst_addr = in.readString();
|
||||||
|
paymentId = in.readString();
|
||||||
|
amount = in.readLong();
|
||||||
|
mixin = in.readInt();
|
||||||
|
priority = PendingTransaction.Priority.fromInteger(in.readInt());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
107
app/src/main/res/layout/gen_fragment.xml
Normal file
107
app/src/main/res/layout/gen_fragment.xml
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:weightSum="2">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etWalletName"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:hint="@string/generate_name_hint"
|
||||||
|
android:imeOptions="actionNext"
|
||||||
|
android:inputType="text"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etWalletPassword"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:hint="@string/generate_password_hint"
|
||||||
|
android:imeOptions="actionNext"
|
||||||
|
android:inputType="text"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etWalletMnemonic"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/generate_mnemonic_hint"
|
||||||
|
android:imeOptions="actionNext"
|
||||||
|
android:inputType="textMultiLine"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etWalletAddress"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/generate_address_hint"
|
||||||
|
android:imeOptions="actionNext"
|
||||||
|
android:inputType="textMultiLine"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llRestoreKeys"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etWalletViewKey"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/generate_viewkey_hint"
|
||||||
|
android:imeOptions="actionNext"
|
||||||
|
android:inputType="textMultiLine"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etWalletSpendKey"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/generate_spendkey_hint"
|
||||||
|
android:imeOptions="actionNext"
|
||||||
|
android:inputType="textMultiLine"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etWalletRestoreHeight"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/generate_restoreheight_hint"
|
||||||
|
android:imeOptions="actionDone"
|
||||||
|
android:inputType="number"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/bGenerate"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:background="@color/colorPrimary"
|
||||||
|
android:enabled="false"
|
||||||
|
android:text="@string/generate_buttonGenerate" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
199
app/src/main/res/layout/gen_review_fragment.xml
Normal file
199
app/src/main/res/layout/gen_review_fragment.xml
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:weightSum="2">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvWalletLabel"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/generate_wallet_label"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvWalletPasswordLabel"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/generate_password_label"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:weightSum="2">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvWalletName"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/colorPrimaryDark"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvWalletPassword"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="***"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/colorPrimaryDark"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/pbProgress"
|
||||||
|
style="@android:style/Widget.ProgressBar.Horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="invisible" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvWalletMnemonicLabel"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/generate_mnemonic_label"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvWalletMnemonic"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/colorPrimaryDark"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvWalletAddressLabel"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="@string/generate_address_label"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvWalletAddress"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/colorPrimaryDark"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:selectAllOnFocus="true"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvWalletViewKeyLabel"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="@string/generate_viewkey_label"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvWalletViewKey"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/colorPrimaryDark"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:selectAllOnFocus="true"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvWalletSpendKeyLabel"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="@string/generate_spendkey_label"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvWalletSpendKey"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/colorPrimaryDark"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:selectAllOnFocus="true"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/bAccept"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:background="@color/colorPrimary"
|
||||||
|
android:text="@string/generate_button_accept"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llFunctions"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="2dip"
|
||||||
|
android:background="@color/colorPrimary" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/bBackup"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:background="@color/colorPrimaryDark"
|
||||||
|
android:text="@string/generate_button_backup" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/bExport"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:background="@color/colorPrimaryDark"
|
||||||
|
android:text="@string/generate_button_export" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/bDelete"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="32dp"
|
||||||
|
android:background="@color/colorAccent"
|
||||||
|
android:text="@string/generate_button_delete" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
20
app/src/main/res/layout/login_activity.xml
Normal file
20
app/src/main/res/layout/login_activity.xml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<android.support.v7.widget.Toolbar
|
||||||
|
android:id="@+id/tbLogin"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:background="?attr/colorPrimary"
|
||||||
|
android:elevation="4dp" />
|
||||||
|
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/fragment_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
@@ -1,18 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:gravity="center_horizontal"
|
android:orientation="vertical">
|
||||||
android:orientation="vertical"
|
|
||||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
|
||||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
|
||||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
|
||||||
android:paddingTop="@dimen/activity_vertical_margin"
|
|
||||||
tools:context="com.m2049r.xmrwallet.LoginActivity">
|
|
||||||
|
|
||||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
@@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/layout_root"
|
android:id="@+id/layout_root"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="fill_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:padding="10dp" >
|
android:padding="10dp" >
|
||||||
|
|
||||||
|
229
app/src/main/res/layout/send_fragment.xml
Normal file
229
app/src/main/res/layout/send_fragment.xml
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:weightSum="2">
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/sMixin"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:entries="@array/mixin"
|
||||||
|
android:textAlignment="center" />
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/sPriority"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:entries="@array/priority"
|
||||||
|
android:textAlignment="center" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etAddress"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/send_address_hint"
|
||||||
|
android:imeOptions="actionNext"
|
||||||
|
android:inputType="textMultiLine"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:weightSum="10">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etPaymentId"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="8"
|
||||||
|
android:hint="@string/send_paymentid_hint"
|
||||||
|
android:imeOptions="actionNext"
|
||||||
|
android:inputType="textMultiLine"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/bPaymentId"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_weight="2"
|
||||||
|
android:background="@color/colorPrimary"
|
||||||
|
android:enabled="true"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:text="@string/send_generate_paymentid_hint" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:weightSum="10">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etAmount"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="8"
|
||||||
|
android:hint="@string/send_amount_hint"
|
||||||
|
android:imeOptions="actionDone"
|
||||||
|
android:inputType="numberDecimal"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/bSweep"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_weight="2"
|
||||||
|
android:background="@color/colorPrimary"
|
||||||
|
android:enabled="true"
|
||||||
|
android:visibility="invisible"
|
||||||
|
android:text="@string/send_sweep_hint" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/bPrepareSend"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:background="@color/colorPrimary"
|
||||||
|
android:enabled="false"
|
||||||
|
android:text="@string/send_prepare_hint" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/pbProgress"
|
||||||
|
style="@android:style/Widget.ProgressBar.Horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llConfirmSend"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:weightSum="3">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvTxAmountLabel"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/send_amount_label"
|
||||||
|
android:textAlignment="textEnd"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:textSize="20sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvTxAmount"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_weight="2"
|
||||||
|
android:textAlignment="textEnd"
|
||||||
|
android:textSize="20sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:weightSum="3">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvTxFeeLabel"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/send_fee_label"
|
||||||
|
android:textAlignment="textEnd"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:textSize="20sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvTxFee"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_weight="2"
|
||||||
|
android:textAlignment="textEnd"
|
||||||
|
android:textSize="20sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:weightSum="3">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvTxDustLabel"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/send_dust_label"
|
||||||
|
android:textAlignment="textEnd"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:textSize="20sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvTxDust"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_weight="2"
|
||||||
|
android:textAlignment="textEnd"
|
||||||
|
android:textSize="20sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etNotes"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:hint="@string/send_notes_hint"
|
||||||
|
android:imeOptions="actionDone"
|
||||||
|
android:inputType="textMultiLine"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/bSend"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:background="@color/colorPrimary"
|
||||||
|
android:enabled="false"
|
||||||
|
android:text="@string/send_send_hint" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user