mirror of
https://github.com/m2049r/xmrwallet
synced 2025-09-02 15:53:04 +02:00
Compare commits
100 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c1f14f9653 | ||
![]() |
2746c52d7b | ||
![]() |
5df323bacb | ||
![]() |
776cc26377 | ||
![]() |
bdfb6a90b6 | ||
![]() |
6db44dfab1 | ||
![]() |
c68ac7db6d | ||
![]() |
e09862e940 | ||
![]() |
c7bd7469a1 | ||
![]() |
b39857fd2e | ||
![]() |
8170f823ab | ||
![]() |
38c0ead45c | ||
![]() |
1d027c1694 | ||
![]() |
45dc21fbf7 | ||
![]() |
d4f4de234a | ||
![]() |
394d5471e3 | ||
![]() |
beb098adb3 | ||
![]() |
fda370d35b | ||
![]() |
99681e1bbb | ||
![]() |
21f44380b1 | ||
![]() |
f4c1af1bb8 | ||
![]() |
c002b81ebd | ||
![]() |
d2f07ba3b6 | ||
![]() |
24fc27b09e | ||
![]() |
cf4ff856d5 | ||
![]() |
b01de1ad6e | ||
![]() |
5fb1bcb552 | ||
![]() |
b937ba38b6 | ||
![]() |
849718fdc7 | ||
![]() |
a6372f701d | ||
![]() |
12f135bb14 | ||
![]() |
16870fcbb9 | ||
![]() |
2fbd152fb3 | ||
![]() |
a7b178e024 | ||
![]() |
c5a035437b | ||
![]() |
75c550fd19 | ||
![]() |
1b680344b1 | ||
![]() |
3329636d32 | ||
![]() |
77e9bf7c43 | ||
![]() |
40f5c9365e | ||
![]() |
850ba7efef | ||
![]() |
548369ca0b | ||
![]() |
afc0d5b7bc | ||
![]() |
02e92db59a | ||
![]() |
2b34454214 | ||
![]() |
12706119d3 | ||
![]() |
f7a762f32b | ||
![]() |
86d5d2a2cb | ||
![]() |
e56369b91a | ||
![]() |
b04aa24269 | ||
![]() |
dda86bd5de | ||
![]() |
a19ad7fd52 | ||
![]() |
0443fd808c | ||
![]() |
faf57c96fc | ||
![]() |
57ddddfce2 | ||
![]() |
ab6069058b | ||
![]() |
d94d6e6925 | ||
![]() |
4a819cc159 | ||
![]() |
f40c3d6c6d | ||
![]() |
82b25df7ad | ||
![]() |
08f815e830 | ||
![]() |
4e59be2dff | ||
![]() |
45c5883e11 | ||
![]() |
067a23e6a5 | ||
![]() |
d21fd41c44 | ||
![]() |
6632547d1e | ||
![]() |
f1b786ec3e | ||
![]() |
a93e96d34c | ||
![]() |
1829d30b61 | ||
![]() |
e5b15b7816 | ||
![]() |
7206857a5b | ||
![]() |
85d84d09ee | ||
![]() |
c6a1b503bc | ||
![]() |
8bda7aa0cf | ||
![]() |
97fb0a5483 | ||
![]() |
fc950c6772 | ||
![]() |
46add5e927 | ||
![]() |
fa0692ceab | ||
![]() |
ff4f4a1c2c | ||
![]() |
79abb89725 | ||
![]() |
ef8301fd6f | ||
![]() |
3a15c842ff | ||
![]() |
1697da55b5 | ||
![]() |
454f3e412a | ||
![]() |
d803a1e220 | ||
![]() |
f2fe781cb5 | ||
![]() |
dcf60ae193 | ||
![]() |
ffdf54c2e1 | ||
![]() |
c060a2ab88 | ||
![]() |
05fc654f3a | ||
![]() |
c32d157150 | ||
![]() |
74e9278baa | ||
![]() |
e41e344d63 | ||
![]() |
e66875437d | ||
![]() |
c1d2db3d7d | ||
![]() |
0c9a2f5e01 | ||
![]() |
64616e3921 | ||
![]() |
82b4d66987 | ||
![]() |
10f2bc6561 | ||
![]() |
2ed9a78d9e |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -15,3 +15,4 @@
|
||||
/app/alphaStagenet
|
||||
/app/prodStagenet
|
||||
/app/.cxx
|
||||
/monerujo.id
|
||||
|
@@ -13,7 +13,7 @@ set(EXTERNAL_LIBS_DIR ${CMAKE_SOURCE_DIR}/../external-libs)
|
||||
|
||||
add_library(sodium STATIC IMPORTED)
|
||||
set_target_properties(sodium PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/libsodium/lib/${ANDROID_ABI}/libsodium.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/libsodium.a)
|
||||
|
||||
############
|
||||
# OpenSSL
|
||||
@@ -21,11 +21,11 @@ set_target_properties(sodium PROPERTIES IMPORTED_LOCATION
|
||||
|
||||
add_library(crypto STATIC IMPORTED)
|
||||
set_target_properties(crypto PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/openssl/lib/${ANDROID_ABI}/libcrypto.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/libcrypto.a)
|
||||
|
||||
add_library(ssl STATIC IMPORTED)
|
||||
set_target_properties(ssl PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/openssl/lib/${ANDROID_ABI}/libssl.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/libssl.a)
|
||||
|
||||
############
|
||||
# Boost
|
||||
@@ -33,39 +33,39 @@ set_target_properties(ssl PROPERTIES IMPORTED_LOCATION
|
||||
|
||||
add_library(boost_chrono STATIC IMPORTED)
|
||||
set_target_properties(boost_chrono PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_chrono.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/libboost_chrono.a)
|
||||
|
||||
add_library(boost_date_time STATIC IMPORTED)
|
||||
set_target_properties(boost_date_time PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_date_time.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/libboost_date_time.a)
|
||||
|
||||
add_library(boost_filesystem STATIC IMPORTED)
|
||||
set_target_properties(boost_filesystem PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_filesystem.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/libboost_filesystem.a)
|
||||
|
||||
add_library(boost_program_options STATIC IMPORTED)
|
||||
set_target_properties(boost_program_options PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_program_options.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/libboost_program_options.a)
|
||||
|
||||
add_library(boost_regex STATIC IMPORTED)
|
||||
set_target_properties(boost_regex PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_regex.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/libboost_regex.a)
|
||||
|
||||
add_library(boost_serialization STATIC IMPORTED)
|
||||
set_target_properties(boost_serialization PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_serialization.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/libboost_serialization.a)
|
||||
|
||||
add_library(boost_system STATIC IMPORTED)
|
||||
set_target_properties(boost_system PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_system.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/libboost_system.a)
|
||||
|
||||
add_library(boost_thread STATIC IMPORTED)
|
||||
set_target_properties(boost_thread PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_thread.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/libboost_thread.a)
|
||||
|
||||
add_library(boost_wserialization STATIC IMPORTED)
|
||||
set_target_properties(boost_wserialization PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_wserialization.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/libboost_wserialization.a)
|
||||
|
||||
#############
|
||||
# Monero
|
||||
@@ -73,99 +73,103 @@ set_target_properties(boost_wserialization PROPERTIES IMPORTED_LOCATION
|
||||
|
||||
add_library(wallet_api STATIC IMPORTED)
|
||||
set_target_properties(wallet_api PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libwallet_api.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libwallet_api.a)
|
||||
|
||||
add_library(wallet STATIC IMPORTED)
|
||||
set_target_properties(wallet PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libwallet.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libwallet.a)
|
||||
|
||||
add_library(cryptonote_core STATIC IMPORTED)
|
||||
set_target_properties(cryptonote_core PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcryptonote_core.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libcryptonote_core.a)
|
||||
|
||||
add_library(cryptonote_basic STATIC IMPORTED)
|
||||
set_target_properties(cryptonote_basic PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcryptonote_basic.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libcryptonote_basic.a)
|
||||
|
||||
add_library(mnemonics STATIC IMPORTED)
|
||||
set_target_properties(mnemonics PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libmnemonics.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libmnemonics.a)
|
||||
|
||||
add_library(common STATIC IMPORTED)
|
||||
set_target_properties(common PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcommon.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libcommon.a)
|
||||
|
||||
add_library(cncrypto STATIC IMPORTED)
|
||||
set_target_properties(cncrypto PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcncrypto.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libcncrypto.a)
|
||||
|
||||
add_library(ringct STATIC IMPORTED)
|
||||
set_target_properties(ringct PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libringct.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libringct.a)
|
||||
|
||||
add_library(ringct_basic STATIC IMPORTED)
|
||||
set_target_properties(ringct_basic PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libringct_basic.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libringct_basic.a)
|
||||
|
||||
add_library(blockchain_db STATIC IMPORTED)
|
||||
set_target_properties(blockchain_db PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libblockchain_db.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libblockchain_db.a)
|
||||
|
||||
add_library(lmdb STATIC IMPORTED)
|
||||
set_target_properties(lmdb PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/liblmdb.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/liblmdb.a)
|
||||
|
||||
add_library(easylogging STATIC IMPORTED)
|
||||
set_target_properties(easylogging PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libeasylogging.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libeasylogging.a)
|
||||
|
||||
add_library(unbound STATIC IMPORTED)
|
||||
set_target_properties(unbound PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libunbound.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libunbound.a)
|
||||
|
||||
add_library(epee STATIC IMPORTED)
|
||||
set_target_properties(epee PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libepee.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libepee.a)
|
||||
|
||||
add_library(blocks STATIC IMPORTED)
|
||||
set_target_properties(blocks PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libblocks.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libblocks.a)
|
||||
|
||||
add_library(checkpoints STATIC IMPORTED)
|
||||
set_target_properties(checkpoints PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcheckpoints.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libcheckpoints.a)
|
||||
|
||||
add_library(device STATIC IMPORTED)
|
||||
set_target_properties(device PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libdevice.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libdevice.a)
|
||||
|
||||
add_library(device_trezor STATIC IMPORTED)
|
||||
set_target_properties(device_trezor PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libdevice_trezor.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libdevice_trezor.a)
|
||||
|
||||
add_library(multisig STATIC IMPORTED)
|
||||
set_target_properties(multisig PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libmultisig.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libmultisig.a)
|
||||
|
||||
add_library(version STATIC IMPORTED)
|
||||
set_target_properties(version PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libversion.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libversion.a)
|
||||
|
||||
add_library(net STATIC IMPORTED)
|
||||
set_target_properties(net PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libnet.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libnet.a)
|
||||
|
||||
add_library(hardforks STATIC IMPORTED)
|
||||
set_target_properties(hardforks PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libhardforks.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libhardforks.a)
|
||||
|
||||
add_library(randomx STATIC IMPORTED)
|
||||
set_target_properties(randomx PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/librandomx.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/librandomx.a)
|
||||
|
||||
add_library(rpc_base STATIC IMPORTED)
|
||||
set_target_properties(rpc_base PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/librpc_base.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/librpc_base.a)
|
||||
|
||||
add_library(wallet-crypto STATIC IMPORTED)
|
||||
set_target_properties(wallet-crypto PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libwallet-crypto.a)
|
||||
|
||||
#############
|
||||
# System
|
||||
@@ -173,10 +177,16 @@ set_target_properties(rpc_base PROPERTIES IMPORTED_LOCATION
|
||||
|
||||
find_library( log-lib log )
|
||||
|
||||
include_directories( ${EXTERNAL_LIBS_DIR}/monero/include )
|
||||
include_directories( ${EXTERNAL_LIBS_DIR}/include )
|
||||
|
||||
message(STATUS EXTERNAL_LIBS_DIR : ${EXTERNAL_LIBS_DIR})
|
||||
|
||||
if(${ANDROID_ABI} STREQUAL "x86_64")
|
||||
set(EXTRA_LIBS "wallet-crypto")
|
||||
else()
|
||||
set(EXTRA_LIBS "")
|
||||
endif()
|
||||
|
||||
target_link_libraries( monerujo
|
||||
|
||||
wallet_api
|
||||
@@ -203,6 +213,7 @@ target_link_libraries( monerujo
|
||||
randomx
|
||||
hardforks
|
||||
rpc_base
|
||||
${EXTRA_LIBS}
|
||||
|
||||
boost_chrono
|
||||
boost_date_time
|
||||
|
@@ -1,16 +1,16 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
buildToolsVersion '29.0.2'
|
||||
compileSdkVersion 30
|
||||
buildToolsVersion '29.0.3'
|
||||
ndkVersion '17.2.4988734'
|
||||
defaultConfig {
|
||||
applicationId "com.m2049r.xmrwallet"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 28
|
||||
versionCode 303
|
||||
versionName "1.13.3 'ReStart'"
|
||||
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
targetSdkVersion 30
|
||||
versionCode 1004
|
||||
versionName "2.0.4.0 'Puginarug'"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
cppFlags "-std=c++11"
|
||||
@@ -18,6 +18,11 @@ android {
|
||||
}
|
||||
}
|
||||
}
|
||||
bundle {
|
||||
language {
|
||||
enableSplit = false
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions 'type', 'net'
|
||||
productFlavors {
|
||||
@@ -29,6 +34,11 @@ android {
|
||||
applicationIdSuffix '.stage'
|
||||
versionNameSuffix ' (stage)'
|
||||
}
|
||||
devnet {
|
||||
dimension 'net'
|
||||
applicationIdSuffix '.test'
|
||||
versionNameSuffix ' (test)'
|
||||
}
|
||||
alpha {
|
||||
dimension 'type'
|
||||
applicationIdSuffix '.alpha'
|
||||
@@ -47,6 +57,9 @@ android {
|
||||
debug {
|
||||
applicationIdSuffix ".debug"
|
||||
}
|
||||
applicationVariants.all { variant ->
|
||||
variant.buildConfigField "String", "ID_A", "\"" + getId("ID_A") + "\""
|
||||
}
|
||||
}
|
||||
|
||||
externalNativeBuild {
|
||||
@@ -71,7 +84,8 @@ android {
|
||||
def availableLocales = ["en"]
|
||||
new File("app/src/main/res/").eachFileMatch(~/^values-.*/) { file ->
|
||||
def languageTag = file.name.substring(7).replace("-r", "-")
|
||||
availableLocales.add(languageTag)
|
||||
if (languageTag != "night")
|
||||
availableLocales.add(languageTag)
|
||||
}
|
||||
|
||||
// APKs for the same app that all have the same version information.
|
||||
@@ -82,8 +96,7 @@ android {
|
||||
variant.outputs.all {
|
||||
output ->
|
||||
def abiName = output.getFilter(com.android.build.OutputFile.ABI)
|
||||
output.versionCodeOverride = abiCodes.get(abiName, 0) + 10 * variant.versionCode
|
||||
//def flavor = output.getFilter(flavor)
|
||||
output.versionCodeOverride = abiCodes.get(abiName, 0) + 10 * versionCode
|
||||
|
||||
if (abiName == null) abiName = "universal"
|
||||
def v = "${variant.versionName}".replaceFirst(" '.*' ?", "")
|
||||
@@ -93,36 +106,49 @@ android {
|
||||
outputFileName = "$rootProject.ext.apkName-" + v + "_" + abiName + ".apk"
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
def getId(name) {
|
||||
def Properties props = new Properties()
|
||||
props.load(new FileInputStream(new File('monerujo.id')))
|
||||
return props[name]
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "com.android.support:appcompat-v7:$rootProject.ext.supportVersion"
|
||||
implementation "com.android.support:design:$rootProject.ext.supportVersion"
|
||||
implementation "com.android.support:support-v4:$rootProject.ext.supportVersion"
|
||||
implementation "com.android.support:recyclerview-v7:$rootProject.ext.supportVersion"
|
||||
implementation "com.android.support:cardview-v7:$rootProject.ext.supportVersion"
|
||||
implementation "com.android.support:swiperefreshlayout:$rootProject.ext.supportVersion"
|
||||
implementation 'androidx.core:core:1.3.2'
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'com.google.android.material:material:1.3.0'
|
||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.2.0'
|
||||
implementation 'androidx.cardview:cardview:1.0.0'
|
||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.2.0-alpha01'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
||||
|
||||
implementation 'me.dm7.barcodescanner:zxing:1.9.8'
|
||||
implementation "com.squareup.okhttp3:okhttp:4.9.0"
|
||||
implementation "io.github.rburgst:okhttp-digest:2.5"
|
||||
implementation "com.jakewharton.timber:timber:4.7.1"
|
||||
|
||||
implementation "com.squareup.okhttp3:okhttp:$rootProject.ext.okHttpVersion"
|
||||
implementation "com.burgstaller:okhttp-digest:1.18"
|
||||
implementation "com.jakewharton.timber:timber:$rootProject.ext.timberVersion"
|
||||
implementation 'com.nulab-inc:zxcvbn:1.3.0'
|
||||
|
||||
implementation 'com.nulab-inc:zxcvbn:1.2.3'
|
||||
|
||||
implementation 'dnsjava:dnsjava:2.1.8'
|
||||
implementation 'org.jitsi:dnssecjava:1.1.3'
|
||||
implementation 'org.slf4j:slf4j-nop:1.7.25'
|
||||
implementation 'dnsjava:dnsjava:2.1.9'
|
||||
implementation 'org.jitsi:dnssecjava:1.2.0'
|
||||
implementation 'org.slf4j:slf4j-nop:1.7.30'
|
||||
implementation 'com.github.brnunes:swipeablerecyclerview:1.0.2'
|
||||
|
||||
// https://mvnrepository.com/artifact/com.github.aelstad/keccakj
|
||||
implementation 'com.github.aelstad:keccakj:1.1.0'
|
||||
|
||||
|
||||
testImplementation "junit:junit:$rootProject.ext.junitVersion"
|
||||
testImplementation "org.mockito:mockito-all:$rootProject.ext.mockitoVersion"
|
||||
testImplementation "com.squareup.okhttp3:mockwebserver:$rootProject.ext.okHttpVersion"
|
||||
testImplementation "com.squareup.okhttp3:mockwebserver:4.9.0"
|
||||
testImplementation 'org.json:json:20180813'
|
||||
testImplementation 'net.jodah:concurrentunit:0.4.4'
|
||||
|
||||
compileOnly 'org.projectlombok:lombok:1.18.16'
|
||||
annotationProcessor 'org.projectlombok:lombok:1.18.16'
|
||||
}
|
||||
|
@@ -4,15 +4,14 @@
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||
<uses-permission android:name="android.permission.NFC" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
|
||||
<application
|
||||
android:preserveLegacyExternalStorage="true"
|
||||
android:name=".XmrWalletApplication"
|
||||
android:allowBackup="false"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
@@ -20,24 +19,28 @@
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/MyMaterialTheme"
|
||||
android:usesCleartextTraffic="true">
|
||||
|
||||
<activity
|
||||
android:name=".WalletActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:label="@string/wallet_activity_name"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="behind" />
|
||||
|
||||
<activity
|
||||
android:name=".LoginActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:label="@string/app_name"
|
||||
android:name=".MainActivity"
|
||||
android:configChanges="orientation|keyboardHidden|uiMode"
|
||||
android:launchMode="singleTop"
|
||||
android:screenOrientation="locked">
|
||||
android:screenOrientation="portrait">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".WalletActivity"
|
||||
android:configChanges="orientation|keyboardHidden|uiMode"
|
||||
android:label="@string/wallet_activity_name"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="behind"/>
|
||||
<activity
|
||||
android:name=".LoginActivity"
|
||||
android:configChanges="orientation|keyboardHidden|uiMode"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTop"
|
||||
android:screenOrientation="locked">
|
||||
<intent-filter>
|
||||
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
|
||||
</intent-filter>
|
||||
@@ -62,6 +65,11 @@
|
||||
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
|
||||
android:resource="@xml/usb_device_filter" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".onboarding.OnBoardingActivity"
|
||||
android:configChanges="orientation|keyboardHidden|uiMode"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<service
|
||||
android:name=".service.WalletService"
|
||||
@@ -70,7 +78,7 @@
|
||||
android:label="Monero Wallet Service" />
|
||||
|
||||
<provider
|
||||
android:name="android.support.v4.content.FileProvider"
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
@@ -79,4 +87,4 @@
|
||||
android:resource="@xml/filepaths" />
|
||||
</provider>
|
||||
</application>
|
||||
</manifest>
|
||||
</manifest>
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -185,7 +185,6 @@ public class Dispatcher implements PeerRetriever.OnGetPeers {
|
||||
|
||||
public void seedPeers(Collection<NodeInfo> seedNodes) {
|
||||
for (NodeInfo node : seedNodes) {
|
||||
node.clear();
|
||||
if (node.isFavourite()) {
|
||||
rpcNodes.add(node);
|
||||
if (listener != null) listener.onGet(node);
|
||||
|
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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.levin.scanner;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020 m2049r et al.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
@@ -15,11 +31,12 @@ import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.PowerManager;
|
||||
import android.support.annotation.CallSuper;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.CallSuper;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.m2049r.xmrwallet.data.BarcodeData;
|
||||
import com.m2049r.xmrwallet.dialog.ProgressDialog;
|
||||
import com.m2049r.xmrwallet.fragment.send.SendFragment;
|
||||
@@ -30,7 +47,8 @@ import java.io.IOException;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
public class BaseActivity extends SecureActivity implements GenerateReviewFragment.ProgressListener {
|
||||
public class BaseActivity extends SecureActivity
|
||||
implements GenerateReviewFragment.ProgressListener, SubaddressFragment.ProgressListener {
|
||||
|
||||
ProgressDialog progressDialog = null;
|
||||
|
||||
@@ -197,7 +215,7 @@ public class BaseActivity extends SecureActivity implements GenerateReviewFragme
|
||||
if (uri == null) {
|
||||
Toast.makeText(this, getString(R.string.nfc_tag_read_undef), Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
BarcodeData bc = BarcodeData.fromQrCode(uri.toString());
|
||||
BarcodeData bc = BarcodeData.fromString(uri.toString());
|
||||
if (bc == null)
|
||||
Toast.makeText(this, getString(R.string.nfc_tag_read_undef), Toast.LENGTH_LONG).show();
|
||||
else
|
||||
|
@@ -17,13 +17,9 @@
|
||||
package com.m2049r.xmrwallet;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.TextInputLayout;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.text.Editable;
|
||||
import android.text.Html;
|
||||
import android.text.InputType;
|
||||
@@ -38,9 +34,15 @@ import android.view.WindowManager;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Switch;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.switchmaterial.SwitchMaterial;
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.model.WalletManager;
|
||||
import com.m2049r.xmrwallet.util.FingerprintHelper;
|
||||
@@ -48,9 +50,8 @@ import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.util.KeyStoreHelper;
|
||||
import com.m2049r.xmrwallet.util.RestoreHeight;
|
||||
import com.m2049r.xmrwallet.util.ledger.Monero;
|
||||
import com.m2049r.xmrwallet.widget.PasswordEntryView;
|
||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||
import com.nulabinc.zxcvbn.Strength;
|
||||
import com.nulabinc.zxcvbn.Zxcvbn;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.ParseException;
|
||||
@@ -68,7 +69,7 @@ public class GenerateFragment extends Fragment {
|
||||
static final String TYPE_VIEWONLY = "view";
|
||||
|
||||
private TextInputLayout etWalletName;
|
||||
private TextInputLayout etWalletPassword;
|
||||
private PasswordEntryView etWalletPassword;
|
||||
private LinearLayout llFingerprintAuth;
|
||||
private TextInputLayout etWalletAddress;
|
||||
private TextInputLayout etWalletMnemonic;
|
||||
@@ -129,21 +130,6 @@ public class GenerateFragment extends Fragment {
|
||||
});
|
||||
clearErrorOnTextEntry(etWalletName);
|
||||
|
||||
etWalletPassword.getEditText().addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void afterTextChanged(Editable editable) {
|
||||
checkPassword();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
});
|
||||
|
||||
etWalletMnemonic.getEditText().setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
||||
@Override
|
||||
public void onFocusChange(View v, boolean hasFocus) {
|
||||
@@ -202,13 +188,13 @@ public class GenerateFragment extends Fragment {
|
||||
if (FingerprintHelper.isDeviceSupported(getContext())) {
|
||||
llFingerprintAuth.setVisibility(View.VISIBLE);
|
||||
|
||||
final Switch swFingerprintAllowed = (Switch) llFingerprintAuth.getChildAt(0);
|
||||
final SwitchMaterial swFingerprintAllowed = (SwitchMaterial) llFingerprintAuth.getChildAt(0);
|
||||
swFingerprintAllowed.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (!swFingerprintAllowed.isChecked()) return;
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getActivity());
|
||||
builder.setMessage(Html.fromHtml(getString(R.string.generate_fingerprint_warn)))
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(getString(R.string.label_ok), null)
|
||||
@@ -352,45 +338,10 @@ public class GenerateFragment extends Fragment {
|
||||
});
|
||||
|
||||
etWalletName.requestFocus();
|
||||
initZxcvbn();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
Zxcvbn zxcvbn = new Zxcvbn();
|
||||
|
||||
// initialize zxcvbn engine in background thread
|
||||
private void initZxcvbn() {
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
zxcvbn.measure("");
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void checkPassword() {
|
||||
String password = etWalletPassword.getEditText().getText().toString();
|
||||
if (!password.isEmpty()) {
|
||||
Strength strength = zxcvbn.measure(password);
|
||||
int msg;
|
||||
double guessesLog10 = strength.getGuessesLog10();
|
||||
if (guessesLog10 < 10)
|
||||
msg = R.string.password_weak;
|
||||
else if (guessesLog10 < 11)
|
||||
msg = R.string.password_fair;
|
||||
else if (guessesLog10 < 12)
|
||||
msg = R.string.password_good;
|
||||
else if (guessesLog10 < 13)
|
||||
msg = R.string.password_strong;
|
||||
else
|
||||
msg = R.string.password_very_strong;
|
||||
etWalletPassword.setError(getResources().getString(msg));
|
||||
} else {
|
||||
etWalletPassword.setError(null);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkName() {
|
||||
String name = etWalletName.getEditText().getText().toString();
|
||||
boolean ok = true;
|
||||
@@ -427,7 +378,7 @@ public class GenerateFragment extends Fragment {
|
||||
}
|
||||
|
||||
private long getHeight() {
|
||||
long height = 0;
|
||||
long height = -1;
|
||||
|
||||
String restoreHeight = etWalletRestoreHeight.getEditText().getText().toString().trim();
|
||||
if (restoreHeight.isEmpty()) return -1;
|
||||
@@ -438,7 +389,7 @@ public class GenerateFragment extends Fragment {
|
||||
height = RestoreHeight.getInstance().getHeight(parser.parse(restoreHeight));
|
||||
} catch (ParseException ex) {
|
||||
}
|
||||
if ((height <= 0) && (restoreHeight.length() == 8))
|
||||
if ((height < 0) && (restoreHeight.length() == 8))
|
||||
try {
|
||||
// is it a date without dashes?
|
||||
SimpleDateFormat parser = new SimpleDateFormat("yyyyMMdd");
|
||||
@@ -446,7 +397,7 @@ public class GenerateFragment extends Fragment {
|
||||
height = RestoreHeight.getInstance().getHeight(parser.parse(restoreHeight));
|
||||
} catch (ParseException ex) {
|
||||
}
|
||||
if (height <= 0)
|
||||
if (height < 0)
|
||||
try {
|
||||
// or is it a height?
|
||||
height = Long.parseLong(restoreHeight);
|
||||
@@ -507,7 +458,7 @@ public class GenerateFragment extends Fragment {
|
||||
|
||||
String name = etWalletName.getEditText().getText().toString();
|
||||
String password = etWalletPassword.getEditText().getText().toString();
|
||||
boolean fingerprintAuthAllowed = ((Switch) llFingerprintAuth.getChildAt(0)).isChecked();
|
||||
boolean fingerprintAuthAllowed = ((SwitchMaterial) llFingerprintAuth.getChildAt(0)).isChecked();
|
||||
|
||||
// create the real wallet password
|
||||
String crazyPass = KeyStoreHelper.getCrazyPass(getActivity(), password);
|
||||
@@ -646,30 +597,13 @@ public class GenerateFragment extends Fragment {
|
||||
if (ledgerDialog != null) return;
|
||||
final Activity activity = getActivity();
|
||||
View promptsView = getLayoutInflater().inflate(R.layout.prompt_ledger_seed, null);
|
||||
android.app.AlertDialog.Builder alertDialogBuilder = new android.app.AlertDialog.Builder(activity);
|
||||
MaterialAlertDialogBuilder alertDialogBuilder = new MaterialAlertDialogBuilder(activity);
|
||||
alertDialogBuilder.setView(promptsView);
|
||||
|
||||
final TextInputLayout etSeed = promptsView.findViewById(R.id.etSeed);
|
||||
final TextInputLayout etPassphrase = promptsView.findViewById(R.id.etPassphrase);
|
||||
|
||||
etSeed.getEditText().addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
if (etSeed.getError() != null) {
|
||||
etSeed.setError(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start,
|
||||
int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start,
|
||||
int before, int count) {
|
||||
}
|
||||
});
|
||||
clearErrorOnTextEntry(etSeed);
|
||||
|
||||
alertDialogBuilder
|
||||
.setCancelable(false)
|
||||
|
@@ -16,14 +16,10 @@
|
||||
|
||||
package com.m2049r.xmrwallet;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.TextInputLayout;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.text.Editable;
|
||||
import android.text.Html;
|
||||
import android.text.TextWatcher;
|
||||
@@ -40,10 +36,17 @@ import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.Switch;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.switchmaterial.SwitchMaterial;
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
import com.m2049r.xmrwallet.ledger.Ledger;
|
||||
import com.m2049r.xmrwallet.ledger.LedgerProgressDialog;
|
||||
import com.m2049r.xmrwallet.model.NetworkType;
|
||||
@@ -53,6 +56,7 @@ import com.m2049r.xmrwallet.util.FingerprintHelper;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.util.KeyStoreHelper;
|
||||
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
|
||||
import com.m2049r.xmrwallet.widget.PasswordEntryView;
|
||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
@@ -118,31 +122,11 @@ public class GenerateReviewFragment extends Fragment {
|
||||
tvWalletSpendKey.setTextIsSelectable(allowCopy);
|
||||
tvWalletPassword.setTextIsSelectable(allowCopy);
|
||||
|
||||
bAccept.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
acceptWallet();
|
||||
}
|
||||
});
|
||||
view.findViewById(R.id.bCopyViewKey).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
copyViewKey();
|
||||
}
|
||||
});
|
||||
bCopyAddress.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
copyAddress();
|
||||
}
|
||||
});
|
||||
bCopyAddress.setClickable(false);
|
||||
view.findViewById(R.id.bAdvancedInfo).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
showAdvancedInfo();
|
||||
}
|
||||
});
|
||||
bAccept.setOnClickListener(v -> acceptWallet());
|
||||
view.findViewById(R.id.bCopyViewKey).setOnClickListener(v -> copyViewKey());
|
||||
bCopyAddress.setEnabled(false);
|
||||
bCopyAddress.setOnClickListener(v -> copyAddress());
|
||||
view.findViewById(R.id.bAdvancedInfo).setOnClickListener(v -> showAdvancedInfo());
|
||||
|
||||
Bundle args = getArguments();
|
||||
type = args.getString(REQUEST_TYPE);
|
||||
@@ -287,8 +271,7 @@ public class GenerateReviewFragment extends Fragment {
|
||||
showAdvanced = true;
|
||||
}
|
||||
if (showAdvanced) bAdvancedInfo.setVisibility(View.VISIBLE);
|
||||
bCopyAddress.setClickable(true);
|
||||
bCopyAddress.setImageResource(R.drawable.ic_content_copy_black_24dp);
|
||||
bCopyAddress.setEnabled(true);
|
||||
activityCallback.setTitle(name, getString(R.string.details_title));
|
||||
activityCallback.setToolbarButton(
|
||||
GenerateReviewFragment.VIEW_TYPE_ACCEPT.equals(type) ? Toolbar.BUTTON_NONE : Toolbar.BUTTON_BACK);
|
||||
@@ -324,7 +307,6 @@ public class GenerateReviewFragment extends Fragment {
|
||||
void dismissProgressDialog();
|
||||
}
|
||||
|
||||
|
||||
public interface AcceptListener {
|
||||
void onAccept(String name, String password);
|
||||
}
|
||||
@@ -352,7 +334,7 @@ public class GenerateReviewFragment extends Fragment {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
public void onAttach(@NonNull Context context) {
|
||||
super.onAttach(context);
|
||||
if (context instanceof Listener) {
|
||||
this.activityCallback = (Listener) context;
|
||||
@@ -399,7 +381,7 @@ public class GenerateReviewFragment extends Fragment {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
|
||||
String type = getArguments().getString(REQUEST_TYPE); // intance variable <type> not set yet
|
||||
if (GenerateReviewFragment.VIEW_TYPE_ACCEPT.equals(type)) {
|
||||
inflater.inflate(R.menu.wallet_details_help_menu, menu);
|
||||
@@ -448,7 +430,7 @@ public class GenerateReviewFragment extends Fragment {
|
||||
protected Boolean doInBackground(String... params) {
|
||||
if (params.length != 2) return false;
|
||||
final String userPassword = params[0];
|
||||
final boolean fingerPassValid = Boolean.valueOf(params[1]);
|
||||
final boolean fingerPassValid = Boolean.parseBoolean(params[1]);
|
||||
newPassword = KeyStoreHelper.getCrazyPass(getActivity(), userPassword);
|
||||
final boolean success = changeWalletPassword(newPassword);
|
||||
if (success) {
|
||||
@@ -488,17 +470,17 @@ public class GenerateReviewFragment extends Fragment {
|
||||
LayoutInflater li = LayoutInflater.from(getActivity());
|
||||
View promptsView = li.inflate(R.layout.prompt_changepw, null);
|
||||
|
||||
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
|
||||
AlertDialog.Builder alertDialogBuilder = new MaterialAlertDialogBuilder(getActivity());
|
||||
alertDialogBuilder.setView(promptsView);
|
||||
|
||||
final TextInputLayout etPasswordA = promptsView.findViewById(R.id.etWalletPasswordA);
|
||||
final PasswordEntryView etPasswordA = promptsView.findViewById(R.id.etWalletPasswordA);
|
||||
etPasswordA.setHint(getString(R.string.prompt_changepw, walletName));
|
||||
|
||||
final TextInputLayout etPasswordB = promptsView.findViewById(R.id.etWalletPasswordB);
|
||||
etPasswordB.setHint(getString(R.string.prompt_changepwB, walletName));
|
||||
|
||||
LinearLayout llFingerprintAuth = promptsView.findViewById(R.id.llFingerprintAuth);
|
||||
final Switch swFingerprintAllowed = (Switch) llFingerprintAuth.getChildAt(0);
|
||||
final SwitchMaterial swFingerprintAllowed = (SwitchMaterial) llFingerprintAuth.getChildAt(0);
|
||||
if (FingerprintHelper.isDeviceSupported(getActivity())) {
|
||||
llFingerprintAuth.setVisibility(View.VISIBLE);
|
||||
|
||||
@@ -507,7 +489,7 @@ public class GenerateReviewFragment extends Fragment {
|
||||
public void onClick(View view) {
|
||||
if (!swFingerprintAllowed.isChecked()) return;
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(getActivity());
|
||||
builder.setMessage(Html.fromHtml(getString(R.string.generate_fingerprint_warn)))
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(getString(R.string.label_ok), null)
|
||||
@@ -527,9 +509,6 @@ public class GenerateReviewFragment extends Fragment {
|
||||
etPasswordA.getEditText().addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
if (etPasswordA.getError() != null) {
|
||||
etPasswordA.setError(null);
|
||||
}
|
||||
if (etPasswordB.getError() != null) {
|
||||
etPasswordB.setError(null);
|
||||
}
|
||||
@@ -549,9 +528,6 @@ public class GenerateReviewFragment extends Fragment {
|
||||
etPasswordB.getEditText().addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
if (etPasswordA.getError() != null) {
|
||||
etPasswordA.setError(null);
|
||||
}
|
||||
if (etPasswordB.getError() != null) {
|
||||
etPasswordB.setError(null);
|
||||
}
|
||||
@@ -582,29 +558,20 @@ public class GenerateReviewFragment extends Fragment {
|
||||
});
|
||||
|
||||
openDialog = alertDialogBuilder.create();
|
||||
openDialog.setOnShowListener(new DialogInterface.OnShowListener() {
|
||||
@Override
|
||||
public void onShow(final DialogInterface dialog) {
|
||||
Button button = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_POSITIVE);
|
||||
button.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
String newPasswordA = etPasswordA.getEditText().getText().toString();
|
||||
String newPasswordB = etPasswordB.getEditText().getText().toString();
|
||||
// disallow empty passwords
|
||||
if (newPasswordA.isEmpty()) {
|
||||
etPasswordA.setError(getString(R.string.generate_empty_passwordB));
|
||||
} else if (!newPasswordA.equals(newPasswordB)) {
|
||||
etPasswordB.setError(getString(R.string.generate_bad_passwordB));
|
||||
} else if (newPasswordA.equals(newPasswordB)) {
|
||||
new AsyncChangePassword().execute(newPasswordA, Boolean.toString(swFingerprintAllowed.isChecked()));
|
||||
Helper.hideKeyboardAlways(getActivity());
|
||||
openDialog.dismiss();
|
||||
openDialog = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
openDialog.setOnShowListener(dialog -> {
|
||||
Button button = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_POSITIVE);
|
||||
button.setOnClickListener(view -> {
|
||||
String newPasswordA = etPasswordA.getEditText().getText().toString();
|
||||
String newPasswordB = etPasswordB.getEditText().getText().toString();
|
||||
if (!newPasswordA.equals(newPasswordB)) {
|
||||
etPasswordB.setError(getString(R.string.generate_bad_passwordB));
|
||||
} else {
|
||||
new AsyncChangePassword().execute(newPasswordA, Boolean.toString(swFingerprintAllowed.isChecked()));
|
||||
Helper.hideKeyboardAlways(getActivity());
|
||||
openDialog.dismiss();
|
||||
openDialog = null;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// accept keyboard "ok"
|
||||
@@ -615,11 +582,9 @@ public class GenerateReviewFragment extends Fragment {
|
||||
String newPasswordA = etPasswordA.getEditText().getText().toString();
|
||||
String newPasswordB = etPasswordB.getEditText().getText().toString();
|
||||
// disallow empty passwords
|
||||
if (newPasswordA.isEmpty()) {
|
||||
etPasswordA.setError(getString(R.string.generate_empty_passwordB));
|
||||
} else if (!newPasswordA.equals(newPasswordB)) {
|
||||
if (!newPasswordA.equals(newPasswordB)) {
|
||||
etPasswordB.setError(getString(R.string.generate_bad_passwordB));
|
||||
} else if (newPasswordA.equals(newPasswordB)) {
|
||||
} else {
|
||||
new AsyncChangePassword().execute(newPasswordA, Boolean.toString(swFingerprintAllowed.isChecked()));
|
||||
Helper.hideKeyboardAlways(getActivity());
|
||||
openDialog.dismiss();
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
39
app/src/main/java/com/m2049r/xmrwallet/MainActivity.java
Normal file
39
app/src/main/java/com/m2049r/xmrwallet/MainActivity.java
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 EarlOfEgo, m2049r
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.m2049r.xmrwallet.onboarding.OnBoardingActivity;
|
||||
import com.m2049r.xmrwallet.onboarding.OnBoardingManager;
|
||||
|
||||
public class MainActivity extends BaseActivity {
|
||||
@Override
|
||||
protected void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (OnBoardingManager.shouldShowOnBoarding(getApplicationContext())) {
|
||||
startActivity(new Intent(this, OnBoardingActivity.class));
|
||||
} else {
|
||||
startActivity(new Intent(this, LoginActivity.class));
|
||||
}
|
||||
finish();
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2021 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 com.m2049r.xmrwallet.model.Wallet;
|
||||
|
||||
public interface OnBlockUpdateListener {
|
||||
void onBlockUpdate(final Wallet wallet);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -19,7 +19,7 @@ package com.m2049r.xmrwallet;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.v4.app.Fragment;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -73,14 +73,7 @@ public class ScannerFragment extends Fragment implements ZXingScannerView.Result
|
||||
// * On older devices continuously stopping and resuming camera preview can result in freezing the app.
|
||||
// * I don't know why this is the case but I don't have the time to figure out.
|
||||
Handler handler = new Handler();
|
||||
handler.postDelayed(new
|
||||
|
||||
Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mScannerView.resumeCameraPreview(ScannerFragment.this);
|
||||
}
|
||||
}, 2000);
|
||||
handler.postDelayed(() -> mScannerView.resumeCameraPreview(ScannerFragment.this), 2000);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -17,13 +17,18 @@
|
||||
package com.m2049r.xmrwallet;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.util.LocaleHelper;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import static android.view.WindowManager.LayoutParams;
|
||||
|
||||
public abstract class SecureActivity extends AppCompatActivity {
|
||||
@@ -37,7 +42,36 @@ public abstract class SecureActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context context) {
|
||||
super.attachBaseContext(LocaleHelper.setLocale(context, LocaleHelper.getLocale(context)));
|
||||
protected void attachBaseContext(Context newBase) {
|
||||
super.attachBaseContext(newBase);
|
||||
applyOverrideConfiguration(new Configuration());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyOverrideConfiguration(Configuration newConfig) {
|
||||
super.applyOverrideConfiguration(updateConfigurationIfSupported(newConfig));
|
||||
}
|
||||
|
||||
private Configuration updateConfigurationIfSupported(Configuration config) {
|
||||
// Configuration.getLocales is added after 24 and Configuration.locale is deprecated in 24
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
if (!config.getLocales().isEmpty()) {
|
||||
return config;
|
||||
}
|
||||
} else {
|
||||
if (config.locale != null) {
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
Locale locale = LocaleHelper.getPreferredLocale(this);
|
||||
if (locale != null) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
config.setLocale(locale);
|
||||
} else {
|
||||
config.locale = locale;
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
251
app/src/main/java/com/m2049r/xmrwallet/SubaddressFragment.java
Normal file
251
app/src/main/java/com/m2049r/xmrwallet/SubaddressFragment.java
Normal file
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* 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.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.transition.MaterialElevationScale;
|
||||
import com.m2049r.xmrwallet.data.Subaddress;
|
||||
import com.m2049r.xmrwallet.layout.SubaddressInfoAdapter;
|
||||
import com.m2049r.xmrwallet.ledger.LedgerProgressDialog;
|
||||
import com.m2049r.xmrwallet.model.TransactionInfo;
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.model.WalletManager;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
|
||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class SubaddressFragment extends Fragment implements SubaddressInfoAdapter.OnInteractionListener,
|
||||
View.OnClickListener, OnBlockUpdateListener {
|
||||
static public final String KEY_MODE = "mode";
|
||||
static public final String MODE_MANAGER = "manager";
|
||||
|
||||
private SubaddressInfoAdapter adapter;
|
||||
|
||||
private Listener activityCallback;
|
||||
|
||||
private Wallet wallet;
|
||||
|
||||
// Container Activity must implement this interface
|
||||
public interface Listener {
|
||||
void onSubaddressSelected(Subaddress subaddress);
|
||||
|
||||
void setSubtitle(String title);
|
||||
|
||||
void setToolbarButton(int type);
|
||||
|
||||
void showSubaddress(View view, final int subaddressIndex);
|
||||
}
|
||||
|
||||
public interface ProgressListener {
|
||||
void showProgressDialog(int msgId);
|
||||
|
||||
void showLedgerProgressDialog(int mode);
|
||||
|
||||
void dismissProgressDialog();
|
||||
}
|
||||
|
||||
private ProgressListener progressCallback = null;
|
||||
|
||||
@Override
|
||||
public void onAttach(@NonNull Context context) {
|
||||
super.onAttach(context);
|
||||
if (context instanceof ProgressListener) {
|
||||
progressCallback = (ProgressListener) context;
|
||||
}
|
||||
if (context instanceof Listener) {
|
||||
activityCallback = (Listener) context;
|
||||
} else {
|
||||
throw new ClassCastException(context.toString()
|
||||
+ " must implement Listener");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
Timber.d("onPause()");
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
activityCallback.setSubtitle(getString(R.string.subbaddress_title));
|
||||
activityCallback.setToolbarButton(Toolbar.BUTTON_BACK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
Timber.d("onCreateView");
|
||||
|
||||
final Bundle b = getArguments();
|
||||
managerMode = ((b != null) && (MODE_MANAGER.equals(b.getString(KEY_MODE))));
|
||||
|
||||
View view = inflater.inflate(R.layout.fragment_subaddress, container, false);
|
||||
|
||||
final MaterialElevationScale exitTransition = new MaterialElevationScale(false);
|
||||
exitTransition.setDuration(getResources().getInteger(R.integer.tx_item_transition_duration));
|
||||
setExitTransition(exitTransition);
|
||||
final MaterialElevationScale reenterTransition = new MaterialElevationScale(true);
|
||||
reenterTransition.setDuration(getResources().getInteger(R.integer.tx_item_transition_duration));
|
||||
setReenterTransition(reenterTransition);
|
||||
|
||||
view.findViewById(R.id.fab).setOnClickListener(this);
|
||||
|
||||
if (managerMode) {
|
||||
view.findViewById(R.id.tvInstruction).setVisibility(View.GONE);
|
||||
view.findViewById(R.id.tvHint).setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
final RecyclerView list = view.findViewById(R.id.list);
|
||||
adapter = new SubaddressInfoAdapter(getActivity(), this);
|
||||
list.setAdapter(adapter);
|
||||
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
|
||||
@Override
|
||||
public void onItemRangeInserted(int positionStart, int itemCount) {
|
||||
list.scrollToPosition(positionStart);
|
||||
}
|
||||
});
|
||||
|
||||
Helper.hideKeyboard(getActivity());
|
||||
|
||||
wallet = WalletManager.getInstance().getWallet();
|
||||
|
||||
loadList();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
postponeEnterTransition();
|
||||
view.getViewTreeObserver().addOnPreDrawListener(() -> {
|
||||
startPostponedEnterTransition();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public void loadList() {
|
||||
Timber.d("loadList()");
|
||||
final int numSubaddresses = wallet.getNumSubaddresses();
|
||||
final List<Subaddress> list = new ArrayList<>();
|
||||
for (int i = 0; i < numSubaddresses; i++) {
|
||||
list.add(wallet.getSubaddressObject(i));
|
||||
}
|
||||
adapter.setInfos(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockUpdate(Wallet wallet) {
|
||||
loadList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int id = v.getId();
|
||||
if (id == R.id.fab) {
|
||||
getNewSubaddress();
|
||||
}
|
||||
}
|
||||
|
||||
private int lastUsedSubaddress() {
|
||||
int lastUsedSubaddress = 0;
|
||||
for (TransactionInfo info : wallet.getHistory().getAll()) {
|
||||
if (info.addressIndex > lastUsedSubaddress)
|
||||
lastUsedSubaddress = info.addressIndex;
|
||||
}
|
||||
return lastUsedSubaddress;
|
||||
}
|
||||
|
||||
private void getNewSubaddress() {
|
||||
final int maxSubaddresses = lastUsedSubaddress() + wallet.getDeviceType().getSubaddressLookahead();
|
||||
if (wallet.getNumSubaddresses() < maxSubaddresses)
|
||||
new AsyncSubaddress().executeOnExecutor(MoneroThreadPoolExecutor.MONERO_THREAD_POOL_EXECUTOR);
|
||||
else
|
||||
Toast.makeText(getActivity(), getString(R.string.max_subaddress_warning), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
@RequiredArgsConstructor
|
||||
private class AsyncSubaddress extends AsyncTask<Void, Void, Boolean> {
|
||||
boolean dialogOpened = false;
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
super.onPreExecute();
|
||||
if ((wallet.getDeviceType() == Wallet.Device.Device_Ledger) && (progressCallback != null)) {
|
||||
progressCallback.showLedgerProgressDialog(LedgerProgressDialog.TYPE_SUBADDRESS);
|
||||
dialogOpened = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... params) {
|
||||
if (params.length != 0) return false;
|
||||
wallet.getNewSubaddress();
|
||||
wallet.store();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean result) {
|
||||
super.onPostExecute(result);
|
||||
if (dialogOpened)
|
||||
progressCallback.dismissProgressDialog();
|
||||
if (!isAdded()) // never mind then
|
||||
return;
|
||||
loadList();
|
||||
}
|
||||
}
|
||||
|
||||
boolean managerMode = false;
|
||||
|
||||
// Callbacks from SubaddressInfoAdapter
|
||||
@Override
|
||||
public void onInteraction(final View view, final Subaddress subaddress) {
|
||||
if (managerMode)
|
||||
activityCallback.showSubaddress(view, subaddress.getAddressIndex());
|
||||
else
|
||||
activityCallback.onSubaddressSelected(subaddress); // also closes the fragment with onBackpressed()
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLongInteraction(View view, Subaddress subaddress) {
|
||||
activityCallback.showSubaddress(view, subaddress.getAddressIndex());
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* 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.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
import com.google.android.material.transition.MaterialContainerTransform;
|
||||
import com.m2049r.xmrwallet.data.Subaddress;
|
||||
import com.m2049r.xmrwallet.layout.TransactionInfoAdapter;
|
||||
import com.m2049r.xmrwallet.model.TransactionInfo;
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.util.ThemeHelper;
|
||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
public class SubaddressInfoFragment extends Fragment
|
||||
implements TransactionInfoAdapter.OnInteractionListener, OnBlockUpdateListener {
|
||||
private TransactionInfoAdapter adapter;
|
||||
|
||||
private Subaddress subaddress;
|
||||
|
||||
private TextInputLayout etName;
|
||||
private TextView tvAddress;
|
||||
private TextView tvTxLabel;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_subaddressinfo, container, false);
|
||||
|
||||
etName = view.findViewById(R.id.etName);
|
||||
tvAddress = view.findViewById(R.id.tvAddress);
|
||||
tvTxLabel = view.findViewById(R.id.tvTxLabel);
|
||||
|
||||
final RecyclerView list = view.findViewById(R.id.list);
|
||||
adapter = new TransactionInfoAdapter(getActivity(), this);
|
||||
list.setAdapter(adapter);
|
||||
|
||||
final Wallet wallet = activityCallback.getWallet();
|
||||
|
||||
Bundle b = getArguments();
|
||||
final int subaddressIndex = b.getInt("subaddressIndex");
|
||||
subaddress = wallet.getSubaddressObject(subaddressIndex);
|
||||
|
||||
etName.getEditText().setText(subaddress.getDisplayLabel());
|
||||
tvAddress.setText(getContext().getString(R.string.subbaddress_info_subtitle,
|
||||
subaddress.getAddressIndex(), subaddress.getSquashedAddress()));
|
||||
|
||||
etName.getEditText().setOnFocusChangeListener((v, hasFocus) -> {
|
||||
if (!hasFocus) {
|
||||
wallet.setSubaddressLabel(subaddressIndex, etName.getEditText().getText().toString());
|
||||
}
|
||||
});
|
||||
etName.getEditText().setOnEditorActionListener((v, actionId, event) -> {
|
||||
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN))
|
||||
|| (actionId == EditorInfo.IME_ACTION_DONE)) {
|
||||
Helper.hideKeyboard(getActivity());
|
||||
wallet.setSubaddressLabel(subaddressIndex, etName.getEditText().getText().toString());
|
||||
onRefreshed(wallet);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
onRefreshed(wallet);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
final MaterialContainerTransform transform = new MaterialContainerTransform();
|
||||
transform.setDrawingViewId(R.id.fragment_container);
|
||||
transform.setDuration(getResources().getInteger(R.integer.tx_item_transition_duration));
|
||||
transform.setAllContainerColors(ThemeHelper.getThemedColor(getContext(), android.R.attr.colorBackground));
|
||||
setSharedElementEnterTransition(transform);
|
||||
}
|
||||
|
||||
public void onRefreshed(final Wallet wallet) {
|
||||
Timber.d("onRefreshed");
|
||||
List<TransactionInfo> list = new ArrayList<>();
|
||||
for (TransactionInfo info : wallet.getHistory().getAll()) {
|
||||
if (info.addressIndex == subaddress.getAddressIndex())
|
||||
list.add(info);
|
||||
}
|
||||
adapter.setInfos(list);
|
||||
if (list.isEmpty())
|
||||
tvTxLabel.setText(R.string.subaddress_notx_label);
|
||||
else
|
||||
tvTxLabel.setText(R.string.subaddress_tx_label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockUpdate(Wallet wallet) {
|
||||
onRefreshed(wallet);
|
||||
}
|
||||
|
||||
// Callbacks from TransactionInfoAdapter
|
||||
@Override
|
||||
public void onInteraction(final View view, final TransactionInfo infoItem) {
|
||||
activityCallback.onTxDetailsRequest(view, infoItem);
|
||||
}
|
||||
|
||||
Listener activityCallback;
|
||||
|
||||
// Container Activity must implement this interface
|
||||
public interface Listener {
|
||||
void onTxDetailsRequest(View view, TransactionInfo info);
|
||||
|
||||
Wallet getWallet();
|
||||
|
||||
void setToolbarButton(int type);
|
||||
|
||||
void setTitle(String title, String subtitle);
|
||||
|
||||
void setSubtitle(String subtitle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(@NonNull Context context) {
|
||||
super.onAttach(context);
|
||||
if (context instanceof Listener) {
|
||||
this.activityCallback = (Listener) context;
|
||||
} else {
|
||||
throw new ClassCastException(context.toString()
|
||||
+ " must implement Listener");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
Timber.d("onResume()");
|
||||
activityCallback.setSubtitle(getString(R.string.subbaddress_title));
|
||||
activityCallback.setToolbarButton(Toolbar.BUTTON_BACK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
}
|
||||
}
|
@@ -16,27 +16,37 @@
|
||||
|
||||
package com.m2049r.xmrwallet;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Paint;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.text.Html;
|
||||
import android.text.InputType;
|
||||
import android.text.Spanned;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.google.android.material.transition.MaterialContainerTransform;
|
||||
import com.google.android.material.transition.MaterialElevationScale;
|
||||
import com.m2049r.xmrwallet.data.Subaddress;
|
||||
import com.m2049r.xmrwallet.data.UserNotes;
|
||||
import com.m2049r.xmrwallet.model.TransactionInfo;
|
||||
import com.m2049r.xmrwallet.model.Transfer;
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.data.UserNotes;
|
||||
import com.m2049r.xmrwallet.util.ThemeHelper;
|
||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
@@ -46,6 +56,8 @@ import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
public class TxFragment extends Fragment {
|
||||
|
||||
static public final String ARG_INFO = "info";
|
||||
@@ -77,17 +89,28 @@ public class TxFragment extends Fragment {
|
||||
private TextView tvTxXmrToKey;
|
||||
private TextView tvDestinationBtc;
|
||||
private TextView tvTxAmountBtc;
|
||||
private TextView tvXmrToSupport;
|
||||
private TextView tvXmrToKeyLabel;
|
||||
private ImageView tvXmrToLogo;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_tx_info, container, false);
|
||||
|
||||
final MaterialElevationScale exitTransition = new MaterialElevationScale(false);
|
||||
exitTransition.setDuration(getResources().getInteger(R.integer.tx_item_transition_duration));
|
||||
setExitTransition(exitTransition);
|
||||
final MaterialElevationScale reenterTransition = new MaterialElevationScale(true);
|
||||
reenterTransition.setDuration(getResources().getInteger(R.integer.tx_item_transition_duration));
|
||||
setReenterTransition(reenterTransition);
|
||||
|
||||
cvXmrTo = view.findViewById(R.id.cvXmrTo);
|
||||
tvTxXmrToKey = view.findViewById(R.id.tvTxXmrToKey);
|
||||
tvDestinationBtc = view.findViewById(R.id.tvDestinationBtc);
|
||||
tvTxAmountBtc = view.findViewById(R.id.tvTxAmountBtc);
|
||||
tvXmrToSupport = view.findViewById(R.id.tvXmrToSupport);
|
||||
tvXmrToKeyLabel = view.findViewById(R.id.tvXmrToKeyLabel);
|
||||
tvXmrToLogo = view.findViewById(R.id.tvXmrToLogo);
|
||||
|
||||
tvAccount = view.findViewById(R.id.tvAccount);
|
||||
tvAddress = view.findViewById(R.id.tvAddress);
|
||||
@@ -104,17 +127,13 @@ public class TxFragment extends Fragment {
|
||||
|
||||
etTxNotes.setRawInputType(InputType.TYPE_CLASS_TEXT);
|
||||
|
||||
tvTxXmrToKey.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Helper.clipBoardCopy(getActivity(), getString(R.string.label_copy_xmrtokey), tvTxXmrToKey.getText().toString());
|
||||
Toast.makeText(getActivity(), getString(R.string.message_copy_xmrtokey), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
tvTxXmrToKey.setOnClickListener(v -> {
|
||||
Helper.clipBoardCopy(getActivity(), getString(R.string.label_copy_xmrtokey), tvTxXmrToKey.getText().toString());
|
||||
Toast.makeText(getActivity(), getString(R.string.message_copy_xmrtokey), Toast.LENGTH_SHORT).show();
|
||||
});
|
||||
|
||||
Bundle args = getArguments();
|
||||
TransactionInfo info = args.getParcelable(ARG_INFO);
|
||||
show(info);
|
||||
info = getArguments().getParcelable(ARG_INFO);
|
||||
show();
|
||||
return view;
|
||||
}
|
||||
|
||||
@@ -183,7 +202,7 @@ public class TxFragment extends Fragment {
|
||||
TransactionInfo info = null;
|
||||
UserNotes userNotes = null;
|
||||
|
||||
void loadNotes(TransactionInfo info) {
|
||||
void loadNotes() {
|
||||
if ((userNotes == null) || (info.notes == null)) {
|
||||
info.notes = activityCallback.getTxNotes(info.hash);
|
||||
}
|
||||
@@ -196,19 +215,28 @@ public class TxFragment extends Fragment {
|
||||
tvTxFee.setTextColor(clr);
|
||||
}
|
||||
|
||||
private void show(TransactionInfo info) {
|
||||
private void showSubaddressLabel() {
|
||||
final Subaddress subaddress = activityCallback.getWalletSubaddress(info.accountIndex, info.addressIndex);
|
||||
final Context ctx = getContext();
|
||||
Spanned label = Html.fromHtml(ctx.getString(R.string.tx_account_formatted,
|
||||
info.accountIndex, info.addressIndex,
|
||||
Integer.toHexString(ContextCompat.getColor(ctx, R.color.monerujoGreen) & 0xFFFFFF),
|
||||
Integer.toHexString(ContextCompat.getColor(ctx, R.color.monerujoBackground) & 0xFFFFFF),
|
||||
subaddress.getDisplayLabel()));
|
||||
tvAccount.setText(label);
|
||||
tvAccount.setOnClickListener(v -> activityCallback.showSubaddress(v, info.addressIndex));
|
||||
}
|
||||
|
||||
private void show() {
|
||||
if (info.txKey == null) {
|
||||
info.txKey = activityCallback.getTxKey(info.hash);
|
||||
}
|
||||
if (info.address == null) {
|
||||
info.address = activityCallback.getTxAddress(info.account, info.subaddress);
|
||||
info.address = activityCallback.getTxAddress(info.accountIndex, info.addressIndex);
|
||||
}
|
||||
loadNotes(info);
|
||||
loadNotes();
|
||||
|
||||
activityCallback.setSubtitle(getString(R.string.tx_title));
|
||||
activityCallback.setToolbarButton(Toolbar.BUTTON_BACK);
|
||||
|
||||
tvAccount.setText(getString(R.string.tx_account_formatted, info.account, info.subaddress));
|
||||
showSubaddressLabel();
|
||||
tvAddress.setText(info.address);
|
||||
|
||||
tvTxTimestamp.setText(TS_FORMATTER.format(new Date(info.timestamp * 1000)));
|
||||
@@ -242,13 +270,13 @@ public class TxFragment extends Fragment {
|
||||
} else if (info.isPending) {
|
||||
setTxColour(ContextCompat.getColor(getContext(), R.color.tx_pending));
|
||||
} else if (info.direction == TransactionInfo.Direction.Direction_In) {
|
||||
setTxColour(ContextCompat.getColor(getContext(), R.color.tx_green));
|
||||
setTxColour(ContextCompat.getColor(getContext(), R.color.tx_plus));
|
||||
} else {
|
||||
setTxColour(ContextCompat.getColor(getContext(), R.color.tx_red));
|
||||
setTxColour(ContextCompat.getColor(getContext(), R.color.tx_minus));
|
||||
}
|
||||
Set<String> destinations = new HashSet<>();
|
||||
StringBuffer sb = new StringBuffer();
|
||||
StringBuffer dstSb = new StringBuffer();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
StringBuilder dstSb = new StringBuilder();
|
||||
if (info.transfers != null) {
|
||||
boolean newline = false;
|
||||
for (Transfer transfer : info.transfers) {
|
||||
@@ -272,23 +300,45 @@ public class TxFragment extends Fragment {
|
||||
}
|
||||
} else {
|
||||
sb.append("-");
|
||||
dstSb.append(info.direction ==
|
||||
TransactionInfo.Direction.Direction_In ?
|
||||
activityCallback.getWalletSubaddress(info.account, info.subaddress) :
|
||||
dstSb.append(info.direction == TransactionInfo.Direction.Direction_In ?
|
||||
activityCallback.getWalletSubaddress(info.accountIndex, info.addressIndex).getAddress() :
|
||||
"-");
|
||||
}
|
||||
tvTxTransfers.setText(sb.toString());
|
||||
tvDestination.setText(dstSb.toString());
|
||||
this.info = info;
|
||||
showBtcInfo();
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
void showBtcInfo() {
|
||||
if (userNotes.xmrtoKey != null) {
|
||||
cvXmrTo.setVisibility(View.VISIBLE);
|
||||
tvTxXmrToKey.setText(userNotes.xmrtoKey);
|
||||
String key = userNotes.xmrtoKey;
|
||||
if ("xmrto".equals(userNotes.xmrtoTag)) { // legacy xmr.to service :(
|
||||
key = "xmrto-" + key;
|
||||
}
|
||||
tvTxXmrToKey.setText(key);
|
||||
tvDestinationBtc.setText(userNotes.xmrtoDestination);
|
||||
tvTxAmountBtc.setText(userNotes.xmrtoAmount + " BTC");
|
||||
tvTxAmountBtc.setText(userNotes.xmrtoAmount + " " + userNotes.xmrtoCurrency);
|
||||
switch (userNotes.xmrtoTag) {
|
||||
case "xmrto":
|
||||
tvXmrToSupport.setVisibility(View.GONE);
|
||||
tvXmrToKeyLabel.setVisibility(View.INVISIBLE);
|
||||
tvXmrToLogo.setImageResource(R.drawable.ic_xmrto_logo);
|
||||
break;
|
||||
case "side": // defaults in layout - just add underline
|
||||
tvXmrToSupport.setPaintFlags(tvXmrToSupport.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
|
||||
tvXmrToSupport.setOnClickListener(v -> {
|
||||
Uri uri = Uri.parse("https://sideshift.ai/orders/" + userNotes.xmrtoKey);
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
startActivity(intent);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
tvXmrToSupport.setVisibility(View.GONE);
|
||||
tvXmrToKeyLabel.setVisibility(View.INVISIBLE);
|
||||
tvXmrToLogo.setVisibility(View.GONE);
|
||||
}
|
||||
} else {
|
||||
cvXmrTo.setVisibility(View.GONE);
|
||||
}
|
||||
@@ -298,6 +348,11 @@ public class TxFragment extends Fragment {
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setHasOptionsMenu(true);
|
||||
final MaterialContainerTransform transform = new MaterialContainerTransform();
|
||||
transform.setDrawingViewId(R.id.fragment_container);
|
||||
transform.setDuration(getResources().getInteger(R.integer.tx_item_transition_duration));
|
||||
transform.setAllContainerColors(ThemeHelper.getThemedColor(getContext(), android.R.attr.colorBackground));
|
||||
setSharedElementEnterTransition(transform);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -309,7 +364,7 @@ public class TxFragment extends Fragment {
|
||||
Listener activityCallback;
|
||||
|
||||
public interface Listener {
|
||||
String getWalletSubaddress(int accountIndex, int subaddressIndex);
|
||||
Subaddress getWalletSubaddress(int accountIndex, int subaddressIndex);
|
||||
|
||||
String getTxKey(String hash);
|
||||
|
||||
@@ -323,6 +378,8 @@ public class TxFragment extends Fragment {
|
||||
|
||||
void setSubtitle(String subtitle);
|
||||
|
||||
void showSubaddress(View view, final int subaddressIndex);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -347,4 +404,13 @@ public class TxFragment extends Fragment {
|
||||
Helper.hideKeyboard(getActivity());
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
Timber.d("onResume()");
|
||||
activityCallback.setSubtitle(getString(R.string.tx_title));
|
||||
activityCallback.setToolbarButton(Toolbar.BUTTON_BACK);
|
||||
showSubaddressLabel();
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -16,13 +16,15 @@
|
||||
|
||||
package com.m2049r.xmrwallet;
|
||||
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Build;
|
||||
|
||||
import com.m2049r.xmrwallet.BuildConfig;
|
||||
import com.m2049r.xmrwallet.model.NetworkType;
|
||||
import com.m2049r.xmrwallet.util.LocaleHelper;
|
||||
import com.m2049r.xmrwallet.util.NightmodeHelper;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
@@ -34,18 +36,23 @@ public class XmrWalletApplication extends Application {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Timber.plant(new Timber.DebugTree());
|
||||
}
|
||||
NightmodeHelper.setPreferredNightmode(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context context) {
|
||||
super.attachBaseContext(LocaleHelper.setLocale(context, LocaleHelper.getLocale(context)));
|
||||
super.attachBaseContext(LocaleHelper.setPreferredLocale(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration configuration) {
|
||||
super.onConfigurationChanged(configuration);
|
||||
LocaleHelper.updateSystemDefaultLocale(configuration.locale);
|
||||
LocaleHelper.setLocale(XmrWalletApplication.this, LocaleHelper.getLocale(XmrWalletApplication.this));
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
LocaleHelper.updateSystemDefaultLocale(configuration.getLocales().get(0));
|
||||
} else {
|
||||
LocaleHelper.updateSystemDefaultLocale(configuration.locale);
|
||||
}
|
||||
LocaleHelper.setPreferredLocale(this);
|
||||
}
|
||||
|
||||
static public NetworkType getNetworkType() {
|
||||
@@ -54,7 +61,7 @@ public class XmrWalletApplication extends Application {
|
||||
return NetworkType.NetworkType_Mainnet;
|
||||
case "stagenet":
|
||||
return NetworkType.NetworkType_Stagenet;
|
||||
case "testnet":
|
||||
case "devnet": // flavors cannot start with "test"
|
||||
return NetworkType.NetworkType_Testnet;
|
||||
default:
|
||||
throw new IllegalStateException("unknown net flavor " + BuildConfig.FLAVOR_net);
|
||||
|
File diff suppressed because it is too large
Load Diff
89
app/src/main/java/com/m2049r/xmrwallet/data/Crypto.java
Normal file
89
app/src/main/java/com/m2049r/xmrwallet/data/Crypto.java
Normal file
@@ -0,0 +1,89 @@
|
||||
package com.m2049r.xmrwallet.data;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.m2049r.xmrwallet.R;
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.util.validator.BitcoinAddressType;
|
||||
import com.m2049r.xmrwallet.util.validator.BitcoinAddressValidator;
|
||||
import com.m2049r.xmrwallet.util.validator.EthAddressValidator;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public enum Crypto {
|
||||
XMR("XMR", true, "monero:tx_amount:recipient_name:tx_description", R.id.ibXMR, R.drawable.ic_monero, R.drawable.ic_monero_bw, Wallet::isAddressValid),
|
||||
BTC("BTC", true, "bitcoin:amount:label:message", R.id.ibBTC, R.drawable.ic_xmrto_btc, R.drawable.ic_xmrto_btc_off, address -> {
|
||||
return BitcoinAddressValidator.validate(address, BitcoinAddressType.BTC);
|
||||
}),
|
||||
DASH("DASH", true, "dash:amount:label:message", R.id.ibDASH, R.drawable.ic_xmrto_dash, R.drawable.ic_xmrto_dash_off, address -> {
|
||||
return BitcoinAddressValidator.validate(address, BitcoinAddressType.DASH);
|
||||
}),
|
||||
DOGE("DOGE", true, "dogecoin:amount:label:message", R.id.ibDOGE, R.drawable.ic_xmrto_doge, R.drawable.ic_xmrto_doge_off, address -> {
|
||||
return BitcoinAddressValidator.validate(address, BitcoinAddressType.DOGE);
|
||||
}),
|
||||
ETH("ETH", false, "ethereum:amount:label:message", R.id.ibETH, R.drawable.ic_xmrto_eth, R.drawable.ic_xmrto_eth_off, EthAddressValidator::validate),
|
||||
LTC("LTC", true, "litecoin:amount:label:message", R.id.ibLTC, R.drawable.ic_xmrto_ltc, R.drawable.ic_xmrto_ltc_off, address -> {
|
||||
return BitcoinAddressValidator.validate(address, BitcoinAddressType.LTC);
|
||||
});
|
||||
|
||||
@Getter
|
||||
@NonNull
|
||||
private final String symbol;
|
||||
@Getter
|
||||
private final boolean casefull;
|
||||
@NonNull
|
||||
private final String uriSpec;
|
||||
@Getter
|
||||
private final int buttonId;
|
||||
@Getter
|
||||
private final int iconEnabledId;
|
||||
@Getter
|
||||
private final int iconDisabledId;
|
||||
@NonNull
|
||||
private final Validator validator;
|
||||
|
||||
@Nullable
|
||||
public static Crypto withScheme(@NonNull String scheme) {
|
||||
for (Crypto crypto : values()) {
|
||||
if (crypto.getUriScheme().equals(scheme)) return crypto;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Crypto withSymbol(@NonNull String symbol) {
|
||||
final String upperSymbol = symbol.toUpperCase();
|
||||
for (Crypto crypto : values()) {
|
||||
if (crypto.symbol.equals(upperSymbol)) return crypto;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
interface Validator {
|
||||
boolean validate(String address);
|
||||
}
|
||||
|
||||
// TODO maybe cache these segments
|
||||
String getUriScheme() {
|
||||
return uriSpec.split(":")[0];
|
||||
}
|
||||
|
||||
String getUriAmount() {
|
||||
return uriSpec.split(":")[1];
|
||||
}
|
||||
|
||||
String getUriLabel() {
|
||||
return uriSpec.split(":")[2];
|
||||
}
|
||||
|
||||
String getUriMessage() {
|
||||
return uriSpec.split(":")[3];
|
||||
}
|
||||
|
||||
boolean validate(String address) {
|
||||
return validator.validate(address);
|
||||
}
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2020 m2049r
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet.data;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
// Nodes stolen from https://moneroworld.com/#nodes
|
||||
|
||||
@AllArgsConstructor
|
||||
public enum DefaultNodes {
|
||||
MONERUJO("nodex.monerujo.io:18081"),
|
||||
XMRTO("node.xmr.to:18081"),
|
||||
SUPPORTXMR("node.supportxmr.com:18081"),
|
||||
HASHVAULT("nodes.hashvault.pro:18081"),
|
||||
MONEROWORLD("node.moneroworld.com:18089"),
|
||||
XMRTW("opennode.xmr-tw.org:18089");
|
||||
|
||||
@Getter
|
||||
private final String uri;
|
||||
}
|
@@ -26,6 +26,8 @@ import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class Node {
|
||||
@@ -33,27 +35,43 @@ public class Node {
|
||||
static public final String STAGENET = "stagenet";
|
||||
static public final String TESTNET = "testnet";
|
||||
|
||||
@Getter
|
||||
private String name = null;
|
||||
@Getter
|
||||
final private NetworkType networkType;
|
||||
InetAddress hostAddress;
|
||||
@Getter
|
||||
private String host;
|
||||
@Getter
|
||||
@Setter
|
||||
int rpcPort = 0;
|
||||
private int levinPort = 0;
|
||||
@Getter
|
||||
@Setter
|
||||
private String username = "";
|
||||
@Getter
|
||||
@Setter
|
||||
private String password = "";
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean favourite = false;
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean selected = false;
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hostAddress.hashCode();
|
||||
}
|
||||
|
||||
// Nodes are equal if they are the same host address & are on the same network
|
||||
// Nodes are equal if they are the same host address:port & are on the same network
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof Node)) return false;
|
||||
final Node anotherNode = (Node) other;
|
||||
return (hostAddress.equals(anotherNode.hostAddress) && (networkType == anotherNode.networkType));
|
||||
return (hostAddress.equals(anotherNode.hostAddress)
|
||||
&& (rpcPort == anotherNode.rpcPort)
|
||||
&& (networkType == anotherNode.networkType));
|
||||
}
|
||||
|
||||
static public Node fromString(String nodeString) {
|
||||
@@ -193,7 +211,6 @@ public class Node {
|
||||
this.levinPort = socketAddress.getPort();
|
||||
this.username = "";
|
||||
this.password = "";
|
||||
//this.name = socketAddress.getHostName(); // triggers DNS so we don't do it by default
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
@@ -204,14 +221,6 @@ public class Node {
|
||||
return hostAddress.getHostAddress();
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public int getRpcPort() {
|
||||
return rpcPort;
|
||||
}
|
||||
|
||||
public void setHost(String host) throws UnknownHostException {
|
||||
if ((host == null) || (host.isEmpty()))
|
||||
throw new UnknownHostException("loopback not supported (yet?)");
|
||||
@@ -219,18 +228,6 @@ public class Node {
|
||||
this.hostAddress = InetAddress.getByName(host);
|
||||
}
|
||||
|
||||
public void setUsername(String user) {
|
||||
username = user;
|
||||
}
|
||||
|
||||
public void setPassword(String pass) {
|
||||
password = pass;
|
||||
}
|
||||
|
||||
public void setRpcPort(int port) {
|
||||
this.rpcPort = port;
|
||||
}
|
||||
|
||||
public void setName() {
|
||||
if (name == null)
|
||||
this.name = hostAddress.getHostName();
|
||||
@@ -243,30 +240,6 @@ public class Node {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public NetworkType getNetworkType() {
|
||||
return networkType;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public boolean isFavourite() {
|
||||
return favourite;
|
||||
}
|
||||
|
||||
public void setFavourite(boolean favourite) {
|
||||
this.favourite = favourite;
|
||||
}
|
||||
|
||||
public void toggleFavourite() {
|
||||
favourite = !favourite;
|
||||
}
|
||||
|
@@ -21,8 +21,8 @@ import com.burgstaller.okhttp.CachingAuthenticatorDecorator;
|
||||
import com.burgstaller.okhttp.digest.CachingAuthenticator;
|
||||
import com.burgstaller.okhttp.digest.Credentials;
|
||||
import com.burgstaller.okhttp.digest.DigestAuthenticator;
|
||||
import com.m2049r.levin.scanner.Dispatcher;
|
||||
import com.m2049r.levin.scanner.LevinPeer;
|
||||
import com.m2049r.xmrwallet.util.NodePinger;
|
||||
import com.m2049r.xmrwallet.util.OkHttpHelper;
|
||||
|
||||
import org.json.JSONException;
|
||||
@@ -36,6 +36,8 @@ import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.OkHttpClient;
|
||||
@@ -46,14 +48,24 @@ import okhttp3.ResponseBody;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class NodeInfo extends Node {
|
||||
final static public int MIN_MAJOR_VERSION = 11;
|
||||
final static public int MIN_MAJOR_VERSION = 14;
|
||||
final static public String RPC_VERSION = "2.0";
|
||||
|
||||
@Getter
|
||||
private long height = 0;
|
||||
@Getter
|
||||
private long timestamp = 0;
|
||||
@Getter
|
||||
private int majorVersion = 0;
|
||||
@Getter
|
||||
private double responseTime = Double.MAX_VALUE;
|
||||
@Getter
|
||||
private int responseCode = 0;
|
||||
@Getter
|
||||
private boolean tested = false;
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean selecting = false;
|
||||
|
||||
public void clear() {
|
||||
height = 0;
|
||||
@@ -61,13 +73,13 @@ public class NodeInfo extends Node {
|
||||
responseTime = Double.MAX_VALUE;
|
||||
responseCode = 0;
|
||||
timestamp = 0;
|
||||
tested = false;
|
||||
}
|
||||
|
||||
static public NodeInfo fromString(String nodeString) {
|
||||
try {
|
||||
return new NodeInfo(nodeString);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
Timber.w(ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -113,26 +125,6 @@ public class NodeInfo extends Node {
|
||||
super();
|
||||
}
|
||||
|
||||
public long getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public int getMajorVersion() {
|
||||
return majorVersion;
|
||||
}
|
||||
|
||||
public double getResponseTime() {
|
||||
return responseTime;
|
||||
}
|
||||
|
||||
public int getResponseCode() {
|
||||
return responseCode;
|
||||
}
|
||||
|
||||
public boolean isSuccessful() {
|
||||
return (responseCode >= 200) && (responseCode < 300);
|
||||
}
|
||||
@@ -145,23 +137,20 @@ public class NodeInfo extends Node {
|
||||
return isSuccessful() && (majorVersion >= MIN_MAJOR_VERSION) && (responseTime < Double.MAX_VALUE);
|
||||
}
|
||||
|
||||
static public Comparator<NodeInfo> BestNodeComparator = new Comparator<NodeInfo>() {
|
||||
@Override
|
||||
public int compare(NodeInfo o1, NodeInfo o2) {
|
||||
if (o1.isValid()) {
|
||||
if (o2.isValid()) { // both are valid
|
||||
// higher node wins
|
||||
int heightDiff = (int) (o2.height - o1.height);
|
||||
if (Math.abs(heightDiff) > Dispatcher.HEIGHT_WINDOW)
|
||||
return heightDiff;
|
||||
// if they are (nearly) equal, faster node wins
|
||||
return (int) Math.signum(o1.responseTime - o2.responseTime);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
static public Comparator<NodeInfo> BestNodeComparator = (o1, o2) -> {
|
||||
if (o1.isValid()) {
|
||||
if (o2.isValid()) { // both are valid
|
||||
// higher node wins
|
||||
int heightDiff = (int) (o2.height - o1.height);
|
||||
if (heightDiff != 0)
|
||||
return heightDiff;
|
||||
// if they are equal, faster node wins
|
||||
return (int) Math.signum(o1.responseTime - o2.responseTime);
|
||||
} else {
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -192,7 +181,7 @@ public class NodeInfo extends Node {
|
||||
}
|
||||
|
||||
private static final int HTTP_TIMEOUT = OkHttpHelper.HTTP_TIMEOUT;
|
||||
public static final double PING_GOOD = HTTP_TIMEOUT / 3; //ms
|
||||
public static final double PING_GOOD = HTTP_TIMEOUT / 3.0; //ms
|
||||
public static final double PING_MEDIUM = 2 * PING_GOOD; //ms
|
||||
public static final double PING_BAD = HTTP_TIMEOUT;
|
||||
|
||||
@@ -200,7 +189,15 @@ public class NodeInfo extends Node {
|
||||
return testRpcService(rpcPort);
|
||||
}
|
||||
|
||||
public boolean testRpcService(NodePinger.Listener listener) {
|
||||
boolean result = testRpcService(rpcPort);
|
||||
if (listener != null)
|
||||
listener.publish(this);
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean testRpcService(int port) {
|
||||
Timber.d("Testing %s", toNodeString());
|
||||
clear();
|
||||
try {
|
||||
OkHttpClient client = OkHttpHelper.getEagerClient();
|
||||
@@ -230,8 +227,7 @@ public class NodeInfo extends Node {
|
||||
if (response.isSuccessful()) {
|
||||
ResponseBody respBody = response.body(); // closed through Response object
|
||||
if ((respBody != null) && (respBody.contentLength() < 2000)) { // sanity check
|
||||
final JSONObject json = new JSONObject(
|
||||
respBody.string());
|
||||
final JSONObject json = new JSONObject(respBody.string());
|
||||
String rpcVersion = json.getString("jsonrpc");
|
||||
if (!RPC_VERSION.equals(rpcVersion))
|
||||
return false;
|
||||
@@ -247,8 +243,9 @@ public class NodeInfo extends Node {
|
||||
}
|
||||
}
|
||||
} catch (IOException | JSONException ex) {
|
||||
// failure
|
||||
Timber.d(ex.getMessage());
|
||||
Timber.d(ex);
|
||||
} finally {
|
||||
tested = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
63
app/src/main/java/com/m2049r/xmrwallet/data/Subaddress.java
Normal file
63
app/src/main/java/com/m2049r/xmrwallet/data/Subaddress.java
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2018 m2049r
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet.data;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
public class Subaddress implements Comparable<Subaddress> {
|
||||
@Getter
|
||||
final private int accountIndex;
|
||||
@Getter
|
||||
final private int addressIndex;
|
||||
@Getter
|
||||
final private String address;
|
||||
@Getter
|
||||
private final String label;
|
||||
@Getter
|
||||
@Setter
|
||||
private long amount;
|
||||
|
||||
@Override
|
||||
public int compareTo(Subaddress another) { // newer is <
|
||||
final int compareAccountIndex = another.accountIndex - accountIndex;
|
||||
if (compareAccountIndex == 0)
|
||||
return another.addressIndex - addressIndex;
|
||||
return compareAccountIndex;
|
||||
}
|
||||
|
||||
public String getSquashedAddress() {
|
||||
return address.substring(0, 8) + "…" + address.substring(address.length() - 8);
|
||||
}
|
||||
|
||||
public static final Pattern DEFAULT_LABEL_FORMATTER = Pattern.compile("^[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{2}:[0-9]{2}:[0-9]{2}$");
|
||||
|
||||
public String getDisplayLabel() {
|
||||
if (label.isEmpty() || (DEFAULT_LABEL_FORMATTER.matcher(label).matches()))
|
||||
return ("#" + addressIndex);
|
||||
else
|
||||
return label;
|
||||
}
|
||||
}
|
@@ -20,6 +20,8 @@ import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.m2049r.xmrwallet.model.PendingTransaction;
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
|
||||
// https://stackoverflow.com/questions/2139134/how-to-send-an-object-from-one-android-activity-to-another-using-intents
|
||||
public class TxData implements Parcelable {
|
||||
@@ -52,6 +54,10 @@ public class TxData implements Parcelable {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public double getAmountAsDouble() {
|
||||
return 1.0 * amount / Helper.ONE_XMR;
|
||||
}
|
||||
|
||||
public int getMixin() {
|
||||
return mixin;
|
||||
}
|
||||
@@ -68,6 +74,10 @@ public class TxData implements Parcelable {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public void setAmount(double amount) {
|
||||
this.amount = Wallet.getAmountFromDouble(amount);
|
||||
}
|
||||
|
||||
public void setMixin(int mixin) {
|
||||
this.mixin = mixin;
|
||||
}
|
||||
|
@@ -18,11 +18,23 @@ package com.m2049r.xmrwallet.data;
|
||||
|
||||
import android.os.Parcel;
|
||||
|
||||
public class TxDataBtc extends TxData {
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
private String xmrtoUuid;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class TxDataBtc extends TxData {
|
||||
@Getter
|
||||
@Setter
|
||||
private String btcSymbol; // the actual non-XMR thing we're sending
|
||||
@Getter
|
||||
@Setter
|
||||
private String xmrtoOrderId; // shown in success screen
|
||||
@Getter
|
||||
@Setter
|
||||
private String btcAddress;
|
||||
private String bip70;
|
||||
@Getter
|
||||
@Setter
|
||||
private double btcAmount;
|
||||
|
||||
public TxDataBtc() {
|
||||
@@ -33,44 +45,12 @@ public class TxDataBtc extends TxData {
|
||||
super(txDataBtc);
|
||||
}
|
||||
|
||||
public String getXmrtoUuid() {
|
||||
return xmrtoUuid;
|
||||
}
|
||||
|
||||
public void setXmrtoUuid(String xmrtoUuid) {
|
||||
this.xmrtoUuid = xmrtoUuid;
|
||||
}
|
||||
|
||||
public String getBtcAddress() {
|
||||
return btcAddress;
|
||||
}
|
||||
|
||||
public void setBtcAddress(String btcAddress) {
|
||||
this.btcAddress = btcAddress;
|
||||
}
|
||||
|
||||
public String getBip70() {
|
||||
return bip70;
|
||||
}
|
||||
|
||||
public void setBip70(String bip70) {
|
||||
this.bip70 = bip70;
|
||||
}
|
||||
|
||||
public double getBtcAmount() {
|
||||
return btcAmount;
|
||||
}
|
||||
|
||||
public void setBtcAmount(double btcAmount) {
|
||||
this.btcAmount = btcAmount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
super.writeToParcel(out, flags);
|
||||
out.writeString(xmrtoUuid);
|
||||
out.writeString(btcSymbol);
|
||||
out.writeString(xmrtoOrderId);
|
||||
out.writeString(btcAddress);
|
||||
out.writeString(bip70);
|
||||
out.writeDouble(btcAmount);
|
||||
}
|
||||
|
||||
@@ -87,23 +67,35 @@ public class TxDataBtc extends TxData {
|
||||
|
||||
protected TxDataBtc(Parcel in) {
|
||||
super(in);
|
||||
xmrtoUuid = in.readString();
|
||||
btcSymbol = in.readString();
|
||||
xmrtoOrderId = in.readString();
|
||||
btcAddress = in.readString();
|
||||
bip70 = in.readString();
|
||||
btcAmount = in.readDouble();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(",xmrtoUuid:");
|
||||
sb.append(xmrtoUuid);
|
||||
sb.append("xmrtoOrderId:");
|
||||
sb.append(xmrtoOrderId);
|
||||
sb.append(",btcSymbol:");
|
||||
sb.append(btcSymbol);
|
||||
sb.append(",btcAddress:");
|
||||
sb.append(btcAddress);
|
||||
sb.append(",bip70:");
|
||||
sb.append(bip70);
|
||||
sb.append(",btcAmount:");
|
||||
sb.append(btcAmount);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public boolean validateAddress(@NonNull String address) {
|
||||
if ((btcSymbol == null) || (btcAddress == null)) return false;
|
||||
final Crypto crypto = Crypto.withSymbol(btcSymbol);
|
||||
if (crypto == null) return false;
|
||||
if (crypto.isCasefull()) { // compare as-is
|
||||
return address.equals(btcAddress);
|
||||
} else { // normalize & compare (e.g. ETH with and without checksum capitals
|
||||
return address.toLowerCase().equals(btcAddress.toLowerCase());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user