mirror of
https://github.com/m2049r/xmrwallet
synced 2025-09-06 02:27:11 +02:00
Compare commits
23 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
cd6f646b63 | ||
![]() |
aa530caa28 | ||
![]() |
5df43f1274 | ||
![]() |
3b0cb3ffdb | ||
![]() |
300551dbe4 | ||
![]() |
942519adb7 | ||
![]() |
0652a8ba14 | ||
![]() |
04d0bd2ffb | ||
![]() |
8473e66c69 | ||
![]() |
2218ff615c | ||
![]() |
54b55b9f8f | ||
![]() |
5abf84f62b | ||
![]() |
6ff75d221f | ||
![]() |
c90f107c3c | ||
![]() |
a3db18032e | ||
![]() |
9db2c10679 | ||
![]() |
eab85c7f0a | ||
![]() |
6bf3229e77 | ||
![]() |
9f4f626acb | ||
![]() |
434dab55ba | ||
![]() |
59cc6b1864 | ||
![]() |
a6e9d0e77c | ||
![]() |
17df7c3faf |
@@ -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
2
.gitignore
vendored
@@ -16,3 +16,5 @@
|
||||
/app/prodStagenet
|
||||
/app/.cxx
|
||||
/monerujo.id
|
||||
/external-libs/VERSION
|
||||
/external-libs/include/wallet2_api.h
|
||||
|
@@ -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'
|
||||
}
|
||||
|
@@ -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" />
|
||||
|
@@ -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();
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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) {
|
||||
|
@@ -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 {
|
||||
|
@@ -33,5 +33,6 @@ public interface ExchangeApi {
|
||||
void queryExchangeRate(@NonNull final String baseCurrency, @NonNull final String quoteCurrency,
|
||||
@NonNull final ExchangeCallback callback);
|
||||
|
||||
String getName();
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -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) {
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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()));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@@ -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();
|
||||
}
|
||||
}
|
@@ -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();
|
||||
|
@@ -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];
|
||||
}
|
||||
}
|
||||
|
@@ -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:
|
||||
|
@@ -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
|
||||
|
@@ -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>
|
||||
|
@@ -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"
|
||||
|
@@ -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
|
||||
|
@@ -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>
|
||||
|
@@ -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>
|
||||
|
@@ -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>
|
||||
|
@@ -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>
|
||||
|
@@ -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"
|
||||
|
@@ -142,8 +142,6 @@
|
||||
<string name="status_remaining">Blocs restants</string>
|
||||
<string name="status_syncing">Escanejant:</string>
|
||||
|
||||
<string name="message_strorage_not_writable">L’emmagatzematge 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
@@ -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>
|
||||
|
@@ -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
Reference in New Issue
Block a user