1
mirror of https://github.com/m2049r/xmrwallet synced 2025-09-03 08:23:04 +02:00

Compare commits

...

52 Commits

Author SHA1 Message Date
m2049r
e56369b91a fix tests (#717) 2021-02-19 17:25:11 +01:00
m2049r
b04aa24269 bump version 2021-02-19 16:35:02 +01:00
m2049r
dda86bd5de fix URI generation (#716) 2021-02-19 16:32:15 +01:00
m2049r
a19ad7fd52 change build to docker (#715) 2021-02-19 16:31:35 +01:00
m2049r
0443fd808c bump version (consolidating with play release) 2021-02-17 00:16:24 +01:00
m2049r
faf57c96fc add more output currencies (#714) 2021-02-15 21:38:26 +01:00
m2049r
57ddddfce2 replace xmr.to with SideShift.ai (#710)
replace xmr.to with SideShift.ai
random bugfixes
upgrade gradle & dependencies
2021-02-13 00:01:19 +01:00
netrik182
ab6069058b new pt-br strings after review (#708) 2021-02-01 23:02:36 +01:00
m2049r
d94d6e6925 downgrade to APK 29 & bump version 2020-11-22 19:39:30 +01:00
m2049r
4a819cc159 bump version 2020-11-21 22:18:36 +01:00
m2049r
f40c3d6c6d catch cases where the qr code produces a null monero address (#702) 2020-11-21 22:08:23 +01:00
m2049r
82b25df7ad better node selection (#701) 2020-11-21 21:54:21 +01:00
m2049r
08f815e830 don't show connection error if we havent tested yet (#700) 2020-11-21 13:22:54 +01:00
m2049r
4e59be2dff New handling of nodes (#699)
* rework node handling

* update block heights
2020-11-19 16:36:01 +01:00
m2049r
45c5883e11 fix potential NPE in updateAccountsList() 2020-10-20 23:47:41 +02:00
m2049r
067a23e6a5 fix crash if back before new address is generated 2020-10-20 23:40:55 +02:00
m2049r
d21fd41c44 update dependencies & fix MethodNotFound exception 2020-10-20 23:31:29 +02:00
m2049r
6632547d1e bump version & fix versionCode (#694) 2020-10-19 23:44:40 +02:00
m2049r
f1b786ec3e fix keyboard crash when no view in focus (#693) 2020-10-19 23:42:22 +02:00
m2049r
a93e96d34c upgrade to monero v0.17.1.1 (#692) 2020-10-19 23:39:30 +02:00
m2049r
1829d30b61 Restyle UI (#690)
* enable testnet flavor
* v0.17.1.0
* migrate to androidx & material
* new color themes
* bump version v1.15.2
2020-10-16 02:52:08 +02:00
m2049r
e5b15b7816 always apply tx_amount from qr code (#687) 2020-09-27 11:00:57 +02:00
m2049r
7206857a5b bump version v1.14.8 2020-09-25 21:49:59 +02:00
m2049r
85d84d09ee fix crash when sending btc (#686) 2020-09-25 20:08:07 +02:00
m2049r
c6a1b503bc bump version 1.14.7 2020-09-23 11:20:16 +02:00
m2049r
8bda7aa0cf fix crash if auth failed (#684) 2020-09-23 11:19:28 +02:00
m2049r
97fb0a5483 bump version 1.14.6 2020-09-21 22:11:35 +02:00
m2049r
fc950c6772 fix onboarding layout (#683) 2020-09-21 22:10:51 +02:00
m2049r
46add5e927 bump version v1.14.5 2020-09-21 14:37:51 +02:00
m2049r
fa0692ceab force agree for fingerprint send (#682) 2020-09-21 14:36:17 +02:00
m2049r
ff4f4a1c2c remove notices covered by onboarding (#681) 2020-09-21 14:35:50 +02:00
m2049r
79abb89725 disable button on finish onbaording (#680) 2020-09-21 14:35:25 +02:00
m2049r
ef8301fd6f bump version v1.14.4 2020-09-18 22:09:32 +02:00
hiddener
3a15c842ff updated Romanian translation 2020-09-18 22:01:41 +02:00
m2049r
1697da55b5 only update if we still have a wallet 2020-09-18 22:00:14 +02:00
m2049r
454f3e412a don't do stuff if the wallet is already closed 2020-09-18 22:00:14 +02:00
m2049r
d803a1e220 remove unused resources (#678) 2020-09-18 21:59:38 +02:00
m2049r
f2fe781cb5 update restore heights 2020-09-17 10:18:58 +02:00
m2049r
dcf60ae193 bump version v1.14.3 2020-09-17 09:35:28 +02:00
m2049r
ffdf54c2e1 Merge pull request #677 from m2049r/fix_various
Various fixes & tweaks
2020-09-17 09:34:04 +02:00
m2049r
c060a2ab88 don't show onboarding every time 2020-09-16 19:59:58 +02:00
m2049r
05fc654f3a clean up code 2020-09-16 18:56:27 +02:00
m2049r
c32d157150 monero addresses are 95 characters 2020-09-16 17:51:47 +02:00
m2049r
74e9278baa MainActivity must be singleTop 2020-09-16 17:45:07 +02:00
m2049r
e41e344d63 bump version v1.14.2 2020-09-14 18:16:35 +02:00
m2049r
e66875437d always show onboarding 2020-09-14 18:14:38 +02:00
m2049r
c1d2db3d7d onboarding tweaks & version bump (#676) 2020-09-14 00:24:57 +02:00
m2049r
0c9a2f5e01 fixups 2020-09-13 18:52:26 +02:00
m2049r
64616e3921 onboarding (#675)
Co-authored-by: Stephan <stephan.hagios@gmail.com>
2020-09-13 18:34:22 +02:00
m2049r
82b4d66987 allow spend with fingerprint only (#674) 2020-09-13 18:26:36 +02:00
m2049r
10f2bc6561 upgrade monero core (#673) 2020-09-05 11:01:34 +02:00
m2049r
2ed9a78d9e upgrade gradle 2020-07-16 14:14:26 +02:00
384 changed files with 13621 additions and 7531 deletions

View File

@@ -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

View File

@@ -1,16 +1,15 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
compileSdkVersion 29
buildToolsVersion '29.0.2'
defaultConfig {
applicationId "com.m2049r.xmrwallet"
minSdkVersion 21
targetSdkVersion 28
versionCode 303
versionName "1.13.3 'ReStart'"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
targetSdkVersion 29
versionCode 707
versionName "1.17.7 'Druk'"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags "-std=c++11"
@@ -18,6 +17,11 @@ android {
}
}
}
bundle {
language {
enableSplit = false
}
}
flavorDimensions 'type', 'net'
productFlavors {
@@ -29,6 +33,11 @@ android {
applicationIdSuffix '.stage'
versionNameSuffix ' (stage)'
}
devnet {
dimension 'net'
applicationIdSuffix '.test'
versionNameSuffix ' (test)'
}
alpha {
dimension 'type'
applicationIdSuffix '.alpha'
@@ -47,6 +56,9 @@ android {
debug {
applicationIdSuffix ".debug"
}
applicationVariants.all { variant ->
variant.buildConfigField "String", "ID_A", "\"" + getId("ID_A") + "\""
}
}
externalNativeBuild {
@@ -71,7 +83,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 +95,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 +105,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.1.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 "com.burgstaller:okhttp-digest:2.1"
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'
}

View File

@@ -13,6 +13,7 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
android:requestLegacyExternalStorage="true"
android:name=".XmrWalletApplication"
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
@@ -20,24 +21,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 +67,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 +80,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 +89,4 @@
android:resource="@xml/filepaths" />
</provider>
</application>
</manifest>
</manifest>

File diff suppressed because it is too large Load Diff

View File

@@ -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);

View File

@@ -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;

View File

@@ -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,9 +31,9 @@ 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 androidx.annotation.CallSuper;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import android.widget.Toast;
import com.m2049r.xmrwallet.data.BarcodeData;
@@ -197,7 +213,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

View File

@@ -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;
@@ -202,13 +204,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)
@@ -507,7 +509,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,7 +648,7 @@ 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);

View File

@@ -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;
@@ -118,31 +121,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 +270,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);
@@ -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,7 +470,7 @@ 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);
@@ -498,7 +480,7 @@ public class GenerateReviewFragment extends Fragment {
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)
@@ -596,7 +578,7 @@ public class GenerateReviewFragment extends Fragment {
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)) {
} else {
new AsyncChangePassword().execute(newPasswordA, Boolean.toString(swFingerprintAllowed.isChecked()));
Helper.hideKeyboardAlways(getActivity());
openDialog.dismiss();
@@ -619,7 +601,7 @@ public class GenerateReviewFragment extends Fragment {
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)) {
} else {
new AsyncChangePassword().execute(newPasswordA, Boolean.toString(swFingerprintAllowed.isChecked()));
Helper.hideKeyboardAlways(getActivity());
openDialog.dismiss();

File diff suppressed because it is too large Load Diff

View File

@@ -19,11 +19,6 @@ package com.m2049r.xmrwallet;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.Fragment;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -38,12 +33,19 @@ import android.widget.RelativeLayout;
import android.widget.TextView;
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.floatingactionbutton.FloatingActionButton;
import com.m2049r.xmrwallet.data.NodeInfo;
import com.m2049r.xmrwallet.layout.NodeInfoAdapter;
import com.m2049r.xmrwallet.layout.WalletInfoAdapter;
import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.KeyStoreHelper;
import com.m2049r.xmrwallet.util.NodePinger;
import com.m2049r.xmrwallet.util.Notice;
import com.m2049r.xmrwallet.widget.Toolbar;
@@ -63,6 +65,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
private List<WalletManager.WalletInfo> walletList = new ArrayList<>();
private List<WalletManager.WalletInfo> displayedList = new ArrayList<>();
private View tvGuntherSays;
private ImageView ivGunther;
private TextView tvNodeName;
private TextView tvNodeAddress;
@@ -103,6 +106,8 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
Set<NodeInfo> getFavouriteNodes();
Set<NodeInfo> getOrPopulateFavourites();
boolean hasLedger();
}
@@ -130,11 +135,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
activityCallback.setTitle(null);
activityCallback.setToolbarButton(Toolbar.BUTTON_CREDITS);
activityCallback.showNet();
NodeInfo node = activityCallback.getNode();
if (node == null)
findBestNode();
else
showNode(node);
pingSelectedNode();
}
@Override
@@ -143,6 +144,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
Timber.d("onCreateView");
View view = inflater.inflate(R.layout.fragment_login, container, false);
tvGuntherSays = view.findViewById(R.id.tvGuntherSays);
ivGunther = view.findViewById(R.id.ivGunther);
fabScreen = view.findViewById(R.id.fabScreen);
fab = view.findViewById(R.id.fab);
@@ -183,23 +185,10 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
pbNode = view.findViewById(R.id.pbNode);
llNode = view.findViewById(R.id.llNode);
llNode.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (activityCallback.getFavouriteNodes().isEmpty())
startNodePrefs();
else
findBestNode();
}
});
llNode.setOnClickListener(v -> startNodePrefs());
tvNodeName = view.findViewById(R.id.tvNodeName);
tvNodeAddress = view.findViewById(R.id.tvNodeAddress);
view.findViewById(R.id.ibOption).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startNodePrefs();
}
});
view.findViewById(R.id.ibRenew).setOnClickListener(v -> findBestNode());
Helper.hideKeyboard(getActivity());
@@ -275,13 +264,15 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
if (displayedList.isEmpty()) {
fab.startAnimation(fab_pulse);
if (ivGunther.getDrawable() == null) {
ivGunther.setImageResource(R.drawable.gunther_desaturated);
ivGunther.setImageResource(R.drawable.ic_emptygunther);
tvGuntherSays.setVisibility(View.VISIBLE);
}
} else {
fab.clearAnimation();
if (ivGunther.getDrawable() != null) {
ivGunther.setImageDrawable(null);
}
tvGuntherSays.setVisibility(View.GONE);
}
// remove information of non-existent wallet
@@ -416,32 +407,57 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
}
public void findBestNode() {
new AsyncFindBestNode().execute();
new AsyncFindBestNode().execute(AsyncFindBestNode.FIND_BEST);
}
private class AsyncFindBestNode extends AsyncTask<Void, Void, NodeInfo> {
public void pingSelectedNode() {
new AsyncFindBestNode().execute(AsyncFindBestNode.PING_SELECTED);
}
private NodeInfo autoselect(Set<NodeInfo> nodes) {
if (nodes.isEmpty()) return null;
NodePinger.execute(nodes, null);
List<NodeInfo> nodeList = new ArrayList<>(nodes);
Collections.sort(nodeList, NodeInfo.BestNodeComparator);
return nodeList.get(0);
}
private class AsyncFindBestNode extends AsyncTask<Integer, Void, NodeInfo> {
final static int PING_SELECTED = 0;
final static int FIND_BEST = 1;
@Override
protected void onPreExecute() {
super.onPreExecute();
pbNode.setVisibility(View.VISIBLE);
llNode.setVisibility(View.INVISIBLE);
activityCallback.setNode(null);
}
@Override
protected NodeInfo doInBackground(Void... params) {
List<NodeInfo> nodesToTest = new ArrayList<>(activityCallback.getFavouriteNodes());
Timber.d("testing best node from %d", nodesToTest.size());
if (nodesToTest.isEmpty()) return null;
for (NodeInfo node : nodesToTest) {
node.testRpcService(); // TODO: do this in parallel?
// no: it's better if it looks like it's doing something
}
Collections.sort(nodesToTest, NodeInfo.BestNodeComparator);
NodeInfo bestNode = nodesToTest.get(0);
if (bestNode.isValid()) {
activityCallback.setNode(bestNode);
return bestNode;
protected NodeInfo doInBackground(Integer... params) {
Set<NodeInfo> favourites = activityCallback.getOrPopulateFavourites();
NodeInfo selectedNode;
if (params[0] == FIND_BEST) {
selectedNode = autoselect(favourites);
} else if (params[0] == PING_SELECTED) {
selectedNode = activityCallback.getNode();
if (!activityCallback.getFavouriteNodes().contains(selectedNode))
selectedNode = null; // it's not in the favourites (any longer)
if (selectedNode == null)
for (NodeInfo node : favourites) {
if (node.isSelected()) {
selectedNode = node;
break;
}
}
if (selectedNode == null) { // autoselect
selectedNode = autoselect(favourites);
} else
selectedNode.testRpcService();
} else throw new IllegalStateException();
if ((selectedNode != null) && selectedNode.isValid()) {
activityCallback.setNode(selectedNode);
return selectedNode;
} else {
activityCallback.setNode(null);
return null;
@@ -457,17 +473,10 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
Timber.d("found a good node %s", result.toString());
showNode(result);
} else {
if (!activityCallback.getFavouriteNodes().isEmpty()) {
tvNodeName.setText(getResources().getText(R.string.node_refresh_hint));
tvNodeName.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_refresh_black_24dp, 0, 0, 0);
tvNodeAddress.setText(null);
tvNodeAddress.setVisibility(View.GONE);
} else {
tvNodeName.setText(getResources().getText(R.string.node_create_hint));
tvNodeName.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
tvNodeAddress.setText(null);
tvNodeAddress.setVisibility(View.GONE);
}
tvNodeName.setText(getResources().getText(R.string.node_create_hint));
tvNodeName.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
tvNodeAddress.setText(null);
tvNodeAddress.setVisibility(View.GONE);
}
}
@@ -480,12 +489,11 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
private void showNode(NodeInfo nodeInfo) {
tvNodeName.setText(nodeInfo.getName());
tvNodeName.setCompoundDrawablesWithIntrinsicBounds(NodeInfoAdapter.getPingIcon(nodeInfo), 0, 0, 0);
tvNodeAddress.setText(nodeInfo.getAddress());
Helper.showTimeDifference(tvNodeAddress, nodeInfo.getTimestamp());
tvNodeAddress.setVisibility(View.VISIBLE);
}
private void startNodePrefs() {
activityCallback.setNode(null);
activityCallback.onNodePrefs();
}
}

View 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

View File

@@ -25,12 +25,6 @@ import android.net.Uri;
import android.nfc.NfcManager;
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.support.v4.content.FileProvider;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.widget.ShareActionProvider;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
@@ -42,7 +36,6 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
@@ -50,13 +43,22 @@ import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.ShareActionProvider;
import androidx.core.content.FileProvider;
import androidx.core.view.MenuItemCompat;
import androidx.fragment.app.Fragment;
import com.google.android.material.textfield.TextInputLayout;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.m2049r.xmrwallet.BuildConfig;
import com.m2049r.xmrwallet.data.BarcodeData;
import com.m2049r.xmrwallet.data.Crypto;
import com.m2049r.xmrwallet.ledger.LedgerProgressDialog;
import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.model.WalletManager;
@@ -82,10 +84,11 @@ public class ReceiveFragment extends Fragment {
private ExchangeView evAmount;
private TextView tvQrCode;
private ImageView ivQrCode;
private View cvQrCode;
private ImageView ivQrCodeFull;
private EditText etDummy;
private ImageButton bCopyAddress;
private Button bSubaddress;
private ImageButton bSubaddress;
private Wallet wallet = null;
private boolean isMyWallet = false;
@@ -109,6 +112,7 @@ public class ReceiveFragment extends Fragment {
tvAddress = view.findViewById(R.id.tvAddress);
etNotes = view.findViewById(R.id.etNotes);
evAmount = view.findViewById(R.id.evAmount);
cvQrCode = view.findViewById(R.id.cvQrCode);
ivQrCode = view.findViewById(R.id.qrCode);
tvQrCode = view.findViewById(R.id.tvQrCode);
ivQrCodeFull = view.findViewById(R.id.qrCodeFull);
@@ -118,13 +122,9 @@ public class ReceiveFragment extends Fragment {
etDummy.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
bCopyAddress.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
copyAddress();
}
});
bCopyAddress.setOnClickListener(v -> copyAddress());
enableCopyAddress(false);
enableSubaddressButton(false);
evAmount.setOnNewAmountListener(new ExchangeView.OnNewAmountListener() {
@Override
@@ -190,7 +190,7 @@ public class ReceiveFragment extends Fragment {
}
});
ivQrCode.setOnClickListener(new View.OnClickListener() {
cvQrCode.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Helper.hideKeyboard(getActivity());
@@ -315,13 +315,8 @@ public class ReceiveFragment extends Fragment {
return null;
}
void enableSubaddressButton(boolean enable) {
private void enableSubaddressButton(boolean enable) {
bSubaddress.setEnabled(enable);
if (enable) {
bSubaddress.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.ic_settings_orange_24dp, 0, 0);
} else {
bSubaddress.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.ic_settings_gray_24dp, 0, 0);
}
}
void copyAddress() {
@@ -371,16 +366,13 @@ public class ReceiveFragment extends Fragment {
listenerCallback.setSubtitle(wallet.getAccountLabel());
tvAddress.setText(wallet.getAddress());
enableCopyAddress(true);
enableSubaddressButton(true);
hideProgress();
generateQr();
}
private void enableCopyAddress(boolean enable) {
bCopyAddress.setClickable(enable);
if (enable)
bCopyAddress.setImageResource(R.drawable.ic_content_copy_black_24dp);
else
bCopyAddress.setImageResource(R.drawable.ic_content_nocopy_black_24dp);
bCopyAddress.setEnabled(enable);
}
private void loadAndShow(String walletPath, String password) {
@@ -478,7 +470,7 @@ public class ReceiveFragment extends Fragment {
Timber.d("CLEARQR");
return;
}
bcData = new BarcodeData(BarcodeData.Asset.XMR, address, null, notes, xmrAmount);
bcData = new BarcodeData(Crypto.XMR, address, notes, xmrAmount);
int size = Math.max(ivQrCode.getWidth(), ivQrCode.getHeight());
Bitmap qr = generate(bcData.getUriString(), size, size);
if (qr != null) {
@@ -620,6 +612,8 @@ public class ReceiveFragment extends Fragment {
super.onPostExecute(result);
if (dialogOpened)
progressCallback.dismissProgressDialog();
if (!isAdded()) // never mind then
return;
tvAddress.setText(newSubaddress);
tvAddressLabel.setText(getString(R.string.generate_address_label_sub,
wallet.getNumSubaddresses() - 1));

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -16,27 +16,31 @@
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.InputType;
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.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.widget.Toolbar;
import java.text.SimpleDateFormat;
@@ -77,6 +81,9 @@ 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,
@@ -88,6 +95,9 @@ public class TxFragment extends Fragment {
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,12 +114,9 @@ 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();
@@ -242,9 +249,9 @@ 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();
@@ -283,12 +290,36 @@ public class TxFragment extends Fragment {
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);
}

View File

@@ -16,7 +16,6 @@
package com.m2049r.xmrwallet;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
@@ -27,14 +26,6 @@ import android.content.pm.PackageManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.NonNull;
import android.support.design.widget.NavigationView;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -45,6 +36,17 @@ import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AlertDialog;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.navigation.NavigationView;
import com.m2049r.xmrwallet.data.BarcodeData;
import com.m2049r.xmrwallet.data.TxData;
import com.m2049r.xmrwallet.data.UserNotes;
@@ -58,6 +60,7 @@ import com.m2049r.xmrwallet.model.TransactionInfo;
import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.service.WalletService;
import com.m2049r.xmrwallet.util.ColorHelper;
import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
import com.m2049r.xmrwallet.widget.Toolbar;
@@ -88,7 +91,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
private ActionBarDrawerToggle drawerToggle;
private Toolbar toolbar;
private boolean needVerifyIdentity;
private boolean requestStreetMode = false;
private String password;
@@ -142,7 +144,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
private void enableStreetMode(boolean enable) {
if (enable) {
needVerifyIdentity = true;
streetMode = getWallet().getDaemonBlockChainHeight();
} else {
streetMode = 0;
@@ -151,11 +152,9 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
getSupportFragmentManager().findFragmentByTag(WalletFragment.class.getName());
if (walletFragment != null) walletFragment.resetDismissedTransactions();
forceUpdate();
runOnUiThread(new Runnable() {
@Override
public void run() {
runOnUiThread(() -> {
if (getWallet() != null)
updateAccountsBalance();
}
});
}
@@ -200,7 +199,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
if (extras != null) {
acquireWakeLock();
String walletId = extras.getString(REQUEST_ID);
needVerifyIdentity = extras.getBoolean(REQUEST_FINGERPRINT_USED);
// we can set the streetmode height AFTER opening the wallet
requestStreetMode = extras.getBoolean(REQUEST_STREETMODE);
password = extras.getString(REQUEST_PW);
@@ -317,11 +315,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
}
private void updateStreetMode() {
if (isStreetMode()) {
toolbar.setBackgroundResource(R.drawable.backgound_toolbar_streetmode);
} else {
showNet();
}
invalidateOptionsMenu();
}
@@ -333,7 +326,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
private void onDisableStreetMode() {
Helper.promptPassword(WalletActivity.this, getWallet().getName(), false, new Helper.PasswordAction() {
@Override
public void action(String walletName, String password, boolean fingerprintUsed) {
public void act(String walletName, String password, boolean fingerprintUsed) {
runOnUiThread(new Runnable() {
@Override
public void run() {
@@ -342,6 +335,10 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
}
});
}
@Override
public void fail(String walletName, String password, boolean fingerprintUsed) {
}
});
}
@@ -427,10 +424,10 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
toolbar.setBackgroundResource(R.drawable.backgound_toolbar_mainnet);
break;
case NetworkType_Testnet:
toolbar.setBackgroundResource(R.color.colorPrimaryDark);
toolbar.setBackgroundResource(ColorHelper.getThemedResourceId(this, R.attr.colorPrimaryDark));
break;
case NetworkType_Stagenet:
toolbar.setBackgroundResource(R.color.colorPrimaryDark);
toolbar.setBackgroundResource(ColorHelper.getThemedResourceId(this, R.attr.colorPrimaryDark));
break;
default:
throw new IllegalStateException("Unsupported Network: " + WalletManager.getInstance().getNetworkType());
@@ -576,18 +573,13 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
@Override
public boolean onRefreshed(final Wallet wallet, final boolean full) {
Timber.d("onRefreshed()");
runOnUiThread(new Runnable() {
public void run() {
runOnUiThread(() -> {
if (getWallet() != null)
updateAccountsBalance();
}
});
if (numAccounts != wallet.getNumAccounts()) {
numAccounts = wallet.getNumAccounts();
runOnUiThread(new Runnable() {
public void run() {
updateAccountsList();
}
});
runOnUiThread(this::updateAccountsList);
}
try {
final WalletFragment walletFragment = (WalletFragment)
@@ -669,7 +661,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
haveWallet = true;
invalidateOptionsMenu();
enableStreetMode(requestStreetMode);
if (requestStreetMode) onEnableStreetMode();
final WalletFragment walletFragment = (WalletFragment)
getSupportFragmentManager().findFragmentById(R.id.fragment_container);
@@ -855,17 +847,16 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
final Bundle extras = new Bundle();
extras.putString(GenerateReviewFragment.REQUEST_TYPE, GenerateReviewFragment.VIEW_TYPE_WALLET);
if (needVerifyIdentity) {
Helper.promptPassword(WalletActivity.this, getWallet().getName(), true, new Helper.PasswordAction() {
@Override
public void action(String walletName, String password, boolean fingerprintUsed) {
replaceFragment(new GenerateReviewFragment(), null, extras);
needVerifyIdentity = false;
}
});
} else {
replaceFragment(new GenerateReviewFragment(), null, extras);
}
Helper.promptPassword(WalletActivity.this, getWallet().getName(), true, new Helper.PasswordAction() {
@Override
public void act(String walletName, String password, boolean fingerprintUsed) {
replaceFragment(new GenerateReviewFragment(), null, extras);
}
@Override
public void fail(String walletName, String password, boolean fingerprintUsed) {
}
});
break;
case DialogInterface.BUTTON_NEGATIVE:
@@ -875,7 +866,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(this);
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(this);
builder.setMessage(getString(R.string.details_alert_message))
.setPositiveButton(getString(R.string.details_alert_yes), dialogClickListener)
.setNegativeButton(getString(R.string.details_alert_no), dialogClickListener)
@@ -930,7 +921,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
@Override
public boolean onScanned(String qrCode) {
// #gurke
BarcodeData bcData = BarcodeData.fromQrCode(qrCode);
BarcodeData bcData = BarcodeData.fromString(qrCode);
if (bcData != null) {
popFragmentStack(null);
Timber.d("AAA");
@@ -1003,12 +994,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
return getWallet().getUnlockedBalance();
}
@Override
public boolean verifyWalletPassword(String password) {
String walletPassword = Helper.getWalletPassword(getApplicationContext(), getWalletName(), password);
return walletPassword != null;
}
@Override
public void onBackPressed() {
if (drawer.isDrawerOpen(GravityCompat.START)) {
@@ -1066,21 +1051,23 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
}
void updateAccountsList() {
final Wallet wallet = getWallet();
Menu menu = accountsView.getMenu();
menu.removeGroup(R.id.accounts_list);
final int n = wallet.getNumAccounts();
final boolean showBalances = (n > 1) && !isStreetMode();
for (int i = 0; i < n; i++) {
final String label = (showBalances ?
getString(R.string.label_account, wallet.getAccountLabel(i), Helper.getDisplayAmount(wallet.getBalance(i), 2))
: wallet.getAccountLabel(i));
final MenuItem item = menu.add(R.id.accounts_list, getAccountId(i), 2 * i, label);
item.setIcon(R.drawable.ic_account_balance_wallet_black_24dp);
if (i == wallet.getAccountIndex())
item.setChecked(true);
final Wallet wallet = getWallet();
if (wallet != null) {
final int n = wallet.getNumAccounts();
final boolean showBalances = (n > 1) && !isStreetMode();
for (int i = 0; i < n; i++) {
final String label = (showBalances ?
getString(R.string.label_account, wallet.getAccountLabel(i), Helper.getDisplayAmount(wallet.getBalance(i), 2))
: wallet.getAccountLabel(i));
final MenuItem item = menu.add(R.id.accounts_list, getAccountId(i), 2 * i, label);
item.setIcon(R.drawable.ic_account_balance_wallet_black_24dp);
if (i == wallet.getAccountIndex())
item.setChecked(true);
}
menu.setGroupCheckable(R.id.accounts_list, true, true);
}
menu.setGroupCheckable(R.id.accounts_list, true, true);
}
@Override
@@ -1102,7 +1089,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
final LayoutInflater li = LayoutInflater.from(this);
final View promptsView = li.inflate(R.layout.prompt_rename, null);
final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
final AlertDialog.Builder alertDialogBuilder = new MaterialAlertDialogBuilder(this);
alertDialogBuilder.setView(promptsView);
final EditText etRename = promptsView.findViewById(R.id.etRename);

View File

@@ -17,12 +17,10 @@
package com.m2049r.xmrwallet;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -38,6 +36,11 @@ import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView;
import com.github.brnunes.swipeablerecyclerview.SwipeableRecyclerViewTouchListener;
import com.m2049r.xmrwallet.layout.TransactionInfoAdapter;
import com.m2049r.xmrwallet.model.TransactionInfo;
@@ -46,6 +49,7 @@ import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate;
import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.ServiceHelper;
import com.m2049r.xmrwallet.widget.Toolbar;
import java.text.NumberFormat;
@@ -70,6 +74,8 @@ public class WalletFragment extends Fragment
private ProgressBar pbProgress;
private Button bReceive;
private Button bSend;
private ImageView ivStreetGunther;
private Drawable streetGunther = null;
private Spinner sCurrency;
@@ -97,11 +103,12 @@ public class WalletFragment extends Fragment
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_wallet, container, false);
ivStreetGunther = view.findViewById(R.id.ivStreetGunther);
tvStreetView = view.findViewById(R.id.tvStreetView);
llBalance = view.findViewById(R.id.llBalance);
flExchange = view.findViewById(R.id.flExchange);
((ProgressBar) view.findViewById(R.id.pbExchange)).getIndeterminateDrawable().
setColorFilter(getResources().getColor(R.color.trafficGray),
setColorFilter(getResources().getColor(R.color.progress_circle),
android.graphics.PorterDuff.Mode.MULTIPLY);
tvProgress = view.findViewById(R.id.tvProgress);
@@ -199,13 +206,15 @@ public class WalletFragment extends Fragment
void showBalance(String balance) {
tvBalance.setText(balance);
if (!activityCallback.isStreetMode()) {
final boolean streetMode = activityCallback.isStreetMode();
if (!streetMode) {
llBalance.setVisibility(View.VISIBLE);
tvStreetView.setVisibility(View.INVISIBLE);
} else {
llBalance.setVisibility(View.INVISIBLE);
tvStreetView.setVisibility(View.VISIBLE);
}
setStreetModeBackground(streetMode);
}
void showUnconfirmed(double unconfirmedAmount) {
@@ -234,7 +243,7 @@ public class WalletFragment extends Fragment
String balanceCurrency = Helper.BASE_CRYPTO;
double balanceRate = 1.0;
private final ExchangeApi exchangeApi = Helper.getExchangeApi();
private final ExchangeApi exchangeApi = ServiceHelper.getExchangeApi();
void refreshBalance() {
double unconfirmedXmr = Helper.getDecimalAmount(balance - unlockedBalance).doubleValue();
@@ -537,4 +546,13 @@ public class WalletFragment extends Fragment
}
}
public void setStreetModeBackground(boolean enable) {
//TODO figure out why gunther disappears on return from send although he is still set
if (enable) {
if (streetGunther == null)
streetGunther = ContextCompat.getDrawable(getContext(), R.drawable.ic_gunther_streetmode);
ivStreetGunther.setImageDrawable(streetGunther);
} else
ivStreetGunther.setImageDrawable(null);
}
}

View File

@@ -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

View 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);
}
}

View File

@@ -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;
}

View File

@@ -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,15 +35,29 @@ 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() {
@@ -193,7 +209,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 +219,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 +226,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 +238,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;
}

View File

@@ -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();
@@ -247,8 +244,9 @@ public class NodeInfo extends Node {
}
}
} catch (IOException | JSONException ex) {
// failure
Timber.d(ex.getMessage());
Timber.d(ex);
} finally {
tested = true;
}
return false;
}

View File

@@ -20,6 +20,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import com.m2049r.xmrwallet.model.PendingTransaction;
import com.m2049r.xmrwallet.model.Wallet;
// 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 +53,10 @@ public class TxData implements Parcelable {
return amount;
}
public double getAmountAsDouble() {
return 1.0 * amount / 1000000000000L;
}
public int getMixin() {
return mixin;
}
@@ -68,6 +73,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;
}

View File

@@ -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());
}
}
}

View File

@@ -16,18 +16,19 @@
package com.m2049r.xmrwallet.data;
import com.m2049r.xmrwallet.xmrto.api.QueryOrderStatus;
import com.m2049r.xmrwallet.service.shift.sideshift.api.CreateOrder;
import com.m2049r.xmrwallet.util.Helper;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import timber.log.Timber;
public class UserNotes {
public String txNotes = "";
public String note = "";
public String xmrtoTag = null;
public String xmrtoKey = null;
public String xmrtoAmount = null; // could be a double - but we are not doing any calculations
public String xmrtoCurrency = null;
public String xmrtoDestination = null;
public UserNotes(final String txNotes) {
@@ -35,13 +36,15 @@ public class UserNotes {
return;
}
this.txNotes = txNotes;
Pattern p = Pattern.compile("^\\{(xmrto-\\w{6}),([0-9.]*)BTC,(\\w*)\\} ?(.*)");
Pattern p = Pattern.compile("^\\{([a-z]+)-(\\w{6,}),([0-9.]*)([A-Z]+),(\\w*)\\} ?(.*)");
Matcher m = p.matcher(txNotes);
if (m.find()) {
xmrtoKey = m.group(1);
xmrtoAmount = m.group(2);
xmrtoDestination = m.group(3);
note = m.group(4);
xmrtoTag = m.group(1);
xmrtoKey = m.group(2);
xmrtoAmount = m.group(3);
xmrtoCurrency = m.group(4);
xmrtoDestination = m.group(5);
note = m.group(6);
} else {
note = txNotes;
}
@@ -56,12 +59,15 @@ public class UserNotes {
txNotes = buildTxNote();
}
public void setXmrtoStatus(QueryOrderStatus xmrtoStatus) {
if (xmrtoStatus != null) {
xmrtoKey = xmrtoStatus.getUuid();
xmrtoAmount = String.valueOf(xmrtoStatus.getBtcAmount());
xmrtoDestination = xmrtoStatus.getBtcDestAddress();
public void setXmrtoOrder(CreateOrder order) {
if (order != null) {
xmrtoTag = order.TAG;
xmrtoKey = order.getOrderId();
xmrtoAmount = Helper.getDisplayAmount(order.getBtcAmount());
xmrtoCurrency = order.getBtcCurrency();
xmrtoDestination = order.getBtcAddress();
} else {
xmrtoTag = null;
xmrtoKey = null;
xmrtoAmount = null;
xmrtoDestination = null;
@@ -70,15 +76,18 @@ public class UserNotes {
}
private String buildTxNote() {
StringBuffer sb = new StringBuffer();
StringBuilder sb = new StringBuilder();
if (xmrtoKey != null) {
if ((xmrtoAmount == null) || (xmrtoDestination == null))
throw new IllegalArgumentException("Broken notes");
sb.append("{");
sb.append(xmrtoTag);
sb.append("-");
sb.append(xmrtoKey);
sb.append(",");
sb.append(xmrtoAmount);
sb.append("BTC,");
sb.append(xmrtoCurrency);
sb.append(",");
sb.append(xmrtoDestination);
sb.append("}");
if ((note != null) && (!note.isEmpty()))

View File

@@ -16,26 +16,25 @@
package com.m2049r.xmrwallet.dialog;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.m2049r.xmrwallet.BuildConfig;
import com.m2049r.xmrwallet.R;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import timber.log.Timber;
@@ -63,15 +62,15 @@ public class AboutFragment extends DialogFragment {
((TextView) view.findViewById(R.id.tvHelp)).setText(Html.fromHtml(getLicencesHtml()));
((TextView) view.findViewById(R.id.tvVersion)).setText(getString(R.string.about_version, BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE));
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(view);
builder.setNegativeButton(R.string.about_close,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getActivity())
.setView(view)
.setNegativeButton(R.string.about_close,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
return builder.create();
}

View File

@@ -16,19 +16,20 @@
package com.m2049r.xmrwallet.dialog;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.m2049r.xmrwallet.R;
public class CreditsFragment extends DialogFragment {
@@ -54,16 +55,15 @@ public class CreditsFragment extends DialogFragment {
((TextView) view.findViewById(R.id.tvCredits)).setText(Html.fromHtml(getString(R.string.credits_text)));
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(view);
builder.setNegativeButton(R.string.about_close,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getActivity())
.setView(view)
.setNegativeButton(R.string.about_close,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
return builder.create();
}
}

View File

@@ -16,19 +16,20 @@
package com.m2049r.xmrwallet.dialog;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.m2049r.xmrwallet.R;
public class HelpFragment extends DialogFragment {
@@ -65,15 +66,15 @@ public class HelpFragment extends DialogFragment {
if (helpId > 0)
((TextView) view.findViewById(R.id.tvHelp)).setText(Html.fromHtml(getString(helpId)));
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(view);
builder.setNegativeButton(R.string.help_ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getActivity())
.setView(view)
.setNegativeButton(R.string.help_ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
return builder.create();
}
}

View File

@@ -16,19 +16,20 @@
package com.m2049r.xmrwallet.dialog;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.m2049r.xmrwallet.R;
public class PrivacyFragment extends DialogFragment {
@@ -54,15 +55,15 @@ public class PrivacyFragment extends DialogFragment {
((TextView) view.findViewById(R.id.tvCredits)).setText(Html.fromHtml(getString(R.string.privacy_policy)));
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(view);
builder.setNegativeButton(R.string.about_close,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getActivity())
.setView(view)
.setNegativeButton(R.string.about_close,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
return builder.create();
}
}

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