1
mirror of https://github.com/m2049r/xmrwallet synced 2025-09-11 14:40:50 +02:00

Compare commits

..

2 Commits

Author SHA1 Message Date
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
44 changed files with 622 additions and 133 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:

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 33
minSdkVersion 21
targetSdkVersion 31
versionCode 3307
versionName "3.3.7 'Pocket Change'"
targetSdkVersion 33
versionCode 3310
versionName "3.3.10 'Argentina'"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
@@ -126,11 +126,11 @@ dependencies {
implementation 'androidx.core:core:1.10.1'
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.1'
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'

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

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

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

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

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

@@ -444,7 +444,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

@@ -445,7 +445,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

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

@@ -433,9 +433,9 @@
<string name="tx_locked">Monto trabado hasta el bloque %1$d (faltan %2$d bloques ≈ %3$,.2f días)</string>
<string name="label_streetmode">Modo calle activado\nSólo se ºmostrarán transacciones nuevas</string>
<string name="label_streetmode">Modo calle activado\nSólo se mostrarán transacciones nuevas</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

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

@@ -683,7 +683,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

@@ -449,7 +449,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

@@ -447,7 +447,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

@@ -448,7 +448,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

@@ -448,7 +448,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

@@ -445,7 +445,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

@@ -445,7 +445,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

@@ -438,7 +438,7 @@ aqui.</string>
<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

@@ -449,8 +449,8 @@
<string name="label_streetmode">Street Mode enabled\nOnly new transactions will be shown</string>
<string name="pocketchange_amount">10 × %1$3.1f XMR</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>
</resources>

View File

@@ -445,7 +445,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