mirror of
https://github.com/m2049r/xmrwallet
synced 2025-09-17 19:10:51 +02:00
Compare commits
21 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5d489a634b | ||
![]() |
59b6f484fd | ||
![]() |
ecaa49d67d | ||
![]() |
d2dc53599e | ||
![]() |
4d8b26f97f | ||
![]() |
581c76e7be | ||
![]() |
6f66862870 | ||
![]() |
dd92f7bb36 | ||
![]() |
46808d306b | ||
![]() |
20503d2cbd | ||
![]() |
604691ca7e | ||
![]() |
1b626ba2b0 | ||
![]() |
0ed7bdfcee | ||
![]() |
524c3dd79f | ||
![]() |
197dffeae1 | ||
![]() |
cdb29bbc2e | ||
![]() |
7b96baeca7 | ||
![]() |
0712efec78 | ||
![]() |
341df6c6a3 | ||
![]() |
ab8fb82c1b | ||
![]() |
22d9173cea |
@@ -3,13 +3,11 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
working_directory: ~/code
|
working_directory: ~/code
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/android:api-28-ndk
|
- image: cimg/android:2022.03-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:
|
||||||
|
@@ -1,15 +1,15 @@
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 30
|
compileSdkVersion 31
|
||||||
buildToolsVersion '30.0.3'
|
buildToolsVersion '30.0.3'
|
||||||
ndkVersion '17.2.4988734'
|
ndkVersion '17.2.4988734'
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "com.m2049r.xmrwallet"
|
applicationId "com.m2049r.xmrwallet"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 30
|
targetSdkVersion 31
|
||||||
versionCode 1201
|
versionCode 1402
|
||||||
versionName "2.2.1 'René'"
|
versionName "2.4.2 'Baldaŭ'"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
@@ -111,6 +111,7 @@ 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'
|
||||||
}
|
}
|
||||||
|
|
||||||
static def getId(name) {
|
static def getId(name) {
|
||||||
@@ -120,38 +121,39 @@ static def getId(name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'androidx.core:core:1.6.0'
|
implementation 'androidx.core:core:1.7.0'
|
||||||
implementation 'androidx.appcompat:appcompat:1.3.1'
|
implementation 'androidx.appcompat:appcompat:1.4.1'
|
||||||
implementation 'com.google.android.material:material:1.4.0'
|
|
||||||
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.2.1'
|
||||||
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.3'
|
||||||
|
implementation 'androidx.preference:preference:1.2.0'
|
||||||
|
|
||||||
|
implementation 'com.google.android.material:material:1.6.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.9.3"
|
||||||
implementation "io.github.rburgst:okhttp-digest:2.5"
|
implementation "io.github.rburgst:okhttp-digest:2.6"
|
||||||
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.5.2'
|
||||||
|
|
||||||
implementation 'dnsjava:dnsjava:2.1.9'
|
implementation 'dnsjava:dnsjava:2.1.9'
|
||||||
implementation 'org.jitsi:dnssecjava:1.2.0'
|
implementation 'org.jitsi:dnssecjava:1.2.0'
|
||||||
implementation 'org.slf4j:slf4j-nop:1.7.30'
|
implementation 'org.slf4j:slf4j-nop:1.7.36'
|
||||||
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.9.3"
|
||||||
testImplementation 'org.json:json:20180813'
|
testImplementation 'org.json:json:20211205'
|
||||||
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.22'
|
||||||
annotationProcessor 'org.projectlombok:lombok:1.18.16'
|
annotationProcessor 'org.projectlombok:lombok:1.18.22'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
<?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-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" />
|
||||||
@@ -18,7 +17,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 +34,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 +56,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 +107,5 @@
|
|||||||
android:resource="@xml/filepaths" />
|
android:resource="@xml/filepaths" />
|
||||||
</provider>
|
</provider>
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
|
||||||
|
</manifest>
|
@@ -229,7 +229,7 @@ std::vector<std::string> java2cpp(JNIEnv *env, jobject arrayList) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
jobject cpp2java(JNIEnv *env, const std::vector<std::string>& vector) {
|
jobject cpp2java(JNIEnv *env, const std::vector<std::string> &vector) {
|
||||||
|
|
||||||
jmethodID java_util_ArrayList_ = env->GetMethodID(class_ArrayList, "<init>", "(I)V");
|
jmethodID java_util_ArrayList_ = env->GetMethodID(class_ArrayList, "<init>", "(I)V");
|
||||||
jmethodID java_util_ArrayList_add = env->GetMethodID(class_ArrayList, "add",
|
jmethodID java_util_ArrayList_add = env->GetMethodID(class_ArrayList, "add",
|
||||||
@@ -301,12 +301,13 @@ Java_com_m2049r_xmrwallet_model_WalletManager_openWalletJ(JNIEnv *env, jobject i
|
|||||||
JNIEXPORT jlong JNICALL
|
JNIEXPORT jlong JNICALL
|
||||||
Java_com_m2049r_xmrwallet_model_WalletManager_recoveryWalletJ(JNIEnv *env, jobject instance,
|
Java_com_m2049r_xmrwallet_model_WalletManager_recoveryWalletJ(JNIEnv *env, jobject instance,
|
||||||
jstring path, jstring password,
|
jstring path, jstring password,
|
||||||
jstring mnemonic,
|
jstring mnemonic, jstring offset,
|
||||||
jint networkType,
|
jint networkType,
|
||||||
jlong restoreHeight) {
|
jlong restoreHeight) {
|
||||||
const char *_path = env->GetStringUTFChars(path, nullptr);
|
const char *_path = env->GetStringUTFChars(path, nullptr);
|
||||||
const char *_password = env->GetStringUTFChars(password, nullptr);
|
const char *_password = env->GetStringUTFChars(password, nullptr);
|
||||||
const char *_mnemonic = env->GetStringUTFChars(mnemonic, nullptr);
|
const char *_mnemonic = env->GetStringUTFChars(mnemonic, nullptr);
|
||||||
|
const char *_offset = env->GetStringUTFChars(offset, nullptr);
|
||||||
Monero::NetworkType _networkType = static_cast<Monero::NetworkType>(networkType);
|
Monero::NetworkType _networkType = static_cast<Monero::NetworkType>(networkType);
|
||||||
|
|
||||||
Bitmonero::Wallet *wallet =
|
Bitmonero::Wallet *wallet =
|
||||||
@@ -315,11 +316,14 @@ Java_com_m2049r_xmrwallet_model_WalletManager_recoveryWalletJ(JNIEnv *env, jobje
|
|||||||
std::string(_password),
|
std::string(_password),
|
||||||
std::string(_mnemonic),
|
std::string(_mnemonic),
|
||||||
_networkType,
|
_networkType,
|
||||||
(uint64_t) restoreHeight);
|
(uint64_t) restoreHeight,
|
||||||
|
1, // kdf_rounds
|
||||||
|
std::string(_offset));
|
||||||
|
|
||||||
env->ReleaseStringUTFChars(path, _path);
|
env->ReleaseStringUTFChars(path, _path);
|
||||||
env->ReleaseStringUTFChars(password, _password);
|
env->ReleaseStringUTFChars(password, _password);
|
||||||
env->ReleaseStringUTFChars(mnemonic, _mnemonic);
|
env->ReleaseStringUTFChars(mnemonic, _mnemonic);
|
||||||
|
env->ReleaseStringUTFChars(offset, _offset);
|
||||||
return reinterpret_cast<jlong>(wallet);
|
return reinterpret_cast<jlong>(wallet);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -533,7 +537,7 @@ Java_com_m2049r_xmrwallet_model_WalletManager_resolveOpenAlias(JNIEnv *env, jobj
|
|||||||
|
|
||||||
JNIEXPORT jboolean JNICALL
|
JNIEXPORT jboolean JNICALL
|
||||||
Java_com_m2049r_xmrwallet_model_WalletManager_setProxy(JNIEnv *env, jobject instance,
|
Java_com_m2049r_xmrwallet_model_WalletManager_setProxy(JNIEnv *env, jobject instance,
|
||||||
jstring address) {
|
jstring address) {
|
||||||
const char *_address = env->GetStringUTFChars(address, nullptr);
|
const char *_address = env->GetStringUTFChars(address, nullptr);
|
||||||
bool rc =
|
bool rc =
|
||||||
Bitmonero::WalletManagerFactory::getWalletManager()->setProxy(std::string(_address));
|
Bitmonero::WalletManagerFactory::getWalletManager()->setProxy(std::string(_address));
|
||||||
@@ -570,9 +574,12 @@ Java_com_m2049r_xmrwallet_model_WalletManager_closeJ(JNIEnv *env, jobject instan
|
|||||||
/**********************************/
|
/**********************************/
|
||||||
|
|
||||||
JNIEXPORT jstring JNICALL
|
JNIEXPORT jstring JNICALL
|
||||||
Java_com_m2049r_xmrwallet_model_Wallet_getSeed(JNIEnv *env, jobject instance) {
|
Java_com_m2049r_xmrwallet_model_Wallet_getSeed(JNIEnv *env, jobject instance, jstring seedOffset) {
|
||||||
|
const char *_seedOffset = env->GetStringUTFChars(seedOffset, nullptr);
|
||||||
Bitmonero::Wallet *wallet = getHandle<Bitmonero::Wallet>(env, instance);
|
Bitmonero::Wallet *wallet = getHandle<Bitmonero::Wallet>(env, instance);
|
||||||
return env->NewStringUTF(wallet->seed().c_str());
|
jstring seed = env->NewStringUTF(wallet->seed(std::string(_seedOffset)).c_str());
|
||||||
|
env->ReleaseStringUTFChars(seedOffset, _seedOffset);
|
||||||
|
return seed;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jstring JNICALL
|
JNIEXPORT jstring JNICALL
|
||||||
@@ -740,7 +747,7 @@ Java_com_m2049r_xmrwallet_model_Wallet_getConnectionStatusJ(JNIEnv *env, jobject
|
|||||||
|
|
||||||
JNIEXPORT jboolean JNICALL
|
JNIEXPORT jboolean JNICALL
|
||||||
Java_com_m2049r_xmrwallet_model_Wallet_setProxy(JNIEnv *env, jobject instance,
|
Java_com_m2049r_xmrwallet_model_Wallet_setProxy(JNIEnv *env, jobject instance,
|
||||||
jstring address) {
|
jstring address) {
|
||||||
const char *_address = env->GetStringUTFChars(address, nullptr);
|
const char *_address = env->GetStringUTFChars(address, nullptr);
|
||||||
Bitmonero::Wallet *wallet = getHandle<Bitmonero::Wallet>(env, instance);
|
Bitmonero::Wallet *wallet = getHandle<Bitmonero::Wallet>(env, instance);
|
||||||
bool rc = wallet->setProxy(std::string(_address));
|
bool rc = wallet->setProxy(std::string(_address));
|
||||||
@@ -1262,7 +1269,7 @@ jobject newTransactionInfo(JNIEnv *env, Bitmonero::TransactionInfo *info) {
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
jobject cpp2java(JNIEnv *env, const std::vector<Bitmonero::TransactionInfo *>& vector) {
|
jobject cpp2java(JNIEnv *env, const std::vector<Bitmonero::TransactionInfo *> &vector) {
|
||||||
|
|
||||||
jmethodID java_util_ArrayList_ = env->GetMethodID(class_ArrayList, "<init>", "(I)V");
|
jmethodID java_util_ArrayList_ = env->GetMethodID(class_ArrayList, "<init>", "(I)V");
|
||||||
jmethodID java_util_ArrayList_add = env->GetMethodID(class_ArrayList, "add",
|
jmethodID java_util_ArrayList_add = env->GetMethodID(class_ArrayList, "add",
|
||||||
|
@@ -78,7 +78,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;
|
||||||
|
@@ -27,6 +27,7 @@ import android.nfc.NfcAdapter;
|
|||||||
import android.nfc.Tag;
|
import android.nfc.Tag;
|
||||||
import android.nfc.tech.Ndef;
|
import android.nfc.tech.Ndef;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
@@ -180,7 +181,7 @@ public class BaseActivity extends SecureActivity
|
|||||||
return;
|
return;
|
||||||
nfcPendingIntent = PendingIntent.getActivity(this, 0,
|
nfcPendingIntent = PendingIntent.getActivity(this, 0,
|
||||||
new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),
|
new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),
|
||||||
0);
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_IMMUTABLE : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processNfcIntent(Intent intent) {
|
private void processNfcIntent(Intent intent) {
|
||||||
|
@@ -36,7 +36,6 @@ 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.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
@@ -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;
|
||||||
|
|
||||||
@@ -81,6 +79,9 @@ public class GenerateFragment extends Fragment {
|
|||||||
private TextInputLayout etWalletRestoreHeight;
|
private TextInputLayout etWalletRestoreHeight;
|
||||||
private Button bGenerate;
|
private Button bGenerate;
|
||||||
|
|
||||||
|
private Button bSeedOffset;
|
||||||
|
private TextInputLayout etSeedOffset;
|
||||||
|
|
||||||
private String type = null;
|
private String type = null;
|
||||||
|
|
||||||
private void clearErrorOnTextEntry(final TextInputLayout textInputLayout) {
|
private void clearErrorOnTextEntry(final TextInputLayout textInputLayout) {
|
||||||
@@ -118,6 +119,8 @@ public class GenerateFragment extends Fragment {
|
|||||||
etWalletSpendKey = view.findViewById(R.id.etWalletSpendKey);
|
etWalletSpendKey = view.findViewById(R.id.etWalletSpendKey);
|
||||||
etWalletRestoreHeight = view.findViewById(R.id.etWalletRestoreHeight);
|
etWalletRestoreHeight = view.findViewById(R.id.etWalletRestoreHeight);
|
||||||
bGenerate = view.findViewById(R.id.bGenerate);
|
bGenerate = view.findViewById(R.id.bGenerate);
|
||||||
|
bSeedOffset = view.findViewById(R.id.bSeedOffset);
|
||||||
|
etSeedOffset = view.findViewById(R.id.etSeedOffset);
|
||||||
|
|
||||||
etWalletAddress.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
etWalletAddress.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||||
etWalletViewKey.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
etWalletViewKey.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||||
@@ -222,6 +225,8 @@ public class GenerateFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
bSeedOffset.setVisibility(View.VISIBLE);
|
||||||
|
bSeedOffset.setOnClickListener(v -> toggleSeedOffset());
|
||||||
break;
|
break;
|
||||||
case TYPE_KEY:
|
case TYPE_KEY:
|
||||||
case TYPE_VIEWONLY:
|
case TYPE_VIEWONLY:
|
||||||
@@ -288,6 +293,18 @@ public class GenerateFragment extends Fragment {
|
|||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void toggleSeedOffset() {
|
||||||
|
if (etSeedOffset.getVisibility() == View.VISIBLE) {
|
||||||
|
etSeedOffset.getEditText().getText().clear();
|
||||||
|
etSeedOffset.setVisibility(View.GONE);
|
||||||
|
bSeedOffset.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_keyboard_arrow_down, 0, 0, 0);
|
||||||
|
} else {
|
||||||
|
etSeedOffset.setVisibility(View.VISIBLE);
|
||||||
|
bSeedOffset.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_keyboard_arrow_up, 0, 0, 0);
|
||||||
|
etSeedOffset.requestFocusFromTouch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean checkName() {
|
private boolean checkName() {
|
||||||
String name = etWalletName.getEditText().getText().toString();
|
String name = etWalletName.getEditText().getText().toString();
|
||||||
boolean ok = true;
|
boolean ok = true;
|
||||||
@@ -422,12 +439,13 @@ public class GenerateFragment extends Fragment {
|
|||||||
break;
|
break;
|
||||||
case TYPE_SEED:
|
case TYPE_SEED:
|
||||||
if (!checkMnemonic()) return;
|
if (!checkMnemonic()) return;
|
||||||
String seed = etWalletMnemonic.getEditText().getText().toString();
|
final String seed = etWalletMnemonic.getEditText().getText().toString();
|
||||||
bGenerate.setEnabled(false);
|
bGenerate.setEnabled(false);
|
||||||
if (fingerprintAuthAllowed) {
|
if (fingerprintAuthAllowed) {
|
||||||
KeyStoreHelper.saveWalletUserPass(requireActivity(), name, password);
|
KeyStoreHelper.saveWalletUserPass(requireActivity(), name, password);
|
||||||
}
|
}
|
||||||
activityCallback.onGenerate(name, crazyPass, seed, height);
|
final String offset = etSeedOffset.getEditText().getText().toString();
|
||||||
|
activityCallback.onGenerate(name, crazyPass, seed, offset, height);
|
||||||
break;
|
break;
|
||||||
case TYPE_LEDGER:
|
case TYPE_LEDGER:
|
||||||
bGenerate.setEnabled(false);
|
bGenerate.setEnabled(false);
|
||||||
@@ -491,7 +509,7 @@ public class GenerateFragment extends Fragment {
|
|||||||
public interface Listener {
|
public interface Listener {
|
||||||
void onGenerate(String name, String password);
|
void onGenerate(String name, String password);
|
||||||
|
|
||||||
void onGenerate(String name, String password, String seed, long height);
|
void onGenerate(String name, String password, String seed, String offset, long height);
|
||||||
|
|
||||||
void onGenerate(String name, String password, String address, String viewKey, String spendKey, long height);
|
void onGenerate(String name, String password, String address, String viewKey, String spendKey, long height);
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -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,19 @@ 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.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 +72,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 +81,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 +285,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 +301,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;
|
||||||
@@ -785,6 +778,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);
|
||||||
@@ -929,7 +927,8 @@ public class LoginActivity extends BaseActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onGenerate(final String name, final String password, final String seed,
|
public void onGenerate(final String name, final String password,
|
||||||
|
final String seed, final String offset,
|
||||||
final long restoreHeight) {
|
final long restoreHeight) {
|
||||||
createWallet(name, password,
|
createWallet(name, password,
|
||||||
new WalletCreator() {
|
new WalletCreator() {
|
||||||
@@ -941,7 +940,7 @@ public class LoginActivity extends BaseActivity
|
|||||||
@Override
|
@Override
|
||||||
public boolean createWallet(File aFile, String password) {
|
public boolean createWallet(File aFile, String password) {
|
||||||
Wallet newWallet = WalletManager.getInstance()
|
Wallet newWallet = WalletManager.getInstance()
|
||||||
.recoveryWallet(aFile, password, seed, restoreHeight);
|
.recoveryWallet(aFile, password, seed, offset, restoreHeight);
|
||||||
return checkAndCloseWallet(newWallet);
|
return checkAndCloseWallet(newWallet);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1088,61 +1087,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);
|
||||||
@@ -1191,9 +1135,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;
|
||||||
@@ -1207,18 +1148,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) {
|
||||||
@@ -1332,7 +1261,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");
|
||||||
|
@@ -38,7 +38,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 +52,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 +143,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 +163,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 +185,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 +297,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 +324,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 +338,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 +348,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 +358,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 +384,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 +415,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);
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
||||||
|
@@ -46,10 +46,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 +86,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 +126,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(() -> {
|
||||||
@@ -211,39 +210,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 +253,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 +291,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 +299,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -462,8 +460,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();
|
||||||
|
@@ -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;
|
||||||
@@ -67,6 +66,8 @@ public class SubaddressFragment extends Fragment implements SubaddressInfoAdapte
|
|||||||
void setToolbarButton(int type);
|
void setToolbarButton(int type);
|
||||||
|
|
||||||
void showSubaddress(View view, final int subaddressIndex);
|
void showSubaddress(View view, final int subaddressIndex);
|
||||||
|
|
||||||
|
void saveWallet();
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ProgressListener {
|
public interface ProgressListener {
|
||||||
@@ -115,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) {
|
||||||
@@ -152,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() {
|
||||||
@@ -217,7 +205,9 @@ public class SubaddressFragment extends Fragment implements SubaddressInfoAdapte
|
|||||||
protected Boolean doInBackground(Void... params) {
|
protected Boolean doInBackground(Void... params) {
|
||||||
if (params.length != 0) return false;
|
if (params.length != 0) return false;
|
||||||
wallet.getNewSubaddress();
|
wallet.getNewSubaddress();
|
||||||
wallet.store();
|
if (activityCallback != null) {
|
||||||
|
activityCallback.saveWallet();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
@@ -97,13 +96,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);
|
||||||
@@ -220,8 +212,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));
|
||||||
@@ -266,13 +258,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();
|
||||||
@@ -348,10 +340,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -356,6 +356,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 +386,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:
|
||||||
@@ -505,6 +506,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
Timber.d("onResume()");
|
Timber.d("onResume()");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void saveWallet() {
|
public void saveWallet() {
|
||||||
if (mIsBound) { // no point in talking to unbound service
|
if (mIsBound) { // no point in talking to unbound service
|
||||||
Intent intent = new Intent(getApplicationContext(), WalletService.class);
|
Intent intent = new Intent(getApplicationContext(), WalletService.class);
|
||||||
@@ -537,7 +539,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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -609,9 +611,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
@Override
|
@Override
|
||||||
public void onWalletStored(final boolean success) {
|
public void onWalletStored(final boolean success) {
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
if (success) {
|
if (!success) {
|
||||||
Toast.makeText(WalletActivity.this, getString(R.string.status_wallet_unloaded), Toast.LENGTH_SHORT).show();
|
|
||||||
} else {
|
|
||||||
Toast.makeText(WalletActivity.this, getString(R.string.status_wallet_unload_failed), Toast.LENGTH_LONG).show();
|
Toast.makeText(WalletActivity.this, getString(R.string.status_wallet_unload_failed), Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -800,10 +800,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
|
||||||
@@ -941,6 +937,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
@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) {
|
||||||
@@ -959,7 +956,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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
@@ -111,7 +111,8 @@ 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(), 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);
|
||||||
@@ -202,11 +203,6 @@ 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) {
|
void showBalance(String balance) {
|
||||||
@@ -331,19 +327,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;
|
||||||
|
|
||||||
@@ -536,8 +522,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);
|
||||||
|
@@ -22,6 +22,7 @@ import android.content.res.Configuration;
|
|||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.model.NetworkType;
|
import com.m2049r.xmrwallet.model.NetworkType;
|
||||||
import com.m2049r.xmrwallet.util.LocaleHelper;
|
import com.m2049r.xmrwallet.util.LocaleHelper;
|
||||||
@@ -35,7 +36,7 @@ public class XmrWalletApplication extends Application {
|
|||||||
@Override
|
@Override
|
||||||
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());
|
||||||
}
|
}
|
||||||
|
@@ -267,14 +267,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, 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) {
|
||||||
|
@@ -40,6 +40,7 @@ import com.m2049r.xmrwallet.service.shift.sideshift.api.SideShiftApi;
|
|||||||
import com.m2049r.xmrwallet.service.shift.sideshift.network.SideShiftApiImpl;
|
import com.m2049r.xmrwallet.service.shift.sideshift.network.SideShiftApiImpl;
|
||||||
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 java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -212,19 +213,27 @@ public class SendBtcSuccessWizardFragment extends SendWizardFragment {
|
|||||||
if (status.isError()) {
|
if (status.isError()) {
|
||||||
tvXmrToStatus.setText(getString(R.string.info_send_xmrto_error, status.toString()));
|
tvXmrToStatus.setText(getString(R.string.info_send_xmrto_error, status.toString()));
|
||||||
statusResource = R.drawable.ic_error_red_24dp;
|
statusResource = R.drawable.ic_error_red_24dp;
|
||||||
pbXmrto.getIndeterminateDrawable().setColorFilter(0xff8b0000, android.graphics.PorterDuff.Mode.MULTIPLY);
|
pbXmrto.getIndeterminateDrawable().setColorFilter(
|
||||||
|
ThemeHelper.getThemedColor(getContext(), android.R.attr.colorError),
|
||||||
|
android.graphics.PorterDuff.Mode.MULTIPLY);
|
||||||
} else if (status.isSent() || status.isPaid()) {
|
} else if (status.isSent() || status.isPaid()) {
|
||||||
tvXmrToStatus.setText(getString(R.string.info_send_xmrto_sent, btcData.getBtcSymbol()));
|
tvXmrToStatus.setText(getString(R.string.info_send_xmrto_sent, btcData.getBtcSymbol()));
|
||||||
statusResource = R.drawable.ic_success_green_24dp;
|
statusResource = R.drawable.ic_success;
|
||||||
pbXmrto.getIndeterminateDrawable().setColorFilter(0xFF417505, android.graphics.PorterDuff.Mode.MULTIPLY);
|
pbXmrto.getIndeterminateDrawable().setColorFilter(
|
||||||
|
ThemeHelper.getThemedColor(getContext(), R.attr.positiveColor),
|
||||||
|
android.graphics.PorterDuff.Mode.MULTIPLY);
|
||||||
} else if (status.isWaiting()) {
|
} else if (status.isWaiting()) {
|
||||||
tvXmrToStatus.setText(getString(R.string.info_send_xmrto_unpaid));
|
tvXmrToStatus.setText(getString(R.string.info_send_xmrto_unpaid));
|
||||||
statusResource = R.drawable.ic_pending_orange_24dp;
|
statusResource = R.drawable.ic_pending;
|
||||||
pbXmrto.getIndeterminateDrawable().setColorFilter(0xFFFF6105, android.graphics.PorterDuff.Mode.MULTIPLY);
|
pbXmrto.getIndeterminateDrawable().setColorFilter(
|
||||||
|
ThemeHelper.getThemedColor(getContext(), R.attr.neutralColor),
|
||||||
|
android.graphics.PorterDuff.Mode.MULTIPLY);
|
||||||
} else if (status.isPending()) {
|
} else if (status.isPending()) {
|
||||||
tvXmrToStatus.setText(getString(R.string.info_send_xmrto_paid));
|
tvXmrToStatus.setText(getString(R.string.info_send_xmrto_paid));
|
||||||
statusResource = R.drawable.ic_pending_orange_24dp;
|
statusResource = R.drawable.ic_pending;
|
||||||
pbXmrto.getIndeterminateDrawable().setColorFilter(0xFFFF6105, android.graphics.PorterDuff.Mode.MULTIPLY);
|
pbXmrto.getIndeterminateDrawable().setColorFilter(
|
||||||
|
ThemeHelper.getThemedColor(getContext(), R.attr.neutralColor),
|
||||||
|
android.graphics.PorterDuff.Mode.MULTIPLY);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("status is broken: " + status.toString());
|
throw new IllegalStateException("status is broken: " + status.toString());
|
||||||
}
|
}
|
||||||
|
@@ -55,7 +55,6 @@ import com.m2049r.xmrwallet.widget.DotBar;
|
|||||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
@@ -202,14 +201,14 @@ public class SendFragment extends Fragment
|
|||||||
CharSequence nextLabel = pagerAdapter.getPageTitle(position + 1);
|
CharSequence nextLabel = pagerAdapter.getPageTitle(position + 1);
|
||||||
bNext.setText(nextLabel);
|
bNext.setText(nextLabel);
|
||||||
if (nextLabel != null) {
|
if (nextLabel != null) {
|
||||||
bNext.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_navigate_next_white_24dp, 0);
|
bNext.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_navigate_next, 0);
|
||||||
} else {
|
} else {
|
||||||
bNext.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
|
bNext.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
CharSequence prevLabel = pagerAdapter.getPageTitle(position - 1);
|
CharSequence prevLabel = pagerAdapter.getPageTitle(position - 1);
|
||||||
bPrev.setText(prevLabel);
|
bPrev.setText(prevLabel);
|
||||||
if (prevLabel != null) {
|
if (prevLabel != null) {
|
||||||
bPrev.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_navigate_prev_white_24dp, 0, 0, 0);
|
bPrev.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_navigate_prev, 0, 0, 0);
|
||||||
} else {
|
} else {
|
||||||
bPrev.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
|
bPrev.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
@@ -23,7 +23,6 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
@@ -230,21 +229,21 @@ public class NodeInfoAdapter extends RecyclerView.Adapter<NodeInfoAdapter.ViewHo
|
|||||||
|
|
||||||
static public int getPingIcon(NodeInfo nodeInfo) {
|
static public int getPingIcon(NodeInfo nodeInfo) {
|
||||||
if (nodeInfo.isUnauthorized()) {
|
if (nodeInfo.isUnauthorized()) {
|
||||||
return R.drawable.ic_wifi_lock_black_24dp;
|
return R.drawable.ic_wifi_lock;
|
||||||
}
|
}
|
||||||
if (nodeInfo.isValid()) {
|
if (nodeInfo.isValid()) {
|
||||||
final double ping = nodeInfo.getResponseTime();
|
final double ping = nodeInfo.getResponseTime();
|
||||||
if (ping < NodeInfo.PING_GOOD) {
|
if (ping < NodeInfo.PING_GOOD) {
|
||||||
return R.drawable.ic_signal_wifi_4_bar_24dp;
|
return R.drawable.ic_wifi_4_bar;
|
||||||
} else if (ping < NodeInfo.PING_MEDIUM) {
|
} else if (ping < NodeInfo.PING_MEDIUM) {
|
||||||
return R.drawable.ic_signal_wifi_3_bar_24dp;
|
return R.drawable.ic_wifi_3_bar;
|
||||||
} else if (ping < NodeInfo.PING_BAD) {
|
} else if (ping < NodeInfo.PING_BAD) {
|
||||||
return R.drawable.ic_signal_wifi_2_bar_24dp;
|
return R.drawable.ic_wifi_2_bar;
|
||||||
} else {
|
} else {
|
||||||
return R.drawable.ic_signal_wifi_1_bar_24dp;
|
return R.drawable.ic_wifi_1_bar;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return R.drawable.ic_signal_wifi_off_24dp;
|
return R.drawable.ic_wifi_off;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -36,6 +36,7 @@ import com.m2049r.xmrwallet.data.Crypto;
|
|||||||
import com.m2049r.xmrwallet.data.UserNotes;
|
import com.m2049r.xmrwallet.data.UserNotes;
|
||||||
import com.m2049r.xmrwallet.model.TransactionInfo;
|
import com.m2049r.xmrwallet.model.TransactionInfo;
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
|
import com.m2049r.xmrwallet.util.ThemeHelper;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -67,10 +68,10 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
|||||||
|
|
||||||
public TransactionInfoAdapter(Context context, OnInteractionListener listener) {
|
public TransactionInfoAdapter(Context context, OnInteractionListener listener) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
inboundColour = ContextCompat.getColor(context, R.color.tx_plus);
|
inboundColour = ThemeHelper.getThemedColor(context, R.attr.positiveColor);
|
||||||
outboundColour = ContextCompat.getColor(context, R.color.tx_minus);
|
outboundColour = ThemeHelper.getThemedColor(context, R.attr.negativeColor);
|
||||||
pendingColour = ContextCompat.getColor(context, R.color.tx_pending);
|
pendingColour = ThemeHelper.getThemedColor(context, R.attr.neutralColor);
|
||||||
failedColour = ContextCompat.getColor(context, R.color.tx_failed);
|
failedColour = ThemeHelper.getThemedColor(context, R.attr.neutralColor);
|
||||||
infoItems = new ArrayList<>();
|
infoItems = new ArrayList<>();
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
Calendar cal = Calendar.getInstance();
|
Calendar cal = Calendar.getInstance();
|
||||||
@@ -253,8 +254,8 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
|||||||
tvPaymentId.setText(info);
|
tvPaymentId.setText(info);
|
||||||
} else {
|
} else {
|
||||||
Spanned label = Html.fromHtml(context.getString(R.string.tx_details_notes,
|
Spanned label = Html.fromHtml(context.getString(R.string.tx_details_notes,
|
||||||
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),
|
||||||
tag, info.isEmpty() ? "" : (" " + info)));
|
tag, info.isEmpty() ? "" : (" " + info)));
|
||||||
tvPaymentId.setText(label);
|
tvPaymentId.setText(label);
|
||||||
}
|
}
|
||||||
|
@@ -129,7 +129,7 @@ public class Wallet {
|
|||||||
ConnectionStatus_WrongVersion
|
ConnectionStatus_WrongVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
public native String getSeed();
|
public native String getSeed(String offset);
|
||||||
|
|
||||||
public native String getSeedLanguage();
|
public native String getSeedLanguage();
|
||||||
|
|
||||||
@@ -147,7 +147,7 @@ public class Wallet {
|
|||||||
|
|
||||||
private native Status statusWithErrorString();
|
private native Status statusWithErrorString();
|
||||||
|
|
||||||
public native boolean setPassword(String password);
|
public native synchronized boolean setPassword(String password);
|
||||||
|
|
||||||
public String getAddress() {
|
public String getAddress() {
|
||||||
return getAddress(accountIndex);
|
return getAddress(accountIndex);
|
||||||
@@ -203,12 +203,10 @@ public class Wallet {
|
|||||||
public native String getSecretSpendKey();
|
public native String getSecretSpendKey();
|
||||||
|
|
||||||
public boolean store() {
|
public boolean store() {
|
||||||
final boolean ok = store("");
|
return store("");
|
||||||
Timber.d("stored");
|
|
||||||
return ok;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public native boolean store(String path);
|
public native synchronized boolean store(String path);
|
||||||
|
|
||||||
public boolean close() {
|
public boolean close() {
|
||||||
disposePendingTransaction();
|
disposePendingTransaction();
|
||||||
|
@@ -124,19 +124,19 @@ public class WalletManager {
|
|||||||
|
|
||||||
private native long openWalletJ(String path, String password, int networkType);
|
private native long openWalletJ(String path, String password, int networkType);
|
||||||
|
|
||||||
public Wallet recoveryWallet(File aFile, String password, String mnemonic) {
|
public Wallet recoveryWallet(File aFile, String password,
|
||||||
return recoveryWallet(aFile, password, mnemonic, 0);
|
String mnemonic, String offset,
|
||||||
}
|
long restoreHeight) {
|
||||||
|
long walletHandle = recoveryWalletJ(aFile.getAbsolutePath(), password,
|
||||||
public Wallet recoveryWallet(File aFile, String password, String mnemonic, long restoreHeight) {
|
mnemonic, offset,
|
||||||
long walletHandle = recoveryWalletJ(aFile.getAbsolutePath(), password, mnemonic,
|
|
||||||
getNetworkType().getValue(), restoreHeight);
|
getNetworkType().getValue(), restoreHeight);
|
||||||
Wallet wallet = new Wallet(walletHandle);
|
Wallet wallet = new Wallet(walletHandle);
|
||||||
manageWallet(wallet);
|
manageWallet(wallet);
|
||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
|
|
||||||
private native long recoveryWalletJ(String path, String password, String mnemonic,
|
private native long recoveryWalletJ(String path, String password,
|
||||||
|
String mnemonic, String offset,
|
||||||
int networkType, long restoreHeight);
|
int networkType, long restoreHeight);
|
||||||
|
|
||||||
public Wallet createWalletWithKeys(File aFile, String password, String language, long restoreHeight,
|
public Wallet createWalletWithKeys(File aFile, String password, String language, long restoreHeight,
|
||||||
|
@@ -568,7 +568,8 @@ public class WalletService extends Service {
|
|||||||
|
|
||||||
private void startNotfication() {
|
private void startNotfication() {
|
||||||
Intent notificationIntent = new Intent(this, WalletActivity.class);
|
Intent notificationIntent = new Intent(this, WalletActivity.class);
|
||||||
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
|
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent,
|
||||||
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_IMMUTABLE : 0);
|
||||||
|
|
||||||
String channelId = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? createNotificationChannel() : "";
|
String channelId = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? createNotificationChannel() : "";
|
||||||
Notification notification = new NotificationCompat.Builder(this, channelId)
|
Notification notification = new NotificationCompat.Builder(this, channelId)
|
||||||
|
@@ -395,7 +395,7 @@ public class Helper {
|
|||||||
final TextView tvOpenPrompt = promptsView.findViewById(R.id.tvOpenPrompt);
|
final TextView tvOpenPrompt = promptsView.findViewById(R.id.tvOpenPrompt);
|
||||||
final Drawable icFingerprint = context.getDrawable(R.drawable.ic_fingerprint);
|
final Drawable icFingerprint = context.getDrawable(R.drawable.ic_fingerprint);
|
||||||
final Drawable icError = context.getDrawable(R.drawable.ic_error_red_36dp);
|
final Drawable icError = context.getDrawable(R.drawable.ic_error_red_36dp);
|
||||||
final Drawable icInfo = context.getDrawable(R.drawable.ic_info_green_36dp);
|
final Drawable icInfo = context.getDrawable(R.drawable.ic_info_white_24dp);
|
||||||
|
|
||||||
final boolean fingerprintAuthCheck = FingerprintHelper.isFingerPassValid(context, wallet);
|
final boolean fingerprintAuthCheck = FingerprintHelper.isFingerPassValid(context, wallet);
|
||||||
|
|
||||||
|
@@ -27,7 +27,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
public class LocaleHelper {
|
public class LocaleHelper {
|
||||||
private static final String PREFERRED_LOCALE_KEY = "preferred_locale";
|
|
||||||
private static Locale SYSTEM_DEFAULT_LOCALE = Locale.getDefault();
|
private static Locale SYSTEM_DEFAULT_LOCALE = Locale.getDefault();
|
||||||
|
|
||||||
public static ArrayList<Locale> getAvailableLocales(Context context) {
|
public static ArrayList<Locale> getAvailableLocales(Context context) {
|
||||||
@@ -93,12 +92,13 @@ public class LocaleHelper {
|
|||||||
|
|
||||||
public static String getPreferredLanguageTag(Context context) {
|
public static String getPreferredLanguageTag(Context context) {
|
||||||
return PreferenceManager.getDefaultSharedPreferences(context)
|
return PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
.getString(PREFERRED_LOCALE_KEY, "");
|
.getString("preferred_locale", "");
|
||||||
|
// cannot access getString here as it's done BEFORE string locale is set
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("ApplySharedPref")
|
@SuppressLint("ApplySharedPref")
|
||||||
private static void savePreferredLangaugeTag(Context context, String locale) {
|
private static void savePreferredLangaugeTag(Context context, String locale) {
|
||||||
PreferenceManager.getDefaultSharedPreferences(context).edit()
|
PreferenceManager.getDefaultSharedPreferences(context).edit()
|
||||||
.putString(PREFERRED_LOCALE_KEY, locale).commit();
|
.putString(context.getString(R.string.preferred_locale), locale).commit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -323,6 +323,7 @@ public class NetCipherHelper implements StatusCallback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private OkHttpClient getClient() {
|
private OkHttpClient getClient() {
|
||||||
|
if (mockClient != null) return mockClient; // Unit-test mode
|
||||||
final OkHttpClient client = getInstance().client;
|
final OkHttpClient client = getInstance().client;
|
||||||
if ((username != null) && (!username.isEmpty())) {
|
if ((username != null) && (!username.isEmpty())) {
|
||||||
final DigestAuthenticator authenticator = new DigestAuthenticator(new Credentials(username, password));
|
final DigestAuthenticator authenticator = new DigestAuthenticator(new Credentials(username, password));
|
||||||
@@ -349,6 +350,9 @@ public class NetCipherHelper implements StatusCallback {
|
|||||||
}
|
}
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for unit tests only
|
||||||
|
static public OkHttpClient mockClient = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String PREFS_NAME = "tor";
|
private static final String PREFS_NAME = "tor";
|
||||||
|
@@ -16,32 +16,37 @@
|
|||||||
|
|
||||||
package com.m2049r.xmrwallet.util;
|
package com.m2049r.xmrwallet.util;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatDelegate;
|
import androidx.appcompat.app.AppCompatDelegate;
|
||||||
|
|
||||||
public class NightmodeHelper {
|
import com.m2049r.xmrwallet.R;
|
||||||
private static final String PREFERRED_NIGHTMODE_KEY = "preferred_nightmode";
|
|
||||||
|
|
||||||
|
public class NightmodeHelper {
|
||||||
public static DayNightMode getPreferredNightmode(Context context) {
|
public static DayNightMode getPreferredNightmode(Context context) {
|
||||||
return DayNightMode.valueOf(PreferenceManager.getDefaultSharedPreferences(context)
|
return DayNightMode.valueOf(PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
.getString(PREFERRED_NIGHTMODE_KEY, "UNKNOWN"));
|
.getString(context.getString(R.string.preferred_nightmode), "UNKNOWN"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setPreferredNightmode(Context context) {
|
public static void setPreferredNightmode(Context context) {
|
||||||
final DayNightMode mode = DayNightMode.valueOf(PreferenceManager.getDefaultSharedPreferences(context)
|
final DayNightMode mode = DayNightMode.valueOf(PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
.getString(PREFERRED_NIGHTMODE_KEY, "UNKNOWN"));
|
.getString(context.getString(R.string.preferred_nightmode), "UNKNOWN"));
|
||||||
if (mode == DayNightMode.UNKNOWN) setAndSavePreferredNightmode(context, DayNightMode.AUTO);
|
if (mode == DayNightMode.UNKNOWN)
|
||||||
setNightMode(mode);
|
setAndSavePreferredNightmode(context, DayNightMode.AUTO);
|
||||||
|
else
|
||||||
|
setNightMode(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setAndSavePreferredNightmode(Context context, DayNightMode mode) {
|
public static void setAndSavePreferredNightmode(Context context, DayNightMode mode) {
|
||||||
PreferenceManager.getDefaultSharedPreferences(context).edit()
|
PreferenceManager.getDefaultSharedPreferences(context).edit()
|
||||||
.putString(PREFERRED_NIGHTMODE_KEY, mode.name()).apply();
|
.putString(context.getString(R.string.preferred_nightmode), mode.name()).apply();
|
||||||
setNightMode(mode);
|
setNightMode(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("WrongConstant")
|
||||||
public static void setNightMode(DayNightMode mode) {
|
public static void setNightMode(DayNightMode mode) {
|
||||||
AppCompatDelegate.setDefaultNightMode(mode.getNightMode());
|
AppCompatDelegate.setDefaultNightMode(mode.getNightMode());
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user