mirror of
https://github.com/m2049r/xmrwallet
synced 2025-09-12 07:10:49 +02:00
Compare commits
83 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
cd6f646b63 | ||
![]() |
aa530caa28 | ||
![]() |
5df43f1274 | ||
![]() |
3b0cb3ffdb | ||
![]() |
300551dbe4 | ||
![]() |
942519adb7 | ||
![]() |
0652a8ba14 | ||
![]() |
04d0bd2ffb | ||
![]() |
8473e66c69 | ||
![]() |
2218ff615c | ||
![]() |
54b55b9f8f | ||
![]() |
5abf84f62b | ||
![]() |
6ff75d221f | ||
![]() |
c90f107c3c | ||
![]() |
a3db18032e | ||
![]() |
9db2c10679 | ||
![]() |
eab85c7f0a | ||
![]() |
6bf3229e77 | ||
![]() |
9f4f626acb | ||
![]() |
434dab55ba | ||
![]() |
59cc6b1864 | ||
![]() |
a6e9d0e77c | ||
![]() |
17df7c3faf | ||
![]() |
bf1829f775 | ||
![]() |
bc4aa0f772 | ||
![]() |
3f09e73df7 | ||
![]() |
11b7e23ad2 | ||
![]() |
ae48027689 | ||
![]() |
a42f750fc4 | ||
![]() |
3406f585f2 | ||
![]() |
7546637c89 | ||
![]() |
4da2106f04 | ||
![]() |
93c11fb90e | ||
![]() |
9fa710f75b | ||
![]() |
c53dd300bc | ||
![]() |
97f40648be | ||
![]() |
1ece6bfbeb | ||
![]() |
4b3b99ff2a | ||
![]() |
ca833d7017 | ||
![]() |
f1b6f859de | ||
![]() |
61d19c7066 | ||
![]() |
ffda0e965b | ||
![]() |
cc7cdb383c | ||
![]() |
ac1ea05ef6 | ||
![]() |
1ddd4f30b9 | ||
![]() |
1dc081834f | ||
![]() |
ce084927e1 | ||
![]() |
3610781f43 | ||
![]() |
ef3ddbac71 | ||
![]() |
0512af1496 | ||
![]() |
bd2c49669a | ||
![]() |
ac7831d0f9 | ||
![]() |
0f0b9a38c7 | ||
![]() |
807db19603 | ||
![]() |
c956f38899 | ||
![]() |
db68f517d3 | ||
![]() |
d4b293af80 | ||
![]() |
f7bbfc2fac | ||
![]() |
e08964749e | ||
![]() |
a05fa9d177 | ||
![]() |
7fe2fbe37d | ||
![]() |
40e30fed08 | ||
![]() |
320c7865ff | ||
![]() |
5e8cf8010e | ||
![]() |
e671fa19e0 | ||
![]() |
20d5b9a100 | ||
![]() |
5d489a634b | ||
![]() |
59b6f484fd | ||
![]() |
ecaa49d67d | ||
![]() |
d2dc53599e | ||
![]() |
4d8b26f97f | ||
![]() |
581c76e7be | ||
![]() |
6f66862870 | ||
![]() |
dd92f7bb36 | ||
![]() |
46808d306b | ||
![]() |
20503d2cbd | ||
![]() |
604691ca7e | ||
![]() |
1b626ba2b0 | ||
![]() |
0ed7bdfcee | ||
![]() |
524c3dd79f | ||
![]() |
197dffeae1 | ||
![]() |
cdb29bbc2e | ||
![]() |
7b96baeca7 |
@@ -3,13 +3,11 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
working_directory: ~/code
|
working_directory: ~/code
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/android:api-28-ndk
|
- image: cimg/android:2023.12-ndk
|
||||||
environment:
|
environment:
|
||||||
JVM_OPTS: -Xmx3200m
|
JVM_OPTS: -Xmx3200m
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run: yes | sdkmanager --licenses || exit 0
|
|
||||||
- run: yes | sdkmanager --update || exit 0
|
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}
|
key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}
|
||||||
- run:
|
- run:
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -16,3 +16,5 @@
|
|||||||
/app/prodStagenet
|
/app/prodStagenet
|
||||||
/app/.cxx
|
/app/.cxx
|
||||||
/monerujo.id
|
/monerujo.id
|
||||||
|
/external-libs/VERSION
|
||||||
|
/external-libs/include/wallet2_api.h
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
cmake_minimum_required(VERSION 3.4.1)
|
cmake_minimum_required(VERSION 3.4.1)
|
||||||
|
project(monerujo)
|
||||||
message(STATUS ABI_INFO = ${ANDROID_ABI})
|
message(STATUS ABI_INFO = ${ANDROID_ABI})
|
||||||
|
|
||||||
add_library( monerujo
|
add_library( monerujo
|
||||||
@@ -121,7 +122,7 @@ set_target_properties(easylogging PROPERTIES IMPORTED_LOCATION
|
|||||||
|
|
||||||
add_library(unbound STATIC IMPORTED)
|
add_library(unbound STATIC IMPORTED)
|
||||||
set_target_properties(unbound PROPERTIES IMPORTED_LOCATION
|
set_target_properties(unbound PROPERTIES IMPORTED_LOCATION
|
||||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libunbound.a)
|
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/libunbound.a)
|
||||||
|
|
||||||
add_library(epee STATIC IMPORTED)
|
add_library(epee STATIC IMPORTED)
|
||||||
set_target_properties(epee PROPERTIES IMPORTED_LOCATION
|
set_target_properties(epee PROPERTIES IMPORTED_LOCATION
|
||||||
|
@@ -1,15 +1,15 @@
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 30
|
|
||||||
buildToolsVersion '30.0.3'
|
|
||||||
ndkVersion '17.2.4988734'
|
ndkVersion '17.2.4988734'
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "com.m2049r.xmrwallet"
|
applicationId "com.m2049r.xmrwallet"
|
||||||
|
buildToolsVersion = '34.0.0'
|
||||||
|
compileSdk 34
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 30
|
targetSdkVersion 33
|
||||||
versionCode 1301
|
versionCode 3311
|
||||||
versionName "2.3.1 'Doménikos'"
|
versionName "3.3.11 'Argentina'"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
@@ -72,7 +72,7 @@ android {
|
|||||||
abi {
|
abi {
|
||||||
enable true
|
enable true
|
||||||
reset()
|
reset()
|
||||||
include 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
|
include 'armeabi-v7a', 'arm64-v8a', 'x86_64'
|
||||||
universalApk true
|
universalApk true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -111,6 +111,18 @@ android {
|
|||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
}
|
}
|
||||||
|
namespace 'com.m2049r.xmrwallet'
|
||||||
|
buildFeatures {
|
||||||
|
buildConfig true
|
||||||
|
}
|
||||||
|
|
||||||
|
testOptions {
|
||||||
|
unitTests {
|
||||||
|
all {
|
||||||
|
jvmArgs '--add-opens=java.base/java.lang=ALL-UNNAMED'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static def getId(name) {
|
static def getId(name) {
|
||||||
@@ -120,38 +132,40 @@ static def getId(name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'androidx.core:core:1.6.0'
|
implementation(platform("org.jetbrains.kotlin:kotlin-bom:1.8.0"))
|
||||||
implementation 'androidx.appcompat:appcompat:1.3.1'
|
|
||||||
implementation 'com.google.android.material:material:1.4.0'
|
implementation 'androidx.core:core:1.12.0'
|
||||||
|
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||||
implementation 'androidx.recyclerview:recyclerview:1.2.1'
|
implementation 'androidx.recyclerview:recyclerview:1.3.2'
|
||||||
implementation 'androidx.cardview:cardview:1.0.0'
|
implementation 'androidx.cardview:cardview:1.0.0'
|
||||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.2.0-alpha01'
|
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
|
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||||
|
implementation 'androidx.preference:preference:1.2.1'
|
||||||
|
|
||||||
|
implementation 'com.google.android.material:material:1.11.0'
|
||||||
|
|
||||||
implementation 'me.dm7.barcodescanner:zxing:1.9.8'
|
implementation 'me.dm7.barcodescanner:zxing:1.9.8'
|
||||||
implementation "com.squareup.okhttp3:okhttp:4.9.0"
|
implementation "com.squareup.okhttp3:okhttp:4.12.0"
|
||||||
implementation "io.github.rburgst:okhttp-digest:2.5"
|
implementation "io.github.rburgst:okhttp-digest:3.1.0"
|
||||||
implementation "com.jakewharton.timber:timber:4.7.1"
|
implementation "com.jakewharton.timber:timber:5.0.1"
|
||||||
|
|
||||||
implementation 'info.guardianproject.netcipher:netcipher:2.1.0'
|
implementation 'info.guardianproject.netcipher:netcipher:2.1.0'
|
||||||
//implementation 'info.guardianproject.netcipher:netcipher-okhttp3:2.1.0'
|
//implementation 'info.guardianproject.netcipher:netcipher-okhttp3:2.1.0'
|
||||||
implementation fileTree(dir: 'libs/classes', include: ['*.jar'])
|
implementation fileTree(dir: 'libs/classes', include: ['*.jar'])
|
||||||
implementation 'com.nulab-inc:zxcvbn:1.3.0'
|
implementation 'com.nulab-inc:zxcvbn:1.8.2'
|
||||||
|
|
||||||
implementation 'dnsjava:dnsjava:2.1.9'
|
implementation 'dnsjava:dnsjava:3.5.3'
|
||||||
implementation 'org.jitsi:dnssecjava:1.2.0'
|
implementation 'org.slf4j:slf4j-nop:2.0.11'
|
||||||
implementation 'org.slf4j:slf4j-nop:1.7.30'
|
|
||||||
implementation 'com.github.brnunes:swipeablerecyclerview:1.0.2'
|
implementation 'com.github.brnunes:swipeablerecyclerview:1.0.2'
|
||||||
|
|
||||||
//noinspection GradleDependency
|
//noinspection GradleDependency
|
||||||
testImplementation "junit:junit:$rootProject.ext.junitVersion"
|
testImplementation "junit:junit:4.13.2"
|
||||||
testImplementation "org.mockito:mockito-all:$rootProject.ext.mockitoVersion"
|
testImplementation "org.mockito:mockito-all:1.10.19"
|
||||||
testImplementation "com.squareup.okhttp3:mockwebserver:4.9.0"
|
testImplementation "com.squareup.okhttp3:mockwebserver:4.12.0"
|
||||||
testImplementation 'org.json:json:20180813'
|
testImplementation 'org.json:json:20231013'
|
||||||
testImplementation 'net.jodah:concurrentunit:0.4.4'
|
testImplementation 'net.jodah:concurrentunit:0.4.6'
|
||||||
|
|
||||||
compileOnly 'org.projectlombok:lombok:1.18.16'
|
compileOnly 'org.projectlombok:lombok:1.18.30'
|
||||||
annotationProcessor 'org.projectlombok:lombok:1.18.16'
|
annotationProcessor 'org.projectlombok:lombok:1.18.30'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,6 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
package="com.m2049r.xmrwallet">
|
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.camera"
|
||||||
|
android:required="false" />
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
@@ -8,7 +11,6 @@
|
|||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||||
<uses-permission android:name="android.permission.NFC" />
|
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
|
||||||
<queries>
|
<queries>
|
||||||
@@ -18,7 +20,6 @@
|
|||||||
<intent>
|
<intent>
|
||||||
<action android:name="org.torproject.android.intent.action.STATUS" />
|
<action android:name="org.torproject.android.intent.action.STATUS" />
|
||||||
</intent>
|
</intent>
|
||||||
|
|
||||||
<intent>
|
<intent>
|
||||||
<action android:name="org.torproject.android.REQUEST_HS_PORT" />
|
<action android:name="org.torproject.android.REQUEST_HS_PORT" />
|
||||||
</intent>
|
</intent>
|
||||||
@@ -36,15 +37,17 @@
|
|||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:preserveLegacyExternalStorage="true"
|
android:preserveLegacyExternalStorage="true"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/MyMaterialTheme"
|
android:theme="@style/MyMaterialThemeClassic"
|
||||||
android:usesCleartextTraffic="true">
|
android:usesCleartextTraffic="true">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:configChanges="orientation|keyboardHidden|uiMode"
|
android:configChanges="orientation|keyboardHidden|uiMode"
|
||||||
|
android:exported="true"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:screenOrientation="portrait">
|
android:screenOrientation="portrait">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
@@ -56,24 +59,25 @@
|
|||||||
android:screenOrientation="behind" />
|
android:screenOrientation="behind" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".LoginActivity"
|
android:name=".LoginActivity"
|
||||||
android:configChanges="orientation|keyboardHidden|uiMode"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
|
android:exported="true"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:screenOrientation="locked">
|
android:screenOrientation="locked">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
|
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
<intent-filter android:label="@string/app_name">
|
<intent-filter android:label="@string/app_name">
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
<data android:scheme="monero" />
|
<data android:scheme="monero" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
<intent-filter android:label="@string/app_name">
|
<intent-filter android:label="@string/app_name">
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
<data android:scheme="bitcoin" />
|
<data android:scheme="bitcoin" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
@@ -106,4 +110,5 @@
|
|||||||
android:resource="@xml/filepaths" />
|
android:resource="@xml/filepaths" />
|
||||||
</provider>
|
</provider>
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
|
||||||
|
</manifest>
|
File diff suppressed because it is too large
Load Diff
@@ -20,8 +20,6 @@
|
|||||||
|
|
||||||
package com.btchip.comm;
|
package com.btchip.comm;
|
||||||
|
|
||||||
import com.btchip.BTChipException;
|
|
||||||
|
|
||||||
public interface BTChipTransport {
|
public interface BTChipTransport {
|
||||||
byte[] exchange(byte[] command);
|
byte[] exchange(byte[] command);
|
||||||
|
|
||||||
|
@@ -28,7 +28,6 @@ import android.hardware.usb.UsbInterface;
|
|||||||
import android.hardware.usb.UsbManager;
|
import android.hardware.usb.UsbManager;
|
||||||
import android.hardware.usb.UsbRequest;
|
import android.hardware.usb.UsbRequest;
|
||||||
|
|
||||||
import com.btchip.BTChipException;
|
|
||||||
import com.btchip.comm.BTChipTransport;
|
import com.btchip.comm.BTChipTransport;
|
||||||
import com.btchip.comm.LedgerHelper;
|
import com.btchip.comm.LedgerHelper;
|
||||||
import com.btchip.utils.Dump;
|
import com.btchip.utils.Dump;
|
||||||
@@ -78,7 +77,7 @@ public class BTChipTransportAndroidHID implements BTChipTransport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static final int VID = 0x2C97;
|
private static final int VID = 0x2C97;
|
||||||
private static final int[] PID_HIDS = {0x0001, 0x0004};
|
private static final int[] PID_HIDS = {0x0001, 0x0004, 0x0005};
|
||||||
|
|
||||||
private UsbDeviceConnection connection;
|
private UsbDeviceConnection connection;
|
||||||
private UsbInterface dongleInterface;
|
private UsbInterface dongleInterface;
|
||||||
|
@@ -16,35 +16,18 @@
|
|||||||
|
|
||||||
package com.m2049r.xmrwallet;
|
package com.m2049r.xmrwallet;
|
||||||
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.nfc.FormatException;
|
|
||||||
import android.nfc.NdefMessage;
|
|
||||||
import android.nfc.NdefRecord;
|
|
||||||
import android.nfc.NfcAdapter;
|
|
||||||
import android.nfc.Tag;
|
|
||||||
import android.nfc.tech.Ndef;
|
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import androidx.annotation.CallSuper;
|
import androidx.annotation.CallSuper;
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.data.BarcodeData;
|
import com.m2049r.xmrwallet.data.BarcodeData;
|
||||||
import com.m2049r.xmrwallet.dialog.ProgressDialog;
|
import com.m2049r.xmrwallet.dialog.ProgressDialog;
|
||||||
import com.m2049r.xmrwallet.fragment.send.SendFragment;
|
|
||||||
import com.m2049r.xmrwallet.ledger.Ledger;
|
import com.m2049r.xmrwallet.ledger.Ledger;
|
||||||
import com.m2049r.xmrwallet.ledger.LedgerProgressDialog;
|
import com.m2049r.xmrwallet.ledger.LedgerProgressDialog;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
public class BaseActivity extends SecureActivity
|
public class BaseActivity extends SecureActivity
|
||||||
@@ -140,91 +123,6 @@ public class BaseActivity extends SecureActivity
|
|||||||
Timber.d("WakeLock released");
|
Timber.d("WakeLock released");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
initNfc();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostResume() {
|
|
||||||
super.onPostResume();
|
|
||||||
if (nfcAdapter != null) {
|
|
||||||
nfcAdapter.enableForegroundDispatch(this, nfcPendingIntent, null, null);
|
|
||||||
// intercept all techs so we can tell the user their tag is no good
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPause() {
|
|
||||||
Timber.d("onPause()");
|
|
||||||
if (nfcAdapter != null)
|
|
||||||
nfcAdapter.disableForegroundDispatch(this);
|
|
||||||
super.onPause();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onNewIntent(Intent intent) {
|
|
||||||
super.onNewIntent(intent);
|
|
||||||
processNfcIntent(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// NFC stuff
|
|
||||||
private NfcAdapter nfcAdapter;
|
|
||||||
private PendingIntent nfcPendingIntent;
|
|
||||||
|
|
||||||
public void initNfc() {
|
|
||||||
nfcAdapter = NfcAdapter.getDefaultAdapter(this);
|
|
||||||
if (nfcAdapter == null) // no NFC support
|
|
||||||
return;
|
|
||||||
nfcPendingIntent = PendingIntent.getActivity(this, 0,
|
|
||||||
new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processNfcIntent(Intent intent) {
|
|
||||||
String action = intent.getAction();
|
|
||||||
Timber.d("ACTION=%s", action);
|
|
||||||
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)
|
|
||||||
|| NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)
|
|
||||||
|| NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) {
|
|
||||||
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
|
|
||||||
Ndef ndef = Ndef.get(tag);
|
|
||||||
if (ndef == null) {
|
|
||||||
Toast.makeText(this, getString(R.string.nfc_tag_unsupported), Toast.LENGTH_LONG).show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Fragment f = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
|
|
||||||
if (f instanceof ReceiveFragment) {
|
|
||||||
// We want to write a Tag from the ReceiveFragment
|
|
||||||
BarcodeData bc = ((ReceiveFragment) f).getBarcodeData();
|
|
||||||
if (bc != null) {
|
|
||||||
new AsyncWriteTag(ndef, bc.getUri()).execute();
|
|
||||||
} // else wallet is not loaded yet or receive is otherwise not ready - ignore
|
|
||||||
} else if (f instanceof SendFragment) {
|
|
||||||
// We want to read a Tag for the SendFragment
|
|
||||||
NdefMessage ndefMessage = ndef.getCachedNdefMessage();
|
|
||||||
if (ndefMessage == null) {
|
|
||||||
Toast.makeText(this, getString(R.string.nfc_tag_read_undef), Toast.LENGTH_LONG).show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
NdefRecord firstRecord = ndefMessage.getRecords()[0];
|
|
||||||
Uri uri = firstRecord.toUri(); // we insist on the first record
|
|
||||||
if (uri == null) {
|
|
||||||
Toast.makeText(this, getString(R.string.nfc_tag_read_undef), Toast.LENGTH_LONG).show();
|
|
||||||
} else {
|
|
||||||
BarcodeData bc = BarcodeData.fromString(uri.toString());
|
|
||||||
if (bc == null)
|
|
||||||
Toast.makeText(this, getString(R.string.nfc_tag_read_undef), Toast.LENGTH_LONG).show();
|
|
||||||
else
|
|
||||||
onUriScanned(bc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// this gets called only if we get data
|
// this gets called only if we get data
|
||||||
@CallSuper
|
@CallSuper
|
||||||
void onUriScanned(BarcodeData barcodeData) {
|
void onUriScanned(BarcodeData barcodeData) {
|
||||||
@@ -238,75 +136,4 @@ public class BaseActivity extends SecureActivity
|
|||||||
barcodeData = null;
|
barcodeData = null;
|
||||||
return popped;
|
return popped;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AsyncWriteTag extends AsyncTask<Void, Void, Boolean> {
|
|
||||||
|
|
||||||
Ndef ndef;
|
|
||||||
Uri uri;
|
|
||||||
String errorMessage = null;
|
|
||||||
|
|
||||||
AsyncWriteTag(Ndef ndef, Uri uri) {
|
|
||||||
this.ndef = ndef;
|
|
||||||
this.uri = uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPreExecute() {
|
|
||||||
super.onPreExecute();
|
|
||||||
showProgressDialog(R.string.progress_nfc_write);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Boolean doInBackground(Void... params) {
|
|
||||||
if (params.length != 0) return false;
|
|
||||||
try {
|
|
||||||
writeNdef(ndef, uri);
|
|
||||||
return true;
|
|
||||||
} catch (IOException | FormatException ex) {
|
|
||||||
Timber.e(ex);
|
|
||||||
} catch (IllegalArgumentException ex) {
|
|
||||||
errorMessage = ex.getMessage();
|
|
||||||
Timber.d(errorMessage);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
ndef.close();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
Timber.e(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(Boolean result) {
|
|
||||||
super.onPostExecute(result);
|
|
||||||
if (isDestroyed()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
dismissProgressDialog();
|
|
||||||
if (!result) {
|
|
||||||
if (errorMessage != null)
|
|
||||||
Toast.makeText(getApplicationContext(), errorMessage, Toast.LENGTH_LONG).show();
|
|
||||||
else
|
|
||||||
Toast.makeText(getApplicationContext(), getString(R.string.nfc_write_failed), Toast.LENGTH_LONG).show();
|
|
||||||
} else {
|
|
||||||
Toast.makeText(getApplicationContext(), getString(R.string.nfc_write_successful), Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeNdef(Ndef ndef, Uri uri) throws IOException, FormatException {
|
|
||||||
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
|
|
||||||
if (nfcAdapter == null) return; // no NFC support here
|
|
||||||
|
|
||||||
NdefRecord recordNFC = NdefRecord.createUri(uri);
|
|
||||||
NdefMessage message = new NdefMessage(recordNFC);
|
|
||||||
ndef.connect();
|
|
||||||
int tagSize = ndef.getMaxSize();
|
|
||||||
int msgSize = message.getByteArrayLength();
|
|
||||||
Timber.d("tagSize=%d, msgSIze=%d, uriSize=%d", tagSize, msgSize, uri.toString().length());
|
|
||||||
if (tagSize < msgSize)
|
|
||||||
throw new IllegalArgumentException(getString(R.string.nfc_tag_size, tagSize, msgSize));
|
|
||||||
ndef.writeNdefMessage(message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -16,8 +16,6 @@
|
|||||||
|
|
||||||
package com.m2049r.xmrwallet;
|
package com.m2049r.xmrwallet;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
@@ -36,8 +34,8 @@ import android.view.WindowManager;
|
|||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
@@ -45,6 +43,7 @@ import androidx.fragment.app.Fragment;
|
|||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
import com.google.android.material.switchmaterial.SwitchMaterial;
|
import com.google.android.material.switchmaterial.SwitchMaterial;
|
||||||
import com.google.android.material.textfield.TextInputLayout;
|
import com.google.android.material.textfield.TextInputLayout;
|
||||||
|
import com.m2049r.xmrwallet.model.NetworkType;
|
||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
import com.m2049r.xmrwallet.model.WalletManager;
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
import com.m2049r.xmrwallet.util.FingerprintHelper;
|
import com.m2049r.xmrwallet.util.FingerprintHelper;
|
||||||
@@ -58,7 +57,6 @@ import com.m2049r.xmrwallet.widget.Toolbar;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
@@ -299,10 +297,10 @@ public class GenerateFragment extends Fragment {
|
|||||||
if (etSeedOffset.getVisibility() == View.VISIBLE) {
|
if (etSeedOffset.getVisibility() == View.VISIBLE) {
|
||||||
etSeedOffset.getEditText().getText().clear();
|
etSeedOffset.getEditText().getText().clear();
|
||||||
etSeedOffset.setVisibility(View.GONE);
|
etSeedOffset.setVisibility(View.GONE);
|
||||||
bSeedOffset.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_baseline_keyboard_arrow_down_24, 0, 0, 0);
|
bSeedOffset.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_keyboard_arrow_down, 0, 0, 0);
|
||||||
} else {
|
} else {
|
||||||
etSeedOffset.setVisibility(View.VISIBLE);
|
etSeedOffset.setVisibility(View.VISIBLE);
|
||||||
bSeedOffset.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_baseline_keyboard_arrow_up_24, 0, 0, 0);
|
bSeedOffset.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_keyboard_arrow_up, 0, 0, 0);
|
||||||
etSeedOffset.requestFocusFromTouch();
|
etSeedOffset.requestFocusFromTouch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -347,21 +345,23 @@ public class GenerateFragment extends Fragment {
|
|||||||
|
|
||||||
String restoreHeight = etWalletRestoreHeight.getEditText().getText().toString().trim();
|
String restoreHeight = etWalletRestoreHeight.getEditText().getText().toString().trim();
|
||||||
if (restoreHeight.isEmpty()) return -1;
|
if (restoreHeight.isEmpty()) return -1;
|
||||||
try {
|
if (WalletManager.getInstance().getNetworkType() == NetworkType.NetworkType_Mainnet) {
|
||||||
// is it a date?
|
|
||||||
SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd");
|
|
||||||
parser.setLenient(false);
|
|
||||||
height = RestoreHeight.getInstance().getHeight(parser.parse(restoreHeight));
|
|
||||||
} catch (ParseException ignored) {
|
|
||||||
}
|
|
||||||
if ((height < 0) && (restoreHeight.length() == 8))
|
|
||||||
try {
|
try {
|
||||||
// is it a date without dashes?
|
// is it a date?
|
||||||
SimpleDateFormat parser = new SimpleDateFormat("yyyyMMdd");
|
SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd");
|
||||||
parser.setLenient(false);
|
parser.setLenient(false);
|
||||||
height = RestoreHeight.getInstance().getHeight(parser.parse(restoreHeight));
|
height = RestoreHeight.getInstance().getHeight(parser.parse(restoreHeight));
|
||||||
} catch (ParseException ignored) {
|
} catch (ParseException ignored) {
|
||||||
}
|
}
|
||||||
|
if ((height < 0) && (restoreHeight.length() == 8))
|
||||||
|
try {
|
||||||
|
// is it a date without dashes?
|
||||||
|
SimpleDateFormat parser = new SimpleDateFormat("yyyyMMdd");
|
||||||
|
parser.setLenient(false);
|
||||||
|
height = RestoreHeight.getInstance().getHeight(parser.parse(restoreHeight));
|
||||||
|
} catch (ParseException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
if (height < 0)
|
if (height < 0)
|
||||||
try {
|
try {
|
||||||
// or is it a height?
|
// or is it a height?
|
||||||
|
@@ -46,7 +46,6 @@ import androidx.appcompat.app.AlertDialog;
|
|||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
import com.google.android.material.progressindicator.CircularProgressIndicator;
|
|
||||||
import com.google.android.material.switchmaterial.SwitchMaterial;
|
import com.google.android.material.switchmaterial.SwitchMaterial;
|
||||||
import com.google.android.material.textfield.TextInputLayout;
|
import com.google.android.material.textfield.TextInputLayout;
|
||||||
import com.m2049r.xmrwallet.ledger.Ledger;
|
import com.m2049r.xmrwallet.ledger.Ledger;
|
||||||
@@ -200,10 +199,10 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
void toggleAdvancedInfo() {
|
void toggleAdvancedInfo() {
|
||||||
if (llAdvancedInfo.getVisibility() == View.VISIBLE) {
|
if (llAdvancedInfo.getVisibility() == View.VISIBLE) {
|
||||||
llAdvancedInfo.setVisibility(View.GONE);
|
llAdvancedInfo.setVisibility(View.GONE);
|
||||||
bAdvancedInfo.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_baseline_keyboard_arrow_down_24, 0, 0, 0);
|
bAdvancedInfo.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_keyboard_arrow_down, 0, 0, 0);
|
||||||
} else {
|
} else {
|
||||||
llAdvancedInfo.setVisibility(View.VISIBLE);
|
llAdvancedInfo.setVisibility(View.VISIBLE);
|
||||||
bAdvancedInfo.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_baseline_keyboard_arrow_up_24, 0, 0, 0);
|
bAdvancedInfo.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_keyboard_arrow_up, 0, 0, 0);
|
||||||
scrollview.post(() -> scrollview.fullScroll(ScrollView.FOCUS_DOWN));
|
scrollview.post(() -> scrollview.fullScroll(ScrollView.FOCUS_DOWN));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -212,10 +211,10 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
if (etSeedOffset.getVisibility() == View.VISIBLE) {
|
if (etSeedOffset.getVisibility() == View.VISIBLE) {
|
||||||
etSeedOffset.getEditText().getText().clear();
|
etSeedOffset.getEditText().getText().clear();
|
||||||
etSeedOffset.setVisibility(View.GONE);
|
etSeedOffset.setVisibility(View.GONE);
|
||||||
bSeedOffset.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_baseline_keyboard_arrow_down_24, 0, 0, 0);
|
bSeedOffset.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_keyboard_arrow_down, 0, 0, 0);
|
||||||
} else {
|
} else {
|
||||||
etSeedOffset.setVisibility(View.VISIBLE);
|
etSeedOffset.setVisibility(View.VISIBLE);
|
||||||
bSeedOffset.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_baseline_keyboard_arrow_up_24, 0, 0, 0);
|
bSeedOffset.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_keyboard_arrow_up, 0, 0, 0);
|
||||||
etSeedOffset.requestFocusFromTouch();
|
etSeedOffset.requestFocusFromTouch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -234,7 +233,6 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
String seed;
|
String seed;
|
||||||
String viewKey;
|
String viewKey;
|
||||||
String spendKey;
|
String spendKey;
|
||||||
boolean isWatchOnly;
|
|
||||||
Wallet.Status walletStatus;
|
Wallet.Status walletStatus;
|
||||||
|
|
||||||
boolean dialogOpened = false;
|
boolean dialogOpened = false;
|
||||||
@@ -286,8 +284,7 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
default:
|
default:
|
||||||
throw new IllegalStateException("Hardware backing not supported. At all!");
|
throw new IllegalStateException("Hardware backing not supported. At all!");
|
||||||
}
|
}
|
||||||
spendKey = isWatchOnly ? getActivity().getString(R.string.label_watchonly) : wallet.getSecretSpendKey();
|
spendKey = wallet.isWatchOnly() ? getActivity().getString(R.string.label_watchonly) : wallet.getSecretSpendKey();
|
||||||
isWatchOnly = wallet.isWatchOnly();
|
|
||||||
if (closeWallet) wallet.close();
|
if (closeWallet) wallet.close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@@ -26,6 +26,7 @@ import android.content.SharedPreferences;
|
|||||||
import android.hardware.usb.UsbDevice;
|
import android.hardware.usb.UsbDevice;
|
||||||
import android.hardware.usb.UsbManager;
|
import android.hardware.usb.UsbManager;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@@ -39,7 +40,6 @@ import android.widget.Toast;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.app.AppCompatDelegate;
|
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
import androidx.fragment.app.FragmentTransaction;
|
import androidx.fragment.app.FragmentTransaction;
|
||||||
@@ -49,24 +49,18 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
|||||||
import com.m2049r.xmrwallet.data.DefaultNodes;
|
import com.m2049r.xmrwallet.data.DefaultNodes;
|
||||||
import com.m2049r.xmrwallet.data.Node;
|
import com.m2049r.xmrwallet.data.Node;
|
||||||
import com.m2049r.xmrwallet.data.NodeInfo;
|
import com.m2049r.xmrwallet.data.NodeInfo;
|
||||||
import com.m2049r.xmrwallet.dialog.AboutFragment;
|
|
||||||
import com.m2049r.xmrwallet.dialog.CreditsFragment;
|
|
||||||
import com.m2049r.xmrwallet.dialog.HelpFragment;
|
import com.m2049r.xmrwallet.dialog.HelpFragment;
|
||||||
import com.m2049r.xmrwallet.dialog.PrivacyFragment;
|
|
||||||
import com.m2049r.xmrwallet.ledger.Ledger;
|
import com.m2049r.xmrwallet.ledger.Ledger;
|
||||||
import com.m2049r.xmrwallet.ledger.LedgerProgressDialog;
|
import com.m2049r.xmrwallet.ledger.LedgerProgressDialog;
|
||||||
import com.m2049r.xmrwallet.model.NetworkType;
|
import com.m2049r.xmrwallet.model.NetworkType;
|
||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
import com.m2049r.xmrwallet.model.WalletManager;
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
import com.m2049r.xmrwallet.service.WalletService;
|
import com.m2049r.xmrwallet.service.WalletService;
|
||||||
import com.m2049r.xmrwallet.util.DayNightMode;
|
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
import com.m2049r.xmrwallet.util.KeyStoreHelper;
|
import com.m2049r.xmrwallet.util.KeyStoreHelper;
|
||||||
import com.m2049r.xmrwallet.util.LegacyStorageHelper;
|
import com.m2049r.xmrwallet.util.LegacyStorageHelper;
|
||||||
import com.m2049r.xmrwallet.util.LocaleHelper;
|
|
||||||
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
|
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
|
||||||
import com.m2049r.xmrwallet.util.NetCipherHelper;
|
import com.m2049r.xmrwallet.util.NetCipherHelper;
|
||||||
import com.m2049r.xmrwallet.util.NightmodeHelper;
|
|
||||||
import com.m2049r.xmrwallet.util.ThemeHelper;
|
import com.m2049r.xmrwallet.util.ThemeHelper;
|
||||||
import com.m2049r.xmrwallet.util.ZipBackup;
|
import com.m2049r.xmrwallet.util.ZipBackup;
|
||||||
import com.m2049r.xmrwallet.util.ZipRestore;
|
import com.m2049r.xmrwallet.util.ZipRestore;
|
||||||
@@ -77,12 +71,8 @@ import java.io.FileInputStream;
|
|||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.channels.FileChannel;
|
import java.nio.channels.FileChannel;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@@ -90,7 +80,8 @@ import timber.log.Timber;
|
|||||||
|
|
||||||
public class LoginActivity extends BaseActivity
|
public class LoginActivity extends BaseActivity
|
||||||
implements LoginFragment.Listener, GenerateFragment.Listener,
|
implements LoginFragment.Listener, GenerateFragment.Listener,
|
||||||
GenerateReviewFragment.Listener, GenerateReviewFragment.AcceptListener, NodeFragment.Listener {
|
GenerateReviewFragment.Listener, GenerateReviewFragment.AcceptListener,
|
||||||
|
NodeFragment.Listener, SettingsFragment.Listener {
|
||||||
private static final String GENERATE_STACK = "gen";
|
private static final String GENERATE_STACK = "gen";
|
||||||
|
|
||||||
private static final String NODES_PREFS_NAME = "nodes";
|
private static final String NODES_PREFS_NAME = "nodes";
|
||||||
@@ -293,6 +284,7 @@ public class LoginActivity extends BaseActivity
|
|||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
Timber.d("onCreate()");
|
Timber.d("onCreate()");
|
||||||
|
ThemeHelper.setPreferred(this);
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
setContentView(R.layout.activity_login);
|
setContentView(R.layout.activity_login);
|
||||||
@@ -308,8 +300,8 @@ public class LoginActivity extends BaseActivity
|
|||||||
case Toolbar.BUTTON_CLOSE:
|
case Toolbar.BUTTON_CLOSE:
|
||||||
finish();
|
finish();
|
||||||
break;
|
break;
|
||||||
case Toolbar.BUTTON_CREDITS:
|
case Toolbar.BUTTON_SETTINGS:
|
||||||
CreditsFragment.display(getSupportFragmentManager());
|
startSettingsFragment();
|
||||||
break;
|
break;
|
||||||
case Toolbar.BUTTON_NONE:
|
case Toolbar.BUTTON_NONE:
|
||||||
break;
|
break;
|
||||||
@@ -666,11 +658,11 @@ public class LoginActivity extends BaseActivity
|
|||||||
break;
|
break;
|
||||||
case NetworkType_Testnet:
|
case NetworkType_Testnet:
|
||||||
toolbar.setSubtitle(getString(R.string.connect_testnet));
|
toolbar.setSubtitle(getString(R.string.connect_testnet));
|
||||||
toolbar.setBackgroundResource(ThemeHelper.getThemedResourceId(this, R.attr.colorPrimaryDark));
|
toolbar.setBackgroundResource(ThemeHelper.getThemedResourceId(this, androidx.appcompat.R.attr.colorPrimaryDark));
|
||||||
break;
|
break;
|
||||||
case NetworkType_Stagenet:
|
case NetworkType_Stagenet:
|
||||||
toolbar.setSubtitle(getString(R.string.connect_stagenet));
|
toolbar.setSubtitle(getString(R.string.connect_stagenet));
|
||||||
toolbar.setBackgroundResource(ThemeHelper.getThemedResourceId(this, R.attr.colorPrimaryDark));
|
toolbar.setBackgroundResource(ThemeHelper.getThemedResourceId(this, androidx.appcompat.R.attr.colorPrimaryDark));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException("NetworkType unknown: " + net);
|
throw new IllegalStateException("NetworkType unknown: " + net);
|
||||||
@@ -785,6 +777,11 @@ public class LoginActivity extends BaseActivity
|
|||||||
Timber.d("NodeFragment placed");
|
Timber.d("NodeFragment placed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void startSettingsFragment() {
|
||||||
|
replaceFragment(new SettingsFragment(), null, null);
|
||||||
|
Timber.d("SettingsFragment placed");
|
||||||
|
}
|
||||||
|
|
||||||
void replaceFragment(Fragment newFragment, String stackName, Bundle extras) {
|
void replaceFragment(Fragment newFragment, String stackName, Bundle extras) {
|
||||||
if (extras != null) {
|
if (extras != null) {
|
||||||
newFragment.setArguments(extras);
|
newFragment.setArguments(extras);
|
||||||
@@ -918,9 +915,9 @@ public class LoginActivity extends BaseActivity
|
|||||||
@Override
|
@Override
|
||||||
public boolean createWallet(File aFile, String password) {
|
public boolean createWallet(File aFile, String password) {
|
||||||
NodeInfo currentNode = getNode();
|
NodeInfo currentNode = getNode();
|
||||||
// get it from the connected node if we have one, and go back ca. 4 days
|
// get it from the connected node if we have one
|
||||||
final long restoreHeight =
|
final long restoreHeight =
|
||||||
(currentNode != null) ? currentNode.getHeight() - 2000 : -1;
|
(currentNode != null) ? currentNode.getHeight() : -1;
|
||||||
Wallet newWallet = WalletManager.getInstance()
|
Wallet newWallet = WalletManager.getInstance()
|
||||||
.createWallet(aFile, password, MNEMONIC_LANGUAGE, restoreHeight);
|
.createWallet(aFile, password, MNEMONIC_LANGUAGE, restoreHeight);
|
||||||
return checkAndCloseWallet(newWallet);
|
return checkAndCloseWallet(newWallet);
|
||||||
@@ -1089,61 +1086,6 @@ public class LoginActivity extends BaseActivity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onChangeLocale() {
|
|
||||||
final ArrayList<Locale> availableLocales = LocaleHelper.getAvailableLocales(LoginActivity.this);
|
|
||||||
Collections.sort(availableLocales, (locale1, locale2) -> {
|
|
||||||
String localeString1 = LocaleHelper.getDisplayName(locale1, true);
|
|
||||||
String localeString2 = LocaleHelper.getDisplayName(locale2, true);
|
|
||||||
return localeString1.compareTo(localeString2);
|
|
||||||
});
|
|
||||||
|
|
||||||
String[] localeDisplayNames = new String[1 + availableLocales.size()];
|
|
||||||
localeDisplayNames[0] = getString(R.string.language_system_default);
|
|
||||||
for (int i = 1; i < localeDisplayNames.length; i++) {
|
|
||||||
localeDisplayNames[i] = LocaleHelper.getDisplayName(availableLocales.get(i - 1), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
int currentLocaleIndex = 0;
|
|
||||||
String currentLocaleTag = LocaleHelper.getPreferredLanguageTag(LoginActivity.this);
|
|
||||||
if (!currentLocaleTag.isEmpty()) {
|
|
||||||
Locale currentLocale = Locale.forLanguageTag(currentLocaleTag);
|
|
||||||
String currentLocaleName = LocaleHelper.getDisplayName(currentLocale, true);
|
|
||||||
currentLocaleIndex = Arrays.asList(localeDisplayNames).indexOf(currentLocaleName);
|
|
||||||
if (currentLocaleIndex < 0) currentLocaleIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(LoginActivity.this);
|
|
||||||
builder.setTitle(getString(R.string.menu_language));
|
|
||||||
builder.setSingleChoiceItems(localeDisplayNames, currentLocaleIndex, (dialog, i) -> {
|
|
||||||
dialog.dismiss();
|
|
||||||
|
|
||||||
LocaleHelper.setAndSaveLocale(this,
|
|
||||||
(i == 0) ? "" : availableLocales.get(i - 1).toLanguageTag());
|
|
||||||
startActivity(getIntent().addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK));
|
|
||||||
});
|
|
||||||
builder.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onChangeTheme() {
|
|
||||||
final DayNightMode currentDayNightSetting = DayNightMode.getValue(AppCompatDelegate.getDefaultNightMode());
|
|
||||||
// selection will be empty if UNKNOWN
|
|
||||||
|
|
||||||
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(LoginActivity.this);
|
|
||||||
builder.setTitle(getString(R.string.menu_daynight));
|
|
||||||
|
|
||||||
String[] modeNames = getResources().getStringArray(R.array.daynight_themes);
|
|
||||||
|
|
||||||
builder.setSingleChoiceItems(modeNames, currentDayNightSetting.ordinal(), (dialog, i) -> {
|
|
||||||
dialog.dismiss();
|
|
||||||
final DayNightMode mode = DayNightMode.values()[i];
|
|
||||||
if (currentDayNightSetting != mode) {
|
|
||||||
NightmodeHelper.setAndSavePreferredNightmode(LoginActivity.this, mode);
|
|
||||||
LoginActivity.this.recreate();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
builder.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
Fragment f = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
|
Fragment f = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
|
||||||
@@ -1192,9 +1134,6 @@ public class LoginActivity extends BaseActivity
|
|||||||
} else if (id == R.id.action_details_changepw) {
|
} else if (id == R.id.action_details_changepw) {
|
||||||
onWalletChangePassword();
|
onWalletChangePassword();
|
||||||
return true;
|
return true;
|
||||||
} else if (id == R.id.action_license_info) {
|
|
||||||
AboutFragment.display(getSupportFragmentManager());
|
|
||||||
return true;
|
|
||||||
} else if (id == R.id.action_help_list) {
|
} else if (id == R.id.action_help_list) {
|
||||||
HelpFragment.display(getSupportFragmentManager(), R.string.help_list);
|
HelpFragment.display(getSupportFragmentManager(), R.string.help_list);
|
||||||
return true;
|
return true;
|
||||||
@@ -1208,18 +1147,6 @@ public class LoginActivity extends BaseActivity
|
|||||||
((NodeFragment) f).restoreDefaultNodes();
|
((NodeFragment) f).restoreDefaultNodes();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else if (id == R.id.action_privacy_policy) {
|
|
||||||
PrivacyFragment.display(getSupportFragmentManager());
|
|
||||||
return true;
|
|
||||||
} else if (id == R.id.action_language) {
|
|
||||||
onChangeLocale();
|
|
||||||
return true;
|
|
||||||
} else if (id == R.id.action_theme) {
|
|
||||||
onChangeTheme();
|
|
||||||
return true;
|
|
||||||
} else if (id == R.id.action_restore) {
|
|
||||||
onWalletRestore();
|
|
||||||
return true;
|
|
||||||
} else if (id == R.id.action_ledger_seed) {
|
} else if (id == R.id.action_ledger_seed) {
|
||||||
Fragment f = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
|
Fragment f = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
|
||||||
if (f instanceof GenerateFragment) {
|
if (f instanceof GenerateFragment) {
|
||||||
@@ -1333,7 +1260,8 @@ public class LoginActivity extends BaseActivity
|
|||||||
registerReceiver(usbPermissionReceiver, new IntentFilter(ACTION_USB_PERMISSION));
|
registerReceiver(usbPermissionReceiver, new IntentFilter(ACTION_USB_PERMISSION));
|
||||||
usbManager.requestPermission(device,
|
usbManager.requestPermission(device,
|
||||||
PendingIntent.getBroadcast(this, 0,
|
PendingIntent.getBroadcast(this, 0,
|
||||||
new Intent(ACTION_USB_PERMISSION), 0));
|
new Intent(ACTION_USB_PERMISSION),
|
||||||
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_IMMUTABLE : 0));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Timber.d("no ledger device found");
|
Timber.d("no ledger device found");
|
||||||
|
@@ -29,7 +29,6 @@ import android.view.View;
|
|||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.animation.Animation;
|
import android.view.animation.Animation;
|
||||||
import android.view.animation.AnimationUtils;
|
import android.view.animation.AnimationUtils;
|
||||||
import android.widget.FrameLayout;
|
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.RelativeLayout;
|
import android.widget.RelativeLayout;
|
||||||
@@ -38,7 +37,6 @@ import android.widget.Toast;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
@@ -53,6 +51,7 @@ import com.m2049r.xmrwallet.util.KeyStoreHelper;
|
|||||||
import com.m2049r.xmrwallet.util.NetCipherHelper;
|
import com.m2049r.xmrwallet.util.NetCipherHelper;
|
||||||
import com.m2049r.xmrwallet.util.NodePinger;
|
import com.m2049r.xmrwallet.util.NodePinger;
|
||||||
import com.m2049r.xmrwallet.util.Notice;
|
import com.m2049r.xmrwallet.util.Notice;
|
||||||
|
import com.m2049r.xmrwallet.util.ThemeHelper;
|
||||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -143,7 +142,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
|||||||
super.onResume();
|
super.onResume();
|
||||||
Timber.d("onResume() %s", activityCallback.getFavouriteNodes().size());
|
Timber.d("onResume() %s", activityCallback.getFavouriteNodes().size());
|
||||||
activityCallback.setTitle(null);
|
activityCallback.setTitle(null);
|
||||||
activityCallback.setToolbarButton(Toolbar.BUTTON_CREDITS);
|
activityCallback.setToolbarButton(Toolbar.BUTTON_SETTINGS);
|
||||||
activityCallback.showNet();
|
activityCallback.showNet();
|
||||||
showNetwork();
|
showNetwork();
|
||||||
//activityCallback.runOnNetCipher(this::pingSelectedNode);
|
//activityCallback.runOnNetCipher(this::pingSelectedNode);
|
||||||
@@ -163,12 +162,14 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
|||||||
fabView = view.findViewById(R.id.fabView);
|
fabView = view.findViewById(R.id.fabView);
|
||||||
fabKey = view.findViewById(R.id.fabKey);
|
fabKey = view.findViewById(R.id.fabKey);
|
||||||
fabSeed = view.findViewById(R.id.fabSeed);
|
fabSeed = view.findViewById(R.id.fabSeed);
|
||||||
|
fabImport = view.findViewById(R.id.fabImport);
|
||||||
fabLedger = view.findViewById(R.id.fabLedger);
|
fabLedger = view.findViewById(R.id.fabLedger);
|
||||||
|
|
||||||
fabNewL = view.findViewById(R.id.fabNewL);
|
fabNewL = view.findViewById(R.id.fabNewL);
|
||||||
fabViewL = view.findViewById(R.id.fabViewL);
|
fabViewL = view.findViewById(R.id.fabViewL);
|
||||||
fabKeyL = view.findViewById(R.id.fabKeyL);
|
fabKeyL = view.findViewById(R.id.fabKeyL);
|
||||||
fabSeedL = view.findViewById(R.id.fabSeedL);
|
fabSeedL = view.findViewById(R.id.fabSeedL);
|
||||||
|
fabImportL = view.findViewById(R.id.fabImportL);
|
||||||
fabLedgerL = view.findViewById(R.id.fabLedgerL);
|
fabLedgerL = view.findViewById(R.id.fabLedgerL);
|
||||||
|
|
||||||
fab_pulse = AnimationUtils.loadAnimation(getContext(), R.anim.fab_pulse);
|
fab_pulse = AnimationUtils.loadAnimation(getContext(), R.anim.fab_pulse);
|
||||||
@@ -183,6 +184,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
|||||||
fabView.setOnClickListener(this);
|
fabView.setOnClickListener(this);
|
||||||
fabKey.setOnClickListener(this);
|
fabKey.setOnClickListener(this);
|
||||||
fabSeed.setOnClickListener(this);
|
fabSeed.setOnClickListener(this);
|
||||||
|
fabImport.setOnClickListener(this);
|
||||||
fabLedger.setOnClickListener(this);
|
fabLedger.setOnClickListener(this);
|
||||||
fabScreen.setOnClickListener(this);
|
fabScreen.setOnClickListener(this);
|
||||||
|
|
||||||
@@ -294,9 +296,9 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isFabOpen = false;
|
private boolean isFabOpen = false;
|
||||||
private FloatingActionButton fab, fabNew, fabView, fabKey, fabSeed, fabLedger;
|
private FloatingActionButton fab, fabNew, fabView, fabKey, fabSeed, fabImport, fabLedger;
|
||||||
private FrameLayout fabScreen;
|
private RelativeLayout fabScreen;
|
||||||
private RelativeLayout fabNewL, fabViewL, fabKeyL, fabSeedL, fabLedgerL;
|
private RelativeLayout fabNewL, fabViewL, fabKeyL, fabSeedL, fabImportL, fabLedgerL;
|
||||||
private Animation fab_open, fab_close, rotate_forward, rotate_backward, fab_open_screen, fab_close_screen;
|
private Animation fab_open, fab_close, rotate_forward, rotate_backward, fab_open_screen, fab_close_screen;
|
||||||
private Animation fab_pulse;
|
private Animation fab_pulse;
|
||||||
|
|
||||||
@@ -321,6 +323,8 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
|||||||
fabKey.setClickable(false);
|
fabKey.setClickable(false);
|
||||||
fabSeedL.startAnimation(fab_close);
|
fabSeedL.startAnimation(fab_close);
|
||||||
fabSeed.setClickable(false);
|
fabSeed.setClickable(false);
|
||||||
|
fabImportL.startAnimation(fab_close);
|
||||||
|
fabImport.setClickable(false);
|
||||||
}
|
}
|
||||||
isFabOpen = false;
|
isFabOpen = false;
|
||||||
} else { // open the fab
|
} else { // open the fab
|
||||||
@@ -333,6 +337,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
|||||||
fabViewL.setVisibility(View.GONE);
|
fabViewL.setVisibility(View.GONE);
|
||||||
fabKeyL.setVisibility(View.GONE);
|
fabKeyL.setVisibility(View.GONE);
|
||||||
fabSeedL.setVisibility(View.GONE);
|
fabSeedL.setVisibility(View.GONE);
|
||||||
|
fabImportL.setVisibility(View.GONE);
|
||||||
|
|
||||||
fabLedgerL.startAnimation(fab_open);
|
fabLedgerL.startAnimation(fab_open);
|
||||||
fabLedger.setClickable(true);
|
fabLedger.setClickable(true);
|
||||||
@@ -342,6 +347,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
|||||||
fabViewL.setVisibility(View.VISIBLE);
|
fabViewL.setVisibility(View.VISIBLE);
|
||||||
fabKeyL.setVisibility(View.VISIBLE);
|
fabKeyL.setVisibility(View.VISIBLE);
|
||||||
fabSeedL.setVisibility(View.VISIBLE);
|
fabSeedL.setVisibility(View.VISIBLE);
|
||||||
|
fabImportL.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
fabNewL.startAnimation(fab_open);
|
fabNewL.startAnimation(fab_open);
|
||||||
fabNew.setClickable(true);
|
fabNew.setClickable(true);
|
||||||
@@ -351,6 +357,8 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
|||||||
fabKey.setClickable(true);
|
fabKey.setClickable(true);
|
||||||
fabSeedL.startAnimation(fab_open);
|
fabSeedL.startAnimation(fab_open);
|
||||||
fabSeed.setClickable(true);
|
fabSeed.setClickable(true);
|
||||||
|
fabImportL.startAnimation(fab_open);
|
||||||
|
fabImport.setClickable(true);
|
||||||
}
|
}
|
||||||
isFabOpen = true;
|
isFabOpen = true;
|
||||||
}
|
}
|
||||||
@@ -375,6 +383,9 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
|||||||
} else if (id == R.id.fabSeed) {
|
} else if (id == R.id.fabSeed) {
|
||||||
animateFAB();
|
animateFAB();
|
||||||
activityCallback.onAddWallet(GenerateFragment.TYPE_SEED);
|
activityCallback.onAddWallet(GenerateFragment.TYPE_SEED);
|
||||||
|
} else if (id == R.id.fabImport) {
|
||||||
|
animateFAB();
|
||||||
|
activityCallback.onWalletRestore();
|
||||||
} else if (id == R.id.fabLedger) {
|
} else if (id == R.id.fabLedger) {
|
||||||
Timber.d("FAB_LEDGER");
|
Timber.d("FAB_LEDGER");
|
||||||
animateFAB();
|
animateFAB();
|
||||||
@@ -403,8 +414,8 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
|||||||
private void setSubtext(String status) {
|
private void setSubtext(String status) {
|
||||||
final Context ctx = getContext();
|
final Context ctx = getContext();
|
||||||
final Spanned text = Html.fromHtml(ctx.getString(R.string.status,
|
final Spanned text = Html.fromHtml(ctx.getString(R.string.status,
|
||||||
Integer.toHexString(ContextCompat.getColor(ctx, R.color.monerujoGreen) & 0xFFFFFF),
|
Integer.toHexString(ThemeHelper.getThemedColor(ctx, R.attr.positiveColor) & 0xFFFFFF),
|
||||||
Integer.toHexString(ContextCompat.getColor(ctx, R.color.monerujoBackground) & 0xFFFFFF),
|
Integer.toHexString(ThemeHelper.getThemedColor(ctx, android.R.attr.colorBackground) & 0xFFFFFF),
|
||||||
status, ""));
|
status, ""));
|
||||||
tvNodeInfo.setText(text);
|
tvNodeInfo.setText(text);
|
||||||
}
|
}
|
||||||
|
@@ -20,7 +20,6 @@ import android.content.Intent;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.onboarding.OnBoardingActivity;
|
import com.m2049r.xmrwallet.onboarding.OnBoardingActivity;
|
||||||
import com.m2049r.xmrwallet.onboarding.OnBoardingManager;
|
import com.m2049r.xmrwallet.onboarding.OnBoardingManager;
|
||||||
|
@@ -415,7 +415,14 @@ public class NodeFragment extends Fragment
|
|||||||
}
|
}
|
||||||
etNodeHost.setError(null);
|
etNodeHost.setError(null);
|
||||||
nodeInfo.setRpcPort(port);
|
nodeInfo.setRpcPort(port);
|
||||||
nodeInfo.setName(etNodeName.getEditText().getText().toString().trim());
|
// setName() may trigger reverse DNS
|
||||||
|
Helper.runWithNetwork(new Helper.Action() {
|
||||||
|
@Override
|
||||||
|
public boolean run() {
|
||||||
|
nodeInfo.setName(etNodeName.getEditText().getText().toString().trim());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
nodeInfo.setUsername(etNodeUser.getEditText().getText().toString().trim());
|
nodeInfo.setUsername(etNodeUser.getEditText().getText().toString().trim());
|
||||||
nodeInfo.setPassword(etNodePass.getEditText().getText().toString()); // no trim for pw
|
nodeInfo.setPassword(etNodePass.getEditText().getText().toString()); // no trim for pw
|
||||||
return true;
|
return true;
|
||||||
|
@@ -22,7 +22,6 @@ import android.graphics.Bitmap;
|
|||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.nfc.NfcManager;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.Html;
|
import android.text.Html;
|
||||||
@@ -46,10 +45,7 @@ import android.widget.Toast;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.widget.ShareActionProvider;
|
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
import androidx.core.content.FileProvider;
|
import androidx.core.content.FileProvider;
|
||||||
import androidx.core.view.MenuItemCompat;
|
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import com.google.android.material.textfield.TextInputLayout;
|
import com.google.android.material.textfield.TextInputLayout;
|
||||||
@@ -89,6 +85,7 @@ public class ReceiveFragment extends Fragment {
|
|||||||
private ImageView ivQrCodeFull;
|
private ImageView ivQrCodeFull;
|
||||||
private EditText etDummy;
|
private EditText etDummy;
|
||||||
private ImageButton bCopyAddress;
|
private ImageButton bCopyAddress;
|
||||||
|
private MenuItem shareItem;
|
||||||
|
|
||||||
private Wallet wallet = null;
|
private Wallet wallet = null;
|
||||||
private boolean isMyWallet = false;
|
private boolean isMyWallet = false;
|
||||||
@@ -128,6 +125,7 @@ public class ReceiveFragment extends Fragment {
|
|||||||
evAmount.setOnNewAmountListener(xmr -> {
|
evAmount.setOnNewAmountListener(xmr -> {
|
||||||
Timber.d("new amount = %s", xmr);
|
Timber.d("new amount = %s", xmr);
|
||||||
generateQr();
|
generateQr();
|
||||||
|
if (shareRequested && (xmr != null)) share();
|
||||||
});
|
});
|
||||||
|
|
||||||
evAmount.setOnFailedExchangeListener(() -> {
|
evAmount.setOnFailedExchangeListener(() -> {
|
||||||
@@ -192,11 +190,6 @@ public class ReceiveFragment extends Fragment {
|
|||||||
throw new IllegalStateException("no wallet info");
|
throw new IllegalStateException("no wallet info");
|
||||||
}
|
}
|
||||||
|
|
||||||
View tvNfc = view.findViewById(R.id.tvNfc);
|
|
||||||
NfcManager manager = (NfcManager) getContext().getSystemService(Context.NFC_SERVICE);
|
|
||||||
if ((manager != null) && (manager.getDefaultAdapter() != null))
|
|
||||||
tvNfc.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,39 +204,38 @@ public class ReceiveFragment extends Fragment {
|
|||||||
setSharedElementEnterTransition(transform);
|
setSharedElementEnterTransition(transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ShareActionProvider shareActionProvider;
|
private boolean shareRequested = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreateOptionsMenu(@NonNull Menu menu, final MenuInflater inflater) {
|
public void onCreateOptionsMenu(@NonNull Menu menu, final MenuInflater inflater) {
|
||||||
inflater.inflate(R.menu.receive_menu, menu);
|
inflater.inflate(R.menu.receive_menu, menu);
|
||||||
super.onCreateOptionsMenu(menu, inflater);
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
|
|
||||||
// Locate MenuItem with ShareActionProvider
|
shareItem = menu.findItem(R.id.menu_item_share);
|
||||||
MenuItem item = menu.findItem(R.id.menu_item_share);
|
shareItem.setOnMenuItemClickListener(item -> {
|
||||||
|
if (shareRequested) return true;
|
||||||
// Fetch and store ShareActionProvider
|
shareRequested = true;
|
||||||
shareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(item);
|
if (!qrValid) {
|
||||||
|
evAmount.doExchange();
|
||||||
shareActionProvider.setOnShareTargetSelectedListener(new ShareActionProvider.OnShareTargetSelectedListener() {
|
} else {
|
||||||
@Override
|
share();
|
||||||
public boolean onShareTargetSelected(ShareActionProvider shareActionProvider, Intent intent) {
|
|
||||||
saveQrCode(); // save it only if we need it
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setShareIntent() {
|
private void share() {
|
||||||
if (shareActionProvider != null) {
|
shareRequested = false;
|
||||||
if (qrValid) {
|
if (saveQrCode()) {
|
||||||
shareActionProvider.setShareIntent(getShareIntent());
|
final Intent sendIntent = getSendIntent();
|
||||||
} else {
|
if (sendIntent != null)
|
||||||
shareActionProvider.setShareIntent(null);
|
startActivity(Intent.createChooser(sendIntent, null));
|
||||||
}
|
} else {
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.message_qr_failed), Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveQrCode() {
|
private boolean saveQrCode() {
|
||||||
if (!qrValid) throw new IllegalStateException("trying to save null qr code!");
|
if (!qrValid) throw new IllegalStateException("trying to save null qr code!");
|
||||||
|
|
||||||
File cachePath = new File(getActivity().getCacheDir(), "images");
|
File cachePath = new File(getActivity().getCacheDir(), "images");
|
||||||
@@ -255,33 +247,35 @@ public class ReceiveFragment extends Fragment {
|
|||||||
Bitmap qrBitmap = ((BitmapDrawable) ivQrCode.getDrawable()).getBitmap();
|
Bitmap qrBitmap = ((BitmapDrawable) ivQrCode.getDrawable()).getBitmap();
|
||||||
qrBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
|
qrBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
|
||||||
stream.close();
|
stream.close();
|
||||||
|
return true;
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
Timber.e(ex);
|
Timber.e(ex);
|
||||||
// make sure we don't share an old qr code
|
// make sure we don't share an old qr code
|
||||||
if (!png.delete()) throw new IllegalStateException("cannot delete old qr code");
|
if (!png.delete()) throw new IllegalStateException("cannot delete old qr code");
|
||||||
// if we manage to delete it, the URI points to nothing and the user gets a toast with the error
|
// if we manage to delete it, the URI points to nothing and the user gets a toast with the error
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Intent getShareIntent() {
|
private Intent getSendIntent() {
|
||||||
File imagePath = new File(getActivity().getCacheDir(), "images");
|
File imagePath = new File(requireActivity().getCacheDir(), "images");
|
||||||
File png = new File(imagePath, "QR.png");
|
File png = new File(imagePath, "QR.png");
|
||||||
Uri contentUri = FileProvider.getUriForFile(getActivity(),
|
Uri contentUri = FileProvider.getUriForFile(requireActivity(), BuildConfig.APPLICATION_ID + ".fileprovider", png);
|
||||||
BuildConfig.APPLICATION_ID + ".fileprovider", png);
|
|
||||||
if (contentUri != null) {
|
if (contentUri != null) {
|
||||||
Intent shareIntent = new Intent();
|
Intent shareIntent = new Intent();
|
||||||
shareIntent.setAction(Intent.ACTION_SEND);
|
shareIntent.setAction(Intent.ACTION_SEND);
|
||||||
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // temp permission for receiving app to read this file
|
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // temp permission for receiving app to read this file
|
||||||
shareIntent.setDataAndType(contentUri, getActivity().getContentResolver().getType(contentUri));
|
shareIntent.setTypeAndNormalize("image/png");
|
||||||
shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
|
shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
|
||||||
shareIntent.putExtra(Intent.EXTRA_TEXT, bcData.getUriString());
|
if (bcData != null)
|
||||||
|
shareIntent.putExtra(Intent.EXTRA_TEXT, bcData.getUriString());
|
||||||
return shareIntent;
|
return shareIntent;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
void copyAddress() {
|
void copyAddress() {
|
||||||
Helper.clipBoardCopy(Objects.requireNonNull(getActivity()), getString(R.string.label_copy_address), subaddress.getAddress());
|
Helper.clipBoardCopy(requireActivity(), getString(R.string.label_copy_address), subaddress.getAddress());
|
||||||
Toast.makeText(getActivity(), getString(R.string.message_copy_address), Toast.LENGTH_SHORT).show();
|
Toast.makeText(getActivity(), getString(R.string.message_copy_address), Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,7 +285,6 @@ public class ReceiveFragment extends Fragment {
|
|||||||
if (qrValid) {
|
if (qrValid) {
|
||||||
ivQrCode.setImageBitmap(null);
|
ivQrCode.setImageBitmap(null);
|
||||||
qrValid = false;
|
qrValid = false;
|
||||||
setShareIntent();
|
|
||||||
if (isLoaded)
|
if (isLoaded)
|
||||||
tvQrCode.setVisibility(View.VISIBLE);
|
tvQrCode.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
@@ -300,7 +293,6 @@ public class ReceiveFragment extends Fragment {
|
|||||||
void setQR(Bitmap qr) {
|
void setQR(Bitmap qr) {
|
||||||
ivQrCode.setImageBitmap(qr);
|
ivQrCode.setImageBitmap(qr);
|
||||||
qrValid = true;
|
qrValid = true;
|
||||||
setShareIntent();
|
|
||||||
tvQrCode.setVisibility(View.GONE);
|
tvQrCode.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -405,7 +397,7 @@ public class ReceiveFragment extends Fragment {
|
|||||||
|
|
||||||
private Bitmap getMoneroLogo() {
|
private Bitmap getMoneroLogo() {
|
||||||
if (logo == null) {
|
if (logo == null) {
|
||||||
logo = Helper.getBitmap(getContext(), R.drawable.ic_monero_logo_b);
|
logo = Helper.getBitmap(getContext(), R.drawable.ic_monerujo_qr);
|
||||||
}
|
}
|
||||||
return logo;
|
return logo;
|
||||||
}
|
}
|
||||||
@@ -462,8 +454,8 @@ public class ReceiveFragment extends Fragment {
|
|||||||
subaddress = newSubaddress;
|
subaddress = newSubaddress;
|
||||||
final Context context = getContext();
|
final Context context = getContext();
|
||||||
Spanned label = Html.fromHtml(context.getString(R.string.receive_subaddress,
|
Spanned label = Html.fromHtml(context.getString(R.string.receive_subaddress,
|
||||||
Integer.toHexString(ContextCompat.getColor(context, R.color.monerujoGreen) & 0xFFFFFF),
|
Integer.toHexString(ThemeHelper.getThemedColor(context, R.attr.positiveColor) & 0xFFFFFF),
|
||||||
Integer.toHexString(ContextCompat.getColor(context, R.color.monerujoBackground) & 0xFFFFFF),
|
Integer.toHexString(ThemeHelper.getThemedColor(context, android.R.attr.colorBackground) & 0xFFFFFF),
|
||||||
subaddress.getDisplayLabel(), subaddress.getAddress()));
|
subaddress.getDisplayLabel(), subaddress.getAddress()));
|
||||||
tvAddress.setText(label);
|
tvAddress.setText(label);
|
||||||
generateQr();
|
generateQr();
|
||||||
|
@@ -19,12 +19,13 @@ package com.m2049r.xmrwallet;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import com.google.zxing.BarcodeFormat;
|
import com.google.zxing.BarcodeFormat;
|
||||||
import com.google.zxing.Result;
|
import com.google.zxing.Result;
|
||||||
|
|
||||||
|
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package com.m2049r.xmrwallet;
|
package com.m2049r.xmrwallet;
|
||||||
|
|
||||||
|
import static android.view.WindowManager.LayoutParams;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
@@ -29,8 +31,6 @@ import com.m2049r.xmrwallet.util.LocaleHelper;
|
|||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import static android.view.WindowManager.LayoutParams;
|
|
||||||
|
|
||||||
public abstract class SecureActivity extends AppCompatActivity {
|
public abstract class SecureActivity extends AppCompatActivity {
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
@@ -66,11 +66,7 @@ public abstract class SecureActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
Locale locale = LocaleHelper.getPreferredLocale(this);
|
Locale locale = LocaleHelper.getPreferredLocale(this);
|
||||||
if (locale != null) {
|
if (locale != null) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
config.setLocale(locale);
|
||||||
config.setLocale(locale);
|
|
||||||
} else {
|
|
||||||
config.locale = locale;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
125
app/src/main/java/com/m2049r/xmrwallet/SettingsFragment.java
Normal file
125
app/src/main/java/com/m2049r/xmrwallet/SettingsFragment.java
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
package com.m2049r.xmrwallet;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import androidx.annotation.StyleRes;
|
||||||
|
import androidx.preference.ListPreference;
|
||||||
|
import androidx.preference.PreferenceFragmentCompat;
|
||||||
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.dialog.AboutFragment;
|
||||||
|
import com.m2049r.xmrwallet.dialog.CreditsFragment;
|
||||||
|
import com.m2049r.xmrwallet.dialog.PrivacyFragment;
|
||||||
|
import com.m2049r.xmrwallet.util.DayNightMode;
|
||||||
|
import com.m2049r.xmrwallet.util.LocaleHelper;
|
||||||
|
import com.m2049r.xmrwallet.util.NightmodeHelper;
|
||||||
|
import com.m2049r.xmrwallet.util.ThemeHelper;
|
||||||
|
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
public class SettingsFragment extends PreferenceFragmentCompat
|
||||||
|
implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||||
|
@Override
|
||||||
|
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||||
|
setPreferencesFromResource(R.xml.root_preferences, rootKey);
|
||||||
|
|
||||||
|
findPreference(getString(R.string.about_info)).setOnPreferenceClickListener(preference -> {
|
||||||
|
AboutFragment.display(getParentFragmentManager());
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
findPreference(getString(R.string.privacy_info)).setOnPreferenceClickListener(preference -> {
|
||||||
|
PrivacyFragment.display(getParentFragmentManager());
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
findPreference(getString(R.string.credits_info)).setOnPreferenceClickListener(preference -> {
|
||||||
|
CreditsFragment.display(getParentFragmentManager());
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||||
|
if (key.equals(getString(R.string.preferred_locale))) {
|
||||||
|
activity.recreate();
|
||||||
|
} else if (key.equals(getString(R.string.preferred_nightmode))) {
|
||||||
|
NightmodeHelper.setNightMode(DayNightMode.valueOf(sharedPreferences.getString(key, "AUTO")));
|
||||||
|
} else if (key.equals(getString(R.string.preferred_theme))) {
|
||||||
|
ThemeHelper.setTheme((Activity) activity, sharedPreferences.getString(key, "Classic"));
|
||||||
|
activity.recreate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SettingsFragment.Listener activity;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Context context) {
|
||||||
|
super.onAttach(context);
|
||||||
|
if (context instanceof SettingsFragment.Listener) {
|
||||||
|
activity = (SettingsFragment.Listener) context;
|
||||||
|
} else {
|
||||||
|
throw new ClassCastException(context + " must implement Listener");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
Timber.d("onResume()");
|
||||||
|
activity.setSubtitle(getString(R.string.menu_settings));
|
||||||
|
activity.setToolbarButton(Toolbar.BUTTON_BACK);
|
||||||
|
populateLanguages();
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
|
.registerOnSharedPreferenceChangeListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
|
.unregisterOnSharedPreferenceChangeListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Listener {
|
||||||
|
void setToolbarButton(int type);
|
||||||
|
|
||||||
|
void setSubtitle(String title);
|
||||||
|
|
||||||
|
void recreate();
|
||||||
|
|
||||||
|
void setTheme(@StyleRes final int resId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void populateLanguages() {
|
||||||
|
ListPreference language = findPreference(getString(R.string.preferred_locale));
|
||||||
|
assert language != null;
|
||||||
|
|
||||||
|
final ArrayList<Locale> availableLocales = LocaleHelper.getAvailableLocales(requireContext());
|
||||||
|
Collections.sort(availableLocales, (locale1, locale2) -> {
|
||||||
|
String localeString1 = LocaleHelper.getDisplayName(locale1, true);
|
||||||
|
String localeString2 = LocaleHelper.getDisplayName(locale2, true);
|
||||||
|
return localeString1.compareTo(localeString2);
|
||||||
|
});
|
||||||
|
|
||||||
|
String[] localeDisplayNames = new String[1 + availableLocales.size()];
|
||||||
|
localeDisplayNames[0] = getString(R.string.language_system_default);
|
||||||
|
for (int i = 1; i < localeDisplayNames.length; i++) {
|
||||||
|
localeDisplayNames[i] = LocaleHelper.getDisplayName(availableLocales.get(i - 1), true);
|
||||||
|
}
|
||||||
|
language.setEntries(localeDisplayNames);
|
||||||
|
|
||||||
|
String[] languageTags = new String[1 + availableLocales.size()];
|
||||||
|
languageTags[0] = "";
|
||||||
|
for (int i = 1; i < languageTags.length; i++) {
|
||||||
|
languageTags[i] = availableLocales.get(i - 1).toLanguageTag();
|
||||||
|
}
|
||||||
|
language.setEntryValues(languageTags);
|
||||||
|
}
|
||||||
|
}
|
@@ -30,7 +30,6 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.google.android.material.transition.MaterialElevationScale;
|
|
||||||
import com.m2049r.xmrwallet.data.Subaddress;
|
import com.m2049r.xmrwallet.data.Subaddress;
|
||||||
import com.m2049r.xmrwallet.layout.SubaddressInfoAdapter;
|
import com.m2049r.xmrwallet.layout.SubaddressInfoAdapter;
|
||||||
import com.m2049r.xmrwallet.ledger.LedgerProgressDialog;
|
import com.m2049r.xmrwallet.ledger.LedgerProgressDialog;
|
||||||
@@ -117,14 +116,6 @@ public class SubaddressFragment extends Fragment implements SubaddressInfoAdapte
|
|||||||
managerMode = ((b != null) && (MODE_MANAGER.equals(b.getString(KEY_MODE))));
|
managerMode = ((b != null) && (MODE_MANAGER.equals(b.getString(KEY_MODE))));
|
||||||
|
|
||||||
View view = inflater.inflate(R.layout.fragment_subaddress, container, false);
|
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);
|
view.findViewById(R.id.fab).setOnClickListener(this);
|
||||||
|
|
||||||
if (managerMode) {
|
if (managerMode) {
|
||||||
@@ -154,11 +145,6 @@ public class SubaddressFragment extends Fragment implements SubaddressInfoAdapte
|
|||||||
@Override
|
@Override
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
postponeEnterTransition();
|
|
||||||
view.getViewTreeObserver().addOnPreDrawListener(() -> {
|
|
||||||
startPostponedEnterTransition();
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadList() {
|
public void loadList() {
|
||||||
@@ -252,4 +238,5 @@ public class SubaddressFragment extends Fragment implements SubaddressInfoAdapte
|
|||||||
activityCallback.showSubaddress(view, subaddress.getAddressIndex());
|
activityCallback.showSubaddress(view, subaddress.getAddressIndex());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -29,15 +29,15 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import androidx.transition.Transition;
|
||||||
|
import androidx.transition.TransitionInflater;
|
||||||
|
|
||||||
import com.google.android.material.textfield.TextInputLayout;
|
import com.google.android.material.textfield.TextInputLayout;
|
||||||
import com.google.android.material.transition.MaterialContainerTransform;
|
|
||||||
import com.m2049r.xmrwallet.data.Subaddress;
|
import com.m2049r.xmrwallet.data.Subaddress;
|
||||||
import com.m2049r.xmrwallet.layout.TransactionInfoAdapter;
|
import com.m2049r.xmrwallet.layout.TransactionInfoAdapter;
|
||||||
import com.m2049r.xmrwallet.model.TransactionInfo;
|
import com.m2049r.xmrwallet.model.TransactionInfo;
|
||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
import com.m2049r.xmrwallet.util.ThemeHelper;
|
|
||||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -46,7 +46,7 @@ import java.util.List;
|
|||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
public class SubaddressInfoFragment extends Fragment
|
public class SubaddressInfoFragment extends Fragment
|
||||||
implements TransactionInfoAdapter.OnInteractionListener, OnBlockUpdateListener {
|
implements TransactionInfoAdapter.Listener, OnBlockUpdateListener {
|
||||||
private TransactionInfoAdapter adapter;
|
private TransactionInfoAdapter adapter;
|
||||||
|
|
||||||
private Subaddress subaddress;
|
private Subaddress subaddress;
|
||||||
@@ -76,7 +76,7 @@ public class SubaddressInfoFragment extends Fragment
|
|||||||
|
|
||||||
etName.getEditText().setText(subaddress.getDisplayLabel());
|
etName.getEditText().setText(subaddress.getDisplayLabel());
|
||||||
tvAddress.setText(getContext().getString(R.string.subbaddress_info_subtitle,
|
tvAddress.setText(getContext().getString(R.string.subbaddress_info_subtitle,
|
||||||
subaddress.getAddressIndex(), subaddress.getSquashedAddress()));
|
subaddress.getAddressIndex(), subaddress.getAddress()));
|
||||||
|
|
||||||
etName.getEditText().setOnFocusChangeListener((v, hasFocus) -> {
|
etName.getEditText().setOnFocusChangeListener((v, hasFocus) -> {
|
||||||
if (!hasFocus) {
|
if (!hasFocus) {
|
||||||
@@ -102,10 +102,8 @@ public class SubaddressInfoFragment extends Fragment
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
final MaterialContainerTransform transform = new MaterialContainerTransform();
|
Transition transform = TransitionInflater.from(requireContext())
|
||||||
transform.setDrawingViewId(R.id.fragment_container);
|
.inflateTransition(R.transition.details);
|
||||||
transform.setDuration(getResources().getInteger(R.integer.tx_item_transition_duration));
|
|
||||||
transform.setAllContainerColors(ThemeHelper.getThemedColor(getContext(), android.R.attr.colorBackground));
|
|
||||||
setSharedElementEnterTransition(transform);
|
setSharedElementEnterTransition(transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,6 +145,8 @@ public class SubaddressInfoFragment extends Fragment
|
|||||||
void setTitle(String title, String subtitle);
|
void setTitle(String title, String subtitle);
|
||||||
|
|
||||||
void setSubtitle(String subtitle);
|
void setSubtitle(String subtitle);
|
||||||
|
|
||||||
|
long getDaemonHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -172,4 +172,9 @@ public class SubaddressInfoFragment extends Fragment
|
|||||||
public void onPause() {
|
public void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getDaemonHeight() {
|
||||||
|
return activityCallback.getDaemonHeight();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -35,11 +35,10 @@ import android.widget.TextView;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.transition.Transition;
|
||||||
|
import androidx.transition.TransitionInflater;
|
||||||
|
|
||||||
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.Subaddress;
|
||||||
import com.m2049r.xmrwallet.data.UserNotes;
|
import com.m2049r.xmrwallet.data.UserNotes;
|
||||||
import com.m2049r.xmrwallet.model.TransactionInfo;
|
import com.m2049r.xmrwallet.model.TransactionInfo;
|
||||||
@@ -80,10 +79,14 @@ public class TxFragment extends Fragment {
|
|||||||
private TextView tvTxPaymentId;
|
private TextView tvTxPaymentId;
|
||||||
private TextView tvTxBlockheight;
|
private TextView tvTxBlockheight;
|
||||||
private TextView tvTxAmount;
|
private TextView tvTxAmount;
|
||||||
|
private TextView tvTxPocketChangeAmount;
|
||||||
private TextView tvTxFee;
|
private TextView tvTxFee;
|
||||||
private TextView tvTxTransfers;
|
private TextView tvTxTransfers;
|
||||||
private TextView etTxNotes;
|
private TextView etTxNotes;
|
||||||
|
|
||||||
|
private View llWarning;
|
||||||
|
private TextView tvWarning;
|
||||||
|
|
||||||
// XMRTO stuff
|
// XMRTO stuff
|
||||||
private View cvXmrTo;
|
private View cvXmrTo;
|
||||||
private TextView tvTxXmrToKey;
|
private TextView tvTxXmrToKey;
|
||||||
@@ -97,13 +100,6 @@ public class TxFragment extends Fragment {
|
|||||||
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);
|
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);
|
cvXmrTo = view.findViewById(R.id.cvXmrTo);
|
||||||
tvTxXmrToKey = view.findViewById(R.id.tvTxXmrToKey);
|
tvTxXmrToKey = view.findViewById(R.id.tvTxXmrToKey);
|
||||||
tvDestinationBtc = view.findViewById(R.id.tvDestinationBtc);
|
tvDestinationBtc = view.findViewById(R.id.tvDestinationBtc);
|
||||||
@@ -121,12 +117,15 @@ public class TxFragment extends Fragment {
|
|||||||
tvTxPaymentId = view.findViewById(R.id.tvTxPaymentId);
|
tvTxPaymentId = view.findViewById(R.id.tvTxPaymentId);
|
||||||
tvTxBlockheight = view.findViewById(R.id.tvTxBlockheight);
|
tvTxBlockheight = view.findViewById(R.id.tvTxBlockheight);
|
||||||
tvTxAmount = view.findViewById(R.id.tvTxAmount);
|
tvTxAmount = view.findViewById(R.id.tvTxAmount);
|
||||||
|
tvTxPocketChangeAmount = view.findViewById(R.id.tvTxPocketChangeAmount);
|
||||||
tvTxFee = view.findViewById(R.id.tvTxFee);
|
tvTxFee = view.findViewById(R.id.tvTxFee);
|
||||||
tvTxTransfers = view.findViewById(R.id.tvTxTransfers);
|
tvTxTransfers = view.findViewById(R.id.tvTxTransfers);
|
||||||
etTxNotes = view.findViewById(R.id.etTxNotes);
|
etTxNotes = view.findViewById(R.id.etTxNotes);
|
||||||
|
|
||||||
etTxNotes.setRawInputType(InputType.TYPE_CLASS_TEXT);
|
etTxNotes.setRawInputType(InputType.TYPE_CLASS_TEXT);
|
||||||
|
|
||||||
|
llWarning = view.findViewById(R.id.llWarning);
|
||||||
|
tvWarning = view.findViewById(R.id.tvWarning);
|
||||||
|
|
||||||
tvTxXmrToKey.setOnClickListener(v -> {
|
tvTxXmrToKey.setOnClickListener(v -> {
|
||||||
Helper.clipBoardCopy(getActivity(), getString(R.string.label_copy_xmrtokey), tvTxXmrToKey.getText().toString());
|
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();
|
Toast.makeText(getActivity(), getString(R.string.message_copy_xmrtokey), Toast.LENGTH_SHORT).show();
|
||||||
@@ -220,8 +219,8 @@ public class TxFragment extends Fragment {
|
|||||||
final Context ctx = getContext();
|
final Context ctx = getContext();
|
||||||
Spanned label = Html.fromHtml(ctx.getString(R.string.tx_account_formatted,
|
Spanned label = Html.fromHtml(ctx.getString(R.string.tx_account_formatted,
|
||||||
info.accountIndex, info.addressIndex,
|
info.accountIndex, info.addressIndex,
|
||||||
Integer.toHexString(ContextCompat.getColor(ctx, R.color.monerujoGreen) & 0xFFFFFF),
|
Integer.toHexString(ThemeHelper.getThemedColor(ctx, R.attr.positiveColor) & 0xFFFFFF),
|
||||||
Integer.toHexString(ContextCompat.getColor(ctx, R.color.monerujoBackground) & 0xFFFFFF),
|
Integer.toHexString(ThemeHelper.getThemedColor(ctx, android.R.attr.colorBackground) & 0xFFFFFF),
|
||||||
subaddress.getDisplayLabel()));
|
subaddress.getDisplayLabel()));
|
||||||
tvAccount.setText(label);
|
tvAccount.setText(label);
|
||||||
tvAccount.setOnClickListener(v -> activityCallback.showSubaddress(v, info.addressIndex));
|
tvAccount.setOnClickListener(v -> activityCallback.showSubaddress(v, info.addressIndex));
|
||||||
@@ -252,8 +251,10 @@ public class TxFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
String sign = (info.direction == TransactionInfo.Direction.Direction_In ? "+" : "-");
|
String sign = (info.direction == TransactionInfo.Direction.Direction_In ? "+" : "-");
|
||||||
|
|
||||||
long realAmount = info.amount;
|
tvTxAmount.setText(sign + Wallet.getDisplayAmount(info.amount));
|
||||||
tvTxAmount.setText(sign + Wallet.getDisplayAmount(realAmount));
|
final long pcAmount = info.getPocketChangeAmount();
|
||||||
|
tvTxPocketChangeAmount.setVisibility(pcAmount > 0 ? View.VISIBLE : View.GONE);
|
||||||
|
tvTxPocketChangeAmount.setText(getString(R.string.pocketchange_tx_detail, Wallet.getDisplayAmount(pcAmount)));
|
||||||
|
|
||||||
if ((info.fee > 0)) {
|
if ((info.fee > 0)) {
|
||||||
String fee = Wallet.getDisplayAmount(info.fee);
|
String fee = Wallet.getDisplayAmount(info.fee);
|
||||||
@@ -266,13 +267,13 @@ public class TxFragment extends Fragment {
|
|||||||
if (info.isFailed) {
|
if (info.isFailed) {
|
||||||
tvTxAmount.setText(getString(R.string.tx_list_amount_failed, Wallet.getDisplayAmount(info.amount)));
|
tvTxAmount.setText(getString(R.string.tx_list_amount_failed, Wallet.getDisplayAmount(info.amount)));
|
||||||
tvTxFee.setText(getString(R.string.tx_list_failed_text));
|
tvTxFee.setText(getString(R.string.tx_list_failed_text));
|
||||||
setTxColour(ContextCompat.getColor(getContext(), R.color.tx_failed));
|
setTxColour(ThemeHelper.getThemedColor(getContext(), R.attr.neutralColor));
|
||||||
} else if (info.isPending) {
|
} else if (info.isPending) {
|
||||||
setTxColour(ContextCompat.getColor(getContext(), R.color.tx_pending));
|
setTxColour(ThemeHelper.getThemedColor(getContext(), R.attr.neutralColor));
|
||||||
} else if (info.direction == TransactionInfo.Direction.Direction_In) {
|
} else if (info.direction == TransactionInfo.Direction.Direction_In) {
|
||||||
setTxColour(ContextCompat.getColor(getContext(), R.color.tx_plus));
|
setTxColour(ThemeHelper.getThemedColor(getContext(), R.attr.positiveColor));
|
||||||
} else {
|
} else {
|
||||||
setTxColour(ContextCompat.getColor(getContext(), R.color.tx_minus));
|
setTxColour(ThemeHelper.getThemedColor(getContext(), R.attr.negativeColor));
|
||||||
}
|
}
|
||||||
Set<String> destinations = new HashSet<>();
|
Set<String> destinations = new HashSet<>();
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
@@ -307,6 +308,20 @@ public class TxFragment extends Fragment {
|
|||||||
tvTxTransfers.setText(sb.toString());
|
tvTxTransfers.setText(sb.toString());
|
||||||
tvDestination.setText(dstSb.toString());
|
tvDestination.setText(dstSb.toString());
|
||||||
showBtcInfo();
|
showBtcInfo();
|
||||||
|
|
||||||
|
showLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showLock() {
|
||||||
|
llWarning.setVisibility(View.GONE);
|
||||||
|
if (info.unlockTime == 0) return;
|
||||||
|
final long blockheight = activityCallback.getDaemonHeight();
|
||||||
|
final long blocks = info.unlockTime - blockheight;
|
||||||
|
final double unlockDays = blocks / (30. * 24);
|
||||||
|
if (unlockDays > 0) {
|
||||||
|
llWarning.setVisibility(View.VISIBLE);
|
||||||
|
tvWarning.setText(getString(R.string.tx_locked, info.unlockTime, blocks, unlockDays));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
@@ -348,10 +363,8 @@ public class TxFragment extends Fragment {
|
|||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
final MaterialContainerTransform transform = new MaterialContainerTransform();
|
Transition transform = TransitionInflater.from(requireContext())
|
||||||
transform.setDrawingViewId(R.id.fragment_container);
|
.inflateTransition(R.transition.details);
|
||||||
transform.setDuration(getResources().getInteger(R.integer.tx_item_transition_duration));
|
|
||||||
transform.setAllContainerColors(ThemeHelper.getThemedColor(getContext(), android.R.attr.colorBackground));
|
|
||||||
setSharedElementEnterTransition(transform);
|
setSharedElementEnterTransition(transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,6 +393,7 @@ public class TxFragment extends Fragment {
|
|||||||
|
|
||||||
void showSubaddress(View view, final int subaddressIndex);
|
void showSubaddress(View view, final int subaddressIndex);
|
||||||
|
|
||||||
|
long getDaemonHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -52,8 +52,8 @@ import com.m2049r.xmrwallet.data.BarcodeData;
|
|||||||
import com.m2049r.xmrwallet.data.Subaddress;
|
import com.m2049r.xmrwallet.data.Subaddress;
|
||||||
import com.m2049r.xmrwallet.data.TxData;
|
import com.m2049r.xmrwallet.data.TxData;
|
||||||
import com.m2049r.xmrwallet.data.UserNotes;
|
import com.m2049r.xmrwallet.data.UserNotes;
|
||||||
import com.m2049r.xmrwallet.dialog.CreditsFragment;
|
|
||||||
import com.m2049r.xmrwallet.dialog.HelpFragment;
|
import com.m2049r.xmrwallet.dialog.HelpFragment;
|
||||||
|
import com.m2049r.xmrwallet.dialog.PocketChangeFragment;
|
||||||
import com.m2049r.xmrwallet.fragment.send.SendAddressWizardFragment;
|
import com.m2049r.xmrwallet.fragment.send.SendAddressWizardFragment;
|
||||||
import com.m2049r.xmrwallet.fragment.send.SendFragment;
|
import com.m2049r.xmrwallet.fragment.send.SendFragment;
|
||||||
import com.m2049r.xmrwallet.ledger.LedgerProgressDialog;
|
import com.m2049r.xmrwallet.ledger.LedgerProgressDialog;
|
||||||
@@ -82,7 +82,8 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
WalletFragment.DrawerLocker,
|
WalletFragment.DrawerLocker,
|
||||||
NavigationView.OnNavigationItemSelectedListener,
|
NavigationView.OnNavigationItemSelectedListener,
|
||||||
SubaddressFragment.Listener,
|
SubaddressFragment.Listener,
|
||||||
SubaddressInfoFragment.Listener {
|
SubaddressInfoFragment.Listener,
|
||||||
|
PocketChangeFragment.Listener {
|
||||||
|
|
||||||
public static final String REQUEST_ID = "id";
|
public static final String REQUEST_ID = "id";
|
||||||
public static final String REQUEST_PW = "pw";
|
public static final String REQUEST_PW = "pw";
|
||||||
@@ -285,8 +286,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
onWalletRescan();
|
onWalletRescan();
|
||||||
} else if (itemId == R.id.action_info) {
|
} else if (itemId == R.id.action_info) {
|
||||||
onWalletDetails();
|
onWalletDetails();
|
||||||
} else if (itemId == R.id.action_credits) {
|
|
||||||
CreditsFragment.display(getSupportFragmentManager());
|
|
||||||
} else if (itemId == R.id.action_share) {
|
} else if (itemId == R.id.action_share) {
|
||||||
onShareTxInfo();
|
onShareTxInfo();
|
||||||
} else if (itemId == R.id.action_help_tx_info) {
|
} else if (itemId == R.id.action_help_tx_info) {
|
||||||
@@ -301,6 +300,8 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
HelpFragment.display(getSupportFragmentManager(), R.string.help_send);
|
HelpFragment.display(getSupportFragmentManager(), R.string.help_send);
|
||||||
} else if (itemId == R.id.action_rename) {
|
} else if (itemId == R.id.action_rename) {
|
||||||
onAccountRename();
|
onAccountRename();
|
||||||
|
} else if (itemId == R.id.action_pocketchange) {
|
||||||
|
PocketChangeFragment.display(getSupportFragmentManager(), getWallet().getPocketChangeSetting());
|
||||||
} else if (itemId == R.id.action_subaddresses) {
|
} else if (itemId == R.id.action_subaddresses) {
|
||||||
showSubaddresses(true);
|
showSubaddresses(true);
|
||||||
} else if (itemId == R.id.action_streetmode) {
|
} else if (itemId == R.id.action_streetmode) {
|
||||||
@@ -356,6 +357,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
Timber.d("onCreate()");
|
Timber.d("onCreate()");
|
||||||
|
ThemeHelper.setPreferred(this);
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
// activity restarted
|
// activity restarted
|
||||||
@@ -385,7 +387,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
case Toolbar.BUTTON_CLOSE:
|
case Toolbar.BUTTON_CLOSE:
|
||||||
finish();
|
finish();
|
||||||
break;
|
break;
|
||||||
case Toolbar.BUTTON_CREDITS:
|
case Toolbar.BUTTON_SETTINGS:
|
||||||
Toast.makeText(WalletActivity.this, getString(R.string.label_credits), Toast.LENGTH_SHORT).show();
|
Toast.makeText(WalletActivity.this, getString(R.string.label_credits), Toast.LENGTH_SHORT).show();
|
||||||
case Toolbar.BUTTON_NONE:
|
case Toolbar.BUTTON_NONE:
|
||||||
default:
|
default:
|
||||||
@@ -421,7 +423,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
break;
|
break;
|
||||||
case NetworkType_Stagenet:
|
case NetworkType_Stagenet:
|
||||||
case NetworkType_Testnet:
|
case NetworkType_Testnet:
|
||||||
toolbar.setBackgroundResource(ThemeHelper.getThemedResourceId(this, R.attr.colorPrimaryDark));
|
toolbar.setBackgroundResource(ThemeHelper.getThemedResourceId(this, androidx.appcompat.R.attr.colorPrimaryDark));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException("Unsupported Network: " + WalletManager.getInstance().getNetworkType());
|
throw new IllegalStateException("Unsupported Network: " + WalletManager.getInstance().getNetworkType());
|
||||||
@@ -450,7 +452,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
if (extras != null) {
|
if (extras != null) {
|
||||||
String walletId = extras.getString(REQUEST_ID);
|
String walletId = extras.getString(REQUEST_ID);
|
||||||
if (walletId != null) {
|
if (walletId != null) {
|
||||||
setTitle(walletId, getString(R.string.status_wallet_connecting));
|
setTitle(walletId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateProgress();
|
updateProgress();
|
||||||
@@ -538,7 +540,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendRequest(View view) {
|
public void onSendRequest(View view) {
|
||||||
replaceFragmentWithTransition(view, SendFragment.newInstance(uri), null, null);
|
replaceFragment(SendFragment.newInstance(uri), null, null);
|
||||||
uri = null; // only use uri once
|
uri = null; // only use uri once
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -645,6 +647,8 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
haveWallet = true;
|
haveWallet = true;
|
||||||
invalidateOptionsMenu();
|
invalidateOptionsMenu();
|
||||||
|
|
||||||
|
loadPocketChangeSettings();
|
||||||
|
|
||||||
if (requestStreetMode) onEnableStreetMode();
|
if (requestStreetMode) onEnableStreetMode();
|
||||||
|
|
||||||
final WalletFragment walletFragment = getWalletFragment();
|
final WalletFragment walletFragment = getWalletFragment();
|
||||||
@@ -799,10 +803,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
int transition;
|
int transition;
|
||||||
if (newFragment instanceof TxFragment)
|
if (newFragment instanceof TxFragment)
|
||||||
transition = R.string.tx_details_transition_name;
|
transition = R.string.tx_details_transition_name;
|
||||||
else if (newFragment instanceof ReceiveFragment)
|
|
||||||
transition = R.string.receive_transition_name;
|
|
||||||
else if (newFragment instanceof SendFragment)
|
|
||||||
transition = R.string.send_transition_name;
|
|
||||||
else if (newFragment instanceof SubaddressInfoFragment)
|
else if (newFragment instanceof SubaddressInfoFragment)
|
||||||
transition = R.string.subaddress_info_transition_name;
|
transition = R.string.subaddress_info_transition_name;
|
||||||
else
|
else
|
||||||
@@ -928,18 +928,15 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
@Override
|
@Override
|
||||||
void onUriScanned(BarcodeData barcodeData) {
|
void onUriScanned(BarcodeData barcodeData) {
|
||||||
super.onUriScanned(barcodeData);
|
super.onUriScanned(barcodeData);
|
||||||
boolean processed = false;
|
|
||||||
if (onUriScannedListener != null) {
|
if (onUriScannedListener != null) {
|
||||||
processed = onUriScannedListener.onUriScanned(barcodeData);
|
onUriScannedListener.onUriScanned(barcodeData);
|
||||||
}
|
|
||||||
if (!processed || (onUriScannedListener == null)) {
|
|
||||||
Toast.makeText(this, getString(R.string.nfc_tag_read_what), Toast.LENGTH_LONG).show();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||||
Timber.d("onRequestPermissionsResult()");
|
Timber.d("onRequestPermissionsResult()");
|
||||||
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||||
if (requestCode == Helper.PERMISSIONS_REQUEST_CAMERA) { // If request is cancelled, the result arrays are empty.
|
if (requestCode == Helper.PERMISSIONS_REQUEST_CAMERA) { // If request is cancelled, the result arrays are empty.
|
||||||
if (grantResults.length > 0
|
if (grantResults.length > 0
|
||||||
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||||
@@ -958,7 +955,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
Bundle b = new Bundle();
|
Bundle b = new Bundle();
|
||||||
b.putString("address", address);
|
b.putString("address", address);
|
||||||
b.putString("name", getWalletName());
|
b.putString("name", getWalletName());
|
||||||
replaceFragmentWithTransition(view, new ReceiveFragment(), null, b);
|
replaceFragment(new ReceiveFragment(), null, b);
|
||||||
Timber.d("ReceiveFragment placed");
|
Timber.d("ReceiveFragment placed");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1030,13 +1027,14 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
final Wallet wallet = getWallet();
|
final Wallet wallet = getWallet();
|
||||||
if (wallet != null) {
|
if (wallet != null) {
|
||||||
final int n = wallet.getNumAccounts();
|
final int n = wallet.getNumAccounts();
|
||||||
|
final int currentAccount = getWallet().getAccountIndex();
|
||||||
final boolean showBalances = (n > 1) && !isStreetMode();
|
final boolean showBalances = (n > 1) && !isStreetMode();
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
final String label = (showBalances ?
|
final String label = (showBalances ?
|
||||||
getString(R.string.label_account, wallet.getAccountLabel(i), Helper.getDisplayAmount(wallet.getBalance(i), 2))
|
getString(R.string.label_account, wallet.getAccountLabel(i), Helper.getDisplayAmount(wallet.getBalance(i), 2))
|
||||||
: wallet.getAccountLabel(i));
|
: wallet.getAccountLabel(i));
|
||||||
final MenuItem item = menu.add(R.id.accounts_list, getAccountId(i), 2 * i, label);
|
final MenuItem item = menu.add(R.id.accounts_list, getAccountId(i), 2 * i, label);
|
||||||
item.setIcon(R.drawable.ic_account_balance_wallet_black_24dp);
|
item.setIcon(i == currentAccount ? R.drawable.ic_outline_folder_open_24 : R.drawable.ic_outline_folder_24);
|
||||||
if (i == wallet.getAccountIndex())
|
if (i == wallet.getAccountIndex())
|
||||||
item.setChecked(true);
|
item.setChecked(true);
|
||||||
}
|
}
|
||||||
@@ -1109,6 +1107,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
|
|
||||||
public void setAccountIndex(int accountIndex) {
|
public void setAccountIndex(int accountIndex) {
|
||||||
getWallet().setAccountIndex(accountIndex);
|
getWallet().setAccountIndex(accountIndex);
|
||||||
|
loadPocketChangeSettings();
|
||||||
selectedSubaddressIndex = 0;
|
selectedSubaddressIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1219,4 +1218,19 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
b.putInt("subaddressIndex", subaddressIndex);
|
b.putInt("subaddressIndex", subaddressIndex);
|
||||||
replaceFragmentWithTransition(view, new SubaddressInfoFragment(), null, b);
|
replaceFragmentWithTransition(view, new SubaddressInfoFragment(), null, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPocketChange(Wallet.PocketChangeSetting setting) {
|
||||||
|
SharedPreferences.Editor editor = getPrefs().edit();
|
||||||
|
editor.putString(getWallet().getAddress() + "_PC", setting.toPrefString());
|
||||||
|
editor.apply();
|
||||||
|
getWallet().setPocketChangeSetting(setting);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void loadPocketChangeSettings() {
|
||||||
|
final String settings = getPrefs().getString(getWallet().getAddress() + "_PC", "0");
|
||||||
|
getWallet().setPocketChangeSetting(Wallet.PocketChangeSetting.from(settings));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -43,7 +43,6 @@ import androidx.fragment.app.Fragment;
|
|||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.github.brnunes.swipeablerecyclerview.SwipeableRecyclerViewTouchListener;
|
import com.github.brnunes.swipeablerecyclerview.SwipeableRecyclerViewTouchListener;
|
||||||
import com.google.android.material.transition.MaterialElevationScale;
|
|
||||||
import com.m2049r.xmrwallet.layout.TransactionInfoAdapter;
|
import com.m2049r.xmrwallet.layout.TransactionInfoAdapter;
|
||||||
import com.m2049r.xmrwallet.model.TransactionInfo;
|
import com.m2049r.xmrwallet.model.TransactionInfo;
|
||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
@@ -52,6 +51,7 @@ import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback;
|
|||||||
import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate;
|
import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate;
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
import com.m2049r.xmrwallet.util.ServiceHelper;
|
import com.m2049r.xmrwallet.util.ServiceHelper;
|
||||||
|
import com.m2049r.xmrwallet.util.ThemeHelper;
|
||||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||||
|
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
@@ -62,7 +62,7 @@ import java.util.List;
|
|||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
public class WalletFragment extends Fragment
|
public class WalletFragment extends Fragment
|
||||||
implements TransactionInfoAdapter.OnInteractionListener {
|
implements TransactionInfoAdapter.Listener {
|
||||||
private TransactionInfoAdapter adapter;
|
private TransactionInfoAdapter adapter;
|
||||||
private final NumberFormat formatter = NumberFormat.getInstance();
|
private final NumberFormat formatter = NumberFormat.getInstance();
|
||||||
|
|
||||||
@@ -111,15 +111,16 @@ public class WalletFragment extends Fragment
|
|||||||
llBalance = view.findViewById(R.id.llBalance);
|
llBalance = view.findViewById(R.id.llBalance);
|
||||||
flExchange = view.findViewById(R.id.flExchange);
|
flExchange = view.findViewById(R.id.flExchange);
|
||||||
((ProgressBar) view.findViewById(R.id.pbExchange)).getIndeterminateDrawable().
|
((ProgressBar) view.findViewById(R.id.pbExchange)).getIndeterminateDrawable().
|
||||||
setColorFilter(getResources().getColor(R.color.progress_circle),
|
setColorFilter(
|
||||||
|
ThemeHelper.getThemedColor(getContext(), com.google.android.material.R.attr.colorPrimaryVariant),
|
||||||
android.graphics.PorterDuff.Mode.MULTIPLY);
|
android.graphics.PorterDuff.Mode.MULTIPLY);
|
||||||
|
|
||||||
tvProgress = view.findViewById(R.id.tvProgress);
|
tvProgress = view.findViewById(R.id.tvProgress);
|
||||||
pbProgress = view.findViewById(R.id.pbProgress);
|
pbProgress = view.findViewById(R.id.pbProgress);
|
||||||
tvBalance = view.findViewById(R.id.tvBalance);
|
tvBalance = view.findViewById(R.id.tvBalance);
|
||||||
showBalance(Helper.getDisplayAmount(0));
|
showBalance();
|
||||||
tvUnconfirmedAmount = view.findViewById(R.id.tvUnconfirmedAmount);
|
tvUnconfirmedAmount = view.findViewById(R.id.tvUnconfirmedAmount);
|
||||||
showUnconfirmed(0);
|
showUnconfirmed();
|
||||||
ivSynced = view.findViewById(R.id.ivSynced);
|
ivSynced = view.findViewById(R.id.ivSynced);
|
||||||
|
|
||||||
sCurrency = view.findViewById(R.id.sCurrency);
|
sCurrency = view.findViewById(R.id.sCurrency);
|
||||||
@@ -202,14 +203,20 @@ public class WalletFragment extends Fragment
|
|||||||
@Override
|
@Override
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
postponeEnterTransition();
|
|
||||||
view.getViewTreeObserver().addOnPreDrawListener(() -> {
|
|
||||||
startPostponedEnterTransition();
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void showBalance(String balance) {
|
String amountToString(double amount) {
|
||||||
|
if (!Helper.BASE_CRYPTO.equals(balanceCurrency)) { // not XMR
|
||||||
|
double amountB = amount * balanceRate;
|
||||||
|
return Helper.getFormattedAmount(amountB, false);
|
||||||
|
} else { // XMR
|
||||||
|
return Helper.getFormattedAmount(amount, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void showBalance() {
|
||||||
|
double amountA = Helper.getDecimalAmount(unlockedBalance).doubleValue();
|
||||||
|
String balance = amountToString(amountA);
|
||||||
tvBalance.setText(balance);
|
tvBalance.setText(balance);
|
||||||
final boolean streetMode = activityCallback.isStreetMode();
|
final boolean streetMode = activityCallback.isStreetMode();
|
||||||
if (!streetMode) {
|
if (!streetMode) {
|
||||||
@@ -222,13 +229,14 @@ public class WalletFragment extends Fragment
|
|||||||
setStreetModeBackground(streetMode);
|
setStreetModeBackground(streetMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void showUnconfirmed(double unconfirmedAmount) {
|
void showUnconfirmed() {
|
||||||
|
double unconfirmedAmount = Helper.getDecimalAmount(balance - unlockedBalance).doubleValue();
|
||||||
if (activityCallback.isStreetMode() || unconfirmedAmount == 0) {
|
if (activityCallback.isStreetMode() || unconfirmedAmount == 0) {
|
||||||
tvUnconfirmedAmount.setText(null);
|
tvUnconfirmedAmount.setText(null);
|
||||||
tvUnconfirmedAmount.setVisibility(View.GONE);
|
tvUnconfirmedAmount.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
String unconfirmed = Helper.getFormattedAmount(unconfirmedAmount, true);
|
String unconfirmed = amountToString(unconfirmedAmount);
|
||||||
tvUnconfirmedAmount.setText(getResources().getString(R.string.xmr_unconfirmed_amount, unconfirmed));
|
tvUnconfirmedAmount.setText(getResources().getString(R.string.xmr_unconfirmed_amount, unconfirmed, balanceCurrency));
|
||||||
tvUnconfirmedAmount.setVisibility(View.VISIBLE);
|
tvUnconfirmedAmount.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -236,15 +244,8 @@ public class WalletFragment extends Fragment
|
|||||||
void updateBalance() {
|
void updateBalance() {
|
||||||
if (isExchanging) return; // wait for exchange to finish - it will fire this itself then.
|
if (isExchanging) return; // wait for exchange to finish - it will fire this itself then.
|
||||||
// at this point selection is XMR in case of error
|
// at this point selection is XMR in case of error
|
||||||
String displayB;
|
showBalance();
|
||||||
double amountA = Helper.getDecimalAmount(unlockedBalance).doubleValue();
|
showUnconfirmed();
|
||||||
if (!Helper.BASE_CRYPTO.equals(balanceCurrency)) { // not XMR
|
|
||||||
double amountB = amountA * balanceRate;
|
|
||||||
displayB = Helper.getFormattedAmount(amountB, false);
|
|
||||||
} else { // XMR
|
|
||||||
displayB = Helper.getFormattedAmount(amountA, true);
|
|
||||||
}
|
|
||||||
showBalance(displayB);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String balanceCurrency = Helper.BASE_CRYPTO;
|
String balanceCurrency = Helper.BASE_CRYPTO;
|
||||||
@@ -253,11 +254,11 @@ public class WalletFragment extends Fragment
|
|||||||
private final ExchangeApi exchangeApi = ServiceHelper.getExchangeApi();
|
private final ExchangeApi exchangeApi = ServiceHelper.getExchangeApi();
|
||||||
|
|
||||||
void refreshBalance() {
|
void refreshBalance() {
|
||||||
double unconfirmedXmr = Helper.getDecimalAmount(balance - unlockedBalance).doubleValue();
|
|
||||||
showUnconfirmed(unconfirmedXmr);
|
|
||||||
if (sCurrency.getSelectedItemPosition() == 0) { // XMR
|
if (sCurrency.getSelectedItemPosition() == 0) { // XMR
|
||||||
double amountXmr = Helper.getDecimalAmount(unlockedBalance).doubleValue();
|
balanceCurrency = Helper.BASE_CRYPTO;
|
||||||
showBalance(Helper.getFormattedAmount(amountXmr, true));
|
balanceRate = 1.0;
|
||||||
|
showBalance();
|
||||||
|
showUnconfirmed();
|
||||||
} else { // not XMR
|
} else { // not XMR
|
||||||
String currency = (String) sCurrency.getSelectedItem();
|
String currency = (String) sCurrency.getSelectedItem();
|
||||||
Timber.d(currency);
|
Timber.d(currency);
|
||||||
@@ -302,8 +303,7 @@ public class WalletFragment extends Fragment
|
|||||||
|
|
||||||
public void exchangeFailed() {
|
public void exchangeFailed() {
|
||||||
sCurrency.setSelection(0, true); // default to XMR
|
sCurrency.setSelection(0, true); // default to XMR
|
||||||
double amountXmr = Helper.getDecimalAmount(unlockedBalance).doubleValue();
|
showBalance();
|
||||||
showBalance(Helper.getFormattedAmount(amountXmr, true));
|
|
||||||
hideExchanging();
|
hideExchanging();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,19 +331,9 @@ public class WalletFragment extends Fragment
|
|||||||
// Callbacks from TransactionInfoAdapter
|
// Callbacks from TransactionInfoAdapter
|
||||||
@Override
|
@Override
|
||||||
public void onInteraction(final View view, final TransactionInfo infoItem) {
|
public void onInteraction(final View view, final TransactionInfo infoItem) {
|
||||||
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);
|
|
||||||
|
|
||||||
activityCallback.onTxDetailsRequest(view, infoItem);
|
activityCallback.onTxDetailsRequest(view, infoItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// called from activity
|
|
||||||
|
|
||||||
|
|
||||||
// if account index has changed scroll to top?
|
// if account index has changed scroll to top?
|
||||||
private int accountIndex = 0;
|
private int accountIndex = 0;
|
||||||
|
|
||||||
@@ -457,12 +447,13 @@ public class WalletFragment extends Fragment
|
|||||||
String sync;
|
String sync;
|
||||||
if (!activityCallback.hasBoundService())
|
if (!activityCallback.hasBoundService())
|
||||||
throw new IllegalStateException("WalletService not bound.");
|
throw new IllegalStateException("WalletService not bound.");
|
||||||
|
ivSynced.setVisibility(View.GONE);
|
||||||
Wallet.ConnectionStatus daemonConnected = activityCallback.getConnectionStatus();
|
Wallet.ConnectionStatus daemonConnected = activityCallback.getConnectionStatus();
|
||||||
if (daemonConnected == Wallet.ConnectionStatus.ConnectionStatus_Connected) {
|
if (daemonConnected == Wallet.ConnectionStatus.ConnectionStatus_Connected) {
|
||||||
if (!wallet.isSynchronized()) {
|
if (!wallet.isSynchronized()) {
|
||||||
long daemonHeight = activityCallback.getDaemonHeight();
|
final long daemonHeight = getDaemonHeight();
|
||||||
long walletHeight = wallet.getBlockChainHeight();
|
final long walletHeight = wallet.getBlockChainHeight();
|
||||||
long n = daemonHeight - walletHeight;
|
final long n = daemonHeight - walletHeight;
|
||||||
sync = getString(R.string.status_syncing) + " " + formatter.format(n) + " " + getString(R.string.status_remaining);
|
sync = getString(R.string.status_syncing) + " " + formatter.format(n) + " " + getString(R.string.status_remaining);
|
||||||
if (firstBlock == 0) {
|
if (firstBlock == 0) {
|
||||||
firstBlock = walletHeight;
|
firstBlock = walletHeight;
|
||||||
@@ -470,7 +461,6 @@ public class WalletFragment extends Fragment
|
|||||||
int x = 100 - Math.round(100f * n / (1f * daemonHeight - firstBlock));
|
int x = 100 - Math.round(100f * n / (1f * daemonHeight - firstBlock));
|
||||||
if (x == 0) x = 101; // indeterminate
|
if (x == 0) x = 101; // indeterminate
|
||||||
setProgress(x);
|
setProgress(x);
|
||||||
ivSynced.setVisibility(View.GONE);
|
|
||||||
} else {
|
} else {
|
||||||
sync = getString(R.string.status_synced) + " " + formatter.format(wallet.getBlockChainHeight());
|
sync = getString(R.string.status_synced) + " " + formatter.format(wallet.getBlockChainHeight());
|
||||||
ivSynced.setVisibility(View.VISIBLE);
|
ivSynced.setVisibility(View.VISIBLE);
|
||||||
@@ -536,8 +526,6 @@ public class WalletFragment extends Fragment
|
|||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
setExitTransition(null);
|
|
||||||
setReenterTransition(null);
|
|
||||||
Timber.d("onResume()");
|
Timber.d("onResume()");
|
||||||
activityCallback.setTitle(walletTitle, walletSubtitle);
|
activityCallback.setTitle(walletTitle, walletSubtitle);
|
||||||
activityCallback.setToolbarButton(Toolbar.BUTTON_NONE);
|
activityCallback.setToolbarButton(Toolbar.BUTTON_NONE);
|
||||||
@@ -572,4 +560,9 @@ public class WalletFragment extends Fragment
|
|||||||
} else
|
} else
|
||||||
ivStreetGunther.setImageDrawable(null);
|
ivStreetGunther.setImageDrawable(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getDaemonHeight() {
|
||||||
|
return activityCallback.getDaemonHeight();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -22,20 +22,27 @@ import android.content.res.Configuration;
|
|||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.OptIn;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
import androidx.fragment.app.FragmentStateManagerControl;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.model.NetworkType;
|
import com.m2049r.xmrwallet.model.NetworkType;
|
||||||
import com.m2049r.xmrwallet.util.LocaleHelper;
|
import com.m2049r.xmrwallet.util.LocaleHelper;
|
||||||
import com.m2049r.xmrwallet.util.NetCipherHelper;
|
import com.m2049r.xmrwallet.util.NetCipherHelper;
|
||||||
import com.m2049r.xmrwallet.util.NightmodeHelper;
|
import com.m2049r.xmrwallet.util.NightmodeHelper;
|
||||||
|
import com.m2049r.xmrwallet.util.ServiceHelper;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
public class XmrWalletApplication extends Application {
|
public class XmrWalletApplication extends Application {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@OptIn(markerClass = FragmentStateManagerControl.class)
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
|
FragmentManager.enableNewStateManager(false);
|
||||||
if (BuildConfig.DEBUG) {
|
if (BuildConfig.DEBUG) {
|
||||||
Timber.plant(new Timber.DebugTree());
|
Timber.plant(new Timber.DebugTree());
|
||||||
}
|
}
|
||||||
|
@@ -29,10 +29,12 @@ public enum DefaultNodes {
|
|||||||
HASHVAULT("nodes.hashvault.pro:18081"),
|
HASHVAULT("nodes.hashvault.pro:18081"),
|
||||||
MONEROWORLD("node.moneroworld.com:18089"),
|
MONEROWORLD("node.moneroworld.com:18089"),
|
||||||
XMRTW("opennode.xmr-tw.org:18089"),
|
XMRTW("opennode.xmr-tw.org:18089"),
|
||||||
|
ds_jetzt("monero.ds-jetzt.de:18089"),
|
||||||
MONERUJO_ONION("monerujods7mbghwe6cobdr6ujih6c22zu5rl7zshmizz2udf7v7fsad.onion:18081/mainnet/monerujo.onion"),
|
MONERUJO_ONION("monerujods7mbghwe6cobdr6ujih6c22zu5rl7zshmizz2udf7v7fsad.onion:18081/mainnet/monerujo.onion"),
|
||||||
Criminales78("56wl7y2ebhamkkiza4b7il4mrzwtyvpdym7bm2bkg3jrei2je646k3qd.onion:18089/mainnet/Criminales78.onion"),
|
Criminales78("56wl7y2ebhamkkiza4b7il4mrzwtyvpdym7bm2bkg3jrei2je646k3qd.onion:18089/mainnet/Criminales78.onion"),
|
||||||
xmrfail("mxcd4577fldb3ppzy7obmmhnu3tf57gbcbd4qhwr2kxyjj2qi3dnbfqd.onion:18081/mainnet/xmrfail.onion"),
|
xmrfail("mxcd4577fldb3ppzy7obmmhnu3tf57gbcbd4qhwr2kxyjj2qi3dnbfqd.onion:18081/mainnet/xmrfail.onion"),
|
||||||
boldsuck("6dsdenp6vjkvqzy4wzsnzn6wixkdzihx3khiumyzieauxuxslmcaeiad.onion:18081/mainnet/boldsuck.onion");
|
boldsuck("6dsdenp6vjkvqzy4wzsnzn6wixkdzihx3khiumyzieauxuxslmcaeiad.onion:18081/mainnet/boldsuck.onion"),
|
||||||
|
ds_jetzt_onion("qvlr4w7yhnjrdg3txa72jwtpnjn4ezsrivzvocbnvpfbdo342fahhoad.onion:18089/mainnet/ds-jetzt.onion");
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final String uri;
|
private final String uri;
|
||||||
|
@@ -21,8 +21,6 @@ import android.text.Html;
|
|||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
|
|
||||||
import com.m2049r.levin.scanner.LevinPeer;
|
import com.m2049r.levin.scanner.LevinPeer;
|
||||||
import com.m2049r.xmrwallet.R;
|
import com.m2049r.xmrwallet.R;
|
||||||
import com.m2049r.xmrwallet.util.NetCipherHelper;
|
import com.m2049r.xmrwallet.util.NetCipherHelper;
|
||||||
@@ -267,14 +265,14 @@ public class NodeInfo extends Node {
|
|||||||
public void showInfo(TextView view, String info, boolean isError) {
|
public void showInfo(TextView view, String info, boolean isError) {
|
||||||
final Context ctx = view.getContext();
|
final Context ctx = view.getContext();
|
||||||
final Spanned text = Html.fromHtml(ctx.getString(R.string.status,
|
final Spanned text = Html.fromHtml(ctx.getString(R.string.status,
|
||||||
Integer.toHexString(ContextCompat.getColor(ctx, R.color.monerujoGreen) & 0xFFFFFF),
|
Integer.toHexString(ThemeHelper.getThemedColor(ctx, R.attr.positiveColor) & 0xFFFFFF),
|
||||||
Integer.toHexString(ContextCompat.getColor(ctx, R.color.monerujoBackground) & 0xFFFFFF),
|
Integer.toHexString(ThemeHelper.getThemedColor(ctx, android.R.attr.colorBackground) & 0xFFFFFF),
|
||||||
(hostAddress.isOnion() ? " .onion " : ""), " " + info));
|
(hostAddress.isOnion() ? " .onion " : ""), " " + info));
|
||||||
view.setText(text);
|
view.setText(text);
|
||||||
if (isError)
|
if (isError)
|
||||||
view.setTextColor(ThemeHelper.getThemedColor(ctx, R.attr.colorError));
|
view.setTextColor(ThemeHelper.getThemedColor(ctx, androidx.appcompat.R.attr.colorError));
|
||||||
else
|
else
|
||||||
view.setTextColor(ThemeHelper.getThemedColor(ctx, R.attr.colorPrimary));
|
view.setTextColor(ThemeHelper.getThemedColor(ctx, android.R.attr.textColorSecondary));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showInfo(TextView view) {
|
public void showInfo(TextView view) {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -41,10 +41,6 @@ public class TxDataBtc extends TxData {
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public TxDataBtc(TxDataBtc txDataBtc) {
|
|
||||||
super(txDataBtc);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeToParcel(Parcel out, int flags) {
|
public void writeToParcel(Parcel out, int flags) {
|
||||||
super.writeToParcel(out, flags);
|
super.writeToParcel(out, flags);
|
||||||
|
@@ -19,15 +19,16 @@ package com.m2049r.xmrwallet.dialog;
|
|||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
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.text.Html;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.TextView;
|
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.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
import com.m2049r.xmrwallet.BuildConfig;
|
import com.m2049r.xmrwallet.BuildConfig;
|
||||||
import com.m2049r.xmrwallet.R;
|
import com.m2049r.xmrwallet.R;
|
||||||
|
@@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 m2049r
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.dialog;
|
||||||
|
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.fragment.app.DialogFragment;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
import androidx.fragment.app.FragmentTransaction;
|
||||||
|
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
|
import com.google.android.material.slider.Slider;
|
||||||
|
import com.google.android.material.switchmaterial.SwitchMaterial;
|
||||||
|
import com.m2049r.xmrwallet.R;
|
||||||
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
|
|
||||||
|
public class PocketChangeFragment extends DialogFragment implements Slider.OnChangeListener {
|
||||||
|
static final String TAG = "PocketChangeFragment";
|
||||||
|
static final String ENABLED = "enabled";
|
||||||
|
static final String TICK = "tick";
|
||||||
|
|
||||||
|
public static PocketChangeFragment newInstance(boolean enabled, int tick) {
|
||||||
|
PocketChangeFragment fragment = new PocketChangeFragment();
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putInt(ENABLED, enabled ? 1 : 0);
|
||||||
|
bundle.putInt(TICK, tick);
|
||||||
|
fragment.setArguments(bundle);
|
||||||
|
return fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void display(FragmentManager fm, @NonNull Wallet.PocketChangeSetting setting) {
|
||||||
|
FragmentTransaction ft = fm.beginTransaction();
|
||||||
|
Fragment prev = fm.findFragmentByTag(TAG);
|
||||||
|
if (prev != null) {
|
||||||
|
ft.remove(prev);
|
||||||
|
}
|
||||||
|
PocketChangeFragment.newInstance(setting.isEnabled(), getTick(setting.getAmount())).show(ft, TAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
SwitchMaterial switchPocketChange;
|
||||||
|
Slider slider;
|
||||||
|
TextView tvProgressLabel;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
final View view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_pocketchange_setting, null);
|
||||||
|
boolean enabled = false;
|
||||||
|
int progress = 0;
|
||||||
|
Bundle arguments = getArguments();
|
||||||
|
if (arguments != null) {
|
||||||
|
enabled = arguments.getInt(ENABLED) > 0;
|
||||||
|
progress = arguments.getInt(TICK);
|
||||||
|
}
|
||||||
|
|
||||||
|
final View llAmount = view.findViewById(R.id.llAmount);
|
||||||
|
switchPocketChange = view.findViewById(R.id.switchPocketChange);
|
||||||
|
switchPocketChange.setOnCheckedChangeListener((buttonView, isChecked) -> llAmount.setVisibility(isChecked ? View.VISIBLE : View.INVISIBLE));
|
||||||
|
slider = view.findViewById(R.id.seekbar);
|
||||||
|
slider.addOnChangeListener(this);
|
||||||
|
switchPocketChange.setChecked(enabled);
|
||||||
|
tvProgressLabel = view.findViewById(R.id.seekbar_value);
|
||||||
|
slider.setValue(progress);
|
||||||
|
llAmount.setVisibility(enabled ? View.VISIBLE : View.INVISIBLE);
|
||||||
|
onValueChange(slider, slider.getValue(), false);
|
||||||
|
|
||||||
|
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity())
|
||||||
|
.setView(view)
|
||||||
|
.setPositiveButton(R.string.label_apply,
|
||||||
|
(dialog, whichButton) -> {
|
||||||
|
final FragmentActivity activity = getActivity();
|
||||||
|
if (activity instanceof Listener) {
|
||||||
|
((Listener) activity).setPocketChange(Wallet.PocketChangeSetting.of(switchPocketChange.isChecked(), getAmount()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return builder.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
private long getAmount() {
|
||||||
|
return Wallet.getAmountFromDouble(getAmount((int) slider.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final double[] AMOUNTS = {0.1, 0.2, 0.3, 0.5, 0.8, 1.3};
|
||||||
|
|
||||||
|
private static double getAmount(int i) {
|
||||||
|
return AMOUNTS[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the closest amount we have
|
||||||
|
private static int getTick(long amount) {
|
||||||
|
int enabled = amount > 0 ? 1 : -1;
|
||||||
|
amount = Math.abs(amount);
|
||||||
|
double lastDiff = Double.MAX_VALUE;
|
||||||
|
for (int i = 0; i < AMOUNTS.length; i++) {
|
||||||
|
final double diff = Math.abs(Helper.ONE_XMR * AMOUNTS[i] - amount);
|
||||||
|
if (lastDiff < diff) return i - 1;
|
||||||
|
lastDiff = diff;
|
||||||
|
}
|
||||||
|
return enabled * (AMOUNTS.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onValueChange(@NonNull Slider slider, float value, boolean fromUser) {
|
||||||
|
tvProgressLabel.setText(getString(R.string.pocketchange_amount, getAmount((int) value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Listener {
|
||||||
|
void setPocketChange(Wallet.PocketChangeSetting setting);
|
||||||
|
}
|
||||||
|
}
|
@@ -17,12 +17,10 @@
|
|||||||
package com.m2049r.xmrwallet.fragment.send;
|
package com.m2049r.xmrwallet.fragment.send;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.nfc.NfcManager;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.Html;
|
import android.text.Html;
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
import android.text.Spanned;
|
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
import android.util.Patterns;
|
import android.util.Patterns;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
@@ -268,11 +266,6 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||||||
etDummy.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
etDummy.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||||
etDummy.requestFocus();
|
etDummy.requestFocus();
|
||||||
|
|
||||||
View tvNfc = view.findViewById(R.id.tvNfc);
|
|
||||||
NfcManager manager = (NfcManager) getContext().getSystemService(Context.NFC_SERVICE);
|
|
||||||
if ((manager != null) && (manager.getDefaultAdapter() != null))
|
|
||||||
tvNfc.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,10 +411,10 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||||||
if (txData instanceof TxDataBtc) {
|
if (txData instanceof TxDataBtc) {
|
||||||
((TxDataBtc) txData).setBtcAddress(etAddress.getEditText().getText().toString());
|
((TxDataBtc) txData).setBtcAddress(etAddress.getEditText().getText().toString());
|
||||||
((TxDataBtc) txData).setBtcSymbol(selectedCrypto.getSymbol());
|
((TxDataBtc) txData).setBtcSymbol(selectedCrypto.getSymbol());
|
||||||
txData.setDestinationAddress(null);
|
txData.setDestination(null);
|
||||||
ServiceHelper.ASSET = selectedCrypto.getSymbol().toLowerCase();
|
ServiceHelper.ASSET = selectedCrypto.getSymbol().toLowerCase();
|
||||||
} else {
|
} else {
|
||||||
txData.setDestinationAddress(etAddress.getEditText().getText().toString());
|
txData.setDestination(etAddress.getEditText().getText().toString());
|
||||||
ServiceHelper.ASSET = null;
|
ServiceHelper.ASSET = null;
|
||||||
}
|
}
|
||||||
txData.setUserNotes(new UserNotes(etNotes.getEditText().getText().toString()));
|
txData.setUserNotes(new UserNotes(etNotes.getEditText().getText().toString()));
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user