1
mirror of https://github.com/m2049r/xmrwallet synced 2025-09-06 02:27:11 +02:00

Compare commits

..

23 Commits

Author SHA1 Message Date
m2049r
cd6f646b63 bump version 2024-03-17 14:10:14 +01:00
m2049r
aa530caa28 improve german transaltion. remove permissions translations 2024-03-17 14:04:49 +01:00
m2049r
5df43f1274 fix translation errors 2024-03-17 13:38:36 +01:00
m2049r
3b0cb3ffdb upgrade gradle 2024-03-17 13:28:22 +01:00
m2049r
300551dbe4 update zlib to 1.3.1 2024-03-17 13:06:05 +01:00
m2049r
942519adb7 ignore monero native stuff 2024-03-17 12:53:51 +01:00
m2049r
0652a8ba14 upgrade dnsjava (#924) 2024-01-13 17:33:23 +01:00
m2049r
04d0bd2ffb fix tests 2024-01-13 16:14:05 +01:00
m2049r
8473e66c69 upgrade dependencies 2024-01-13 15:58:00 +01:00
m2049r
2218ff615c fix unescaped quotes 2024-01-13 15:41:23 +01:00
m2049r
54b55b9f8f optimize build time 2024-01-13 15:33:21 +01:00
m2049r
5abf84f62b optimize build time 2024-01-13 15:31:14 +01:00
m2049r
6ff75d221f add RSD (#923) 2024-01-13 14:28:30 +01:00
audioz
c90f107c3c Hebrew Translation (#895) 2024-01-13 14:13:56 +01:00
Digitale Souveränität - JETZT!
a3db18032e add ds-jetzt node (#905)
add ds-jetzt node as clear & onion
2024-01-13 14:13:18 +01:00
anhdres
9db2c10679 updated texts for eng and spa (#911)
Co-authored-by: m2049r <m2049r@monerujo.io>
2024-01-13 14:11:41 +01:00
XD22
eab85c7f0a Fix Docker libs Builds (#918)
Co-authored-by: m2049r <m2049r@monerujo.io>
2024-01-13 14:08:02 +01:00
kuznetsovgm
6bf3229e77 fixed a translation error (#912) 2024-01-13 14:05:52 +01:00
audioz
9f4f626acb Docker build fix. (#896)
* Hebrew Translation

* ~~ https://zlib.net/
Version 1.2.13 has these key updates from 1.2.12:

    Fix a bug when getting a gzip header extra field with inflateGetHeader(). This remedies CVE-2022-37434.
    Fix a bug in block type selection when Z_FIXED used. Now the smallest block type is selected, for better compression.
    Fix a configure issue that discarded the provided CC definition.
    Correct incorrect inputs provided to the CRC functions. This mitigates a bug in Java.
    Repair prototypes and exporting of the new CRC functions.
    Fix inflateBack to detect invalid input with distances too far.

Due to the first bug fix, any installations of 1.2.12 or earlier should be replaced with 1.2.13.

* Delete app/src/main/res/values-he directory
2024-01-13 14:05:22 +01:00
XD22
434dab55ba Fix TalkBack Screen reader (#917)
* Fixing TalkBack p1

* Fix TalkBack español translate p2

* Fix TalkBack français translate p3

* Escape some apostrophe, Fix wrong Locale codes
2024-01-13 14:03:31 +01:00
m2049r
59cc6b1864 upgrade dependencies 2024-01-13 13:59:38 +01:00
m2049r
a6e9d0e77c use yadio for pricing "exotic" fiat (#921)
* yadio api

* add more currencies

* fix es typo

* bump version & fix cicleci build
2023-12-10 14:24:35 +01:00
m2049r
17df7c3faf Pocket Change V2 (#914)
* show PC on btc confirm
* random slots to refill
2023-08-28 19:24:45 +02:00
73 changed files with 1872 additions and 2102 deletions

View File

@@ -3,7 +3,7 @@ jobs:
build:
working_directory: ~/code
docker:
- image: cimg/android:2022.03-ndk
- image: cimg/android:2023.12-ndk
environment:
JVM_OPTS: -Xmx3200m
steps:

2
.gitignore vendored
View File

@@ -16,3 +16,5 @@
/app/prodStagenet
/app/.cxx
/monerujo.id
/external-libs/VERSION
/external-libs/include/wallet2_api.h

View File

@@ -1,15 +1,15 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 33
buildToolsVersion '33.0.2'
ndkVersion '17.2.4988734'
defaultConfig {
applicationId "com.m2049r.xmrwallet"
buildToolsVersion = '34.0.0'
compileSdk 34
minSdkVersion 21
targetSdkVersion 31
versionCode 3307
versionName "3.3.7 'Pocket Change'"
targetSdkVersion 33
versionCode 3311
versionName "3.3.11 'Argentina'"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
@@ -112,6 +112,17 @@ android {
targetCompatibility JavaVersion.VERSION_1_8
}
namespace 'com.m2049r.xmrwallet'
buildFeatures {
buildConfig true
}
testOptions {
unitTests {
all {
jvmArgs '--add-opens=java.base/java.lang=ALL-UNNAMED'
}
}
}
}
static def getId(name) {
@@ -123,39 +134,38 @@ static def getId(name) {
dependencies {
implementation(platform("org.jetbrains.kotlin:kotlin-bom:1.8.0"))
implementation 'androidx.core:core:1.10.1'
implementation 'androidx.core:core:1.12.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.3.0'
implementation 'androidx.recyclerview:recyclerview:1.3.2'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.preference:preference:1.2.0'
implementation 'androidx.preference:preference:1.2.1'
implementation 'com.google.android.material:material:1.9.0'
implementation 'com.google.android.material:material:1.11.0'
implementation 'me.dm7.barcodescanner:zxing:1.9.8'
implementation "com.squareup.okhttp3:okhttp:4.9.3"
implementation "io.github.rburgst:okhttp-digest:2.6"
implementation "com.squareup.okhttp3:okhttp:4.12.0"
implementation "io.github.rburgst:okhttp-digest:3.1.0"
implementation "com.jakewharton.timber:timber:5.0.1"
implementation 'info.guardianproject.netcipher:netcipher:2.1.0'
//implementation 'info.guardianproject.netcipher:netcipher-okhttp3:2.1.0'
implementation fileTree(dir: 'libs/classes', include: ['*.jar'])
implementation 'com.nulab-inc:zxcvbn:1.5.2'
implementation 'com.nulab-inc:zxcvbn:1.8.2'
implementation 'dnsjava:dnsjava:2.1.9'
implementation 'org.jitsi:dnssecjava:1.2.0'
implementation 'org.slf4j:slf4j-nop:1.7.36'
implementation 'dnsjava:dnsjava:3.5.3'
implementation 'org.slf4j:slf4j-nop:2.0.11'
implementation 'com.github.brnunes:swipeablerecyclerview:1.0.2'
//noinspection GradleDependency
testImplementation "junit:junit:4.13.2"
testImplementation "org.mockito:mockito-all:1.10.19"
testImplementation "com.squareup.okhttp3:mockwebserver:4.9.3"
testImplementation 'org.json:json:20211205'
testImplementation "com.squareup.okhttp3:mockwebserver:4.12.0"
testImplementation 'org.json:json:20231013'
testImplementation 'net.jodah:concurrentunit:0.4.6'
compileOnly 'org.projectlombok:lombok:1.18.22'
annotationProcessor 'org.projectlombok:lombok:1.18.22'
compileOnly 'org.projectlombok:lombok:1.18.30'
annotationProcessor 'org.projectlombok:lombok:1.18.30'
}

View File

@@ -1,6 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />

View File

@@ -629,7 +629,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
@Override
public void onWalletStarted(final Wallet.Status walletStatus) {
loadPocketChangeSettings();
runOnUiThread(() -> {
dismissProgressDialog();
if (walletStatus == null) {
@@ -648,6 +647,8 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
haveWallet = true;
invalidateOptionsMenu();
loadPocketChangeSettings();
if (requestStreetMode) onEnableStreetMode();
final WalletFragment walletFragment = getWalletFragment();

View File

@@ -22,18 +22,24 @@ import android.content.res.Configuration;
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.OptIn;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStateManagerControl;
import com.m2049r.xmrwallet.model.NetworkType;
import com.m2049r.xmrwallet.util.LocaleHelper;
import com.m2049r.xmrwallet.util.NetCipherHelper;
import com.m2049r.xmrwallet.util.NightmodeHelper;
import com.m2049r.xmrwallet.util.ServiceHelper;
import java.util.Arrays;
import timber.log.Timber;
public class XmrWalletApplication extends Application {
@Override
@OptIn(markerClass = FragmentStateManagerControl.class)
public void onCreate() {
super.onCreate();
FragmentManager.enableNewStateManager(false);

View File

@@ -29,10 +29,12 @@ public enum DefaultNodes {
HASHVAULT("nodes.hashvault.pro:18081"),
MONEROWORLD("node.moneroworld.com:18089"),
XMRTW("opennode.xmr-tw.org:18089"),
ds_jetzt("monero.ds-jetzt.de:18089"),
MONERUJO_ONION("monerujods7mbghwe6cobdr6ujih6c22zu5rl7zshmizz2udf7v7fsad.onion:18081/mainnet/monerujo.onion"),
Criminales78("56wl7y2ebhamkkiza4b7il4mrzwtyvpdym7bm2bkg3jrei2je646k3qd.onion:18089/mainnet/Criminales78.onion"),
xmrfail("mxcd4577fldb3ppzy7obmmhnu3tf57gbcbd4qhwr2kxyjj2qi3dnbfqd.onion:18081/mainnet/xmrfail.onion"),
boldsuck("6dsdenp6vjkvqzy4wzsnzn6wixkdzihx3khiumyzieauxuxslmcaeiad.onion:18081/mainnet/boldsuck.onion");
boldsuck("6dsdenp6vjkvqzy4wzsnzn6wixkdzihx3khiumyzieauxuxslmcaeiad.onion:18081/mainnet/boldsuck.onion"),
ds_jetzt_onion("qvlr4w7yhnjrdg3txa72jwtpnjn4ezsrivzvocbnvpfbdo342fahhoad.onion:18089/mainnet/ds-jetzt.onion");
@Getter
private final String uri;

View File

@@ -26,6 +26,7 @@ import com.m2049r.xmrwallet.model.Wallet;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import lombok.Data;
@@ -136,8 +137,9 @@ public class TxData implements Parcelable {
//////////////////////////
final static public int POCKETCHANGE_IDX = 1; // subaddress index of first pocketchange slot
final static public int POCKETCHANGE_SLOTS = 10; // number of pocketchange slots
final static public int POCKETCHANGE_IDX_MAX = POCKETCHANGE_IDX + POCKETCHANGE_SLOTS - 1;
final static public int POCKETCHANGE_SLOTS_MIN = 6; // min number of pocketchange slots
final static public int POCKETCHANGE_SLOTS_MAX = 14; // max number of pocketchange slots
final static public int POCKETCHANGE_IDX_MAX = POCKETCHANGE_IDX + POCKETCHANGE_SLOTS_MAX - 1;
@Data
static private class PocketChangeSlot {
@@ -171,8 +173,8 @@ public class TxData implements Parcelable {
List<CoinsInfo> coins = wallet.getCoinsInfos(true);
Set<Integer> spendableSubaddressIdx = new HashSet<>();
PocketChangeSlot reserves = new PocketChangeSlot(); // everything not in a slot spendable
PocketChangeSlot[] slots = new PocketChangeSlot[POCKETCHANGE_SLOTS];
for (int i = 0; i < POCKETCHANGE_SLOTS; i++) {
PocketChangeSlot[] slots = new PocketChangeSlot[POCKETCHANGE_SLOTS_MAX];
for (int i = 0; i < POCKETCHANGE_SLOTS_MAX; i++) {
slots[i] = new PocketChangeSlot();
}
for (CoinsInfo coin : coins) {
@@ -205,7 +207,8 @@ public class TxData implements Parcelable {
// find any slots to fill if possible:
List<Integer> slotsToFill = new ArrayList<>();
List<Long> slotToFillAmounts = new ArrayList<>();
for (int i = 0; i < POCKETCHANGE_SLOTS; i++) {
final int randomSlotCount = new Random().nextInt(POCKETCHANGE_SLOTS_MAX - POCKETCHANGE_SLOTS_MIN + 1) + POCKETCHANGE_SLOTS_MIN;
for (int i = 0; i < randomSlotCount; i++) {
if (slots[i].getAmount() < pocketChangeAmount) {
final long topupAmount = pocketChangeAmount - slots[i].getAmount();
if (topupAmount <= spendableAmount) {

View File

@@ -74,6 +74,9 @@ public class SendBtcConfirmWizardFragment extends SendWizardFragment implements
private View llConfirmSend;
private Button bSend;
private View pbProgressSend;
private TextView tvTxChange;
private View llPocketChange;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
@@ -92,6 +95,8 @@ public class SendBtcConfirmWizardFragment extends SendWizardFragment implements
tvTxFee = view.findViewById(R.id.tvTxFee);
tvTxTotal = view.findViewById(R.id.tvTxTotal);
tvTxChange = view.findViewById(R.id.tvTxChange);
llPocketChange = view.findViewById(R.id.llPocketChange);
llStageA = view.findViewById(R.id.llStageA);
evStageA = view.findViewById(R.id.evStageA);
@@ -217,6 +222,13 @@ public class SendBtcConfirmWizardFragment extends SendWizardFragment implements
tvTxFee.setText(Wallet.getDisplayAmount(pendingTransaction.getFee()));
tvTxTotal.setText(Wallet.getDisplayAmount(
pendingTransaction.getFee() + pendingTransaction.getAmount()));
final long change = pendingTransaction.getPocketChange();
if (change > 0) {
llPocketChange.setVisibility(View.VISIBLE);
tvTxChange.setText(Wallet.getDisplayAmount(change));
} else {
llPocketChange.setVisibility(View.GONE);
}
updateSendButton();
});
} else {

View File

@@ -33,5 +33,6 @@ public interface ExchangeApi {
void queryExchangeRate(@NonNull final String baseCurrency, @NonNull final String quoteCurrency,
@NonNull final ExchangeCallback callback);
String getName();
}

View File

@@ -67,9 +67,9 @@ public class ExchangeApiImpl implements ExchangeApi {
// data is daily and is refreshed around 16:00 CET every working day
}
public static boolean isSameDay(Calendar calendar, Calendar anotherCalendar) {
return (calendar.get(Calendar.YEAR) == anotherCalendar.get(Calendar.YEAR)) &&
(calendar.get(Calendar.DAY_OF_YEAR) == anotherCalendar.get(Calendar.DAY_OF_YEAR));
@Override
public String getName() {
return "ecb";
}
@Override
@@ -121,12 +121,12 @@ public class ExchangeApiImpl implements ExchangeApi {
final NetCipherHelper.Request httpRequest = new NetCipherHelper.Request(baseUrl);
httpRequest.enqueue(new okhttp3.Callback() {
@Override
public void onFailure(final Call call, final IOException ex) {
public void onFailure(@NonNull final Call call, @NonNull final IOException ex) {
callback.onError(ex);
}
@Override
public void onResponse(final Call call, final Response response) throws IOException {
public void onResponse(@NonNull final Call call, @NonNull final Response response) throws IOException {
if (response.isSuccessful()) {
try {
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
@@ -178,11 +178,12 @@ public class ExchangeApiImpl implements ExchangeApi {
Element cube = (Element) node;
if (cube.hasAttribute("time")) { // a time Cube
final Date time = DATE_FORMAT.parse(cube.getAttribute("time"));
assert time != null;
date.setTime(time);
} else if (cube.hasAttribute("currency")
&& cube.hasAttribute("rate")) { // a rate Cube
String currency = cube.getAttribute("currency");
double rate = Double.valueOf(cube.getAttribute("rate"));
double rate = Double.parseDouble(cube.getAttribute("rate"));
entries.put(currency, rate);
} // else an empty Cube - ignore
}
@@ -191,13 +192,10 @@ public class ExchangeApiImpl implements ExchangeApi {
Timber.d(ex);
}
synchronized (this) {
if (date != null) {
fetchDate = Calendar.getInstance(TimeZone.getTimeZone("CET"));
fxDate = date;
fxEntries.clear();
fxEntries.putAll(entries);
}
// else don't change what we have
fetchDate = Calendar.getInstance(TimeZone.getTimeZone("CET"));
fxDate = date;
fxEntries.clear();
fxEntries.putAll(entries);
}
}
}

View File

@@ -51,6 +51,11 @@ public class ExchangeApiImpl implements ExchangeApi {
this(HttpUrl.parse("https://api.kraken.com/0/public/Ticker"));
}
@Override
public String getName() {
return "kraken";
}
@Override
public void queryExchangeRate(@NonNull final String baseCurrency, @NonNull final String quoteCurrency,
@NonNull final ExchangeCallback callback) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 m2049r@monerujo.io
* Copyright (c) 2019-2023 m2049r@monerujo.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
// https://developer.android.com/training/basics/network-ops/xml
package com.m2049r.xmrwallet.service.exchange.krakenEcb;
package com.m2049r.xmrwallet.service.exchange.krakenFiat;
import androidx.annotation.NonNull;
@@ -24,23 +24,39 @@ import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate;
import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.ServiceHelper;
import timber.log.Timber;
/*
Gets the XMR/EUR rate from kraken and then gets the EUR/fiat rate from the ECB
Gets the XMR/EUR rate from kraken and then gets the EUR/fiat rate from the yadio
*/
public class ExchangeApiImpl implements ExchangeApi {
static public final String BASE_FIAT = "EUR";
final ExchangeApi krakenApi = new com.m2049r.xmrwallet.service.exchange.kraken.ExchangeApiImpl();
private ExchangeApi getFiatApi(String symbol) {
return ServiceHelper.getFiatApi(symbol);
}
@Override
public String getName() {
return krakenApi.getName() + "+";
}
public String getRealName(String fiatService) {
return getName() + fiatService;
}
@Override
public void queryExchangeRate(@NonNull final String baseCurrency, @NonNull final String quoteCurrency,
@NonNull final ExchangeCallback callback) {
Timber.d("B=%s Q=%s", baseCurrency, quoteCurrency);
if (baseCurrency.equals(quoteCurrency)) {
Timber.d("BASE=QUOTE=1");
callback.onSuccess(new ExchangeRateImpl(baseCurrency, quoteCurrency, 1.0));
callback.onSuccess(new ExchangeRateImpl(getName(), baseCurrency, quoteCurrency, 1.0));
return;
}
@@ -52,24 +68,21 @@ public class ExchangeApiImpl implements ExchangeApi {
final String quote = Helper.BASE_CRYPTO.equals(baseCurrency) ? quoteCurrency : baseCurrency;
final ExchangeApi krakenApi =
new com.m2049r.xmrwallet.service.exchange.kraken.ExchangeApiImpl();
krakenApi.queryExchangeRate(Helper.BASE_CRYPTO, BASE_FIAT, new ExchangeCallback() {
@Override
public void onSuccess(final ExchangeRate krakenRate) {
Timber.d("kraken = %f", krakenRate.getRate());
final ExchangeApi ecbApi =
new com.m2049r.xmrwallet.service.exchange.ecb.ExchangeApiImpl();
ecbApi.queryExchangeRate(BASE_FIAT, quote, new ExchangeCallback() {
final ExchangeApi fiatApi = getFiatApi(quote);
fiatApi.queryExchangeRate(BASE_FIAT, quote, new ExchangeCallback() {
@Override
public void onSuccess(final ExchangeRate ecbRate) {
Timber.d("ECB = %f", ecbRate.getRate());
double rate = ecbRate.getRate() * krakenRate.getRate();
public void onSuccess(final ExchangeRate fiatRate) {
Timber.d("FIAT = %f", fiatRate.getRate());
double rate = fiatRate.getRate() * krakenRate.getRate();
Timber.d("Q=%s QC=%s", quote, quoteCurrency);
if (!quote.equals(quoteCurrency)) rate = 1.0d / rate;
Timber.d("rate = %f", rate);
final ExchangeRate exchangeRate =
new ExchangeRateImpl(baseCurrency, quoteCurrency, rate);
new ExchangeRateImpl(getRealName(fiatApi.getName()), baseCurrency, quoteCurrency, rate);
callback.onSuccess(exchangeRate);
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2019-2023 m2049r et al.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.m2049r.xmrwallet.service.exchange.krakenFiat;
import androidx.annotation.NonNull;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate;
import lombok.Getter;
class ExchangeRateImpl implements ExchangeRate {
@Getter
private final String serviceName;
@Getter
private final String baseCurrency;
@Getter
private final String quoteCurrency;
@Getter
private final double rate;
ExchangeRateImpl(@NonNull final String serviceName, @NonNull final String baseCurrency, @NonNull final String quoteCurrency, double rate) {
super();
this.serviceName = serviceName;
this.baseCurrency = baseCurrency;
this.quoteCurrency = quoteCurrency;
this.rate = rate;
}
}

View File

@@ -0,0 +1,105 @@
/*
* Copyright (c) 2019 m2049r@monerujo.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// https://developer.android.com/training/basics/network-ops/xml
package com.m2049r.xmrwallet.service.exchange.yadio;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeException;
import com.m2049r.xmrwallet.util.NetCipherHelper;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.HttpUrl;
import okhttp3.Response;
import timber.log.Timber;
public class ExchangeApiImpl implements ExchangeApi {
@NonNull
private final HttpUrl baseUrl;
//so we can inject the mockserver url
@VisibleForTesting
public ExchangeApiImpl(@NonNull final HttpUrl baseUrl) {
this.baseUrl = baseUrl;
}
public ExchangeApiImpl() {
this(HttpUrl.parse("https://api.yadio.io/convert/1/eur"));
}
@Override
public String getName() {
return "yadio";
}
@Override
public void queryExchangeRate(@NonNull final String baseCurrency, @NonNull final String quoteCurrency,
@NonNull final ExchangeCallback callback) {
if (!baseCurrency.equals("EUR")) {
callback.onError(new IllegalArgumentException("Only EUR supported as base"));
return;
}
if (baseCurrency.equals(quoteCurrency)) {
callback.onSuccess(new ExchangeRateImpl(quoteCurrency, 1.0, 0));
return;
}
final HttpUrl url = baseUrl.newBuilder()
.addPathSegments(quoteCurrency.substring(0, 3))
.build();
final NetCipherHelper.Request httpRequest = new NetCipherHelper.Request(url);
httpRequest.enqueue(new okhttp3.Callback() {
@Override
public void onFailure(@NonNull final Call call, @NonNull final IOException ex) {
callback.onError(ex);
}
@Override
public void onResponse(@NonNull final Call call, @NonNull final Response response) throws IOException {
if (response.isSuccessful()) {
try {
assert response.body() != null;
final JSONObject json = new JSONObject(response.body().string());
if (json.has("error")) {
Timber.d("%d: %s", response.code(), json.getString("error"));
callback.onError(new ExchangeException(response.code(), json.getString("error")));
return;
}
double rate = json.getDouble("rate");
long timestamp = json.getLong("timestamp");
callback.onSuccess(new ExchangeRateImpl(quoteCurrency, rate, timestamp));
} catch (JSONException ex) {
callback.onError(ex);
}
} else {
callback.onError(new ExchangeException(response.code(), response.message()));
}
}
});
}
}

View File

@@ -14,41 +14,34 @@
* limitations under the License.
*/
package com.m2049r.xmrwallet.service.exchange.krakenEcb;
package com.m2049r.xmrwallet.service.exchange.yadio;
import androidx.annotation.NonNull;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate;
import java.util.Date;
import lombok.Getter;
class ExchangeRateImpl implements ExchangeRate {
private final String baseCurrency;
@Getter
private final String baseCurrency = "EUR";
@Getter
private final String quoteCurrency;
@Getter
private final double rate;
private final Date date;
@Override
public String getServiceName() {
return "kraken+ecb";
return "yadio.io";
}
@Override
public String getBaseCurrency() {
return baseCurrency;
}
@Override
public String getQuoteCurrency() {
return quoteCurrency;
}
@Override
public double getRate() {
return rate;
}
ExchangeRateImpl(@NonNull final String baseCurrency, @NonNull final String quoteCurrency, double rate) {
ExchangeRateImpl(@NonNull final String quoteCurrency, double rate, final long timestamp) {
super();
this.baseCurrency = baseCurrency;
this.quoteCurrency = quoteCurrency;
this.rate = rate;
this.date = timestamp > 0 ? new Date(timestamp) : new Date();
}
}

View File

@@ -23,7 +23,6 @@ import android.os.AsyncTask;
import com.m2049r.xmrwallet.data.BarcodeData;
import com.m2049r.xmrwallet.data.Crypto;
import org.jitsi.dnssec.validator.ValidatingResolver;
import org.xbill.DNS.DClass;
import org.xbill.DNS.Flags;
import org.xbill.DNS.Message;
@@ -35,9 +34,11 @@ import org.xbill.DNS.Section;
import org.xbill.DNS.SimpleResolver;
import org.xbill.DNS.TXTRecord;
import org.xbill.DNS.Type;
import org.xbill.DNS.dnssec.ValidatingResolver;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -107,7 +108,7 @@ public class OpenAliasHelper {
SimpleResolver sr = new SimpleResolver(DNSSEC_SERVERS[new Random().nextInt(DNSSEC_SERVERS.length)]);
ValidatingResolver vr = new ValidatingResolver(sr);
vr.setTimeout(0, DNS_LOOKUP_TIMEOUT);
vr.loadTrustAnchors(new ByteArrayInputStream(ROOT.getBytes("ASCII")));
vr.loadTrustAnchors(new ByteArrayInputStream(ROOT.getBytes(StandardCharsets.US_ASCII)));
Record qr = Record.newRecord(Name.fromConstantString(name + "."), Type.TXT, DClass.IN);
Message response = vr.send(Message.newQuery(qr));
final int rcode = response.getRcode();

View File

@@ -1,9 +1,16 @@
package com.m2049r.xmrwallet.util;
import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.model.NetworkType;
import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import lombok.Getter;
import lombok.NonNull;
import okhttp3.HttpUrl;
public class ServiceHelper {
@@ -19,6 +26,14 @@ public class ServiceHelper {
}
static public ExchangeApi getExchangeApi() {
return new com.m2049r.xmrwallet.service.exchange.krakenEcb.ExchangeApiImpl();
return new com.m2049r.xmrwallet.service.exchange.krakenFiat.ExchangeApiImpl();
}
static private final ExchangeApi[] fiatApis = new ExchangeApi[]{
new com.m2049r.xmrwallet.service.exchange.ecb.ExchangeApiImpl(),
new com.m2049r.xmrwallet.service.exchange.yadio.ExchangeApiImpl()};
static public ExchangeApi getFiatApi(String symbol) {
return (symbol.length() == 3) ? fiatApis[0] : fiatApis[1];
}
}

View File

@@ -126,21 +126,25 @@ public class Toolbar extends MaterialToolbar {
Timber.d("BUTTON_BACK");
bSettings.setImageResource(R.drawable.ic_arrow_back);
bSettings.setVisibility(View.VISIBLE);
bSettings.setContentDescription(getResources().getString(R.string.menu_back));
break;
case BUTTON_CLOSE:
Timber.d("BUTTON_CLOSE");
bSettings.setImageResource(R.drawable.ic_close_white_24dp);
bSettings.setVisibility(View.VISIBLE);
bSettings.setContentDescription(getResources().getString(R.string.menu_close));
break;
case BUTTON_SETTINGS:
Timber.d("BUTTON_SETTINGS");
bSettings.setImageResource(R.drawable.ic_settings);
bSettings.setVisibility(View.VISIBLE);
bSettings.setContentDescription(getResources().getString(R.string.menu_settings));
break;
case BUTTON_CANCEL:
Timber.d("BUTTON_CANCEL");
bSettings.setImageResource(R.drawable.ic_close_white_24dp);
bSettings.setVisibility(View.VISIBLE);
bSettings.setContentDescription(getResources().getString(R.string.menu_cancel));
break;
case BUTTON_NONE:
default:

View File

@@ -60,7 +60,8 @@
android:background="?android:attr/selectableItemBackgroundBorderless"
android:gravity="center"
android:padding="12dp"
android:src="@drawable/ic_network_clearnet" />
android:src="@drawable/ic_network_clearnet"
android:contentDescription="@string/tor_enable" />
<FrameLayout
android:layout_width="match_parent"
@@ -103,7 +104,8 @@
android:background="?android:attr/selectableItemBackgroundBorderless"
android:gravity="center"
android:padding="12dp"
android:src="@drawable/ic_renew" />
android:src="@drawable/ic_renew"
android:contentDescription="@string/node_refresh_hint" />
</RelativeLayout>
<EditText

View File

@@ -69,6 +69,7 @@
app:elevation="0dp"
app:fabSize="normal"
app:pressedTranslationZ="0dp"
app:tint="?attr/toolbarTextColor" />
app:tint="?attr/toolbarTextColor"
android:contentDescription="@string/node_fab_add" />
</FrameLayout>
</RelativeLayout>

View File

@@ -54,7 +54,8 @@
android:layout_marginStart="8dp"
android:background="?android:selectableItemBackground"
android:padding="8dp"
android:src="@drawable/ic_content_copy_24dp" />
android:src="@drawable/ic_content_copy_24dp"
android:contentDescription="@string/copy_receive_address" />
</LinearLayout>
@@ -97,7 +98,8 @@
android:backgroundTint="#ffffffff"
android:clickable="true"
android:focusable="true"
card_view:contentPadding="4dp">
card_view:contentPadding="4dp"
android:contentDescription="@string/label_receive_info_gen_qr_code" >
<TextView
android:id="@+id/tvQrCode"

View File

@@ -56,7 +56,8 @@
android:layout_gravity="center"
android:layout_marginStart="8dp"
android:background="?android:selectableItemBackgroundBorderless"
android:src="@drawable/ic_content_paste_24dp" />
android:src="@drawable/ic_content_paste_24dp"
android:contentDescription="@string/paste_give_address" />
</RelativeLayout>
<LinearLayout
@@ -78,7 +79,8 @@
android:layout_weight="1"
android:background="@null"
android:padding="8dp"
android:src="@drawable/ic_monero" />
android:src="@drawable/ic_monero"
android:contentDescription="XMR" />
<ImageButton
android:id="@+id/ibBTC"
@@ -87,7 +89,8 @@
android:layout_weight="1"
android:background="@null"
android:padding="8dp"
android:src="@drawable/ic_xmrto_btc_off" />
android:src="@drawable/ic_xmrto_btc_off"
android:contentDescription="BTC" />
<ImageButton
android:id="@+id/ibLTC"
@@ -96,7 +99,8 @@
android:layout_weight="1"
android:background="@null"
android:padding="8dp"
android:src="@drawable/ic_xmrto_ltc_off" />
android:src="@drawable/ic_xmrto_ltc_off"
android:contentDescription="LTC"/>
<ImageButton
android:id="@+id/ibETH"
@@ -105,7 +109,8 @@
android:layout_weight="1"
android:background="@null"
android:padding="8dp"
android:src="@drawable/ic_xmrto_eth_off" />
android:src="@drawable/ic_xmrto_eth_off"
android:contentDescription="ETH"/>
<ImageButton
android:id="@+id/ibDASH"
@@ -114,7 +119,8 @@
android:layout_weight="1"
android:background="@null"
android:padding="8dp"
android:src="@drawable/ic_xmrto_dash_off" />
android:src="@drawable/ic_xmrto_dash_off"
android:contentDescription="DASH"/>
<ImageButton
android:id="@+id/ibDOGE"
@@ -123,7 +129,8 @@
android:layout_weight="1"
android:background="@null"
android:padding="8dp"
android:src="@drawable/ic_xmrto_doge_off" />
android:src="@drawable/ic_xmrto_doge_off"
android:contentDescription="DOGE"/>
</LinearLayout>
<FrameLayout

View File

@@ -169,6 +169,31 @@
android:orientation="vertical"
android:visibility="invisible">
<LinearLayout
android:id="@+id/llPocketChange"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:visibility="gone">
<TextView
style="@style/MoneroLabel.Gray"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/pocketchange_title"
android:textAlignment="textStart" />
<TextView
android:id="@+id/tvTxChange"
style="@style/MoneroText.Gray"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:textAlignment="textEnd"
tools:text="143.008000000000" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -182,8 +207,7 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/send_fee_btc_label"
android:textAlignment="textStart"
android:textSize="16sp" />
android:textAlignment="textStart" />
<TextView
android:id="@+id/tvTxFee"
@@ -192,7 +216,6 @@
android:layout_height="wrap_content"
android:layout_weight="2"
android:textAlignment="textEnd"
android:textSize="16sp"
tools:text="0.006817000000" />
</LinearLayout>
@@ -209,8 +232,7 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/send_total_btc_label"
android:textAlignment="textStart"
android:textSize="16sp" />
android:textAlignment="textStart" />
<TextView
android:id="@+id/tvTxTotal"
@@ -219,7 +241,6 @@
android:layout_height="wrap_content"
android:layout_weight="2"
android:textAlignment="textEnd"
android:textSize="16sp"
tools:text="143.014817000000" />
</LinearLayout>
</LinearLayout>

View File

@@ -70,6 +70,7 @@
app:elevation="0dp"
app:fabSize="normal"
app:pressedTranslationZ="0dp"
app:tint="?attr/toolbarTextColor" />
app:tint="?attr/toolbarTextColor"
android:contentDescription="@string/subaddress_add" />
</FrameLayout>
</FrameLayout>

View File

@@ -12,6 +12,7 @@
android:layout_alignEnd="@id/fabL"
android:alpha="0.93"
android:background="?android:attr/colorBackground"
android:focusable="true"
android:visibility="invisible">
<RelativeLayout
@@ -28,7 +29,8 @@
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginEnd="8dp"
android:text="@string/fab_create_new" />
android:text="@string/fab_create_new"
android:contentDescription="@string/fab_create_new" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fabNew"
@@ -61,7 +63,8 @@
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginEnd="8dp"
android:text="@string/fab_restore_viewonly" />
android:text="@string/fab_restore_viewonly"
android:contentDescription="@string/fab_restore_viewonly" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fabView"
@@ -91,7 +94,8 @@
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginEnd="8dp"
android:text="@string/fab_restore_key" />
android:text="@string/fab_restore_key"
android:contentDescription="@string/fab_restore_key" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fabKey"
@@ -121,7 +125,8 @@
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginEnd="8dp"
android:text="@string/fab_restore_seed" />
android:text="@string/fab_restore_seed"
android:contentDescription="@string/fab_restore_seed" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fabSeed"
@@ -151,7 +156,8 @@
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginEnd="8dp"
android:text="@string/menu_restore" />
android:text="@string/menu_restore"
android:contentDescription="@string/menu_restore" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fabImport"
@@ -226,7 +232,8 @@
app:elevation="0dp"
app:fabSize="normal"
app:pressedTranslationZ="0dp"
app:tint="?attr/toolbarTextColor" />
app:tint="?attr/toolbarTextColor"
android:contentDescription="@string/fab_create_new" />
</LinearLayout>
</RelativeLayout>

View File

@@ -32,5 +32,6 @@
android:backgroundTint="#00000000"
android:padding="8dp"
android:src="@drawable/ic_close_white_24dp"
app:tint="?colorOnSecondary" />
app:tint="?colorOnSecondary"
android:contentDescription="@string/label_close" />
</LinearLayout>

View File

@@ -10,7 +10,8 @@
android:background="?android:attr/selectableItemBackgroundBorderless"
android:padding="2dp"
android:src="@drawable/ic_settings"
app:tint="?attr/toolbarTextColor" />
app:tint="?attr/toolbarTextColor"
android:contentDescription="@string/menu_settings" />
<FrameLayout
android:layout_width="wrap_content"

View File

@@ -142,8 +142,6 @@
<string name="status_remaining">Blocs restants</string>
<string name="status_syncing">Escanejant:</string>
<string name="message_strorage_not_writable">Lemmagatzematge extern no es pot escriure! Pànic!</string>
<string name="message_strorage_not_permitted">De veritat que necessitem els permisos per l\'Emmagatzematge Extern!</string>
<string name="message_camera_not_permitted">Sense càmara = Cap escaneig QR!</string>
<string name="label_copy_viewkey">Clau de visualització</string>
@@ -443,7 +441,7 @@
<string name="label_streetmode">Street Mode enabled\nOnly new transactions will be shown</string>
<string name="pocketchange_info">To reduce waiting time on repeated spending, Monerujo can create spare change at the expense of higher fees. It\'ll try to create and maintain 10 coins of the selected amount.</string>
<string name="pocketchange_info">To reduce waiting time on repeated spending, Monerujo can create spare change at the expense of higher fees. It\'ll try to create and maintain at least 6 coins of the selected amount.</string>
<string name="pocketchange_create_title">Create Change</string>
<string name="label_apply">APPLY</string>

File diff suppressed because it is too large Load Diff

View File

@@ -131,8 +131,6 @@
<string name="status_remaining">Μπλοκς που απομένουν</string>
<string name="status_syncing">Έρευνα:</string>
<string name="message_strorage_not_writable">Η εξωτερική αποθήκευση δεν είναι εγγράψιμη! Πανικός!</string>
<string name="message_strorage_not_permitted">Χρειαζόμαστε πραγματικά αυτά τα δικαιώματα εξωτερικής αποθήκευσης!</string>
<string name="message_camera_not_permitted">Όχι κάμερα = Όχι QR σκανάρισμα!</string>
<string name="label_copy_viewkey">Κλειδί Προβολής(View Key)</string>
@@ -445,7 +443,7 @@
<string name="label_streetmode">Street Mode enabled\nOnly new transactions will be shown</string>
<string name="pocketchange_info">To reduce waiting time on repeated spending, Monerujo can create spare change at the expense of higher fees. It\'ll try to create and maintain 10 coins of the selected amount.</string>
<string name="pocketchange_info">To reduce waiting time on repeated spending, Monerujo can create spare change at the expense of higher fees. It\'ll try to create and maintain at least 6 coins of the selected amount.</string>
<string name="pocketchange_create_title">Create Change</string>
<string name="label_apply">APPLY</string>

View File

@@ -142,8 +142,6 @@
<string name="status_remaining">Restaj blokoj</string>
<string name="status_syncing">Skanante:</string>
<string name="message_strorage_not_writable">La ekstera memorilo ne skribeblas! Paniko!</string>
<string name="message_strorage_not_permitted">Ni vere bezonas tiujn permesojn je la ekstera memorilo!</string>
<string name="message_camera_not_permitted">Neniu filmilo = Neniu QR-kodo skaniĝas!</string>
<string name="label_copy_viewkey">Vida ŝlosilo</string>
@@ -443,7 +441,7 @@
<string name="label_streetmode">Street Mode enabled\nOnly new transactions will be shown</string>
<string name="pocketchange_info">To reduce waiting time on repeated spending, Monerujo can create spare change at the expense of higher fees. It\'ll try to create and maintain 10 coins of the selected amount.</string>
<string name="pocketchange_info">To reduce waiting time on repeated spending, Monerujo can create spare change at the expense of higher fees. It\'ll try to create and maintain at least 6 coins of the selected amount.</string>
<string name="pocketchange_create_title">Create Change</string>
<string name="label_apply">APPLY</string>

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