This commit is contained in:
Paxriel 2022-03-02 14:54:14 +08:00
parent 7c78d6be41
commit 8f3d64405d
119 changed files with 2996 additions and 1973 deletions

View File

@ -171,6 +171,10 @@ add_library(wallet-crypto STATIC IMPORTED)
set_target_properties(wallet-crypto PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libwallet-crypto.a)
add_library(cryptonote_format_utils_basic STATIC IMPORTED)
set_target_properties(cryptonote_format_utils_basic PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libcryptonote_format_utils_basic.a)
#############
# System
#############
@ -193,6 +197,7 @@ target_link_libraries( monerujo
wallet
cryptonote_core
cryptonote_basic
cryptonote_format_utils_basic
mnemonics
ringct
ringct_basic

View File

@ -8,8 +8,8 @@ android {
applicationId "com.m2049r.xmrwallet"
minSdkVersion 21
targetSdkVersion 30
versionCode 1008
versionName "2.0.8 'Puginarug'"
versionCode 1301
versionName "2.3.1 'Doménikos'"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
@ -113,27 +113,30 @@ android {
}
}
def getId(name) {
def Properties props = new Properties()
static def getId(name) {
Properties props = new Properties()
props.load(new FileInputStream(new File('monerujo.id')))
return props[name]
}
dependencies {
implementation 'androidx.core:core:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.core:core:1.6.0'
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.2.0'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.2.0-alpha01'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
implementation 'me.dm7.barcodescanner:zxing:1.9.8'
implementation "com.squareup.okhttp3:okhttp:4.9.0"
implementation "io.github.rburgst:okhttp-digest:2.5"
implementation "com.jakewharton.timber:timber:4.7.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.3.0'
implementation 'dnsjava:dnsjava:2.1.9'
@ -142,8 +145,7 @@ dependencies {
implementation 'com.unstoppabledomains:resolution:3.0.0'
implementation 'com.github.brnunes:swipeablerecyclerview:1.0.2'
implementation 'com.github.aelstad:keccakj:1.1.0'
//noinspection GradleDependency
testImplementation "junit:junit:$rootProject.ext.junitVersion"
testImplementation "org.mockito:mockito-all:$rootProject.ext.mockitoVersion"
testImplementation "com.squareup.okhttp3:mockwebserver:4.9.0"
@ -153,3 +155,4 @@ dependencies {
compileOnly 'org.projectlombok:lombok:1.18.16'
annotationProcessor 'org.projectlombok:lombok:1.18.16'
}

View File

@ -11,6 +11,24 @@
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<queries>
<intent>
<action android:name="org.torproject.android.intent.action.START" />
</intent>
<intent>
<action android:name="org.torproject.android.intent.action.STATUS" />
</intent>
<intent>
<action android:name="org.torproject.android.REQUEST_HS_PORT" />
</intent>
<intent>
<action android:name="org.torproject.android.REQUEST_V3_ONION_SERVICE" />
</intent>
<package android:name="org.torproject.android" />
</queries>
<application
android:name=".XmrWalletApplication"
android:allowBackup="false"

View File

@ -229,7 +229,7 @@ std::vector<std::string> java2cpp(JNIEnv *env, jobject arrayList) {
return result;
}
jobject cpp2java(JNIEnv *env, const std::vector<std::string>& vector) {
jobject cpp2java(JNIEnv *env, const std::vector<std::string> &vector) {
jmethodID java_util_ArrayList_ = env->GetMethodID(class_ArrayList, "<init>", "(I)V");
jmethodID java_util_ArrayList_add = env->GetMethodID(class_ArrayList, "add",
@ -301,12 +301,13 @@ Java_com_m2049r_xmrwallet_model_WalletManager_openWalletJ(JNIEnv *env, jobject i
JNIEXPORT jlong JNICALL
Java_com_m2049r_xmrwallet_model_WalletManager_recoveryWalletJ(JNIEnv *env, jobject instance,
jstring path, jstring password,
jstring mnemonic,
jstring mnemonic, jstring offset,
jint networkType,
jlong restoreHeight) {
const char *_path = env->GetStringUTFChars(path, nullptr);
const char *_password = env->GetStringUTFChars(password, nullptr);
const char *_mnemonic = env->GetStringUTFChars(mnemonic, nullptr);
const char *_offset = env->GetStringUTFChars(offset, nullptr);
Monero::NetworkType _networkType = static_cast<Monero::NetworkType>(networkType);
Bitmonero::Wallet *wallet =
@ -315,11 +316,14 @@ Java_com_m2049r_xmrwallet_model_WalletManager_recoveryWalletJ(JNIEnv *env, jobje
std::string(_password),
std::string(_mnemonic),
_networkType,
(uint64_t) restoreHeight);
(uint64_t) restoreHeight,
1, // kdf_rounds
std::string(_offset));
env->ReleaseStringUTFChars(path, _path);
env->ReleaseStringUTFChars(password, _password);
env->ReleaseStringUTFChars(mnemonic, _mnemonic);
env->ReleaseStringUTFChars(offset, _offset);
return reinterpret_cast<jlong>(wallet);
}
@ -531,6 +535,17 @@ Java_com_m2049r_xmrwallet_model_WalletManager_resolveOpenAlias(JNIEnv *env, jobj
return env->NewStringUTF(resolvedAlias.c_str());
}
JNIEXPORT jboolean JNICALL
Java_com_m2049r_xmrwallet_model_WalletManager_setProxy(JNIEnv *env, jobject instance,
jstring address) {
const char *_address = env->GetStringUTFChars(address, nullptr);
bool rc =
Bitmonero::WalletManagerFactory::getWalletManager()->setProxy(std::string(_address));
env->ReleaseStringUTFChars(address, _address);
return rc;
}
//TODO static std::tuple<bool, std::string, std::string, std::string, std::string> checkUpdates(const std::string &software, const std::string &subdir);
JNIEXPORT jboolean JNICALL
@ -559,9 +574,12 @@ Java_com_m2049r_xmrwallet_model_WalletManager_closeJ(JNIEnv *env, jobject instan
/**********************************/
JNIEXPORT jstring JNICALL
Java_com_m2049r_xmrwallet_model_Wallet_getSeed(JNIEnv *env, jobject instance) {
Java_com_m2049r_xmrwallet_model_Wallet_getSeed(JNIEnv *env, jobject instance, jstring seedOffset) {
const char *_seedOffset = env->GetStringUTFChars(seedOffset, nullptr);
Bitmonero::Wallet *wallet = getHandle<Bitmonero::Wallet>(env, instance);
return env->NewStringUTF(wallet->seed().c_str());
jstring seed = env->NewStringUTF(wallet->seed(std::string(_seedOffset)).c_str());
env->ReleaseStringUTFChars(seedOffset, _seedOffset);
return seed;
}
JNIEXPORT jstring JNICALL
@ -727,6 +745,16 @@ Java_com_m2049r_xmrwallet_model_Wallet_getConnectionStatusJ(JNIEnv *env, jobject
//TODO virtual void setTrustedDaemon(bool arg) = 0;
//TODO virtual bool trustedDaemon() const = 0;
JNIEXPORT jboolean JNICALL
Java_com_m2049r_xmrwallet_model_Wallet_setProxy(JNIEnv *env, jobject instance,
jstring address) {
const char *_address = env->GetStringUTFChars(address, nullptr);
Bitmonero::Wallet *wallet = getHandle<Bitmonero::Wallet>(env, instance);
bool rc = wallet->setProxy(std::string(_address));
env->ReleaseStringUTFChars(address, _address);
return rc;
}
JNIEXPORT jlong JNICALL
Java_com_m2049r_xmrwallet_model_Wallet_getBalance(JNIEnv *env, jobject instance,
jint accountIndex) {
@ -1241,7 +1269,7 @@ jobject newTransactionInfo(JNIEnv *env, Bitmonero::TransactionInfo *info) {
#include <stdio.h>
#include <stdlib.h>
jobject cpp2java(JNIEnv *env, const std::vector<Bitmonero::TransactionInfo *>& vector) {
jobject cpp2java(JNIEnv *env, const std::vector<Bitmonero::TransactionInfo *> &vector) {
jmethodID java_util_ArrayList_ = env->GetMethodID(class_ArrayList, "<init>", "(I)V");
jmethodID java_util_ArrayList_add = env->GetMethodID(class_ArrayList, "add",

View File

@ -77,7 +77,7 @@ public class Dispatcher implements PeerRetriever.OnGetPeers {
final NodeInfo nodeInfo = retrievedPeer.getNodeInfo();
Timber.d("Retrieved %s", nodeInfo);
if ((nodeInfo.isValid() || nodeInfo.isFavourite())) {
nodeInfo.setName();
nodeInfo.setDefaultName();
rpcNodes.add(nodeInfo);
Timber.d("RPC: %s", nodeInfo);
// the following is not totally correct but it works (otherwise we need to

View File

@ -16,6 +16,8 @@
package com.m2049r.xmrwallet;
import androidx.annotation.NonNull;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
@ -56,6 +58,7 @@ import com.m2049r.xmrwallet.widget.Toolbar;
import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Objects;
import timber.log.Timber;
@ -78,6 +81,9 @@ public class GenerateFragment extends Fragment {
private TextInputLayout etWalletRestoreHeight;
private Button bGenerate;
private Button bSeedOffset;
private TextInputLayout etSeedOffset;
private String type = null;
private void clearErrorOnTextEntry(final TextInputLayout textInputLayout) {
@ -115,65 +121,51 @@ public class GenerateFragment extends Fragment {
etWalletSpendKey = view.findViewById(R.id.etWalletSpendKey);
etWalletRestoreHeight = view.findViewById(R.id.etWalletRestoreHeight);
bGenerate = view.findViewById(R.id.bGenerate);
bSeedOffset = view.findViewById(R.id.bSeedOffset);
etSeedOffset = view.findViewById(R.id.etSeedOffset);
etWalletAddress.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
etWalletViewKey.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
etWalletSpendKey.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
etWalletName.getEditText().setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
etWalletName.getEditText().setOnFocusChangeListener((v, hasFocus) -> {
if (!hasFocus) {
checkName();
}
}
});
clearErrorOnTextEntry(etWalletName);
etWalletMnemonic.getEditText().setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
etWalletMnemonic.getEditText().setOnFocusChangeListener((v, hasFocus) -> {
if (!hasFocus) {
checkMnemonic();
}
}
});
clearErrorOnTextEntry(etWalletMnemonic);
etWalletAddress.getEditText().setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
etWalletAddress.getEditText().setOnFocusChangeListener((v, hasFocus) -> {
if (!hasFocus) {
checkAddress();
}
}
});
clearErrorOnTextEntry(etWalletAddress);
etWalletViewKey.getEditText().setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
etWalletViewKey.getEditText().setOnFocusChangeListener((v, hasFocus) -> {
if (!hasFocus) {
checkViewKey();
}
}
});
clearErrorOnTextEntry(etWalletViewKey);
etWalletSpendKey.getEditText().setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
etWalletSpendKey.getEditText().setOnFocusChangeListener((v, hasFocus) -> {
if (!hasFocus) {
checkSpendKey();
}
}
});
clearErrorOnTextEntry(etWalletSpendKey);
Helper.showKeyboard(getActivity());
Helper.showKeyboard(requireActivity());
etWalletName.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
etWalletName.getEditText().setOnEditorActionListener((v, actionId, event) -> {
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN))
|| (actionId == EditorInfo.IME_ACTION_NEXT)) {
if (checkName()) {
@ -182,72 +174,50 @@ public class GenerateFragment extends Fragment {
return true;
}
return false;
}
});
if (FingerprintHelper.isDeviceSupported(getContext())) {
llFingerprintAuth.setVisibility(View.VISIBLE);
final SwitchMaterial swFingerprintAllowed = (SwitchMaterial) llFingerprintAuth.getChildAt(0);
swFingerprintAllowed.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
swFingerprintAllowed.setOnClickListener(view1 -> {
if (!swFingerprintAllowed.isChecked()) return;
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getActivity());
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity());
builder.setMessage(Html.fromHtml(getString(R.string.generate_fingerprint_warn)))
.setCancelable(false)
.setPositiveButton(getString(R.string.label_ok), null)
.setNegativeButton(getString(R.string.label_cancel), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
swFingerprintAllowed.setChecked(false);
}
})
.setNegativeButton(getString(R.string.label_cancel), (dialogInterface, i) -> swFingerprintAllowed.setChecked(false))
.show();
}
});
}
if (type.equals(TYPE_NEW)) {
switch (type) {
case TYPE_NEW:
etWalletPassword.getEditText().setImeOptions(EditorInfo.IME_ACTION_UNSPECIFIED);
break;
case TYPE_LEDGER:
etWalletPassword.getEditText().setImeOptions(EditorInfo.IME_ACTION_DONE);
etWalletPassword.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN))
|| (actionId == EditorInfo.IME_ACTION_DONE)) {
Helper.hideKeyboard(getActivity());
generateWallet();
return true;
}
return false;
}
});
} else if (type.equals(TYPE_LEDGER)) {
etWalletPassword.getEditText().setImeOptions(EditorInfo.IME_ACTION_DONE);
etWalletPassword.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
etWalletPassword.getEditText().setOnEditorActionListener((v, actionId, event) -> {
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN))
|| (actionId == EditorInfo.IME_ACTION_DONE)) {
etWalletRestoreHeight.requestFocus();
return true;
}
return false;
}
});
} else if (type.equals(TYPE_SEED)) {
etWalletPassword.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
break;
case TYPE_SEED:
etWalletPassword.getEditText().setOnEditorActionListener((v, actionId, event) -> {
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN))
|| (actionId == EditorInfo.IME_ACTION_NEXT)) {
etWalletMnemonic.requestFocus();
return true;
}
return false;
}
});
etWalletMnemonic.setVisibility(View.VISIBLE);
etWalletMnemonic.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
etWalletMnemonic.getEditText().setOnEditorActionListener((v, actionId, event) -> {
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN))
|| (actionId == EditorInfo.IME_ACTION_NEXT)) {
if (checkMnemonic()) {
@ -256,22 +226,22 @@ public class GenerateFragment extends Fragment {
return true;
}
return false;
}
});
} else if (type.equals(TYPE_KEY) || type.equals(TYPE_VIEWONLY)) {
etWalletPassword.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
bSeedOffset.setVisibility(View.VISIBLE);
bSeedOffset.setOnClickListener(v -> toggleSeedOffset());
break;
case TYPE_KEY:
case TYPE_VIEWONLY:
etWalletPassword.getEditText().setOnEditorActionListener((v, actionId, event) -> {
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN))
|| (actionId == EditorInfo.IME_ACTION_NEXT)) {
etWalletAddress.requestFocus();
return true;
}
return false;
}
});
etWalletAddress.setVisibility(View.VISIBLE);
etWalletAddress.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
etWalletAddress.getEditText().setOnEditorActionListener((v, actionId, event) -> {
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN))
|| (actionId == EditorInfo.IME_ACTION_NEXT)) {
if (checkAddress()) {
@ -280,11 +250,9 @@ public class GenerateFragment extends Fragment {
return true;
}
return false;
}
});
etWalletViewKey.setVisibility(View.VISIBLE);
etWalletViewKey.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
etWalletViewKey.getEditText().setOnEditorActionListener((v, actionId, event) -> {
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN))
|| (actionId == EditorInfo.IME_ACTION_NEXT)) {
if (checkViewKey()) {
@ -297,13 +265,12 @@ public class GenerateFragment extends Fragment {
return true;
}
return false;
}
});
break;
}
if (type.equals(TYPE_KEY)) {
etWalletSpendKey.setVisibility(View.VISIBLE);
etWalletSpendKey.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
etWalletSpendKey.getEditText().setOnEditorActionListener((v, actionId, event) -> {
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN))
|| (actionId == EditorInfo.IME_ACTION_NEXT)) {
if (checkSpendKey()) {
@ -312,29 +279,15 @@ public class GenerateFragment extends Fragment {
return true;
}
return false;
}
});
}
if (!type.equals(TYPE_NEW)) {
etWalletRestoreHeight.setVisibility(View.VISIBLE);
etWalletRestoreHeight.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN))
|| (actionId == EditorInfo.IME_ACTION_DONE)) {
etWalletRestoreHeight.getEditText().setImeOptions(EditorInfo.IME_ACTION_UNSPECIFIED);
}
bGenerate.setOnClickListener(v -> {
Helper.hideKeyboard(getActivity());
generateWallet();
return true;
}
return false;
}
});
}
bGenerate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Helper.hideKeyboard(getActivity());
generateWallet();
}
});
etWalletName.requestFocus();
@ -342,6 +295,18 @@ public class GenerateFragment extends Fragment {
return view;
}
void toggleSeedOffset() {
if (etSeedOffset.getVisibility() == View.VISIBLE) {
etSeedOffset.getEditText().getText().clear();
etSeedOffset.setVisibility(View.GONE);
bSeedOffset.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_baseline_keyboard_arrow_down_24, 0, 0, 0);
} else {
etSeedOffset.setVisibility(View.VISIBLE);
bSeedOffset.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_baseline_keyboard_arrow_up_24, 0, 0, 0);
etSeedOffset.requestFocusFromTouch();
}
}
private boolean checkName() {
String name = etWalletName.getEditText().getText().toString();
boolean ok = true;
@ -387,7 +352,7 @@ public class GenerateFragment extends Fragment {
SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd");
parser.setLenient(false);
height = RestoreHeight.getInstance().getHeight(parser.parse(restoreHeight));
} catch (ParseException ex) {
} catch (ParseException ignored) {
}
if ((height < 0) && (restoreHeight.length() == 8))
try {
@ -395,7 +360,7 @@ public class GenerateFragment extends Fragment {
SimpleDateFormat parser = new SimpleDateFormat("yyyyMMdd");
parser.setLenient(false);
height = RestoreHeight.getInstance().getHeight(parser.parse(restoreHeight));
} catch (ParseException ex) {
} catch (ParseException ignored) {
}
if (height < 0)
try {
@ -466,27 +431,33 @@ public class GenerateFragment extends Fragment {
long height = getHeight();
if (height < 0) height = 0;
if (type.equals(TYPE_NEW)) {
switch (type) {
case TYPE_NEW:
bGenerate.setEnabled(false);
if (fingerprintAuthAllowed) {
KeyStoreHelper.saveWalletUserPass(getActivity(), name, password);
KeyStoreHelper.saveWalletUserPass(requireActivity(), name, password);
}
activityCallback.onGenerate(name, crazyPass);
} else if (type.equals(TYPE_SEED)) {
break;
case TYPE_SEED:
if (!checkMnemonic()) return;
String seed = etWalletMnemonic.getEditText().getText().toString();
final String seed = etWalletMnemonic.getEditText().getText().toString();
bGenerate.setEnabled(false);
if (fingerprintAuthAllowed) {
KeyStoreHelper.saveWalletUserPass(getActivity(), name, password);
KeyStoreHelper.saveWalletUserPass(requireActivity(), name, password);
}
activityCallback.onGenerate(name, crazyPass, seed, height);
} else if (type.equals(TYPE_LEDGER)) {
final String offset = etSeedOffset.getEditText().getText().toString();
activityCallback.onGenerate(name, crazyPass, seed, offset, height);
break;
case TYPE_LEDGER:
bGenerate.setEnabled(false);
if (fingerprintAuthAllowed) {
KeyStoreHelper.saveWalletUserPass(getActivity(), name, password);
KeyStoreHelper.saveWalletUserPass(requireActivity(), name, password);
}
activityCallback.onGenerateLedger(name, crazyPass, height);
} else if (type.equals(TYPE_KEY) || type.equals(TYPE_VIEWONLY)) {
break;
case TYPE_KEY:
case TYPE_VIEWONLY:
if (checkAddress() && checkViewKey() && checkSpendKey()) {
bGenerate.setEnabled(false);
String address = etWalletAddress.getEditText().getText().toString();
@ -496,10 +467,11 @@ public class GenerateFragment extends Fragment {
spendKey = etWalletSpendKey.getEditText().getText().toString();
}
if (fingerprintAuthAllowed) {
KeyStoreHelper.saveWalletUserPass(getActivity(), name, password);
KeyStoreHelper.saveWalletUserPass(requireActivity(), name, password);
}
activityCallback.onGenerate(name, crazyPass, address, viewKey, spendKey, height);
}
break;
}
}
@ -539,7 +511,7 @@ public class GenerateFragment extends Fragment {
public interface Listener {
void onGenerate(String name, String password);
void onGenerate(String name, String password, String seed, long height);
void onGenerate(String name, String password, String seed, String offset, long height);
void onGenerate(String name, String password, String address, String viewKey, String spendKey, long height);
@ -552,7 +524,7 @@ public class GenerateFragment extends Fragment {
}
@Override
public void onAttach(Context context) {
public void onAttach(@NonNull Context context) {
super.onAttach(context);
if (context instanceof GenerateFragment.Listener) {
this.activityCallback = (GenerateFragment.Listener) context;
@ -595,7 +567,7 @@ public class GenerateFragment extends Fragment {
public void convertLedgerSeed() {
if (ledgerDialog != null) return;
final Activity activity = getActivity();
final Activity activity = requireActivity();
View promptsView = getLayoutInflater().inflate(R.layout.prompt_ledger_seed, null);
MaterialAlertDialogBuilder alertDialogBuilder = new MaterialAlertDialogBuilder(activity);
alertDialogBuilder.setView(promptsView);
@ -620,13 +592,9 @@ public class GenerateFragment extends Fragment {
ledgerDialog = alertDialogBuilder.create();
ledgerDialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
ledgerDialog.setOnShowListener(dialog -> {
Button button = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_POSITIVE);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
button.setOnClickListener(view -> {
String ledgerSeed = etSeed.getEditText().getText().toString();
String ledgerPassphrase = etPassphrase.getEditText().getText().toString();
String moneroSeed = Monero.convert(ledgerSeed, ledgerPassphrase);
@ -637,9 +605,7 @@ public class GenerateFragment extends Fragment {
} else {
etSeed.setError(getString(R.string.bad_ledger_seed));
}
}
});
}
});
if (Helper.preventScreenshot()) {

View File

@ -32,6 +32,7 @@ import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
@ -45,6 +46,7 @@ import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.progressindicator.CircularProgressIndicator;
import com.google.android.material.switchmaterial.SwitchMaterial;
import com.google.android.material.textfield.TextInputLayout;
import com.m2049r.xmrwallet.ledger.Ledger;
@ -77,6 +79,7 @@ public class GenerateReviewFragment extends Fragment {
private ProgressBar pbProgress;
private TextView tvWalletPassword;
private TextView tvWalletAddress;
private FrameLayout flWalletMnemonic;
private TextView tvWalletMnemonic;
private TextView tvWalletHeight;
private TextView tvWalletViewKey;
@ -90,6 +93,9 @@ public class GenerateReviewFragment extends Fragment {
private Button bAdvancedInfo;
private Button bAccept;
private Button bSeedOffset;
private TextInputLayout etSeedOffset;
private String walletPath;
private String walletName;
@ -106,6 +112,7 @@ public class GenerateReviewFragment extends Fragment {
tvWalletViewKey = view.findViewById(R.id.tvWalletViewKey);
tvWalletSpendKey = view.findViewById(R.id.tvWalletSpendKey);
tvWalletMnemonic = view.findViewById(R.id.tvWalletMnemonic);
flWalletMnemonic = view.findViewById(R.id.flWalletMnemonic);
tvWalletHeight = view.findViewById(R.id.tvWalletHeight);
bCopyAddress = view.findViewById(R.id.bCopyAddress);
bAdvancedInfo = view.findViewById(R.id.bAdvancedInfo);
@ -115,6 +122,9 @@ public class GenerateReviewFragment extends Fragment {
llSpendKey = view.findViewById(R.id.llSpendKey);
llViewKey = view.findViewById(R.id.llViewKey);
etSeedOffset = view.findViewById(R.id.etSeedOffset);
bSeedOffset = view.findViewById(R.id.bSeedOffset);
bAccept = view.findViewById(R.id.bAccept);
boolean allowCopy = WalletManager.getInstance().getNetworkType() != NetworkType.NetworkType_Mainnet;
@ -126,7 +136,25 @@ public class GenerateReviewFragment extends Fragment {
view.findViewById(R.id.bCopyViewKey).setOnClickListener(v -> copyViewKey());
bCopyAddress.setEnabled(false);
bCopyAddress.setOnClickListener(v -> copyAddress());
view.findViewById(R.id.bAdvancedInfo).setOnClickListener(v -> showAdvancedInfo());
bAdvancedInfo.setOnClickListener(v -> toggleAdvancedInfo());
bSeedOffset.setOnClickListener(v -> toggleSeedOffset());
etSeedOffset.getEditText().addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
showSeed();
}
@Override
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
}
});
Bundle args = getArguments();
type = args.getString(REQUEST_TYPE);
@ -136,18 +164,32 @@ public class GenerateReviewFragment extends Fragment {
return view;
}
String getSeedOffset() {
return etSeedOffset.getEditText().getText().toString();
}
boolean seedOffsetInProgress = false;
void showSeed() {
synchronized (this) {
if (seedOffsetInProgress) return;
seedOffsetInProgress = true;
}
new AsyncShowSeed().executeOnExecutor(MoneroThreadPoolExecutor.MONERO_THREAD_POOL_EXECUTOR, walletPath);
}
void showDetails() {
tvWalletPassword.setText(null);
new AsyncShow().executeOnExecutor(MoneroThreadPoolExecutor.MONERO_THREAD_POOL_EXECUTOR, walletPath);
}
void copyViewKey() {
Helper.clipBoardCopy(getActivity(), getString(R.string.label_copy_viewkey), tvWalletViewKey.getText().toString());
Helper.clipBoardCopy(requireActivity(), getString(R.string.label_copy_viewkey), tvWalletViewKey.getText().toString());
Toast.makeText(getActivity(), getString(R.string.message_copy_viewkey), Toast.LENGTH_SHORT).show();
}
void copyAddress() {
Helper.clipBoardCopy(getActivity(), getString(R.string.label_copy_address), tvWalletAddress.getText().toString());
Helper.clipBoardCopy(requireActivity(), getString(R.string.label_copy_address), tvWalletAddress.getText().toString());
Toast.makeText(getActivity(), getString(R.string.message_copy_address), Toast.LENGTH_SHORT).show();
}
@ -155,15 +197,27 @@ public class GenerateReviewFragment extends Fragment {
Toast.makeText(getActivity(), getString(R.string.message_nocopy), Toast.LENGTH_SHORT).show();
}
void showAdvancedInfo() {
void toggleAdvancedInfo() {
if (llAdvancedInfo.getVisibility() == View.VISIBLE) {
llAdvancedInfo.setVisibility(View.GONE);
bAdvancedInfo.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_baseline_keyboard_arrow_down_24, 0, 0, 0);
} else {
llAdvancedInfo.setVisibility(View.VISIBLE);
bAdvancedInfo.setVisibility(View.GONE);
scrollview.post(new Runnable() {
@Override
public void run() {
scrollview.fullScroll(ScrollView.FOCUS_DOWN);
bAdvancedInfo.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_baseline_keyboard_arrow_up_24, 0, 0, 0);
scrollview.post(() -> scrollview.fullScroll(ScrollView.FOCUS_DOWN));
}
}
void toggleSeedOffset() {
if (etSeedOffset.getVisibility() == View.VISIBLE) {
etSeedOffset.getEditText().getText().clear();
etSeedOffset.setVisibility(View.GONE);
bSeedOffset.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_baseline_keyboard_arrow_down_24, 0, 0, 0);
} else {
etSeedOffset.setVisibility(View.VISIBLE);
bSeedOffset.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_baseline_keyboard_arrow_up_24, 0, 0, 0);
etSeedOffset.requestFocusFromTouch();
}
});
}
String type;
@ -180,7 +234,6 @@ public class GenerateReviewFragment extends Fragment {
String seed;
String viewKey;
String spendKey;
boolean isWatchOnly;
Wallet.Status walletStatus;
boolean dialogOpened = false;
@ -215,14 +268,13 @@ public class GenerateReviewFragment extends Fragment {
name = wallet.getName();
walletStatus = wallet.getStatus();
if (!walletStatus.isOk()) {
Timber.e(walletStatus.getErrorString());
if (closeWallet) wallet.close();
return false;
}
address = wallet.getAddress();
height = wallet.getRestoreHeight();
seed = wallet.getSeed();
seed = wallet.getSeed(getSeedOffset());
switch (wallet.getDeviceType()) {
case Device_Ledger:
viewKey = Ledger.Key();
@ -233,8 +285,7 @@ public class GenerateReviewFragment extends Fragment {
default:
throw new IllegalStateException("Hardware backing not supported. At all!");
}
spendKey = isWatchOnly ? getActivity().getString(R.string.label_watchonly) : wallet.getSecretSpendKey();
isWatchOnly = wallet.isWatchOnly();
spendKey = wallet.isWatchOnly() ? getActivity().getString(R.string.label_watchonly) : wallet.getSecretSpendKey();
if (closeWallet) wallet.close();
return true;
}
@ -367,7 +418,7 @@ public class GenerateReviewFragment extends Fragment {
}
public void hideProgress() {
pbProgress.setVisibility(View.GONE);
pbProgress.setVisibility(View.INVISIBLE);
}
boolean backOk() {
@ -407,10 +458,7 @@ public class GenerateReviewFragment extends Fragment {
Wallet.Status walletStatus = wallet.getStatus();
if (walletStatus.isOk()) {
wallet.setPassword(newPassword);
wallet.store();
ok = true;
} else {
Timber.e(walletStatus.getErrorString());
}
if (closeWallet) wallet.close();
return ok;
@ -470,7 +518,7 @@ public class GenerateReviewFragment extends Fragment {
LayoutInflater li = LayoutInflater.from(getActivity());
View promptsView = li.inflate(R.layout.prompt_changepw, null);
AlertDialog.Builder alertDialogBuilder = new MaterialAlertDialogBuilder(getActivity());
AlertDialog.Builder alertDialogBuilder = new MaterialAlertDialogBuilder(requireActivity());
alertDialogBuilder.setView(promptsView);
final PasswordEntryView etPasswordA = promptsView.findViewById(R.id.etWalletPasswordA);
@ -484,12 +532,10 @@ public class GenerateReviewFragment extends Fragment {
if (FingerprintHelper.isDeviceSupported(getActivity())) {
llFingerprintAuth.setVisibility(View.VISIBLE);
swFingerprintAllowed.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
swFingerprintAllowed.setOnClickListener(view -> {
if (!swFingerprintAllowed.isChecked()) return;
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(getActivity());
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(requireActivity());
builder.setMessage(Html.fromHtml(getString(R.string.generate_fingerprint_warn)))
.setCancelable(false)
.setPositiveButton(getString(R.string.label_ok), null)
@ -500,7 +546,6 @@ public class GenerateReviewFragment extends Fragment {
}
})
.show();
}
});
swFingerprintAllowed.setChecked(FingerprintHelper.isFingerPassValid(getActivity(), walletName));
@ -551,7 +596,7 @@ public class GenerateReviewFragment extends Fragment {
.setNegativeButton(getString(R.string.label_cancel),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Helper.hideKeyboardAlways(getActivity());
Helper.hideKeyboardAlways(requireActivity());
dialog.cancel();
openDialog = null;
}
@ -567,7 +612,7 @@ public class GenerateReviewFragment extends Fragment {
etPasswordB.setError(getString(R.string.generate_bad_passwordB));
} else {
new AsyncChangePassword().execute(newPasswordA, Boolean.toString(swFingerprintAllowed.isChecked()));
Helper.hideKeyboardAlways(getActivity());
Helper.hideKeyboardAlways(requireActivity());
openDialog.dismiss();
openDialog = null;
}
@ -575,8 +620,7 @@ public class GenerateReviewFragment extends Fragment {
});
// accept keyboard "ok"
etPasswordB.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
etPasswordB.getEditText().setOnEditorActionListener((v, actionId, event) -> {
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN))
|| (actionId == EditorInfo.IME_ACTION_DONE)) {
String newPasswordA = etPasswordA.getEditText().getText().toString();
@ -586,14 +630,13 @@ public class GenerateReviewFragment extends Fragment {
etPasswordB.setError(getString(R.string.generate_bad_passwordB));
} else {
new AsyncChangePassword().execute(newPasswordA, Boolean.toString(swFingerprintAllowed.isChecked()));
Helper.hideKeyboardAlways(getActivity());
Helper.hideKeyboardAlways(requireActivity());
openDialog.dismiss();
openDialog = null;
}
return true;
}
return false;
}
});
if (Helper.preventScreenshot()) {
@ -609,4 +652,61 @@ public class GenerateReviewFragment extends Fragment {
&& !key.toLowerCase().equals("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
// ledger implmenetation returns the spend key as f's
}
private class AsyncShowSeed extends AsyncTask<String, Void, Boolean> {
String seed;
String offset;
Wallet.Status walletStatus;
@Override
protected void onPreExecute() {
super.onPreExecute();
offset = getSeedOffset();
flWalletMnemonic.setAlpha(0.1f);
}
@Override
protected Boolean doInBackground(String... params) {
if (params.length != 1) return false;
String walletPath = params[0];
Wallet wallet;
boolean closeWallet;
if (type.equals(GenerateReviewFragment.VIEW_TYPE_WALLET)) {
wallet = GenerateReviewFragment.this.walletCallback.getWallet();
closeWallet = false;
} else {
wallet = WalletManager.getInstance().openWallet(walletPath, getPassword());
closeWallet = true;
}
walletStatus = wallet.getStatus();
if (!walletStatus.isOk()) {
if (closeWallet) wallet.close();
return false;
}
seed = wallet.getSeed(offset);
if (closeWallet) wallet.close();
return true;
}
@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
if (!isAdded()) return; // never mind
if (result) {
if (!seed.isEmpty()) {
llMnemonic.setVisibility(View.VISIBLE);
tvWalletMnemonic.setText(seed);
}
} else {
tvWalletMnemonic.setText(walletStatus.toString());
}
seedOffsetInProgress = false;
if (!getSeedOffset().equals(offset)) { // make sure we have encrypted with the correct offset
showSeed(); // seed has changed in the meantime - recalc
} else
flWalletMnemonic.setAlpha(1);
}
}
}

View File

@ -65,6 +65,7 @@ import com.m2049r.xmrwallet.util.KeyStoreHelper;
import com.m2049r.xmrwallet.util.LegacyStorageHelper;
import com.m2049r.xmrwallet.util.LocaleHelper;
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
import com.m2049r.xmrwallet.util.NetCipherHelper;
import com.m2049r.xmrwallet.util.NightmodeHelper;
import com.m2049r.xmrwallet.util.ThemeHelper;
import com.m2049r.xmrwallet.util.ZipBackup;
@ -701,6 +702,7 @@ public class LoginActivity extends BaseActivity
new AsyncWaitForService().execute();
}
if (!Ledger.isConnected()) attachLedger();
registerTor();
}
private class AsyncWaitForService extends AsyncTask<Void, Void, Void> {
@ -927,7 +929,8 @@ public class LoginActivity extends BaseActivity
}
@Override
public void onGenerate(final String name, final String password, final String seed,
public void onGenerate(final String name, final String password,
final String seed, final String offset,
final long restoreHeight) {
createWallet(name, password,
new WalletCreator() {
@ -939,7 +942,7 @@ public class LoginActivity extends BaseActivity
@Override
public boolean createWallet(File aFile, String password) {
Wallet newWallet = WalletManager.getInstance()
.recoveryWallet(aFile, password, seed, restoreHeight);
.recoveryWallet(aFile, password, seed, offset, restoreHeight);
return checkAndCloseWallet(newWallet);
}
});
@ -1469,4 +1472,69 @@ public class LoginActivity extends BaseActivity
}
return usbManager;
}
//
// Tor (Orbot) stuff
//
void torNotify() {
final Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
if (fragment == null) return;
if (fragment instanceof LoginFragment) {
runOnUiThread(((LoginFragment) fragment)::showNetwork);
}
}
private void deregisterTor() {
NetCipherHelper.deregister();
}
private void registerTor() {
NetCipherHelper.register(new NetCipherHelper.OnStatusChangedListener() {
@Override
public void connected() {
Timber.d("CONNECTED");
WalletManager.getInstance().setProxy(NetCipherHelper.getProxy());
torNotify();
if (waitingUiTask != null) {
Timber.d("RUN");
runOnUiThread(waitingUiTask);
waitingUiTask = null;
}
}
@Override
public void disconnected() {
Timber.d("DISCONNECTED");
WalletManager.getInstance().setProxy("");
torNotify();
}
@Override
public void notInstalled() {
Timber.d("NOT INSTALLED");
WalletManager.getInstance().setProxy("");
torNotify();
}
@Override
public void notEnabled() {
Timber.d("NOT ENABLED");
notInstalled();
}
});
}
private Runnable waitingUiTask;
@Override
public void runOnNetCipher(Runnable uiTask) {
if (waitingUiTask != null) throw new IllegalStateException("only one tor task at a time");
if (NetCipherHelper.hasClient()) {
runOnUiThread(uiTask);
} else {
waitingUiTask = uiTask;
}
}
}

View File

@ -19,6 +19,8 @@ package com.m2049r.xmrwallet;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.Html;
import android.text.Spanned;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@ -28,22 +30,27 @@ import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.progressindicator.CircularProgressIndicator;
import com.m2049r.xmrwallet.data.NodeInfo;
import com.m2049r.xmrwallet.layout.NodeInfoAdapter;
import com.m2049r.xmrwallet.dialog.HelpFragment;
import com.m2049r.xmrwallet.layout.WalletInfoAdapter;
import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.KeyStoreHelper;
import com.m2049r.xmrwallet.util.NetCipherHelper;
import com.m2049r.xmrwallet.util.NodePinger;
import com.m2049r.xmrwallet.util.Notice;
import com.m2049r.xmrwallet.widget.Toolbar;
@ -66,9 +73,9 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
private View tvGuntherSays;
private ImageView ivGunther;
private TextView tvNodeName;
private TextView tvNodeAddress;
private View pbNode;
private View llNode;
private TextView tvNodeInfo;
private ImageButton ibNetwork;
private CircularProgressIndicator pbNetwork;
private Listener activityCallback;
@ -109,6 +116,8 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
Set<NodeInfo> getOrPopulateFavourites();
boolean hasLedger();
void runOnNetCipher(Runnable runnable);
}
@Override
@ -125,6 +134,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
@Override
public void onPause() {
Timber.d("onPause()");
torStatus = null;
super.onPause();
}
@ -135,7 +145,8 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
activityCallback.setTitle(null);
activityCallback.setToolbarButton(Toolbar.BUTTON_CREDITS);
activityCallback.showNet();
pingSelectedNode();
showNetwork();
//activityCallback.runOnNetCipher(this::pingSelectedNode);
}
@Override
@ -183,12 +194,14 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
ViewGroup llNotice = view.findViewById(R.id.llNotice);
Notice.showAll(llNotice, ".*_login");
pbNode = view.findViewById(R.id.pbNode);
llNode = view.findViewById(R.id.llNode);
llNode.setOnClickListener(v -> startNodePrefs());
view.findViewById(R.id.llNode).setOnClickListener(v -> startNodePrefs());
tvNodeName = view.findViewById(R.id.tvNodeName);
tvNodeAddress = view.findViewById(R.id.tvNodeAddress);
tvNodeInfo = view.findViewById(R.id.tvInfo);
view.findViewById(R.id.ibRenew).setOnClickListener(v -> findBestNode());
ibNetwork = view.findViewById(R.id.ibNetwork);
ibNetwork.setOnClickListener(v -> changeNetwork());
ibNetwork.setEnabled(false);
pbNetwork = view.findViewById(R.id.pbNetwork);
Helper.hideKeyboard(getActivity());
@ -387,15 +400,29 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
return nodeList.get(0);
}
private void setSubtext(String status) {
final Context ctx = getContext();
final Spanned text = Html.fromHtml(ctx.getString(R.string.status,
Integer.toHexString(ContextCompat.getColor(ctx, R.color.monerujoGreen) & 0xFFFFFF),
Integer.toHexString(ContextCompat.getColor(ctx, R.color.monerujoBackground) & 0xFFFFFF),
status, ""));
tvNodeInfo.setText(text);
}
private class AsyncFindBestNode extends AsyncTask<Integer, Void, NodeInfo> {
final static int PING_SELECTED = 0;
final static int FIND_BEST = 1;
private boolean netState;
@Override
protected void onPreExecute() {
super.onPreExecute();
pbNode.setVisibility(View.VISIBLE);
llNode.setVisibility(View.INVISIBLE);
tvNodeName.setVisibility(View.GONE);
pbNetwork.setVisibility(View.VISIBLE);
netState = ibNetwork.isClickable();
ibNetwork.setClickable(false);
setSubtext(getString(R.string.node_waiting));
}
@Override
@ -417,8 +444,9 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
}
if (selectedNode == null) { // autoselect
selectedNode = autoselect(favourites);
} else
} else {
selectedNode.testRpcService();
}
} else throw new IllegalStateException();
if ((selectedNode != null) && selectedNode.isValid()) {
activityCallback.setNode(selectedNode);
@ -432,16 +460,17 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
@Override
protected void onPostExecute(NodeInfo result) {
if (!isAdded()) return;
pbNode.setVisibility(View.INVISIBLE);
llNode.setVisibility(View.VISIBLE);
tvNodeName.setVisibility(View.VISIBLE);
pbNetwork.setVisibility(View.INVISIBLE);
ibNetwork.setClickable(netState);
if (result != null) {
Timber.d("found a good node %s", result.toString());
showNode(result);
} else {
tvNodeName.setText(getResources().getText(R.string.node_create_hint));
tvNodeName.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
tvNodeAddress.setText(null);
tvNodeAddress.setVisibility(View.GONE);
tvNodeInfo.setText(null);
tvNodeInfo.setVisibility(View.GONE);
}
}
@ -453,12 +482,70 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
private void showNode(NodeInfo nodeInfo) {
tvNodeName.setText(nodeInfo.getName());
tvNodeName.setCompoundDrawablesWithIntrinsicBounds(NodeInfoAdapter.getPingIcon(nodeInfo), 0, 0, 0);
Helper.showTimeDifference(tvNodeAddress, nodeInfo.getTimestamp());
tvNodeAddress.setVisibility(View.VISIBLE);
nodeInfo.showInfo(tvNodeInfo);
tvNodeInfo.setVisibility(View.VISIBLE);
}
private void startNodePrefs() {
activityCallback.onNodePrefs();
}
// Network (Tor) stuff
private void changeNetwork() {
Timber.d("S: %s", NetCipherHelper.getStatus());
final NetCipherHelper.Status status = NetCipherHelper.getStatus();
if (status == NetCipherHelper.Status.NOT_INSTALLED) {
HelpFragment.display(requireActivity().getSupportFragmentManager(), R.string.help_tor);
} else if (status == NetCipherHelper.Status.NOT_ENABLED) {
Toast.makeText(getActivity(), getString(R.string.tor_enable_background), Toast.LENGTH_LONG).show();
} else {
pbNetwork.setVisibility(View.VISIBLE);
ibNetwork.setEnabled(false);
NetCipherHelper.getInstance().toggle();
}
}
private NetCipherHelper.Status torStatus = null;
void showNetwork() {
final NetCipherHelper.Status status = NetCipherHelper.getStatus();
Timber.d("SHOW %s", status);
if (status == torStatus) return;
torStatus = status;
switch (status) {
case ENABLED:
ibNetwork.setImageResource(R.drawable.ic_network_tor_on);
ibNetwork.setEnabled(true);
ibNetwork.setClickable(true);
pbNetwork.setVisibility(View.INVISIBLE);
break;
case NOT_ENABLED:
case DISABLED:
ibNetwork.setImageResource(R.drawable.ic_network_clearnet);
ibNetwork.setEnabled(true);
ibNetwork.setClickable(true);
pbNetwork.setVisibility(View.INVISIBLE);
break;
case STARTING:
ibNetwork.setImageResource(R.drawable.ic_network_clearnet);
ibNetwork.setEnabled(false);
pbNetwork.setVisibility(View.VISIBLE);
break;
case STOPPING:
ibNetwork.setImageResource(R.drawable.ic_network_clearnet);
ibNetwork.setEnabled(false);
pbNetwork.setVisibility(View.VISIBLE);
break;
case NOT_INSTALLED:
ibNetwork.setEnabled(true);
ibNetwork.setClickable(true);
pbNetwork.setVisibility(View.INVISIBLE);
ibNetwork.setImageResource(R.drawable.ic_network_clearnet);
break;
default:
return;
}
activityCallback.runOnNetCipher(this::pingSelectedNode);
}
}

View File

@ -20,7 +20,6 @@ import android.content.Context;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@ -59,7 +58,6 @@ import java.text.NumberFormat;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Objects;
import java.util.Set;
import timber.log.Timber;
@ -219,8 +217,8 @@ public class NodeFragment extends Fragment
activityCallback.setNode(nodeItem); // this marks it as selected & saves it as well
nodeItem.setSelecting(false);
try {
Objects.requireNonNull(getActivity()).runOnUiThread(() -> nodesAdapter.allowClick(true));
} catch (NullPointerException ex) {
requireActivity().runOnUiThread(() -> nodesAdapter.allowClick(true));
} catch (IllegalStateException ex) {
// it's ok
}
});
@ -403,17 +401,13 @@ public class NodeFragment extends Fragment
etNodeHost.setError(getString(R.string.node_host_empty));
return false;
}
final boolean setHostSuccess = Helper.runWithNetwork(new Helper.Action() {
@Override
public boolean run() {
final boolean setHostSuccess = Helper.runWithNetwork(() -> {
try {
nodeInfo.setHost(host);
return true;
} catch (UnknownHostException ex) {
etNodeHost.setError(getString(R.string.node_host_unresolved));
return false;
}
}
});
if (!setHostSuccess) {
etNodeHost.setError(getString(R.string.node_host_unresolved));
@ -421,14 +415,7 @@ public class NodeFragment extends Fragment
}
etNodeHost.setError(null);
nodeInfo.setRpcPort(port);
// setName() may trigger reverse DNS
Helper.runWithNetwork(new Helper.Action() {
@Override
public boolean run() {
nodeInfo.setName(etNodeName.getEditText().getText().toString().trim());
return true;
}
});
nodeInfo.setUsername(etNodeUser.getEditText().getText().toString().trim());
nodeInfo.setPassword(etNodePass.getEditText().getText().toString()); // no trim for pw
return true;
@ -532,20 +519,10 @@ public class NodeFragment extends Fragment
@Override
public void onShow(final DialogInterface dialog) {
Button testButton = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_NEUTRAL);
testButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
test();
}
});
testButton.setOnClickListener(view -> test());
Button button = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_POSITIVE);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
apply();
}
});
button.setOnClickListener(view -> apply());
}
});
@ -553,15 +530,13 @@ public class NodeFragment extends Fragment
editDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
}
etNodePass.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
etNodePass.getEditText().setOnEditorActionListener((v, actionId, event) -> {
if (actionId == EditorInfo.IME_ACTION_DONE) {
editDialog.getButton(DialogInterface.BUTTON_NEUTRAL).requestFocus();
test();
return true;
}
return false;
}
});
}
@ -589,6 +564,7 @@ public class NodeFragment extends Fragment
} else {
nodesAdapter.setNodes();
}
nodesAdapter.notifyItemChanged(nodeInfo);
}
}
}

View File

@ -67,6 +67,8 @@ public class SubaddressFragment extends Fragment implements SubaddressInfoAdapte
void setToolbarButton(int type);
void showSubaddress(View view, final int subaddressIndex);
void saveWallet();
}
public interface ProgressListener {
@ -217,7 +219,9 @@ public class SubaddressFragment extends Fragment implements SubaddressInfoAdapte
protected Boolean doInBackground(Void... params) {
if (params.length != 0) return false;
wallet.getNewSubaddress();
wallet.store();
if (activityCallback != null) {
activityCallback.saveWallet();
}
return true;
}

View File

@ -505,6 +505,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
Timber.d("onResume()");
}
@Override
public void saveWallet() {
if (mIsBound) { // no point in talking to unbound service
Intent intent = new Intent(getApplicationContext(), WalletService.class);
@ -609,9 +610,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
@Override
public void onWalletStored(final boolean success) {
runOnUiThread(() -> {
if (success) {
Toast.makeText(WalletActivity.this, getString(R.string.status_wallet_unloaded), Toast.LENGTH_SHORT).show();
} else {
if (!success) {
Toast.makeText(WalletActivity.this, getString(R.string.status_wallet_unload_failed), Toast.LENGTH_LONG).show();
}
});

View File

@ -223,11 +223,13 @@ public class WalletFragment extends Fragment
}
void showUnconfirmed(double unconfirmedAmount) {
if (!activityCallback.isStreetMode()) {
if (activityCallback.isStreetMode() || unconfirmedAmount == 0) {
tvUnconfirmedAmount.setText(null);
tvUnconfirmedAmount.setVisibility(View.GONE);
} else {
String unconfirmed = Helper.getFormattedAmount(unconfirmedAmount, true);
tvUnconfirmedAmount.setText(getResources().getString(R.string.xmr_unconfirmed_amount, unconfirmed));
} else {
tvUnconfirmedAmount.setText(null);
tvUnconfirmedAmount.setVisibility(View.VISIBLE);
}
}
@ -349,14 +351,14 @@ public class WalletFragment extends Fragment
Timber.d("onRefreshed(%b)", full);
if (adapter.needsTransactionUpdateOnNewBlock()) {
wallet.getHistory().refresh();
wallet.refreshHistory();
full = true;
}
if (full) {
List<TransactionInfo> list = new ArrayList<>();
final long streetHeight = activityCallback.getStreetModeHeight();
Timber.d("StreetHeight=%d", streetHeight);
wallet.getHistory().refresh();
wallet.refreshHistory();
for (TransactionInfo info : wallet.getHistory().getAll()) {
Timber.d("TxHeight=%d, Label=%s", info.blockheight, info.subaddressLabel);
if ((info.isPending || (info.blockheight >= streetHeight))

View File

@ -21,14 +21,17 @@ import android.content.Context;
import android.content.res.Configuration;
import android.os.Build;
import com.m2049r.xmrwallet.BuildConfig;
import androidx.annotation.NonNull;
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 timber.log.Timber;
public class XmrWalletApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
@ -36,7 +39,10 @@ public class XmrWalletApplication extends Application {
if (BuildConfig.DEBUG) {
Timber.plant(new Timber.DebugTree());
}
NightmodeHelper.setPreferredNightmode(this);
NetCipherHelper.createInstance(this);
}
@Override
@ -45,7 +51,7 @@ public class XmrWalletApplication extends Application {
}
@Override
public void onConfigurationChanged(Configuration configuration) {
public void onConfigurationChanged(@NonNull Configuration configuration) {
super.onConfigurationChanged(configuration);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
LocaleHelper.updateSystemDefaultLocale(configuration.getLocales().get(0));

View File

@ -28,7 +28,11 @@ public enum DefaultNodes {
SUPPORTXMR("node.supportxmr.com:18081"),
HASHVAULT("nodes.hashvault.pro:18081"),
MONEROWORLD("node.moneroworld.com:18089"),
XMRTW("opennode.xmr-tw.org:18089");
XMRTW("opennode.xmr-tw.org: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");
@Getter
private final String uri;

View File

@ -18,6 +18,7 @@ package com.m2049r.xmrwallet.data;
import com.m2049r.xmrwallet.model.NetworkType;
import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.util.OnionHelper;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
@ -35,11 +36,63 @@ public class Node {
static public final String STAGENET = "stagenet";
static public final String TESTNET = "testnet";
static class Address {
final private InetAddress inet;
final private String onion;
public boolean isOnion() {
return onion != null;
}
public String getHostName() {
if (inet != null) {
return inet.getHostName();
} else {
return onion;
}
}
public String getHostAddress() {
if (inet != null) {
return inet.getHostAddress();
} else {
return onion;
}
}
private Address(InetAddress address, String onion) {
this.inet = address;
this.onion = onion;
}
static Address of(InetAddress address) {
return new Address(address, null);
}
static Address of(String host) throws UnknownHostException {
if (OnionHelper.isOnionHost(host)) {
return new Address(null, host);
} else {
return new Address(InetAddress.getByName(host), null);
}
}
@Override
public int hashCode() {
return getHostAddress().hashCode();
}
@Override
public boolean equals(Object other) {
return (other instanceof Address) && (getHostAddress().equals(((Address) other).getHostAddress()));
}
}
@Getter
private String name = null;
@Getter
final private NetworkType networkType;
InetAddress hostAddress;
Address hostAddress;
@Getter
private String host;
@Getter
@ -74,6 +127,10 @@ public class Node {
&& (networkType == anotherNode.networkType));
}
public boolean isOnion() {
return hostAddress.isOnion();
}
static public Node fromString(String nodeString) {
try {
return new Node(nodeString);
@ -205,7 +262,7 @@ public class Node {
// constructor used for created nodes from retrieved peer lists
public Node(InetSocketAddress socketAddress) {
this();
this.hostAddress = socketAddress.getAddress();
this.hostAddress = Address.of(socketAddress.getAddress());
this.host = socketAddress.getHostString();
this.rpcPort = 0; // unknown
this.levinPort = socketAddress.getPort();
@ -225,17 +282,25 @@ public class Node {
if ((host == null) || (host.isEmpty()))
throw new UnknownHostException("loopback not supported (yet?)");
this.host = host;
this.hostAddress = InetAddress.getByName(host);
this.hostAddress = Address.of(host);
}
public void setName() {
if (name == null)
this.name = hostAddress.getHostName();
public void setDefaultName() {
if (name != null) return;
String nodeName = hostAddress.getHostName();
if (hostAddress.isOnion()) {
nodeName = nodeName.substring(0, nodeName.length() - ".onion".length());
if (nodeName.length() > 16) {
nodeName = nodeName.substring(0, 8) + "" + nodeName.substring(nodeName.length() - 6);
}
nodeName = nodeName + ".onion";
}
this.name = nodeName;
}
public void setName(String name) {
if ((name == null) || (name.isEmpty()))
this.name = hostAddress.getHostName();
setDefaultName();
else
this.name = name;
}

View File

@ -16,14 +16,19 @@
package com.m2049r.xmrwallet.data;
import com.burgstaller.okhttp.AuthenticationCacheInterceptor;
import com.burgstaller.okhttp.CachingAuthenticatorDecorator;
import com.burgstaller.okhttp.digest.CachingAuthenticator;
import com.burgstaller.okhttp.digest.Credentials;
import com.burgstaller.okhttp.digest.DigestAuthenticator;
import android.content.Context;
import android.text.Html;
import android.text.Spanned;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import com.m2049r.levin.scanner.LevinPeer;
import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.util.NetCipherHelper;
import com.m2049r.xmrwallet.util.NetCipherHelper.Request;
import com.m2049r.xmrwallet.util.NodePinger;
import com.m2049r.xmrwallet.util.OkHttpHelper;
import com.m2049r.xmrwallet.util.ThemeHelper;
import org.json.JSONException;
import org.json.JSONObject;
@ -32,17 +37,12 @@ import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import lombok.Getter;
import lombok.Setter;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import timber.log.Timber;
@ -94,7 +94,7 @@ public class NodeInfo extends Node {
synchronized public SocketAddress getLevinSocketAddress() {
if (levinSocketAddress == null) {
// use default peer port if not set - very few peers use nonstandard port
levinSocketAddress = new InetSocketAddress(hostAddress, getDefaultLevinPort());
levinSocketAddress = new InetSocketAddress(hostAddress.getHostAddress(), getDefaultLevinPort());
}
return levinSocketAddress;
}
@ -180,7 +180,7 @@ public class NodeInfo extends Node {
return sb.toString();
}
private static final int HTTP_TIMEOUT = OkHttpHelper.HTTP_TIMEOUT;
private static final int HTTP_TIMEOUT = 1000; //ms
public static final double PING_GOOD = HTTP_TIMEOUT / 3.0; //ms
public static final double PING_MEDIUM = 2 * PING_GOOD; //ms
public static final double PING_BAD = HTTP_TIMEOUT;
@ -196,32 +196,29 @@ public class NodeInfo extends Node {
return result;
}
private boolean testRpcService(int port) {
Timber.d("Testing %s", toNodeString());
clear();
try {
OkHttpClient client = OkHttpHelper.getEagerClient();
if (!getUsername().isEmpty()) {
final DigestAuthenticator authenticator =
new DigestAuthenticator(new Credentials(getUsername(), getPassword()));
final Map<String, CachingAuthenticator> authCache = new ConcurrentHashMap<>();
client = client.newBuilder()
.authenticator(new CachingAuthenticatorDecorator(authenticator, authCache))
.addInterceptor(new AuthenticationCacheInterceptor(authCache))
.build();
}
HttpUrl url = new HttpUrl.Builder()
private Request rpcServiceRequest(int port) {
final HttpUrl url = new HttpUrl.Builder()
.scheme("http")
.host(getHostAddress())
.host(getHost())
.port(port)
.addPathSegment("json_rpc")
.build();
final RequestBody reqBody = RequestBody
.create(MediaType.parse("application/json"),
"{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"getlastblockheader\"}");
Request request = OkHttpHelper.getPostRequest(url, reqBody);
final String json = "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"getlastblockheader\"}";
return new Request(url, json, getUsername(), getPassword());
}
private boolean testRpcService(int port) {
Timber.d("Testing %s", toNodeString());
clear();
if (hostAddress.isOnion() && !NetCipherHelper.isTor()) {
tested = true; // sortof
responseCode = 418; // I'm a teapot - or I need an Onion - who knows
return false; // autofail
}
try {
long ta = System.nanoTime();
try (Response response = client.newCall(request).execute()) {
try (Response response = rpcServiceRequest(port).execute()) {
Timber.d("%s: %s", response.code(), response.request().url());
responseTime = (System.nanoTime() - ta) / 1000000.0;
responseCode = response.code();
if (response.isSuccessful()) {
@ -243,7 +240,7 @@ public class NodeInfo extends Node {
}
}
} catch (IOException | JSONException ex) {
Timber.d(ex);
Timber.d("EX: %s", ex.getMessage()); //TODO: do something here (show error?)
} finally {
tested = true;
}
@ -264,4 +261,43 @@ public class NodeInfo extends Node {
}
return false;
}
static public final int STALE_NODE_HOURS = 2;
public void showInfo(TextView view, String info, boolean isError) {
final Context ctx = view.getContext();
final Spanned text = Html.fromHtml(ctx.getString(R.string.status,
Integer.toHexString(ContextCompat.getColor(ctx, R.color.monerujoGreen) & 0xFFFFFF),
Integer.toHexString(ContextCompat.getColor(ctx, R.color.monerujoBackground) & 0xFFFFFF),
(hostAddress.isOnion() ? "&nbsp;.onion&nbsp;&nbsp;" : ""), " " + info));
view.setText(text);
if (isError)
view.setTextColor(ThemeHelper.getThemedColor(ctx, R.attr.colorError));
else
view.setTextColor(ThemeHelper.getThemedColor(ctx, R.attr.colorPrimary));
}
public void showInfo(TextView view) {
if (!isTested()) {
showInfo(view, "", false);
return;
}
final Context ctx = view.getContext();
final long now = Calendar.getInstance().getTimeInMillis() / 1000;
final long secs = (now - timestamp);
final long mins = secs / 60;
final long hours = mins / 60;
final long days = hours / 24;
String info;
if (mins < 2) {
info = ctx.getString(R.string.node_updated_now, secs);
} else if (hours < 2) {
info = ctx.getString(R.string.node_updated_mins, mins);
} else if (days < 2) {
info = ctx.getString(R.string.node_updated_hours, hours);
} else {
info = ctx.getString(R.string.node_updated_days, days);
}
showInfo(view, info, hours >= STALE_NODE_HOURS);
}
}

View File

@ -17,13 +17,17 @@
package com.m2049r.xmrwallet.dialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.text.Html;
import android.text.Spanned;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
@ -31,15 +35,20 @@ import androidx.fragment.app.FragmentTransaction;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.util.NetCipherHelper;
public class HelpFragment extends DialogFragment {
static final String TAG = "HelpFragment";
private static final String HELP_ID = "HELP_ID";
private static final String TOR_BUTTON = "TOR";
public static HelpFragment newInstance(int helpResourceId) {
HelpFragment fragment = new HelpFragment();
Bundle bundle = new Bundle();
bundle.putInt(HELP_ID, helpResourceId);
// a hack for the tor button
if (helpResourceId == R.string.help_tor)
bundle.putInt(TOR_BUTTON, 7);
fragment.setArguments(bundle);
return fragment;
}
@ -54,27 +63,53 @@ public class HelpFragment extends DialogFragment {
HelpFragment.newInstance(helpResourceId).show(ft, TAG);
}
private Spanned getHtml(String html, double textSize) {
final Html.ImageGetter imageGetter = source -> {
final int imageId = getResources().getIdentifier(source.replace("/", ""), "drawable", requireActivity().getPackageName());
// Don't die if we don't find the image - use a heart instead
final Drawable drawable = ContextCompat.getDrawable(requireActivity(), imageId > 0 ? imageId : R.drawable.ic_favorite_24dp);
final double f = textSize / drawable.getIntrinsicHeight();
drawable.setBounds(0, 0, (int) (f * drawable.getIntrinsicWidth()), (int) textSize);
return drawable;
};
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY, imageGetter, null);
} else {
return Html.fromHtml(html, imageGetter, null);
}
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final View view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_help, null);
int helpId = 0;
boolean torButton = false;
Bundle arguments = getArguments();
if (arguments != null) {
helpId = arguments.getInt(HELP_ID);
torButton = arguments.getInt(TOR_BUTTON) > 0;
}
final TextView helpTv = view.findViewById(R.id.tvHelp);
if (helpId > 0)
((TextView) view.findViewById(R.id.tvHelp)).setText(Html.fromHtml(getString(helpId)));
helpTv.setText(getHtml(getString(helpId), helpTv.getTextSize()));
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getActivity())
.setView(view)
.setNegativeButton(R.string.help_ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
MaterialAlertDialogBuilder builder =
new MaterialAlertDialogBuilder(requireActivity())
.setView(view);
if (torButton) {
builder.setNegativeButton(R.string.help_nok,
(dialog, id) -> dialog.dismiss())
.setPositiveButton(R.string.help_getorbot,
(dialog, id) -> {
dialog.dismiss();
}
NetCipherHelper.getInstance().installOrbot(requireActivity());
});
} else {
builder.setNegativeButton(R.string.help_ok,
(dialog, id) -> dialog.dismiss());
}
return builder.create();
}
}

View File

@ -22,6 +22,7 @@ import android.os.Bundle;
import android.text.Editable;
import android.text.Html;
import android.text.InputType;
import android.text.Spanned;
import android.text.TextWatcher;
import android.util.Patterns;
import android.view.KeyEvent;
@ -95,6 +96,7 @@ public class SendAddressWizardFragment extends SendWizardFragment {
private TextInputLayout etAddress;
private TextInputLayout etNotes;
private TextView tvXmrTo;
private TextView tvTor;
private Map<Crypto, ImageButton> ibCrypto;
final private Set<Crypto> possibleCryptos = new HashSet<>();
private Crypto selectedCrypto = null;
@ -121,11 +123,12 @@ public class SendAddressWizardFragment extends SendWizardFragment {
View view = inflater.inflate(R.layout.fragment_send_address, container, false);
if (Helper.ALLOW_SHIFT) {
tvTor = view.findViewById(R.id.tvTor);
tvXmrTo = view.findViewById(R.id.tvXmrTo);
ibCrypto = new HashMap<>();
for (Crypto crypto : Crypto.values()) {
final ImageButton button = view.findViewById(crypto.getButtonId());
if (Helper.ALLOW_SHIFT || (crypto == Crypto.XMR)) {
ibCrypto.put(crypto, button);
button.setOnClickListener(v -> {
if (possibleCryptos.contains(crypto)) {
@ -141,14 +144,21 @@ public class SendAddressWizardFragment extends SendWizardFragment {
} else {
tvXmrTo.setText(Html.fromHtml(getString(R.string.info_xmrto_help_xmr)));
tvXmrTo.setVisibility(View.VISIBLE);
tvTor.setVisibility(View.INVISIBLE);
}
}
});
} else {
button.setImageResource(crypto.getIconDisabledId());
button.setImageAlpha(128);
button.setEnabled(false);
}
}
if (!Helper.ALLOW_SHIFT) {
tvTor.setVisibility(View.VISIBLE);
}
updateCryptoButtons(true);
} else {
view.findViewById(R.id.llExchange).setVisibility(View.GONE);
}
etAddress = view.findViewById(R.id.etAddress);
etAddress.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
etAddress.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
@ -515,6 +525,7 @@ public class SendAddressWizardFragment extends SendWizardFragment {
Timber.d("BUT ONLY XMR SUPPORTED");
barcodeData = null;
sendListener.setBarcodeData(barcodeData);
return;
}
if (barcodeData.address != null) {
etAddress.getEditText().setText(barcodeData.address);

View File

@ -35,7 +35,6 @@ import com.m2049r.xmrwallet.service.shift.sideshift.api.QueryOrderParameters;
import com.m2049r.xmrwallet.service.shift.sideshift.api.SideShiftApi;
import com.m2049r.xmrwallet.service.shift.sideshift.network.SideShiftApiImpl;
import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.OkHttpHelper;
import com.m2049r.xmrwallet.util.ServiceHelper;
import com.m2049r.xmrwallet.widget.ExchangeOtherEditText;
import com.m2049r.xmrwallet.widget.SendProgressView;
@ -255,8 +254,7 @@ public class SendBtcAmountWizardFragment extends SendWizardFragment {
if (xmrToApi == null) {
synchronized (this) {
if (xmrToApi == null) {
xmrToApi = new SideShiftApiImpl(OkHttpHelper.getOkHttpClient(),
ServiceHelper.getXmrToBaseUrl());
xmrToApi = new SideShiftApiImpl(ServiceHelper.getXmrToBaseUrl());
}
}
}

View File

@ -37,7 +37,6 @@ import com.m2049r.xmrwallet.service.shift.sideshift.api.RequestQuote;
import com.m2049r.xmrwallet.service.shift.sideshift.api.SideShiftApi;
import com.m2049r.xmrwallet.service.shift.sideshift.network.SideShiftApiImpl;
import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.OkHttpHelper;
import com.m2049r.xmrwallet.util.ServiceHelper;
import com.m2049r.xmrwallet.widget.SendProgressView;
@ -543,8 +542,7 @@ public class SendBtcConfirmWizardFragment extends SendWizardFragment implements
if (xmrToApi == null) {
synchronized (this) {
if (xmrToApi == null) {
xmrToApi = new SideShiftApiImpl(OkHttpHelper.getOkHttpClient(),
ServiceHelper.getXmrToBaseUrl());
xmrToApi = new SideShiftApiImpl(ServiceHelper.getXmrToBaseUrl());
}
}
}

View File

@ -39,7 +39,6 @@ import com.m2049r.xmrwallet.service.shift.sideshift.api.QueryOrderStatus;
import com.m2049r.xmrwallet.service.shift.sideshift.api.SideShiftApi;
import com.m2049r.xmrwallet.service.shift.sideshift.network.SideShiftApiImpl;
import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.OkHttpHelper;
import com.m2049r.xmrwallet.util.ServiceHelper;
import java.text.NumberFormat;
@ -245,8 +244,7 @@ public class SendBtcSuccessWizardFragment extends SendWizardFragment {
if (xmrToApi == null) {
synchronized (this) {
if (xmrToApi == null) {
xmrToApi = new SideShiftApiImpl(OkHttpHelper.getOkHttpClient(),
ServiceHelper.getXmrToBaseUrl());
xmrToApi = new SideShiftApiImpl(ServiceHelper.getXmrToBaseUrl());
}
}
}

View File

@ -23,28 +23,25 @@ import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentActivity;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.RecyclerView;
import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.data.NodeInfo;
import com.m2049r.xmrwallet.util.ThemeHelper;
import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.dialog.HelpFragment;
import com.m2049r.xmrwallet.util.NetCipherHelper;
import java.net.HttpURLConnection;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.TimeZone;
public class NodeInfoAdapter extends RecyclerView.Adapter<NodeInfoAdapter.ViewHolder> {
private final SimpleDateFormat TS_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm");
public interface OnInteractionListener {
void onInteraction(View view, NodeInfo item);
@ -54,14 +51,16 @@ public class NodeInfoAdapter extends RecyclerView.Adapter<NodeInfoAdapter.ViewHo
private final List<NodeInfo> nodeItems = new ArrayList<>();
private final OnInteractionListener listener;
private final Context context;
private final FragmentActivity activity;
public NodeInfoAdapter(Context context, OnInteractionListener listener) {
this.context = context;
public NodeInfoAdapter(FragmentActivity activity, OnInteractionListener listener) {
this.activity = activity;
this.listener = listener;
Calendar cal = Calendar.getInstance();
TimeZone tz = cal.getTimeZone(); //get the local time zone.
TS_FORMATTER.setTimeZone(tz);
}
public void notifyItemChanged(NodeInfo nodeInfo) {
final int pos = nodeItems.indexOf(nodeInfo);
if (pos >= 0) notifyItemChanged(pos);
}
private static class NodeDiff extends DiffCallback<NodeInfo> {
@ -142,7 +141,7 @@ public class NodeInfoAdapter extends RecyclerView.Adapter<NodeInfoAdapter.ViewHo
final ImageButton ibBookmark;
final View pbBookmark;
final TextView tvName;
final TextView tvIp;
final TextView tvInfo;
final ImageView ivPing;
NodeInfo nodeItem;
@ -151,7 +150,7 @@ public class NodeInfoAdapter extends RecyclerView.Adapter<NodeInfoAdapter.ViewHo
ibBookmark = itemView.findViewById(R.id.ibBookmark);
pbBookmark = itemView.findViewById(R.id.pbBookmark);
tvName = itemView.findViewById(R.id.tvName);
tvIp = itemView.findViewById(R.id.tvAddress);
tvInfo = itemView.findViewById(R.id.tvInfo);
ivPing = itemView.findViewById(R.id.ivPing);
ibBookmark.setOnClickListener(v -> {
nodeItem.toggleFavourite();
@ -179,13 +178,12 @@ public class NodeInfoAdapter extends RecyclerView.Adapter<NodeInfoAdapter.ViewHo
ivPing.setImageResource(getPingIcon(nodeItem));
if (nodeItem.isTested()) {
if (nodeItem.isValid()) {
Helper.showTimeDifference(tvIp, nodeItem.getTimestamp());
nodeItem.showInfo(tvInfo);
} else {
tvIp.setText(getResponseErrorText(context, nodeItem.getResponseCode()));
tvIp.setTextColor(ThemeHelper.getThemedColor(context, R.attr.colorError));
nodeItem.showInfo(tvInfo, getResponseErrorText(activity, nodeItem.getResponseCode()), true);
}
} else {
tvIp.setText(context.getResources().getString(R.string.node_testing, nodeItem.getHostAddress()));
nodeItem.showInfo(tvInfo);
}
itemView.setSelected(nodeItem.isSelected());
itemView.setClickable(itemsClickable);
@ -201,6 +199,16 @@ public class NodeInfoAdapter extends RecyclerView.Adapter<NodeInfoAdapter.ViewHo
int position = getAdapterPosition(); // gets item position
if (position != RecyclerView.NO_POSITION) { // Check if an item was deleted, but the user clicked it before the UI removed it
final NodeInfo node = nodeItems.get(position);
if (node.isOnion()) {
switch (NetCipherHelper.getStatus()) {
case NOT_INSTALLED:
HelpFragment.display(activity.getSupportFragmentManager(), R.string.help_tor);
return;
case DISABLED:
HelpFragment.display(activity.getSupportFragmentManager(), R.string.help_tor_enable);
return;
}
}
node.setSelecting(true);
allowClick(false);
listener.onInteraction(view, node);
@ -245,6 +253,8 @@ public class NodeInfoAdapter extends RecyclerView.Adapter<NodeInfoAdapter.ViewHo
return ctx.getResources().getString(R.string.node_general_error);
} else if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) {
return ctx.getResources().getString(R.string.node_auth_error);
} else if (responseCode == 418) {
return ctx.getResources().getString(R.string.node_tor_error);
} else {
return ctx.getResources().getString(R.string.node_test_error, responseCode);
}

View File

@ -49,8 +49,6 @@ import java.util.TimeZone;
import timber.log.Timber;
public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfoAdapter.ViewHolder> {
private final static int MAX_CONFIRMATIONS = 10;
private final static SimpleDateFormat DATETIME_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm");
private final int outboundColour;
@ -81,7 +79,7 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
}
public boolean needsTransactionUpdateOnNewBlock() {
return (infoItems.size() > 0) && (infoItems.get(0).confirmations < MAX_CONFIRMATIONS);
return (infoItems.size() > 0) && !infoItems.get(0).isConfirmed();
}
private static class TransactionInfoDiff extends DiffCallback<TransactionInfo> {
@ -102,7 +100,7 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
return (oldItem.direction == newItem.direction)
&& (oldItem.isPending == newItem.isPending)
&& (oldItem.isFailed == newItem.isFailed)
&& (oldItem.confirmations == newItem.confirmations)
&& ((oldItem.confirmations == newItem.confirmations) || (oldItem.isConfirmed()))
&& (oldItem.subaddressLabel.equals(newItem.subaddressLabel))
&& (Objects.equals(oldItem.notes, newItem.notes));
}
@ -154,7 +152,7 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
final ImageView ivTxType;
final TextView tvAmount;
final TextView tvFee;
final TextView tvFailed;
final TextView tvPaymentId;
final TextView tvDateTime;
final CircularProgressIndicator pbConfirmations;
@ -165,11 +163,11 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
super(itemView);
ivTxType = itemView.findViewById(R.id.ivTxType);
tvAmount = itemView.findViewById(R.id.tx_amount);
tvFee = itemView.findViewById(R.id.tx_fee);
tvFailed = itemView.findViewById(R.id.tx_failed);
tvPaymentId = itemView.findViewById(R.id.tx_paymentid);
tvDateTime = itemView.findViewById(R.id.tx_datetime);
pbConfirmations = itemView.findViewById(R.id.pbConfirmations);
pbConfirmations.setMax(MAX_CONFIRMATIONS);
pbConfirmations.setMax(TransactionInfo.CONFIRMATION);
tvConfirmations = itemView.findViewById(R.id.tvConfirmations);
}
@ -205,18 +203,10 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
tvAmount.setText(context.getString(R.string.tx_list_amount_positive, displayAmount));
}
if ((infoItem.fee > 0)) {
String fee = Helper.getDisplayAmount(infoItem.fee, Helper.DISPLAY_DIGITS_INFO);
tvFee.setText(context.getString(R.string.tx_list_fee, fee));
tvFee.setVisibility(View.VISIBLE);
} else {
tvFee.setText("");
tvFee.setVisibility(View.GONE);
}
tvFailed.setVisibility(View.GONE);
if (infoItem.isFailed) {
this.tvAmount.setText(context.getString(R.string.tx_list_amount_failed, displayAmount));
this.tvFee.setText(context.getString(R.string.tx_list_failed_text));
tvFee.setVisibility(View.VISIBLE);
tvFailed.setVisibility(View.VISIBLE);
setTxColour(failedColour);
pbConfirmations.setVisibility(View.GONE);
tvConfirmations.setVisibility(View.GONE);
@ -228,9 +218,9 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
tvConfirmations.setVisibility(View.GONE);
} else if (infoItem.direction == TransactionInfo.Direction.Direction_In) {
setTxColour(inboundColour);
final int confirmations = (int) infoItem.confirmations;
if (confirmations <= MAX_CONFIRMATIONS) {
if (!infoItem.isConfirmed()) {
pbConfirmations.setVisibility(View.VISIBLE);
final int confirmations = (int) infoItem.confirmations;
pbConfirmations.setProgressCompat(confirmations, true);
final String confCount = Integer.toString(confirmations);
tvConfirmations.setText(confCount);

View File

@ -43,7 +43,7 @@ public class TransactionHistory {
this.accountIndex = accountIndex;
}
public void loadNotes(Wallet wallet) {
private void loadNotes(Wallet wallet) {
for (TransactionInfo info : transactions) {
info.notes = wallet.getUserNote(info.hash);
}
@ -61,30 +61,22 @@ public class TransactionHistory {
private List<TransactionInfo> transactions = new ArrayList<>();
public void refreshWithNotes(Wallet wallet) {
void refreshWithNotes(Wallet wallet) {
refresh();
loadNotes(wallet);
}
// public void refresh() {
// transactions = refreshJ();
// }
public void refresh() {
private void refresh() {
List<TransactionInfo> transactionInfos = refreshJ();
Timber.d("refreshed %d", transactionInfos.size());
Timber.d("refresh size=%d", transactionInfos.size());
for (Iterator<TransactionInfo> iterator = transactionInfos.iterator(); iterator.hasNext(); ) {
TransactionInfo info = iterator.next();
if (info.accountIndex != accountIndex) {
iterator.remove();
Timber.d("removed %s", info.hash);
} else {
Timber.d("kept %s", info.hash);
}
}
transactions = transactionInfos;
}
private native List<TransactionInfo> refreshJ();
}

View File

@ -29,6 +29,8 @@ import lombok.RequiredArgsConstructor;
// this is not the TransactionInfo from the API as that is owned by the TransactionHistory
// this is a POJO for the TransactionInfoAdapter
public class TransactionInfo implements Parcelable, Comparable<TransactionInfo> {
public static final int CONFIRMATION = 10; // blocks
@RequiredArgsConstructor
public enum Direction {
Direction_In(0),
@ -98,6 +100,10 @@ public class TransactionInfo implements Parcelable, Comparable<TransactionInfo>
this.transfers = transfers;
}
public boolean isConfirmed() {
return confirmations >= CONFIRMATION;
}
public String getDisplayLabel() {
if (subaddressLabel.isEmpty() || (Subaddress.DEFAULT_LABEL_FORMATTER.matcher(subaddressLabel).matches()))
return ("#" + addressIndex);

View File

@ -75,7 +75,7 @@ public class Wallet {
@Override
@NonNull
public String toString() {
return "Wallet.Status: (" + status + "/" + errorString + ", " + connectionStatus;
return "Wallet.Status: " + status + "/" + errorString + "/" + connectionStatus;
}
}
@ -129,7 +129,7 @@ public class Wallet {
ConnectionStatus_WrongVersion
}
public native String getSeed();
public native String getSeed(String offset);
public native String getSeedLanguage();
@ -147,7 +147,7 @@ public class Wallet {
private native Status statusWithErrorString();
public native boolean setPassword(String password);
public native synchronized boolean setPassword(String password);
public String getAddress() {
return getAddress(accountIndex);
@ -203,12 +203,10 @@ public class Wallet {
public native String getSecretSpendKey();
public boolean store() {
final boolean ok = store("");
Timber.d("stored");
return ok;
return store("");
}
public native boolean store(String path);
public native synchronized boolean store(String path);
public boolean close() {
disposePendingTransaction();
@ -247,6 +245,8 @@ public class Wallet {
//TODO virtual void setTrustedDaemon(bool arg) = 0;
//TODO virtual bool trustedDaemon() const = 0;
public native boolean setProxy(String address);
public long getBalance() {
return getBalance(accountIndex);
}
@ -398,6 +398,10 @@ public class Wallet {
private native long getHistoryJ();
public void refreshHistory() {
getHistory().refreshWithNotes(this);
}
//virtual AddressBook * addressBook() const = 0;
//virtual void setListener(WalletListener *) = 0;
@ -462,7 +466,7 @@ public class Wallet {
public void setSubaddressLabel(int addressIndex, String label) {
setSubaddressLabel(accountIndex, addressIndex, label);
getHistory().refreshWithNotes(this);
refreshHistory();
}
public native void setSubaddressLabel(int accountIndex, int addressIndex, String label);

View File

@ -124,19 +124,19 @@ public class WalletManager {
private native long openWalletJ(String path, String password, int networkType);
public Wallet recoveryWallet(File aFile, String password, String mnemonic) {
return recoveryWallet(aFile, password, mnemonic, 0);
}
public Wallet recoveryWallet(File aFile, String password, String mnemonic, long restoreHeight) {
long walletHandle = recoveryWalletJ(aFile.getAbsolutePath(), password, mnemonic,
public Wallet recoveryWallet(File aFile, String password,
String mnemonic, String offset,
long restoreHeight) {
long walletHandle = recoveryWalletJ(aFile.getAbsolutePath(), password,
mnemonic, offset,
getNetworkType().getValue(), restoreHeight);
Wallet wallet = new Wallet(walletHandle);
manageWallet(wallet);
return wallet;
}
private native long recoveryWalletJ(String path, String password, String mnemonic,
private native long recoveryWalletJ(String path, String password,
String mnemonic, String offset,
int networkType, long restoreHeight);
public Wallet createWalletWithKeys(File aFile, String password, String language, long restoreHeight,
@ -309,6 +309,8 @@ public class WalletManager {
public native String resolveOpenAlias(String address, boolean dnssec_valid);
public native boolean setProxy(String address);
//TODO static std::tuple<bool, std::string, std::string, std::string, std::string> checkUpdates(const std::string &software, const std::string &subdir);
static public native void initLogger(String argv0, String defaultLogBaseName);

View File

@ -45,6 +45,7 @@ import com.m2049r.xmrwallet.model.WalletListener;
import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.LocaleHelper;
import com.m2049r.xmrwallet.util.NetCipherHelper;
import timber.log.Timber;
@ -124,7 +125,7 @@ public class WalletService extends Service {
if (!wallet.isSynchronized()) {
updated = true;
// we want to see our transactions as they come in
wallet.getHistory().refresh();
wallet.refreshHistory();
int txCount = wallet.getHistory().getCount();
if (txCount > lastTxCount) {
// update the transaction list only if we have more than before
@ -152,7 +153,7 @@ public class WalletService extends Service {
wallet.setSynchronized();
if (updated) {
updateDaemonState(wallet, wallet.getBlockChainHeight());
wallet.getHistory().refreshWithNotes(wallet);
wallet.refreshHistory();
if (observer != null) {
updated = !observer.onRefreshed(wallet, true);
}
@ -531,6 +532,7 @@ public class WalletService extends Service {
Timber.d("Using daemon %s", WalletManager.getInstance().getDaemonAddress());
showProgress(55);
wallet.init(0);
wallet.setProxy(NetCipherHelper.getProxy());
showProgress(90);
}
return wallet;

View File

@ -25,6 +25,7 @@ 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.service.exchange.api.ExchangeRate;
import com.m2049r.xmrwallet.util.NetCipherHelper;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@ -48,26 +49,21 @@ import javax.xml.parsers.ParserConfigurationException;
import okhttp3.Call;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import timber.log.Timber;
public class ExchangeApiImpl implements ExchangeApi {
@NonNull
private final OkHttpClient okHttpClient;
@NonNull
private final HttpUrl baseUrl;
//so we can inject the mockserver url
@VisibleForTesting
public ExchangeApiImpl(@NonNull final OkHttpClient okHttpClient, @NonNull final HttpUrl baseUrl) {
this.okHttpClient = okHttpClient;
public ExchangeApiImpl(@NonNull final HttpUrl baseUrl) {
this.baseUrl = baseUrl;
}
public ExchangeApiImpl(@NonNull final OkHttpClient okHttpClient) {
this(okHttpClient, HttpUrl.parse("https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml"));
public ExchangeApiImpl() {
this(HttpUrl.parse("https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml"));
// data is daily and is refreshed around 16:00 CET every working day
}
@ -122,9 +118,8 @@ public class ExchangeApiImpl implements ExchangeApi {
}
}
final Request httpRequest = createHttpRequest(baseUrl);
okHttpClient.newCall(httpRequest).enqueue(new okhttp3.Callback() {
final NetCipherHelper.Request httpRequest = new NetCipherHelper.Request(baseUrl);
httpRequest.enqueue(new okhttp3.Callback() {
@Override
public void onFailure(final Call call, final IOException ex) {
callback.onError(ex);
@ -155,13 +150,6 @@ public class ExchangeApiImpl implements ExchangeApi {
});
}
private Request createHttpRequest(final HttpUrl url) {
return new Request.Builder()
.url(url)
.get()
.build();
}
final private Map<String, Double> fxEntries = new HashMap<>();
private Calendar fxDate = null;
private Calendar fetchDate = null;

View File

@ -24,6 +24,7 @@ import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeException;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate;
import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.NetCipherHelper;
import org.json.JSONArray;
import org.json.JSONException;
@ -33,27 +34,21 @@ import java.io.IOException;
import okhttp3.Call;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import timber.log.Timber;
public class ExchangeApiImpl implements ExchangeApi {
@NonNull
private final OkHttpClient okHttpClient;
private final HttpUrl baseUrl;
//so we can inject the mockserver url
@VisibleForTesting
public ExchangeApiImpl(@NonNull final OkHttpClient okHttpClient, final HttpUrl baseUrl) {
this.okHttpClient = okHttpClient;
public ExchangeApiImpl(final HttpUrl baseUrl) {
this.baseUrl = baseUrl;
}
public ExchangeApiImpl(@NonNull final OkHttpClient okHttpClient) {
this(okHttpClient, HttpUrl.parse("https://api.kraken.com/0/public/Ticker"));
public ExchangeApiImpl() {
this(HttpUrl.parse("https://api.kraken.com/0/public/Ticker"));
}
@Override
@ -86,9 +81,8 @@ public class ExchangeApiImpl implements ExchangeApi {
.addQueryParameter("pair", base + (quote.equals("BTC") ? "XBT" : quote))
.build();
final Request httpRequest = createHttpRequest(url);
okHttpClient.newCall(httpRequest).enqueue(new okhttp3.Callback() {
final NetCipherHelper.Request httpRequest = new NetCipherHelper.Request(url);
httpRequest.enqueue(new okhttp3.Callback() {
@Override
public void onFailure(final Call call, final IOException ex) {
callback.onError(ex);
@ -127,11 +121,4 @@ public class ExchangeApiImpl implements ExchangeApi {
callback.onError(ex);
}
}
private Request createHttpRequest(final HttpUrl url) {
return new Request.Builder()
.url(url)
.get()
.build();
}
}

View File

@ -35,13 +35,6 @@ import timber.log.Timber;
public class ExchangeApiImpl implements ExchangeApi {
static public final String BASE_FIAT = "EUR";
@NonNull
private final OkHttpClient okHttpClient;
public ExchangeApiImpl(@NonNull final OkHttpClient okHttpClient) {
this.okHttpClient = okHttpClient;
}
@Override
public void queryExchangeRate(@NonNull final String baseCurrency, @NonNull final String quoteCurrency,
@NonNull final ExchangeCallback callback) {
@ -61,13 +54,13 @@ 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(okHttpClient);
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(okHttpClient);
new com.m2049r.xmrwallet.service.exchange.ecb.ExchangeApiImpl();
ecbApi.queryExchangeRate(BASE_FIAT, quote, new ExchangeCallback() {
@Override
public void onSuccess(final ExchangeRate ecbRate) {

View File

@ -20,21 +20,21 @@ import androidx.annotation.NonNull;
import com.m2049r.xmrwallet.service.shift.NetworkCallback;
import com.m2049r.xmrwallet.service.shift.ShiftApiCall;
import com.m2049r.xmrwallet.util.DateHelper;
import com.m2049r.xmrwallet.service.shift.sideshift.api.RequestQuote;
import com.m2049r.xmrwallet.service.shift.sideshift.api.SideShiftApi;
import com.m2049r.xmrwallet.service.shift.ShiftCallback;
import com.m2049r.xmrwallet.service.shift.sideshift.api.RequestQuote;
import com.m2049r.xmrwallet.util.DateHelper;
import com.m2049r.xmrwallet.util.ServiceHelper;
import org.json.JSONException;
import org.json.JSONObject;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.ParseException;
import java.util.Date;
import java.util.Locale;
import lombok.Getter;
import timber.log.Timber;
class RequestQuoteImpl implements RequestQuote {
@Getter
@ -101,7 +101,7 @@ class RequestQuoteImpl implements RequestQuote {
/**
* Create JSON request object
*
* @param xmrAmount how much XMR to shift to BTC
* @param btcAmount how much XMR to shift to BTC
*/
static JSONObject createRequest(final double btcAmount) throws JSONException {
@ -114,5 +114,13 @@ class RequestQuoteImpl implements RequestQuote {
return jsonObject;
}
static DecimalFormat AmountFormatter = new DecimalFormat("#.############");
static final DecimalFormat AmountFormatter;
static {
AmountFormatter = new DecimalFormat();
AmountFormatter.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));
AmountFormatter.setMinimumIntegerDigits(1);
AmountFormatter.setMaximumFractionDigits(12);
AmountFormatter.setGroupingUsed(false);
}
}

View File

@ -30,7 +30,7 @@ import com.m2049r.xmrwallet.service.shift.sideshift.api.QueryOrderParameters;
import com.m2049r.xmrwallet.service.shift.sideshift.api.QueryOrderStatus;
import com.m2049r.xmrwallet.service.shift.sideshift.api.RequestQuote;
import com.m2049r.xmrwallet.service.shift.sideshift.api.SideShiftApi;
import com.m2049r.xmrwallet.util.OkHttpHelper;
import com.m2049r.xmrwallet.util.NetCipherHelper;
import org.json.JSONException;
import org.json.JSONObject;
@ -39,22 +39,14 @@ import java.io.IOException;
import okhttp3.Call;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import timber.log.Timber;
public class SideShiftApiImpl implements SideShiftApi, ShiftApiCall {
@NonNull
private final OkHttpClient okHttpClient;
private final HttpUrl baseUrl;
public SideShiftApiImpl(@NonNull final OkHttpClient okHttpClient, final HttpUrl baseUrl) {
this.okHttpClient = okHttpClient;
public SideShiftApiImpl(final HttpUrl baseUrl) {
this.baseUrl = baseUrl;
}
@ -95,9 +87,9 @@ public class SideShiftApiImpl implements SideShiftApi, ShiftApiCall {
final HttpUrl url = baseUrl.newBuilder()
.addPathSegments(path)
.build();
final Request httpRequest = createHttpRequest(request, url);
okHttpClient.newCall(httpRequest).enqueue(new okhttp3.Callback() {
NetCipherHelper.Request httpRequest = new NetCipherHelper.Request(url, request);
httpRequest.enqueue(new okhttp3.Callback() {
@Override
public void onFailure(final Call call, final IOException ex) {
callback.onError(ex);
@ -127,13 +119,4 @@ public class SideShiftApiImpl implements SideShiftApi, ShiftApiCall {
}
});
}
private Request createHttpRequest(final JSONObject request, final HttpUrl url) {
if (request != null) {
final RequestBody body = RequestBody.create(request.toString(), MediaType.parse("application/json"));
return OkHttpHelper.getPostRequest(url, body);
} else {
return OkHttpHelper.getGetRequest(url);
}
}
}

View File

@ -84,7 +84,7 @@ public class Helper {
static public final long ONE_XMR = Math.round(Math.pow(10, Helper.XMR_DECIMALS));
static public final boolean SHOW_EXCHANGERATES = true;
static public final boolean ALLOW_SHIFT = true;
static public boolean ALLOW_SHIFT = false;
static private final String WALLET_DIR = "wallets";
static private final String MONERO_DIR = "monero";
@ -606,30 +606,4 @@ public class Helper {
static public boolean preventScreenshot() {
return !(BuildConfig.DEBUG || BuildConfig.FLAVOR_type.equals("alpha"));
}
static public final int STALE_NODE_HOURS = 2;
static public void showTimeDifference(TextView view, long timeInSeconds) {
final Context ctx = view.getContext();
final long now = Calendar.getInstance().getTimeInMillis() / 1000;
final long secs = (now - timeInSeconds);
final long mins = secs / 60; // in minutes
final long hours = mins / 60;
final long days = hours / 24;
String msg;
if (mins < 2) {
msg = ctx.getString(R.string.node_updated_now, secs);
} else if (hours < 2) {
msg = ctx.getString(R.string.node_updated_mins, mins);
} else if (days < 2) {
msg = ctx.getString(R.string.node_updated_hours, hours);
} else {
msg = ctx.getString(R.string.node_updated_days, days);
}
view.setText(msg);
if (hours >= STALE_NODE_HOURS)
view.setTextColor(ThemeHelper.getThemedColor(view.getContext(), R.attr.colorError));
else
view.setTextColor(ThemeHelper.getThemedColor(view.getContext(), android.R.attr.textColorPrimary));
}
}

View File

@ -0,0 +1,393 @@
/*
* Copyright (c) 2021 m2049r
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.m2049r.xmrwallet.util;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import com.burgstaller.okhttp.AuthenticationCacheInterceptor;
import com.burgstaller.okhttp.CachingAuthenticatorDecorator;
import com.burgstaller.okhttp.digest.CachingAuthenticator;
import com.burgstaller.okhttp.digest.Credentials;
import com.burgstaller.okhttp.digest.DigestAuthenticator;
import org.json.JSONObject;
import java.io.IOException;
import java.net.Proxy;
import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import info.guardianproject.netcipher.client.StrongOkHttpClientBuilder;
import info.guardianproject.netcipher.proxy.OrbotHelper;
import info.guardianproject.netcipher.proxy.SignatureUtils;
import info.guardianproject.netcipher.proxy.StatusCallback;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;
import okhttp3.Response;
import timber.log.Timber;
@RequiredArgsConstructor
public class NetCipherHelper implements StatusCallback {
public static final String USER_AGENT = "Monerujo/1.0";
public static final int HTTP_TIMEOUT = 1000; //ms
public static final int TOR_TIMEOUT_CONNECT = 5000; //ms
public static final int TOR_TIMEOUT = 2000; //ms
public interface OnStatusChangedListener {
void connected();
void disconnected();
void notInstalled();
void notEnabled();
}
final private Context context;
final private OrbotHelper orbot;
@SuppressLint("StaticFieldLeak")
private static NetCipherHelper Instance;
public static void createInstance(Context context) {
if (Instance == null) {
synchronized (NetCipherHelper.class) {
if (Instance == null) {
final Context applicationContext = context.getApplicationContext();
Instance = new NetCipherHelper(applicationContext, OrbotHelper.get(context).statusTimeout(5000));
}
}
}
}
public static NetCipherHelper getInstance() {
if (Instance == null) throw new IllegalStateException("NetCipherHelper is null");
return Instance;
}
private OkHttpClient client;
private void createTorClient(Intent statusIntent) {
String orbotStatus = statusIntent.getStringExtra(OrbotHelper.EXTRA_STATUS);
if (orbotStatus == null) throw new IllegalStateException("status is null");
if (!orbotStatus.equals(OrbotHelper.STATUS_ON))
throw new IllegalStateException("Orbot is not ON");
try {
final OkHttpClient.Builder okBuilder = new OkHttpClient.Builder()
.connectTimeout(TOR_TIMEOUT_CONNECT, TimeUnit.MILLISECONDS)
.writeTimeout(TOR_TIMEOUT, TimeUnit.MILLISECONDS)
.readTimeout(TOR_TIMEOUT, TimeUnit.MILLISECONDS);
client = new StrongOkHttpClientBuilder(context)
.withSocksProxy()
.applyTo(okBuilder, statusIntent)
.build();
Helper.ALLOW_SHIFT = false; // no shifting with Tor
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
private void createClearnetClient() {
try {
client = new OkHttpClient.Builder()
.connectTimeout(HTTP_TIMEOUT, TimeUnit.MILLISECONDS)
.writeTimeout(HTTP_TIMEOUT, TimeUnit.MILLISECONDS)
.readTimeout(HTTP_TIMEOUT, TimeUnit.MILLISECONDS)
.build();
Helper.ALLOW_SHIFT = true;
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
private OnStatusChangedListener onStatusChangedListener;
public static void deregister() {
getInstance().onStatusChangedListener = null;
}
public static void register(OnStatusChangedListener listener) {
final NetCipherHelper me = getInstance();
me.onStatusChangedListener = listener;
// NOT_INSTALLED is dealt with through the callbacks
me.orbot.removeStatusCallback(me) // make sure we are registered just once
.addStatusCallback(me);
// deal with org.torproject.android.intent.action.STATUS = STARTS_DISABLED
me.context.registerReceiver(orbotStatusReceiver, new IntentFilter(OrbotHelper.ACTION_STATUS));
me.startTor();
}
// for StatusCallback
public enum Status {
STARTING,
ENABLED,
STOPPING,
DISABLED,
NOT_INSTALLED,
NOT_ENABLED,
UNKNOWN;
}
private Status status = Status.UNKNOWN;
@Override
public void onStarting() {
Timber.d("onStarting");
status = Status.STARTING;
}
@Override
public void onEnabled(Intent statusIntent) {
Timber.d("onEnabled");
if (getTorPref() != Status.ENABLED) return; // do we want Tor?
createTorClient(statusIntent);
status = Status.ENABLED;
if (onStatusChangedListener != null) {
new Thread(() -> onStatusChangedListener.connected()).start();
}
}
@Override
public void onStopping() {
Timber.d("onStopping");
status = Status.STOPPING;
}
@Override
public void onDisabled() {
Timber.d("onDisabled");
createClearnetClient();
status = Status.DISABLED;
if (onStatusChangedListener != null) {
new Thread(() -> onStatusChangedListener.disconnected()).start();
}
}
@Override
public void onStatusTimeout() {
Timber.d("onStatusTimeout");
createClearnetClient();
// (timeout does not not change the status)
if (onStatusChangedListener != null) {
new Thread(() -> onStatusChangedListener.disconnected()).start();
}
orbotInit = false; // do init() next time we try to open Tor
}
@Override
public void onNotYetInstalled() {
Timber.d("onNotYetInstalled");
// never mind then
orbot.removeStatusCallback(this);
createClearnetClient();
status = Status.NOT_INSTALLED;
if (onStatusChangedListener != null) {
new Thread(() -> onStatusChangedListener.notInstalled()).start();
}
}
// user has not enabled background Orbot starts
public void onNotEnabled() {
Timber.d("onNotEnabled");
// keep the callback in case they turn it on manually
setTorPref(Status.DISABLED);
createClearnetClient();
status = Status.NOT_ENABLED;
if (onStatusChangedListener != null) {
new Thread(() -> onStatusChangedListener.notEnabled()).start();
}
}
static public Status getStatus() {
return getInstance().status;
}
public void toggle() {
switch (getStatus()) {
case ENABLED:
onDisabled();
setTorPref(Status.DISABLED);
break;
case DISABLED:
setTorPref(Status.ENABLED);
startTor();
break;
}
}
private boolean orbotInit = false;
private void startTor() {
if (!isOrbotInstalled()) {
onNotYetInstalled();
} else if (getTorPref() == Status.DISABLED) {
onDisabled();
} else if (!orbotInit) {
orbotInit = orbot.init();
} else {
orbot.requestStart(context);
}
}
// extracted from OrbotHelper
private boolean isOrbotInstalled() {
ArrayList<String> hashes = new ArrayList<>();
// Tor Project signing key
hashes.add("A4:54:B8:7A:18:47:A8:9E:D7:F5:E7:0F:BA:6B:BA:96:F3:EF:29:C2:6E:09:81:20:4F:E3:47:BF:23:1D:FD:5B");
// f-droid.org signing key
hashes.add("A7:02:07:92:4F:61:FF:09:37:1D:54:84:14:5C:4B:EE:77:2C:55:C1:9E:EE:23:2F:57:70:E1:82:71:F7:CB:AE");
return null != SignatureUtils.validateBroadcastIntent(context,
OrbotHelper.getOrbotStartIntent(context),
hashes, false);
}
static public boolean hasClient() {
return getInstance().client != null;
}
static public boolean isTor() {
return getStatus() == Status.ENABLED;
}
static public String getProxy() {
if (!isTor()) return "";
final Proxy proxy = getInstance().client.proxy();
if (proxy == null) return "";
return proxy.address().toString().substring(1);
}
@ToString
static public class Request {
final HttpUrl url;
final String json;
final String username;
final String password;
public Request(final HttpUrl url, final String json, final String username, final String password) {
this.url = url;
this.json = json;
this.username = username;
this.password = password;
}
public Request(final HttpUrl url, final JSONObject json) {
this(url, json == null ? null : json.toString(), null, null);
}
public Request(final HttpUrl url) {
this(url, null, null, null);
}
public void enqueue(Callback callback) {
newCall().enqueue(callback);
}
public Response execute() throws IOException {
return newCall().execute();
}
private Call newCall() {
return getClient().newCall(getRequest());
}
private OkHttpClient getClient() {
if (mockClient != null) return mockClient; // Unit-test mode
final OkHttpClient client = getInstance().client;
if ((username != null) && (!username.isEmpty())) {
final DigestAuthenticator authenticator = new DigestAuthenticator(new Credentials(username, password));
final Map<String, CachingAuthenticator> authCache = new ConcurrentHashMap<>();
return client.newBuilder()
.authenticator(new CachingAuthenticatorDecorator(authenticator, authCache))
.addInterceptor(new AuthenticationCacheInterceptor(authCache))
.build();
// TODO: maybe cache & reuse the client for these credentials?
} else {
return client;
}
}
private okhttp3.Request getRequest() {
final okhttp3.Request.Builder builder =
new okhttp3.Request.Builder()
.url(url)
.header("User-Agent", USER_AGENT);
if (json != null) {
builder.post(RequestBody.create(json, MediaType.parse("application/json")));
} else {
builder.get();
}
return builder.build();
}
// for unit tests only
static public OkHttpClient mockClient = null;
}
private static final String PREFS_NAME = "tor";
private static final String PREFS_STATUS = "status";
private Status currentPref = Status.UNKNOWN;
private Status getTorPref() {
if (currentPref != Status.UNKNOWN) return currentPref;
currentPref = Status.valueOf(context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
.getString(PREFS_STATUS, "DISABLED"));
return currentPref;
}
private void setTorPref(Status status) {
if (getTorPref() == status) return; // no change
context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
.edit()
.putString(PREFS_STATUS, status.name())
.apply();
currentPref = status;
}
private static final BroadcastReceiver orbotStatusReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Timber.d("%s/%s", intent.getAction(), intent.getStringExtra(OrbotHelper.EXTRA_STATUS));
if (OrbotHelper.ACTION_STATUS.equals(intent.getAction())) {
if (OrbotHelper.STATUS_STARTS_DISABLED.equals(intent.getStringExtra(OrbotHelper.EXTRA_STATUS))) {
getInstance().onNotEnabled();
}
}
}
};
public void installOrbot(Activity host) {
host.startActivity(OrbotHelper.getOrbotInstallIntent(context));
}
}

View File

@ -1,72 +0,0 @@
/*
* Copyright (c) 2017 m2049r
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.m2049r.xmrwallet.util;
import java.util.concurrent.TimeUnit;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
public class OkHttpHelper {
static private OkHttpClient Singleton;
static public OkHttpClient getOkHttpClient() {
if (Singleton == null) {
synchronized (OkHttpHelper.class) {
if (Singleton == null) {
Singleton = new OkHttpClient();
}
}
}
return Singleton;
}
public static final int HTTP_TIMEOUT = 1000; //ms
static private OkHttpClient EagerSingleton;
static public OkHttpClient getEagerClient() {
if (EagerSingleton == null) {
synchronized (OkHttpHelper.class) {
if (EagerSingleton == null) {
EagerSingleton = new OkHttpClient.Builder()
.connectTimeout(HTTP_TIMEOUT, TimeUnit.MILLISECONDS)
.writeTimeout(HTTP_TIMEOUT, TimeUnit.MILLISECONDS)
.readTimeout(HTTP_TIMEOUT, TimeUnit.MILLISECONDS)
.build();
}
}
}
return EagerSingleton;
}
static final public String USER_AGENT = "Monerujo/1.0";
static public Request getPostRequest(HttpUrl url, RequestBody requestBody) {
return new Request.Builder().url(url).post(requestBody)
.header("User-Agent", USER_AGENT)
.build();
}
static public Request getGetRequest(HttpUrl url) {
return new Request.Builder().url(url).get()
.header("User-Agent", USER_AGENT)
.build();
}
}

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) 2021 m2049r
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.m2049r.xmrwallet.util;
public class OnionHelper {
public static boolean isOnionHost(String hostname) {
return hostname.endsWith(".onion");
}
}

View File

@ -19,6 +19,6 @@ public class ServiceHelper {
}
static public ExchangeApi getExchangeApi() {
return new com.m2049r.xmrwallet.service.exchange.krakenEcb.ExchangeApiImpl(OkHttpHelper.getOkHttpClient());
return new com.m2049r.xmrwallet.service.exchange.krakenEcb.ExchangeApiImpl();
}
}

View File

@ -344,8 +344,8 @@ public class ExchangeEditText extends LinearLayout {
if (rate > 0) {
tvAmountB.setText(Helper.getFormattedAmount(rate * amount, getCurrencyB() == 0));
} else {
tvAmountB.setText(null);
Timber.w("No rate!");
tvAmountB.setText("--");
Timber.d("No rate!");
}
}

View File

@ -321,23 +321,13 @@ public class ExchangeView extends LinearLayout {
@Override
public void onSuccess(final ExchangeRate exchangeRate) {
if (isAttachedToWindow())
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
exchange(exchangeRate);
}
});
new Handler(Looper.getMainLooper()).post(() -> exchange(exchangeRate));
}
@Override
public void onError(final Exception e) {
Timber.e(e.getLocalizedMessage());
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
exchangeFailed();
}
});
new Handler(Looper.getMainLooper()).post(() -> exchangeFailed());
}
});
}
@ -362,11 +352,10 @@ public class ExchangeView extends LinearLayout {
}
tvAmountB.setText(xmrAmount);
} else { // no XMR currency - cannot happen!
Timber.e("No XMR currency!");
setXmr(null);
notXmrAmount = null;
return;
throw new IllegalStateException("No XMR currency!");
}
if (rate == 0)
tvAmountB.setText("--");
}
boolean prepareExchange() {

View File

@ -0,0 +1,115 @@
/*
* Copyright 2012-2016 Nathan Freitas
* Copyright 2015 str4d
* Portions Copyright (c) 2016 CommonsWare, LLC
*
* 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 info.guardianproject.netcipher.client;
import android.content.Context;
import android.content.Intent;
import javax.net.ssl.SSLSocketFactory;
import okhttp3.OkHttpClient;
import okhttp3.Request;
/**
* Creates an OkHttpClient using NetCipher configuration. Use
* build() if you have no other OkHttpClient configuration
* that you need to perform. Or, use applyTo() to augment an
* existing OkHttpClient.Builder with NetCipher.
*/
public class StrongOkHttpClientBuilder extends
StrongBuilderBase<StrongOkHttpClientBuilder, OkHttpClient> {
/**
* Creates a StrongOkHttpClientBuilder using the strongest set
* of options for security. Use this if the strongest set of
* options is what you want; otherwise, create a
* builder via the constructor and configure it as you see fit.
*
* @param context any Context will do
* @return a configured StrongOkHttpClientBuilder
* @throws Exception
*/
static public StrongOkHttpClientBuilder forMaxSecurity(Context context)
throws Exception {
return(new StrongOkHttpClientBuilder(context)
.withBestProxy());
}
/**
* Creates a builder instance.
*
* @param context any Context will do; builder will hold onto
* Application context
*/
public StrongOkHttpClientBuilder(Context context) {
super(context);
}
/**
* Copy constructor.
*
* @param original builder to clone
*/
public StrongOkHttpClientBuilder(StrongOkHttpClientBuilder original) {
super(original);
}
/**
* OkHttp3 does not support SOCKS proxies:
* https://github.com/square/okhttp/issues/2315
*
* @return false
*/
@Override
public boolean supportsSocksProxy() {
return(true);
}
/**
* {@inheritDoc}
*/
@Override
public OkHttpClient build(Intent status) {
return(applyTo(new OkHttpClient.Builder(), status).build());
}
/**
* Adds NetCipher configuration to an existing OkHttpClient.Builder,
* in case you have additional configuration that you wish to
* perform.
*
* @param builder a new or partially-configured OkHttpClient.Builder
* @return the same builder
*/
public OkHttpClient.Builder applyTo(OkHttpClient.Builder builder, Intent status) {
SSLSocketFactory factory=buildSocketFactory();
if (factory!=null) {
builder.sslSocketFactory(factory);
}
return(builder
.proxy(buildProxy(status)));
}
@Override
protected String get(Intent status, OkHttpClient connection,
String url) throws Exception {
Request request=new Request.Builder().url(url).build();
return(connection.newCall(request).execute().body().string());
}
}

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?attr/colorSecondary" android:state_enabled="true"/>
<item android:color="?attr/colorOnBackground"/>
<item android:color="?attr/colorPrimary" android:state_enabled="true"/>
<item android:color="?attr/colorPrimaryVariant"/>
</selector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?colorPrimaryVariant"
android:pathData="M12,2C6.47,2 2,6.47 2,12s4.47,10 10,10 10,-4.47 10,-10S17.53,2 12,2zM17,15.59L15.59,17 12,13.41 8.41,17 7,15.59 10.59,12 7,8.41 8.41,7 12,10.59 15.59,7 17,8.41 13.41,12 17,15.59z" />
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?colorPrimaryVariant"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?colorPrimaryVariant"
android:pathData="M7.41,8.59L12,13.17l4.59,-4.58L18,10l-6,6 -6,-6 1.41,-1.41z" />
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?colorPrimaryVariant"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?colorPrimaryVariant"
android:pathData="M7.41,15.41L12,10.83l4.59,4.58L18,14l-6,-6 -6,6z" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#2D1A2E"
android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="100"
android:viewportHeight="100">
<path
android:fillColor="@color/btn_color_selector"
android:pathData="M50,8.33A41.67,41.67 0,1 0,91.67 50,41.65 41.65,0 0,0 50,8.33ZM78.87,33.33L66.54,33.33A65.26,65.26 0,0 0,60.79 18.5,33.48 33.48,0 0,1 78.83,33.33ZM50,16.83a58.59,58.59 0,0 1,8 16.5L42,33.33A58.72,58.72 0,0 1,50 16.83ZM17.75,58.33a32.66,32.66 0,0 1,0 -16.66L31.83,41.67A69.49,69.49 0,0 0,31.25 50a69.49,69.49 0,0 0,0.58 8.33ZM21.17,66.67L33.46,66.67A64.9,64.9 0,0 0,39.21 81.5,33.26 33.26,0 0,1 21.17,66.67ZM33.46,33.33L21.17,33.33a33.26,33.26 0,0 1,18 -14.83A65.26,65.26 0,0 0,33.46 33.33ZM50,83.17a58.72,58.72 0,0 1,-8 -16.5L58,66.67A58.72,58.72 0,0 1,50 83.17ZM59.75,58.33L40.25,58.33A60.51,60.51 0,0 1,39.58 50a59.88,59.88 0,0 1,0.67 -8.33h19.5A59.88,59.88 0,0 1,60.42 50,60.51 60.51,0 0,1 59.75,58.33ZM60.75,81.5a65.08,65.08 0,0 0,5.75 -14.83L78.83,66.67A33.44,33.44 0,0 1,60.79 81.5ZM68.13,58.33A69.49,69.49 0,0 0,68.75 50a69.49,69.49 0,0 0,-0.58 -8.33L82.25,41.67a32.66,32.66 0,0 1,0 16.66Z" />
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="100"
android:viewportHeight="100">
<path
android:fillColor="@color/btn_color_selector"
android:fillType="evenOdd"
android:pathData="M50.08,84.36L50.08,79.27a29.27,29.27 0,0 0,0 -58.54L50.08,15.64a34.36,34.36 0,0 1,0 68.72ZM50.08,66.54a16.55,16.55 0,0 0,0 -33.09L50.08,28.36a21.64,21.64 0,0 1,0 43.27ZM50.08,41.09a8.91,8.91 0,0 1,0 17.82ZM8,50A42,42 0,1 0,50 8,42 42,0 0,0 8,50Z" />
</vector>

View File

@ -15,7 +15,6 @@
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/header_top_first"
app:errorEnabled="true">
<com.google.android.material.textfield.TextInputEditText
@ -34,7 +33,7 @@
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/header_top_first"
android:layout_marginTop="@dimen/header_top_first"
app:boxStrokeErrorColor="@color/monerujoPrimary"
app:errorEnabled="true"
app:errorIconDrawable="@drawable/ic_smiley_gunther_filled"
@ -78,7 +77,7 @@
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/header_top_first"
android:layout_marginTop="@dimen/header_top_first"
android:visibility="gone"
app:errorEnabled="true">
@ -92,12 +91,41 @@
android:textAlignment="textStart" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/bSeedOffset"
style="@style/MoneroIconButton.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone"
android:background="?android:selectableItemBackground"
android:text="@string/label_seed_offset_encrypt"
app:icon="@drawable/ic_baseline_keyboard_arrow_down_24" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/etSeedOffset"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/header_top_first"
android:visibility="gone">
<com.google.android.material.textfield.TextInputEditText
style="@style/MoneroEdit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/seed_offset_hint"
android:inputType="textVisiblePassword"
android:maxLines="1"
android:textAlignment="textStart" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/etWalletAddress"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/header_top_first"
android:layout_marginTop="@dimen/header_top_first"
android:visibility="gone"
app:counterEnabled="true"
app:counterMaxLength="95"
@ -118,7 +146,7 @@
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/header_top_first"
android:layout_marginTop="@dimen/header_top_first"
android:visibility="gone"
app:counterEnabled="true"
app:counterMaxLength="64"
@ -139,7 +167,7 @@
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/header_top_first"
android:layout_marginTop="@dimen/header_top_first"
android:visibility="gone"
app:counterEnabled="true"
app:counterMaxLength="64"
@ -160,7 +188,7 @@
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/header_top_first"
android:layout_marginTop="@dimen/header_top_first"
android:visibility="gone"
app:errorEnabled="true">
@ -179,7 +207,7 @@
style="@style/MoneroButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginTop="@dimen/header_top_first"
android:text="@string/generate_buttonGenerate" />
</LinearLayout>

View File

@ -7,16 +7,6 @@
android:paddingTop="8dp"
android:paddingEnd="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="48dp"
android:src="@mipmap/ic_launcher" />
<TextView
android:id="@+id/tvHelp"
style="@style/MoneroText"
@ -27,6 +17,4 @@
android:gravity="start"
android:textSize="14sp"
tools:text="@string/menu_help" />
</LinearLayout>
</ScrollView>

View File

@ -29,28 +29,49 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp">
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/pbNetwork"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_alignStart="@id/ibNetwork"
android:layout_alignTop="@+id/ibNetwork"
android:layout_alignEnd="@id/ibNetwork"
android:layout_alignBottom="@id/ibNetwork"
android:layout_gravity="center"
android:indeterminate="true"
android:progress="100"
android:visibility="visible"
app:indicatorInset="9dp"
app:indicatorSize="30dp"
app:trackThickness="2dp" />
<ImageButton
android:id="@+id/ibNetwork"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerInParent="true"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:gravity="center"
android:padding="12dp"
android:src="@drawable/ic_network_clearnet" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginStart="16dp"
android:layout_toStartOf="@+id/ibRenew">
<ProgressBar
android:id="@+id/pbNode"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:visibility="invisible" />
android:layout_height="0dp"
android:layout_alignTop="@+id/ibNetwork"
android:layout_alignBottom="@id/ibNetwork"
android:layout_toStartOf="@+id/ibRenew"
android:layout_toEndOf="@+id/ibNetwork">
<LinearLayout
android:id="@+id/llNode"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/selectableItemBackground"
android:gravity="start|center_vertical"
android:gravity="center_vertical"
android:orientation="vertical">
<TextView
@ -58,17 +79,14 @@
style="@style/MoneroText.PosAmount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawablePadding="8dp"
app:drawableStartCompat="@drawable/ic_refresh_black_24dp"
tools:text="monero-v9.monerujo.io" />
<TextView
android:id="@+id/tvNodeAddress"
android:id="@+id/tvInfo"
style="@style/MoneroText.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
tools:text="128.130.233.151:18089" />
tools:text="Last Block: 2 minutes ago" />
</LinearLayout>
</FrameLayout>

View File

@ -111,8 +111,9 @@
android:text="@string/label_receive_info_gen_qr_code"
android:textAlignment="center"
android:textSize="16sp"
android:visibility="gone"
card_view:drawableStartCompat="@drawable/ic_info_outline_gray_24dp" />
android:textColor="#2D1A2E"
android:visibility="visible"
card_view:drawableStartCompat="@drawable/ic_info_outline_black_24dp" />
<ImageView
android:id="@+id/qrCode"

View File

@ -18,12 +18,11 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="true"
android:visibility="gone" />
android:visibility="invisible" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/header_top">
android:layout_height="wrap_content">
<TextView
style="@style/MoneroLabel.Heading"
@ -57,7 +56,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/header_top"
android:orientation="vertical"
android:visibility="gone">
android:visibility="visible">
<TextView
style="@style/MoneroLabel.Heading"
@ -66,15 +65,49 @@
android:layout_gravity="center"
android:text="@string/generate_mnemonic_label" />
<FrameLayout
android:id="@+id/flWalletMnemonic"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/data_top">
<TextView
android:id="@+id/tvWalletMnemonic"
style="@style/MoneroText.Monospace.Mnemonic"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/data_top"
android:background="@drawable/backgound_seed"
android:textAlignment="center"
tools:text="tucks slackens vehicle doctor oaks aloof balding knife rays wise haggled cuisine navy ladder suitcase dusted last thorn pixels karate ticket nibs violin zapped slackens" />
</FrameLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/bSeedOffset"
style="@style/MoneroIconButton.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="?android:selectableItemBackground"
android:text="@string/label_seed_offset_encrypt"
app:icon="@drawable/ic_baseline_keyboard_arrow_down_24" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/etSeedOffset"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/header_top_first"
android:visibility="gone">
<com.google.android.material.textfield.TextInputEditText
style="@style/MoneroEdit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/seed_offset_hint"
android:inputType="textVisiblePassword"
android:maxLines="1"
android:textAlignment="textStart" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
<LinearLayout
@ -148,7 +181,7 @@
android:drawablePadding="4dp"
android:text="@string/label_wallet_advanced_details"
android:visibility="gone"
app:icon="@drawable/ic_add_circle_outline" />
app:icon="@drawable/ic_baseline_keyboard_arrow_down_24" />
<LinearLayout
android:id="@+id/llAdvancedInfo"
@ -163,7 +196,6 @@
android:id="@+id/llViewKey"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/header_top"
android:orientation="vertical"
android:visibility="gone">

View File

@ -126,23 +126,38 @@
android:src="@drawable/ic_xmrto_doge_off" />
</LinearLayout>
<TextView
android:id="@+id/tvXmrTo"
style="@style/MoneroText.Info"
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginTop="16dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="16dp"
android:layout_marginBottom="16dp">
<TextView
android:id="@+id/tvXmrTo"
style="@style/MoneroText.Info"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:drawablePadding="8dp"
android:gravity="start"
android:gravity="start|center_vertical"
android:singleLine="false"
android:text="@string/label_send_btc_xmrto_key"
android:textSize="18sp"
android:visibility="invisible"
app:drawableStartCompat="@drawable/gunther_24dp"
tools:text="@string/info_xmrto" />
<TextView
android:id="@+id/tvTor"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:drawablePadding="8dp"
android:gravity="start|center_vertical"
android:singleLine="false"
android:text="@string/tor_noshift"
android:visibility="invisible"
app:drawableStartCompat="@drawable/gunther_24dp" />
</FrameLayout>
</LinearLayout>
<com.google.android.material.textfield.TextInputLayout

View File

@ -53,7 +53,7 @@
tools:text="monero-v9.monerujo.io" />
<TextView
android:id="@+id/tvAddress"
android:id="@+id/tvInfo"
style="@style/MoneroText.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"

View File

@ -48,7 +48,7 @@
<TextView
android:id="@+id/tvConfirmations"
style="@style/MoneroText"
style="@style/MoneroText.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
@ -73,12 +73,12 @@
tools:text="+ 999.999999" />
<TextView
android:id="@+id/tx_fee"
android:id="@+id/tx_failed"
style="@style/MoneroText.PosFee"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end"
tools:text="Fee 0.06817" />
android:text="@string/tx_list_failed_text" />
</LinearLayout>
</LinearLayout>

View File

@ -1,48 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:locale="en">
<string name="about_close">أغلق</string>
<string name="about_whoami">أنا مونيرويو</string>
<string name="about_version">النسخة %1$s (%2$d)</string>
<string name="credits_text"><![CDATA[
<b>الاعتمادات</b>
<br/>
m2049r, baltsar777, anhdres, keejef,
rehrar, EarlOfEgo, ErCiccione et al.
<br/><br/>
<a href="https://monerujo.io/">monerujo.io</a>
]]></string>
<string name="privacy_policy"><![CDATA[
<h1>سياسة الخصوصية</h1>
<p>
هذه الصفحة تخبرك بسياستنا بخصوص التجميع، الاستخدام، و الافصاح عن المعلومات الشخصيةالتي نستلمها من مستخدمي تطبيقنا (مونيرويو: محفظة مونيرو)
</p>
<p>باستخدامك هذا التطبيق أنت توافق تجميع و استخدام المعلومات وفقاً لهذه السياسة
</p>
<h2>البيانات المجمعة</h2>
<p> المعلومات الشخصية هي نوع من البيانات التي قد تعرف هوية شخص ما
</p>
<p> مفاتيح مونيرو و العناوين العامة مجمعة و معالجة من قبل التطبيق محليا لغرض معالجة المعاملات و هي ترسل الى شبكة مونيرو في حالة مشفرة
</p>
<p>لا يجمع التطبيق أي معلومات شخصية أخرى</p>
<p> إذا أنت تستخدم خدمة الصراف (اختياري)، مونيرويو يجلب سعر الصرف عبر api coinmarketcap.com. اطلع على سياسة الخصوصية الخاصة بهم على https://coinmarketcap.com/privacy لتفاصيل على كيف تجمع بياناتك التي في الطلب. </p>
<p> عندما تستعمل التطبيق لتدفع إلى عنوانين بيتكوين، فأنت تستعمل خدمة SideShift.ai. اطلع على سياسة الخصوصية الخاصة بهم على https://sideshift.ai للتفاصيل. يرسل مونيرويو عنوان بيتوين و المبلغ إليهم. سيأخذ أيضاً عنوان بروتوكول الإنترنت (ip) الخاص بك.</p>
<h2>صلاحيات التطبيق</h2>
<ul>
<li>الإنترنت: للإتصال بشبكة مونيرو عبر عقدة مونيرو</li>
<li>قرائة ملفات التخزين الخارجي: لقرائة ملفات المحفظة المخزنة على الجهاز</li>
<li>الكتابة إلى التخزين الخارجي: لكتابة ملفات المحفظة المخزنة على الجهاز</li>
<li>قفل الإيقاظ: لإبقاء الجهاز ياقظاً عند التزامن</li>
<li>الكاميرا: لمسح رموز الاستجابة السريعة (qr) لاستلام مونيرو</li>
</ul>
<h2>التغيرات لسياسة الخصوصية هذه</h2>
<p>. يمكن أن نحدث سياسة الخصوصية هذه من حين إلى أخرى. سنقوم بتنبيهك لأاي تغيرات بنشر سياسة الخصوصية الجديدة في التطبيق و على الموقع (www.monerujo.io)
ننصحك أن تراجع هذه السياسة بشكل دوري لأاي تغيرات
<p>آخر تحديث لسياسة الخصوصية هذه كان في 10/11/2017
</p>
<h2>تواصل معنا</h2>
<p>privacy@monerujo.io.إذا كان لديك أي سؤال عن سياستنا أو عن كيفية تجميع بياناتك و معالجتها، الرجاء إرسال بريد الكتروني إلى
</p>
]]></string>
</resources>

View File

@ -1,215 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:locale="en">
<string name="help_create_new"><![CDATA[
<h1>أنشئ محفظة - جديدة</h1>
<p>إذا كنت تحتاج إلى عنوان مونيرو جديد!</p>
<p>أدخل اسم محفظة و كلمة سر فريدين.
كلمة المرور مستخدمة لتأمين بيانات محفظتك على الجهاز. استخدم كلمة سر قوية - و استخدام عبارة سر أفضل.</p>
<h2>دون البذرة الذاكرية!</h2>
<p>سترى في الشاشة التالية \"البذرة الذاكرية\" ذات 25 كلمة خاصة بك. هي كل ما تحتاجه لاسترجاع محفظتك لاحقاً و الحصول على وصول كامل لمالك.
إبقائها آمنة و خاصة مهم جداً، فهي تعطي <em>أي أحد<em> وصولاً كاملاً لمالك!</p>
<p>إذا نسيت كلمة مرور محفظتك يمكنك استرجاع محفظتك باستعمال بذرة الذاكرة.</p>
<p>ليس هناك طريقة لاسترجاع البذرة الذاكرية، إذا أضعتها ضاع مالك!
أيضاً، لا يمكن لبذرة الذاكرية أن تتغير و إذا ما سرقت أو انفضحت،
عليك أن تحول مالك إلى محفظة جديدة (مع بذرة ذاكرية جديدة). لذا من
الأفضل عمل نسخ احتياطية من بذرتك بكتابتها و تخزينها في <em>أكثر<em> من
مكان آمن</p>
]]></string>
<string name="help_create_seed"><![CDATA[
<h1>أنشئ محفظة - بذرة</h1>
<p>إذا لديك عنوان مونيرو و تريد استعادة المعاملات من سلسلة الكتل!</p>
<p>أدخل اسم محفظة و كلمة سر فريدين.
كلمة المرور مستخدمة لتأمين بيانات محفظتك على الجهاز. استخدم كلمة سر قوية - و استخدام عبارة سر أفضل.</p>
<p>أدخل بذرتك في حقل \"البذرة الذاكيرة\".<p>
<p>أدخل رقم الكتلة لأول معاملة لهذا العنوان في حقل \""\. يمكنك أيضاًاستعمال تاريخ في صيغة سسسس-شش-يي. إن لم تكن متأكداً أدخل تاريخ/كتلة تقريبي(ة) <em> قبل <em> استخدامك الأول لهذا العنوان.</p>
]]></string>
<string name="help_create_ledger"><![CDATA[
<h1>أنشئ محفظة - لدجر</h1>
<p>إذا كنت تسترجع محفظتك من جهاز لدجر نانو اس.</p>
<p>مفاتيحك السرية لا تغادر جهاز لدجر، لذا تجتاج إلى توصيله كلما أردت الوصول لمحفظتك.</p>
<p>أدخل اسم محفظة و كلمة سر فريدين. كلمة المرور مستخدمة لتأمين بيانات محفظتك على جهاز الأندرويد. استخدم كلمة سر قوية - واستخدام عبارة سر أفضل.</p>
<p>أدخل رقم الكتلة لأول معاملة لهذا العنوان في حقل \""\. يمكنك أيضاًاستعمال تاريخ في صيغة سسسس-شش-يي. إن لم تكن متأكداً أدخل تاريخ/كتلة تقريبي(ة) <em> قبل <em> استخدامك الأول لهذا العنوان.</p>
]]></string>
<string name="help_create_keys"><![CDATA[
<h1>أنشئ محفظة - مفاتيح</h1>
<p>إذا كنت تسترجع محفظتك باستخدام مفاتيحك!</p>
<p>أدخل اسم محفظة و كلمة سر فريدين. كلمة المرور مستخدمة لتأمين بيانات محفظتك على جهاز الأندرويد. استخدم كلمة سر قوية - واستخدام عبارة سر أفضل.<p>
<p>أدخل عنوان مونيرو في حقل \"العنوان العام\" و عبئ \"مفتاح الرؤية\" و \"مفتاح الانفاق\".</p>
<p>أدخل رقم الكتلة لأول معاملة لهذا العنوان في حقل \""\. يمكنك أيضاًاستعمال تاريخ في صيغة سسسس-شش-يي. إن لم تكن متأكداً أدخل تاريخ/كتلة تقريبي(ة) <em> قبل <em> استخدامك الأول لهذا العنوان.</p>
]]></string>
<string name="help_create_view"><![CDATA[
<h1>أنشئ محفظة - رؤية</h1>
<p>إذا كنت تريد مراقبة المعاملات القادمة إلى المحفظة!</p>
<p>أدخل اسم محفظة و كلمة سر فريدين. كلمة المرور مستخدمة لتأمين بيانات محفظتك على جهاز الأندرويد. استخدم كلمة سر قوية - واستخدام عبارة سر أفضل.<p>
<p>أدخل عنوان مونيرو ملكك في حقل "\عنوان عام"\ و املأ \مفتاح الرؤية"\".</p>
<p>أدخل رقم الكتلة لأول معاملة لهذا العنوان في حقل \""\. يمكنك أيضاًاستعمال تاريخ في صيغة سسسس-شش-يي. إن لم تكن متأكداً أدخل تاريخ/كتلة تقريبي(ة) <em> قبل <em> استخدامك الأول لهذا العنوان.</p>
]]></string>
<string name="help_details"><![CDATA[
<h1>تفاصيل المحفظة</h1>
<h2>العنوان العام</h2>
عنوانك العام بمثابة رقم حسابك البنكي يمكنك مشاركته مع أي أحد دون خوف من خسارة مونيرو الخاص بك. يرسل الناس المونيرو إلى محفظتك باستخدام هذا العنوان.
<h2>البذرة الذاكرية</h2>
هي كل ما تحتاجه لاسترجاع محفظتك و الحصول على وصول كامل لمالك. إبقائها خاصة و آمنة مهم جداًَ، فهي تعطي <em>لي أحد<em> وصولاً كاملاً لمونيرواتك! إذا لم تكتبها في مكان آمن رجاءً افعل!
<h2>كلمة مرور استرجاع ملفات المحفظة</h2>
تأكد من تدوين كلمة المرور هذه. ستحتاج إليها إذا أعدت ضبط جهازك أو ألغيت تثبيت التطبيق.<br/>
<h3>CrAzYpass</h3>
إذا كانت كلمة المرور المعروضة هنا هي أبجدية رقمية من 52 جزء في مجموعات من 4 - تهانينا!
ملفات محفظتك مؤمنة باستخدام مفتاح 256 بت مولد باستخدام خصائص أمان جهازك
أساساً على عبارة المرور التي خترتها (عند الإنشاء أو بتغييرها). هذا يجعلها صعبة جداً للاختراق!<br/>
هذه الميزة اجبارية لكل المحافظ الجديدة.
<h3>كلمة السر القديمة</h3>
إذا ترى عبارة مرورك هنا، محفظتك ليسب بأمان استخدام CrAzYpass. لإصلاح هذا فقط اختار \"غير كلمة المرور\" من القائمة. بعد إدخالك عبارة مرور جديدة (ربما نفسها القديمة) سيولد التطبيق CrAzYpass لك و سيؤمن ملفات محفظتك به. اكتبه!
<h3>CrAzYpass محافظ</h3>
إذا احبجت في أي وقت إلى إعادة تثبيت مونيرويو (بعد إعادة ضبط هاتفك أو التبديل إلى جهاز جديد مثلاً) أو إذا أردت استخدام ملفات المحفظة جهاز مختلف أو حاسوب، فيجب عليك استعمال كلمة المرور الاسترجاعية هذه للوصول إلى محفظتك مجدداً.<br/>
بإختيارك \"غير عبارة المرور\" من القاءمة، يمكنك اختيار عبارة مرور أخرى. انتبة أن هذا سيولد كلمة مرور استرجاعية جديدة. اكتبها!
<h2>مفتاح الرؤية</h2>
يمكنك استخدام مفتاح الرؤية الخاص بك لمراقبة المعاملات القادمة لمحفظتك دون اعطاء إذن لإنفاق المال داخل محفظتك.
<h2>مفتاح الإنفاق</h2>
مفتاح الانفاق الخاص بك يسمح لأي شحص بانفاق المونيرو المتعلق بمحفظتك، لذا لا تخبر أجداً بالمفتاح. أبقه آمناً كبذرة الذاكرية.
]]></string>
<string name="help_list"><![CDATA[
<h1>قائمة المحافظ</h1>
<h2>العقدة</h2>
<p>.مونيرويو يستخدم عقدة بعيدة للاتصال بشبكة مونيرو دون الحاجة إلى تنزيل و الاحتفاظ بنسخة كاملة من سلسة الكتل. يمكنك العثور على قائمة من العقد الشائعة أو تعلم كيف تشغل عقدة خاصة بك هنا https://moneroworld.com<p>
<p>يأتي مونيرويو مع بعض العقد البعيدة المحددة مسبقاً. مونيرويو يتذكر آخر خمس عقد مستخدمة.</p>
<h2>المحافظ</h2>
<p>هنا ترى محافظك. هن موجودات في مجلد <tt>monerujo</tt> في التخزين الداخلى لجهازك.
يمكنك استعمال تطبيق مستكشف ملفات لرؤيتهن. ينبغي عليك عمل نسخ احتياطية من هذا المجلد
على أسس منتظمة لتخزين خارج جهازك في حالة انفجاره أو سرقته</p>
<p>اختر محفظة لتفتحها أو المس زر \"+\" لإنشاء واحدة جديدة. أو اختر واحدة من عمليات المحفظة:</p>
<h3>التفاصيل</h3>
<p>أظهر تفاصيل المحفظة، البذرة و المفاتيح.</p>
<h3>استلم</h3>
<p>أنشئ رمز استجابة سريعة(qr code) لاستلام المونيرو.</p>
<h3>أعد التسمية</h3>
<p>أعد تسمية المحفظة. النسخ الاحتياطية لا تعاد التسمية.</p>
<h3>نسخة احتياطية</h3>
<p>أنشئ نسخة من المحفظة في مجلد <tt>backups</tt> داخل مجلد <tt>monerujo</tt> مستبدلة النسخ السابقة هناك. </p>
<h3>أرشيف</h3>
<p>أنشئ نسخة احتياطية ثم احذف المحفظة. النسخة تبقى في مجلد <tt>backups</tt> إذا لم تعد بحاجة إلى نسخك الاحتياطية ينبغي أن تحذفهم باستعمال متصفح ملفات أو تطبيق حذف آمن.</p>
]]></string>
<string name="help_tx_details"><![CDATA[
<h1>تفاصيل المعاملة</h1>
<h2>الوجهة</h2>
هذا هو العنوان العام للمحفظة التي تريد إرسال مونيرو إليها.
<h2>معرف الدفع</h2>
يمكنك استخدام معرف دفع لتعريف السبب لارسالك مونيرو بين طرفين. هذا اختياري
و خاص. فمثلاً يسمح لشركة بتسوية معاملتك مع غرض شريته.
<h2>TX ID</h2>
هذا هو معرف معاملتك. يمكنك استخدامه لتعريف معاملتك المشوشة في مستكشف سلسلة كتل مونيرو مثل <a href="https://xmrchain.net/">https://xmrchain.net/</a>
<h2>TX KEY (مفتاح المعاملة)</h2>
هذا هو مفتاح معاملتك الخاص، أبقه آمناً فإظهاره إلى طرف ثالث يظهر أي توقيع في (حلقة/طوق/خاتم) هو الخاص بك، جاعلاً معاملاتك شفافة.
<h2>كتلة</h2>
هذه هي الكتلة التي تحتوي معاملتك.
]]></string>
<string name="help_send"><![CDATA[
<h1>أرسل</h1>
<h2>عنوان المستلم</h2>
<p>هذا هو العنوان العام للمحفظة التي تريد إرسال مونيرو إليها، يمكنك نسخه من الحافظة
، مسح رمز استجابة سريعة (QR) أو إدخاله يدوياً. تأكد من العنوان لضمان عدم الارسال إلى عنوان خطأ.</p>
<p>بالإضافة إلى عنوان مونيرو يمكنك استعمال
<ul>
<li>مفتوحة (OpenAlias) لXMR أو BTC</li>
<li>عنوان بيتكوين</li>
</u>
يرجى ملاحظة أن إرسال BTC يتم من خلال خدمة Sideshift.ai (انظر https://sideshift.ai
للتفاصيل). راجع قسم إرسال BTC أدناه.</p>
<h2>معرف الدفع</h2>
<p> يمكنك استخدام معرف دفع لتعريف السبب لارسالك مونيرو بين طرفين. هذا اختياري
و خاص. فمثلاً يسمح لشركة بتسوية معاملتك مع غرض شريته<p>
<h1>إرسال بيتكوين</h1>
<h2>SideShift.ai</h2>
<p>Sideshift.ai خدمة طرف ثالث تعمل كصرافة من مونيرو إلى بيتكوين. نستخدم API Sideshift.ai لإدراج دفع بيتكوين في مونيرويو. رجاءاً اطلع على https://sideshift.ai و قرر لنفسك إذا ما كانت جدمة تريد استخدامها. فريق مونيرويو ليس مرتبطاً بSideshift.ai ولا يمكنه مساعدتك مع خدمتهم</p>
<h2>SideShift.ai سعر صرف<h2>
<p>في شاشة \"المبلغ\" ستعرض عليك الضوابط الحالية لخدمة Sideshift.ai
هذه الضوابط تتضمن سعر الصرف الحالي بالإضافة إلى حدود BTC الدنيا و العليا. لاحظ أن هذا السعر ليس مضموناً في هذه المرحلة</p>
<h2>SideShift.ai طلب<h2>
<p>في شاشة \"أكد\" سترى طلب Sideshift.ai الفعلي. هذا الطلب صحيح لفترة محدودة
قد تلاحظ عداًَ تنازلياً على زر \"spend\". قد يكون سعر الصرف مختلفاً عن السعر الدلالي في الشاشة السابقة</p>
<h2>السري SideShift.ai مفتاح<h2>
<p>لأن مونيرويو فقط يتعامل مع جزء مونيرو من معاملتك يمكن لمفتاح Sideshift.ai السري الخاص البك أن يستعل لتتبع جزء بيتكوين من طلبك على موقع Sideshift.ai</p>
<h2>SideShift.ai عد تنازلي</h2>
<p>عند وصول العد التنازلي إلى الصفر، تحتاج إلى الحصول على سعر جديد من Sideshift.ai بالرجوع إلى الخطوة السابقة ثم العودة إلى شاشة \"أكد\"</p>
]]></string>
<string name="help_xmrto"><![CDATA[
<h1>إرسال بيتكوين</h1>
<h2>SideShift.ai</h2>
<p>Sideshift.ai خدمة طرف ثالث تعمل كصرافة من مونيرو إلى بيتكوين. نستخدم API Sideshift.ai لإدراج دفع بيتكوين في مونيرويو. رجاءاً اطلع على https://sideshift.ai و قرر لنفسك إذا ما كانت جدمة تريد استخدامها. فريق مونيرويو ليس مرتبطاً بSideshift.ai ولا يمكنه مساعدتك مع خدمتهم.</p>
<h2>SideShift.ai سعر صرف<h2>
<p>في شاشة \"المبلغ\" ستعرض عليك الضوابط الحالية لخدمة Sideshift.ai
هذه الضوابط تتضمن سعر الصرف الحالي بالإضافة إلى حدود BTC الدنيا و العليا. لاحظ أن هذا السعر ليس مضموناً في هذه المرحلة.</p>
<h2>SideShift.ai طلب<h2>
<p>في شاشة \"أكد\" سترى طلب Sideshift.ai الفعلي. هذا الطلب صحيح لفترة محدودة
قد تلاحظ عداًَ تنازلياً على زر \"spend\". قد يكون سعر الصرف مختلفاً عن السعر الدلالي في الشاشة السابقة.</p>
<h2>السري SideShift.ai مفتاح<h2>
<p>لأن مونيرويو فقط يتعامل مع جزء مونيرو من معاملتك يمكن لمفتاح Sideshift.ai السري الخاص البك أن يستعل لتتبع جزء بيتكوين من طلبك على موقع Sideshift.ai</p>
<h2>التنازلي! SideShift.ai عد</h2>
<p>عند وصول العد التنازلي إلى الصفر، تحتاج إلى الحصول على سعر جديد من Sideshift.ai بالرجوع إلى الخطوة السابقة ثم العودة إلى شاشة \"أكد\"</p>
<string name="help_wallet"><![CDATA[
<h1>المحفظة</h1>
<h2>وضع الشارع</h2>
<p>
يمكنك تفعيل/تعطيل وضع الشارع في القائمة أو أيقونة رأس غونثر. في هذا الوضع، رصيدك لا يظهر على أي شاشة لذا يمكنك استخدام محفظتك بأمان في الشارع، القهوة، أو أي مكان عام. المعاملات السابقة أيضاً مخفية. ستعرض المعاملات الجديدة لترى أنك أرسلت/استلمت موينرو.</p>
<h2>مسح</h2>
لأن مونيرو يحب إبقاء الأشياء خاصة، كل مرة تفتح محفظة موينيرويو علينا مسح سلسلة الكتل لنرى إذا ما أرسل مونيرة إلى محفظتك. أحياناً يستغرق فترةً لأنك لم تزامن منذ فترة طويلة.
<h2>الرصيد</h2>
<p><b>النجدة! رصيد محفظتي اختفى أو هو غير مؤكد!</b><br/>
لا تفزع! عندما ترسل المال من محفظتك، بعض رصيدك سيظهر مؤقتاً كغير مؤكد.
يحصل نتيجةً لكيفية تبادل مونيرو على سلسلة الكتل و كيفية عمل الفكة. إقرأ أكثر عن الفكة على https://getmonero.org/resources/moneropedia/change.html
<h2>قائمة المعاملات</h2>
<p>في محافظ الرؤية، فقط تعرض المعاملات القادمة.</p>
]]></string>
<string name="help_node"><![CDATA[
<h1>العقد</h1>
<h2>المختصر المفيد</h2>
<p>أعد تحميل قائمة العقد بالسحب للأسفل &amp; bookmark 3&#8211;5 عقد لتسمح لمونيرويو أن يختار الأفضل لك!</p>
<h2>ما هي العقد؟</h2>
<p>مونيرويو يستخدم عقدة خارجية لالتواصل بشبكة مونيرو دون الحاجة لتنزيل نسخة كاملة من سلسلة الكتل .<p>
<h2>قائمة العقد</h2>
<p>إذا القائمة فارغة، يمكنك إما إضافة العقد يدوياً أو دع مونيرويو يمسح الشبكة لك. أو كلا الأمرين. إقرأ أكثر&#8230;</p>
<p>تعرض قائمة العقد كل العقد المعروفة حالياً. إضافةً، الطابع \ الختم الزمني لأحدث كتلة معروفة لكل عقدة يظهر
تحت اسم العقدة. تظهر أيقونة تمثل سلوك استجابة العقدة (يشير إلى مستوى الاتصال المتوقع) بجانب كل عقدة.</p>
<p>أي عقدة في القائمة يمكن أن تعلم لاستعمال لاحق.
العقد التي لم تعلم ستنسى.<p>
<p>سيختار مونيرويو العقدة المعلمة الأمثل كل مرة تستعمله.
يفعل هذا بالتأكد من ارتفاع الكتلة (ما هي حداثة العقدة؟)
إضافة إلى استجابتها (ما سرعة استجابة العقدة للطلبات؟).</p>
<p>هذه القائمة مفروزة حسب هذه الخصائص، فالعقدة العليا هي التي يختارها مونيرويو الآن. سيظهر الجزء السفلى عقد بطيئة جداً أو غير متوفرة.</p>
<h2>أضف عقدة</h2>
<p>عند لمس زر "أضف عقدة" في الأسفل، سيطلب منك إدخال تفاصيل العقدة في الحوار التالى.
"العنوان" هو اسم المضيف أو عنوان IP للعقدة - هذا المدخل الإلزامي الوحيد.
أدخل "المنفذ" إذا تشتغل العقدة في منفذ غير افتراضي )18089)
يمكنك أيضاً تسمية العقدة لتتمكن من التعرف عليها بسهولة في وقت لاحق.
بعض العقد تتطلب بيانات اعتماد لاستخدامهم. أدخل اسم المستخدم و كلمة المرور المزودين في الحقول المناسبة. الآن يمكنك "اختبار" هذه الاعدادات.
ستعرض "نتائج الاختبار" ارتفاع الكتلة، وقت الاستجابة، و عنوان IP المستعمل.
قد تكون النتيجة خطأً - عادة لأن اسم المصيف المزود لا يمكن الوصول إليه في وقت معقول أو أن بيانات الاعتماد غير صحيحة.أو أن اسم المضيف/المنفذ لا يشيران إلى عقدة مونيرو حقيقية!
عند اجتياز الاختبار (لا اخطاء) - يمكنك لمس "حسناً" لحفظ و تعليم هذه العقدة</p>
<h2>ابحث عن العقد</h2>
<p>إضافةً، يمكنك مسح الشبكة للعقد. مونيرويو سيبدأ مسح الشبكة للعقد البعيدة في منفذ 18098. يبدأ بيؤال العقد المعلمة عن أنداد آخرين في شبكة مونيرو ثم يستمر بسؤالهم عن أندادهم، وهكذا. إذا لا تملك عقد معلمة (أو لا يخبروننا عن أندادهم)، مونيرويو سيتجه مباشرةً إلى عقد بذور مونيرو ضمن مونيرو. سيتوقف المسح عند العثور على 10 عقد بعيدة. </p>
]]></string>
<string name="help_uri"><![CDATA[
<h1>استخدام رابط دفع</h1>
<p>لقد بدأت مونيرويو باستخدام رابط دفق. لإرسال المال افعل التالي:</p>
<p>
1. المحفظة التي تريد الانفاق منها<br>
2. انتظر حتى تزامن المحفظة وamp; يظهر زر "أعط"<br>
3. المس زر "أعط"
</p>
<p>.ستعبأ تفاصيل الدفع. تأكد منهم ثم أكمل كأي معاملة أخرى</p>
]]></string>
<string name="help_ok">فهمت!</string> <!-- Note: "Got it" as in "I understand this" -->
</resources>

View File

@ -1,427 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="wallet_activity_name">محفظة</string>
<string name="menu_about">عن</string>
<string name="menu_privacy">سياسة الخصوصية</string>
<string name="menu_share">شارك</string>
<string name="menu_help">ساعدني</string>
<string name="menu_receive">استلم</string>
<string name="menu_rename">أعد التسمية &#8230;</string>
<string name="menu_delete">Delete</string>
<string name="menu_backup">انشئ نسخة احتياطية</string>
<string name="menu_changepw">غير كلمة المرور</string>
<string name="password_weak">&#8230; أكمل الكتابة</string>
<string name="password_fair">&#8230; مه</string>
<string name="password_good">هيا يمكنك القيام بأفضل من هذا!</string>
<string name="password_strong">تكاد تصل &#8230;</string>
<string name="password_very_strong">أجل، كالمحترفين!</string>
<string name="label_login_wallets">المحافظ</string>
<string name="label_credits">الاعتمادات</string>
<string name="label_ok">حسناً</string>
<string name="label_cancel">إلغاء</string>
<string name="label_close">أغلق</string>
<string name="label_wallet_advanced_details">المس لالتفاصيل</string>
<string name="label_send_success">نجح الإرسال</string>
<string name="label_send_done">تم</string>
<string name="label_receive_info_gen_qr_code">المس لرمز استجابة سريعة (qr)</string>
<string name="info_xmrto_enabled">دفع BTC مفعل، المس لمعلومات أكثر.</string>
<string name="info_ledger_enabled">لدجر مفعل، المس لمعلومات أكثر.</string>
<string name="info_xmrto"><![CDATA[
<b>أدخلت عنوان بيتكوين.</b><br/>
<i>سترسل XMR و سيستلم المستلم %1$s باستخدام خدمة <b>Sideshift.ai</b></i>
]]></string>
<string name="info_send_xmrto_success_order_label">Sideshift.ai طلب</string>
<string name="info_send_xmrto_success_btc">%1$s BTC</string>
<string name="info_send_xmrto_paid">التأكيد معلق</string>
<string name="info_send_xmrto_unpaid">الدفع معلق</string>
<string name="info_send_xmrto_error">Sideshift.ai عطل (%1$s)</string>
<string name="info_send_xmrto_sent">BTC أرسل</string>
<string name="info_send_xmrto_query">جار الاستعلام &#8230;</string>
<string name="info_send_xmrto_parms"><![CDATA[
<b>يمكنك إرسال %1$s &#8212; %2$s BTC</b>.<br/>
<i><b>Sideshift.ai</b> يعطيك سعر صرف <b>%3$s BTC</b> <u>حالياً</u></i>.
]]></string>
<string name="send_available_btc">الرصيد: %2$s BTC (%1$s XMR)</string>
<string name="info_paymentid_integrated">&#x2714; معرف الدفع مدمج</string>
<string name="info_prepare_tx">تجهيز عمليتك</string>
<string name="label_send_progress_xmrto_create">جار إنشاء طلب Sideshift.ai</string>
<string name="label_send_progress_xmrto_query">استعلام طلب Sideshift.ai</string>
<string name="label_send_progress_create_tx">جار تجهيز معاملة مونيرو</string>
<string name="label_send_progress_queryparms">استعلام ضوابط Sideshift.ai</string>
<string name="label_generic_xmrto_error">Sideshift.ai عطل</string>
<string name="text_generic_xmrto_error">رمز: %1$d</string>
<string name="text_retry">المس لإعادة المحوالة</string>
<string name="text_noretry_monero">علقنا هنا!</string>
<string name="text_noretry">يبدو أن Sideshift.ai ليس متوفراً حالياً!</string>
<string name="text_send_btc_amount">%1$s BTC = %2$s XMR</string>
<string name="text_send_btc_rate">(الصرف: %1$s BTC/XMR)</string>
<string name="label_send_btc_xmrto_info">قم بزيارة Sideshift.ai للدعم و التتبع</string>
<string name="label_send_btc_xmrto_key_lb">المفتاح السري\nSideshift.ai</string>
<string name="label_send_btc_xmrto_key">السري Sideshift.ai مفتاح</string>
<string name="label_send_btc_address">عنوان الوجهة BTC</string>
<string name="label_send_btc_amount">المبلغ</string>
<string name="label_send_txid">معرف المعاملة</string>
<string name="label_send_address">عنوان الوجهة</string>
<string name="label_send_notes">ملاحظات</string>
<string name="backup_progress">جار إنشاء النسخة الاحتياطية</string>
<string name="archive_progress">جار الأرشفة</string>
<string name="rename_progress">جار إعادة التسمية</string>
<string name="changepw_progress">جار تغيير كلمة المرور</string>
<string name="service_progress">جار اختتام الأمور &#8230;\nقد يستغرق هذا برهةً!</string>
<string name="backup_success">نجح النسخ الاحتياطي</string>
<string name="backup_failed">فشل النسخ الاحتياطي!</string>
<string name="delete_failed">Delete failed!</string>
<string name="rename_failed">فشلت إعادة التسمية!</string>
<string name="changepw_failed">فشل تغيير كلمة السر!</string>
<string name="changepw_success">تم تغيير كلمة السر</string>
<string name="label_daemon">العقدة</string>
<string name="status_wallet_loading">جار تحميل المحفظة &#8230;</string>
<string name="status_wallet_unloaded">حفظت المحفظة</string>
<string name="status_wallet_unload_failed">فشل حفظ المحفظة!</string>
<string name="status_wallet_connecting">جار الاتصال &#8230;</string>
<string name="status_wallet_connect_failed">فشل الاتصال بالعقدة!\nتأكد من اسم المستخدم/كلمة المرور</string>
<string name="status_wallet_connect_wrongversion">نسخة العقدة غير متوافقة - حدث رجاءً!</string>
<string name="status_wallet_node_invalid">العقدة غير صحيحة!\nجرب عقدة أخرى.</string>
<string name="status_wallet_connect_ioex">لا يمكن الوصول للعقدة!\nحاول مجدداً أو جرب عقدة أخرى.</string>
<string name="status_wallet_disconnected">منقطعة</string>
<string name="status_transaction_failed">فشلت المعاملة: %1sd</string>
<string name="send_xmrto_timeout">!انتظرت طويلاً يا صاحبي!</string>
<string name="service_busy">&#8230;ما زلت مشغولاً بمحفظتك الأخيرة </string>
<string name="prompt_rename">أعد التسمية %1$s</string>
<string name="prompt_changepw">كلمة مرور جديدة ل %1$s</string>
<string name="prompt_changepwB">أعد كلمة المرور ل %1$s</string>
<string name="prompt_password">كلمة السر ل%1$s</string>
<string name="prompt_fingerprint_auth">يمكنك أيضاً فتح المحفظة باستعمال البصمة.\nرجاءً المس الحساس.</string>
<string name="prompt_open_wallet">جار فتح المحفظة&#8230;</string>
<string name="bad_fingerprint">لم يتعرف على البصمة. حاول مجدداً.</string>
<string name="bad_password">كلمة السر خاطئة!</string>
<string name="bad_saved_password">كلمة المرور المحفوظة غير صحيحة.\nرجاءً أدخل كلمة المرور يدوياً.</string>
<string name="bad_wallet">المحفظة غير موجودة!</string>
<string name="prompt_daemon_missing">!يجب ضبط العقدة!</string>
<string name="prompt_wrong_net">المحفظة لا تطابق الشبكة المختارة</string>
<string name="label_watchonly">(مشاهدة فقط)</string>
<string name="label_wallet_receive">استلم</string>
<string name="label_wallet_send">أعط</string>
<string name="xmr_unconfirmed_amount">+ %1$s XMR غير مأكد</string>
<string name="service_description">خدمة مونيرويو</string>
<string name="status_synced">تزامن؛</string>
<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">مفتاح الرؤية</string>
<string name="label_copy_address">العنوان العام</string>
<string name="label_copy_xmrtokey">Sideshift.ai مفتاح</string>
<string name="message_copy_viewkey">نسخ مفتاح الرؤية إلى الحافظة!</string>
<string name="message_copy_xmrtokey">نسخ مفتاح Sideshift.ai إلى الناسخة!</string>
<string name="message_copy_address">نسخ عنوان المحفظة للحافظة!</string>
<string name="message_copy_txid">نسخ معرف المعاملة إلى الحافظة!</string>
<string name="message_nocopy">النسخ معطل لأسباب أمنية!</string>
<string name="message_exchange_failed">لا يمكن الحصول على سعر الصرف!\nاستعمل XMR/XMR أو حاول مجدداً</string>
<string name="generate_title">أنشئ محفظة</string>
<string name="generate_name_hint">اسم المحفظة</string>
<string name="generate_password_hint">كلمة مرور المحفظة</string>
<string name="generate_fingerprint_hint">اسمح لفتح المحفظة بالبصمة</string>
<string name="generate_fingerprint_warn"><![CDATA[
<strong>التوثيق بالبصمة</strong>
<p>عند تفعيل التوثيق بالبصمة، يمكنك رؤية رصيد المحفظة و استلام المال دون ادخال كلمة السر.</p>
<p>لكن لزيادة الأمان، مونيرويو سيتطلب منك أن تدخل كلمةالمرور عند رؤية تفاصيل المحفضة أو إرسال المال.</p>
<strong>تحذير أمني</strong>
<pأخيراً، نريد أن نذكرك أن أي أحد يمكنه الحصول على بصمتك سيتمكن من يطل على رصيد محفظتك.</p>
<p>مثلا، ينكن لشخص خبيث فتح محفظتك و أنت نائم.</p>
<strong> هل أنت متأكد أنك تريد تفعيل هذه ال</strong>
]]></string>
<string name="generate_bad_passwordB">السر لا تتطابق</string>
<string name="generate_empty_passwordB">لا يمكن لعبارة المرور أن تكون فارغة</string>
<string name="generate_buttonGenerate">انشئ لي محفظة و خلصنا!</string>
<string name="generate_button_accept">دونت بذرة الذاكرة</string>
<string name="generate_wallet_name">أعطني اسماً</string>
<string name="generate_wallet_exists">المحفظة موجودة!</string>
<string name="generate_wallet_dot">لا يمكن البدء ب.</string>
<string name="generate_wallet_creating">جار إنشاء المحفظة</string>
<string name="generate_wallet_created">أنشأت المحفظة</string>
<string name="generate_restoreheight_error">أدخل رقماً أو تاريخاً (سسسس-شش-يي)</string>
<string name="generate_wallet_type_key">المفاتيح</string>
<string name="generate_wallet_type_new">جديد</string>
<string name="generate_wallet_type_seed">بذرة</string>
<string name="generate_wallet_type_view">رؤية</string>
<string name="generate_address_hint">العنوان العام</string>
<string name="generate_viewkey_hint">مفتاح الرؤية</string>
<string name="generate_spendkey_hint">مفاح الإنفاق</string>
<string name="generate_mnemonic_hint">بذرة الذاكرة ذات 25 كلمة</string>
<string name="generate_restoreheight_hint">استرجع الارتفاع أو التاريخ (سسسس-شش-يي)</string>
<string name="generate_address_label">العنوان العام</string>
<string name="generate_viewkey_label">مفتاح الرؤية</string>
<string name="generate_spendkey_label">مفتاح الإنفاق</string>
<string name="generate_mnemonic_label">بذرة الذاكرة</string>
<string name="generate_crazypass_label">ملفات المحفظة استرجع كلمة المرور</string>
<string name="generate_check_key">أدخل مفتاحاً صحيحاً</string>
<string name="generate_check_address">أدخل عنواناً صحيحاً</string>
<string name="generate_check_mnemonic">أدخل بذرتك ذات 25 كلمة</string>
<string name="send_notes_hint">الملاحظات الخاصة (اختياري)</string>
<string name="send_generate_paymentid_hint">ولد</string>
<string name="send_send_label">أنفق مونيرواتي الحبيبة</string>
<string name="send_send_timed_label">أرسل مونيرواتي الحبيبة (%1$s)</string>
<string name="send_qr_invalid">ليس رمز استجابة سريعة (QR)</string>
<string name="send_qr_address_invalid">ليس رمزاً حصيحاً</string>
<string name="send_address_invalid">ليس عنواناً صحيحاً</string>
<string name="send_address_not_openalias">عنوان OpenAlias ليس متوفر</string>
<string name="send_address_openalias">آمن &#x2714;</string>
<string name="send_address_resolve_openalias">حل OpenAlias&#8230;</string>
<string name="send_address_no_dnssec">OpenAlias دون DNSSEC - قد يكون العنوان منتحل</string>
<string name="send_title">أرسل</string>
<string name="send_available">الرصيد: %1$s XMR</string>
<string name="send_address_title">العنوان</string>
<string name="send_amount_title">المبلغ</string>
<string name="send_confirm_title">أكد</string>
<string name="send_success_title">تم</string>
<string name="send_amount_label">المبلغ</string>
<string name="send_fee_btc_label">الرسوم (xmr)</string>
<string name="send_fee_label">الرسوم</string>
<string name="send_total_btc_label">المجموع (xmr)</string>
<string name="send_total_label">المجموع</string>
<string name="send_amount">%1$s XMR</string>
<string name="send_fee">+%1$s رسوم</string>
<string name="send_create_tx_error_title">عطل إنشاء المعاملة</string>
<string name="tx_list_fee">- رسوم %1$s</string>
<string name="tx_list_amount_failed">(%1$s)</string>
<string name="tx_list_failed_text">فشل</string>
<string name="tx_list_amount_negative">- %1$s</string>
<string name="tx_list_amount_positive">+ %1$s</string>
<string name="tx_timestamp">الختم الزمني</string>
<string name="tx_id">TX ID</string>
<string name="tx_key">TX Key</string>
<string name="tx_destination">الوجهة</string>
<string name="tx_paymentId">معرف الدفع</string>
<string name="tx_blockheight">الكتلة</string>
<string name="tx_amount">المبلغ</string>
<string name="tx_fee">الرسوم</string>
<string name="tx_transfers">التحويلات</string>
<string name="tx_notes">ملاحظات</string>
<string name="tx_notes_hint">(اختياري)</string>
<string name="tx_title">تفاصيل المعاملة</string>
<string name="tx_pending">معلقة</string>
<string name="tx_failed">فشلت</string>
<string name="receive_amount_hint">المبلغ</string>
<string name="receive_desc_hint">وصف (اختياري)</string>
<string name="receive_cannot_open">لم يتمكن من فتح المحفظة!</string>
<string name="receive_amount_too_big">%1$s أقصى</string>
<string name="receive_amount_negative">0 أدنى</string>
<string name="receive_amount_nan">XMR ليس رقماً</string>
<string name="details_alert_message">ستظهر بيانات حساسة.\nتفحص خلف ظهرك!</string>
<string name="details_alert_yes">أنا في أمان</string>
<string name="details_alert_no">أرجعني!</string>
<string name="details_title">التفاصيل</string>
<string name="fab_create_new">أنشئ محفظة جديدة</string>
<string name="fab_restore_viewonly">استرجع محفظة رؤية-فقط</string>
<string name="fab_restore_key">استرجع محفظة من المفاتيح الخاصة</string>
<string name="fab_restore_seed">استرجع محفظة من بذرة 25 كلمة</string>
<string name="accounts_drawer_new">أنشئ حساباً</string>
<string name="accounts_new">أضيف حساب جديد #%1$d</string>
<string name="tx_account">الحساب #</string>
<string name="send_sweepall">أرسل كل المال المؤكد في هذا الحساب!</string>
<string name="tx_subaddress">العنوان الفرعي #%1$d</string>
<string name="generate_address_label_sub">العنوان الفرعي العام #%1$d</string>
<string name="menu_language">اللغة</string>
<string name="language_system_default">استخدم لغة النظام</string>
<string name="fab_restore_ledger">استرجع من لدجر نانو اس</string>
<string name="progress_ledger_progress">جار التواصل مع اللدجر</string>
<string name="progress_ledger_confirm">التأكيد على اللدجر مطلوب!</string>
<string name="progress_ledger_lookahead">استلام العناوين الفرعية</string>
<string name="progress_ledger_verify">التأكد من صحة المفاتيح</string>
<string name="progress_ledger_opentx">القيام بحسابات مجنونة</string>
<string name="progress_ledger_mlsag">تشفير الأشياء</string>
<string name="open_wallet_ledger_missing">رجاءً (إعادة) إيصال جهاز لدجر</string>
<string name="accounts_progress_new">جار إنشاء الحساب</string>
<string name="toast_ledger_attached">%1$s اربط</string>
<string name="toast_ledger_detached">%1$s فصل</string>
<string name="progress_nfc_write">جار كتابة العلامة</string>
<string name="nfc_write_failed">فشلت كتابة العلامة</string>
<string name="nfc_write_successful">نجحت كتابة العلامة</string>
<string name="nfc_tag_unsupported">العلامة لا تدعم NDEF!</string>
<string name="nfc_tag_size">العلامة تزود %1$dلأ بايتاً، لكننا نحتاج %2$dل!</string>
<string name="nfc_tag_read_undef">لا أفهم العلامة!</string>
<string name="nfc_tag_read_what">لا أعرف ماذا تريد!</string>
<string name="nfc_tag_tap">NFC متوفر!</string>
<string name="menu_info">أظهر أسراري!</string>
<string name="menu_streetmode">وضع الشارع</string>
<string name="info_nodes_enabled">Node-o-matiC مفعل، المس لمعلومات أكثر.</string>
<string name="node_height">آخر كتلة تحدثت: %1$s</string>
<string name="label_nodes">العقد</string>
<string name="node_name_hint">اسم العقدة (اختياري)</string>
<string name="node_address_hint">اسم المضيف</string>
<string name="node_port_hint">المنفظ</string>
<string name="node_user_hint">اسم المستخدم (اختياري)</string>
<string name="node_pass_hint">كلمة المرور (اختياري)</string>
<string name="node_host_unresolved">لا يمكن حل المضيف</string>
<string name="node_host_empty">نحتاج لهذا!</string>
<string name="node_port_numeric">يجب أن يكون رقماً</string>
<string name="node_port_range">1&#8211;65535 يجب أن يكون</string>
<string name="node_fab_add">أضف عقدة</string>
<string name="node_refresh_hint">المس لإعادة التحميل</string>
<string name="node_test_error">%1$d عطل إطصال</string>
<string name="node_general_error">عطل في الاتصال</string>
<string name="node_auth_error">فشل التوثيق</string>
<string name="node_result_label">نتيجة الاختبار:</string>
<string name="node_result">الارتفاع: %1$s (v%2$d), Ping: %3$.0fms, IP: %4$s</string>
<string name="node_testing">اختبار IP: %1$s &#8230;</string>
<string name="node_refresh_wait">رجاءً انتظر انتهاء المسح</string>
<string name="node_create_hint">المس لاختيار أو إضافة العقد</string>
<string name="node_pull_hint">أضف العقد يدوياً أو اسحب للأسفل للمسح</string>
<string name="node_scanning">جار مسح الشبكة&#8230;</string>
<string name="node_nobookmark">علمت أفضل %1$d عقد تلقائياً</string>
<string name="label_test">اختبر</string><!--note: as in "Test a network connection"-->
<string name="send_address_hint">المستلم</string>
<string name="street_sweep_amount">كل شيء!</string>
<string name="menu_ledger_seed">حول بذرة اللدجر</string>
<string name="prompt_ledger_seed">كلمات بذرة اللدجر</string>
<string name="prompt_ledger_phrase">عبارة دخول اللدجر (متقدم)</string>
<string name="bad_ledger_seed">بذرة اللدجر غير صحيحة!</string>
<string name="prompt_ledger_seed_warn">إدخال بذرة اللدجر هنا خطر أمني كبير!</string>
<string name="label_restoreheight">استرجع الارتفاع</string>
<string name="toast_ledger_start_app">ابدأ تطبيق مونيرو في %1$s</string>
<string name="menu_rescan">أعد المسح!</string>
<string name="onboarding_agree">فهمت!</string>
<string name="onboarding_button_next">التالي</string>
<string name="onboarding_button_ready">أنا جاهز!</string>
<string name="onboarding_welcome_title">مرحباً بك في مونيرويو!</string>
<string name="onboarding_welcome_information">هذا التطبيق يسمح لك بإنشاء و استخدام محافظ مونيرو. يمكنك الاحتفاظ بالحبيب مونيرو فيهم.</string>
<string name="onboarding_seed_title">أبق بذرتك آمنة</string>
<string name="onboarding_seed_information">البذرة تمنح وصولاً كاملاً لمن يمتلكها.إذا ما أضعتها لا يمكننا مساعدتك في استرجاعها و ستخسر مونيرواتك الحبيبة.</string>
<string name="onboarding_xmrto_title">أرسل بيتكوين</string>
<string name="onboarding_xmrto_information">لدى مونيرويو دعم داخلي لSideshift.ai. فقط الصق أو امسح عنوان بيتكوين و سترسل بيتكون بانفاق مونيرو.</string>
<string name="onboarding_nodes_title">العقد، كما تشاء</string>
<string name="onboarding_nodes_information">العقد تصلك بشبكة مونيرو. اختر ما بين العقد العامة أو كن متمرداً سبرانياً و استخدم خاصتك.</string>
<string name="onboarding_fpsend_title">أرسل بالبصمة</string>
<string name="onboarding_fpsend_information">يمكنك الآن إرسال XMR فقط ببصمتك إذا فعلتها. لطلب كلمة المرور، فقط عطل الدخول بالبصمة.</string>
<string name="menu_daynight">الوضع الليلي</string>
<string-array name="daynight_themes">
<item>تلقائي</item>
<item>يوم</item>
<item>ليل</item>
</string-array>
<string name="gunther_says">لا شيء هنا\nالرجاء إنشاء أو استعادة محفظة</string>
<string name="menu_default_nodes">أرجع العقد الافتراضية</string>
<string name="toast_default_nodes">الاسترجاع يتقدم بالفعل...</string>
<string name="node_updated_now">الكتلة الأخيرة: منذ %1$d ثوان</string>
<string name="node_updated_mins">الكتلة الخيرة: منذ %1$d ساعة</string>
<string name="node_updated_hours">الكتلة الأخيرة: منذ %1$d ساعة</string>
<string name="node_updated_days">الكتلة الأخيرة: منذ %1$d أيام</string>
<string name="shift_noquote">لا يمكن الحصول على سعر</string>
<string name="shift_checkamount">تأكد من البلغ و حاول مجدداً</string>
<string name="info_xmrto_ambiguous"><![CDATA[
<b>عنوان مبهم.</b><br/>
<i>رجاء حدد النوع أعلاه. </i>
]]></string>
<string name="info_xmrto_help"><![CDATA[
<b>رجاء أدخل أو امسح عنوان %1$s</b><br/>
<i>سترسل XMR و سيتلقى المستلم %2$s باستعمال خدمة <b>SideShift.ai</b></i>
]]></string>
<string name="info_xmrto_help_xmr"><![CDATA[
<b>رجاء أدخل أو امسح عنوان مونيرو</b>
]]></string>
<string name="subbaddress_title">العناوين الفرعية</string>
<string name="subbaddress_name_hint">اسم العنوان الفرعي</string>
<string name="max_subaddress_warning">عناوين غير مستعملة كثيرة - استعمل بعضها لتتمكن من إنشاء المزيد!</string>
<string name="max_account_warning">حسابات غير مستعملة كثيرة - استعمل بعضها لتتمكن من إنشاء المزيد!</string>
<string name="subaddress_tx_label">المعاملات لهذا العنوان الفرعي:</string>
<string name="subaddress_notx_label">لا معاملات لهذا العنوان الفرعي بعد</string>
<string name="subaddress_select_label">اختر عنواناً فرعياً</string>
<string name="subaddress_details_hint">المس طويلاً للتفاصيل</string>
<string name="menu_restore">استورد محفظة</string>
<string name="restore_failed">فشل الاستيراد</string>
<string name="menu_deletecache">أعد ضبط المحفظة!</string>
<string name="deletecache_alert_message">ستتم إعادة ضبط هذه المحفظة ، وفقدان جميع البيانات خارج السلسلة (مثل الملاحظات ، وأسماء الحسابات والعناوين الفرعية ، ومفاتيح المعاملات الخاصة ، ...)! استخدم هذا فقط إذا كانت هذه المحفظة تالفة و لا تحمل!</string>
<string name="delete_alert_message">This wallet will be deleted. Your funds will be gone forever unless you have your seed or a working backup to recover it.</string>
<string name="delete_alert_yes">Yes, do that!</string>
<string name="delete_alert_no">No thanks!</string>
<string name="send_address_resolve_ud">Resolving ENS / UD&#8230;</string>
<string name="send_address_no_ud_records">No address found for ENS / UD domain</string>
</resources>

View File

@ -4,11 +4,11 @@
<h1>Crear Portamonedes - New</h1>
<p>Per si necessiteu una nova adreça de Monero!</p>
<p>Introduïu un nom i contrasenya únics del portamonedes.
         La contrasenya sutilitza per protegir les dades del seu portamonedes en el dispositiu. Utilitzeu una contrasenya sòlida - encara millor si utiliza una frase.</p>
La contrasenya sutilitza per protegir les dades del seu portamonedes en el dispositiu. Utilitzeu una contrasenya sòlida - encara millor si utiliza una frase.</p>
<h2>Apunteu la vostra llavor mnemotècnica!</h2>
<p>A la pantalla següent trobareu la vostra "Llavor Mnemotècnica" de 25 paraules.
         Aquestes són les úniques dades necessàries per a recuperar el vostre portamonedes i obtenir accés total als vostres fons.
         Mantenir-la segura i privada és molt important ja que permet que <em> qualsevol persona</em> tingui accés total als vostres fons!.</p>
Aquestes són les úniques dades necessàries per a recuperar el vostre portamonedes i obtenir accés total als vostres fons.
Mantenir-la segura i privada és molt important ja que permet que <em> qualsevol persona</em> tingui accés total als vostres fons!.</p>
<p>Si perdeu la contrasenya del portamonedes encara podrieu recuperar-lo amb la llavor Mnemotècnica.</p>
<p>La llavor Mnemotècnica tampoc no es pot canviar mai, i si és robada o compromesa dalguna manera haureu de traslladar els vostres fons a un nou portamonedes (amb una nova llavor mnemotècnica). Per tant, es recomana que feu còpies de seguretat de la vostra llavor mnemotècnica escrivint-la i emmagatzemant-la a <em> múltiple </em> llocs de forma segura.</p>
]]></string>
@ -17,7 +17,7 @@
<h1>Crear Portamonedes - Llavor</h1>
<p>Si ja teniu una adreça Monero i voleu recuperar les transaccions de la blockchain!</p>
<p>Introduïu un nom i contrasenya únics del portamonedes.
         La contrasenya sutilitza per protegir les dades del seu portamonedes en el dispositiu. Utilitzeu una contrasenya sòlida - encara millor si utiliza una frase.</p>
La contrasenya sutilitza per protegir les dades del seu portamonedes en el dispositiu. Utilitzeu una contrasenya sòlida - encara millor si utiliza una frase.</p>
<p>Introduïu la Llavor en el camp \"Llavor Mnemotècnica\".<p>
<p>Introduïu el número de bloc de la primera transacció realitzada en aquesta adreça en el camp "Restaurar Alçada". També podeu utilitzar una data en el format AAAA-MM-DD. Si no esteu segurs, introduïu una data / alçada de bloc aproximada <em> abans </em> dhaver fer servir aquesta adreça del portamonedes.</p>
]]></string>
@ -36,7 +36,7 @@
<p>Introduïu un nom i contrasenya únics del portamonedes. La contrasenya sutilitza per protegir les dades de la seva cartera al dispositiu. Utilitzeu una contrasenya sòlida - encara millor si utiliza una frase.<p>
<p>Introduïu la vostra Adreça Monero en el camp \"Adreça Pública\" i ompliu \"Clau de Visualització\" i \"Clau de Despesa\" </p>
<p>Introduïu el número de bloc de la primera transacció realitzada en aquesta adreça en el
         camp "Restaurar Alçada". També podeu utilitzar una data en el format AAAA-MM-DD. Si no esteu segurs, introduïu una data / alçada de bloc aproximada <em> abans </em> dhaver fer servir aquesta adreça del portamonedes.</p>
camp "Restaurar Alçada". També podeu utilitzar una data en el format AAAA-MM-DD. Si no esteu segurs, introduïu una data / alçada de bloc aproximada <em> abans </em> dhaver fer servir aquesta adreça del portamonedes.</p>
]]></string>
<string name="help_create_view"><![CDATA[
@ -53,18 +53,18 @@
La vostra adreça pública és com el vostre número de compte bancari que podeu compartir amb qualsevol persona sense haver de tenir por de perdre el vostres Monero. La gent enviarà Monero al seu portamonedes mitjançant aquesta adreça.
<h2>Clau Mnemotècnica</h2>
Aquestes són les úniques dades necessàries per a recuperar el vostre portamonedes i obtenir accés total als vostres fons.
         Mantenir-la segura i privada és molt important ja que permet que <em> qualsevol persona</em> tingui accés total als vostres fons! Si no us heu escrit en cap lloc segur, feu-ho!
Mantenir-la segura i privada és molt important ja que permet que <em> qualsevol persona</em> tingui accés total als vostres fons! Si no us heu escrit en cap lloc segur, feu-ho!
<h2>Contrasenya de Recuperació dArxius del Portamonedes</h2>
Assegureu-vos que heu escrit aquesta contrasenya. Si restabliu el dispositiu o desinstal·leu laplicació, la necessitarà per tornar a accedir al seu portamonedes.<br/>
<h3>CrAzYsenya</h3>
Si la contrasenya que es mostra aquí és de 52 caràcters alfanumèrics en grups de 4 - felicitats!
        Els fitxers del portamonedes estan protegits amb una clau de 256 bits generada per la funció de seguretat del vostre dispositiu basades en la contrasenya que heu triat (durant la creació o al canviar-la). Això ho fa extremadament difícil de piratejar!<br/>
Els fitxers del portamonedes estan protegits amb una clau de 256 bits generada per la funció de seguretat del vostre dispositiu basades en la contrasenya que heu triat (durant la creació o al canviar-la). Això ho fa extremadament difícil de piratejar!<br/>
Aquesta opció és obligatoria per a tots els nous portamonedes.
<h3>Contrasenya de Llegat</h3>
Si veieu la vostra contrasenya aquí, els fitxers del portamonedes no estan tan segurs com quan sutilitza la CrAzYsenya. Per solucionar-ho, seleccioneu \"Canviar Contrasenya\" des del menú. Després dentrar una nova contrasenya (potser fins i tot la mateixa que abans) laplicació generarà una CrAzYsenya per a protegir els vostres arxius del portamonedes. Anoteu-la!
<h3>CrAzYsenya del Portamonedes</h3>
Si mai necessiteu tornar a instal·lar Monerujo (per exemple, després de restablir el telèfon o canviar-lo per un de nou) o voleu utilitzar els arxius del portamonedes en un altre dispositiu o PC, cal que ho feu utilitzant aquesta Contrasenya de Recuperació (CrAzYsenya) per tornar a accedir al vostre portamonedes. <br/>
        En seleccionar \"Canviar Contrasenya\" des del menú, podeu triar una nova contrasenya. Aneu amb compte que això generarà una nova Contrasenya de Recuperació (CrAzYsenya). Anoteu-la!
En seleccionar \"Canviar Contrasenya\" des del menú, podeu triar una nova contrasenya. Aneu amb compte que això generarà una nova Contrasenya de Recuperació (CrAzYsenya). Anoteu-la!
<h2>Clau de Visualització</h2>
La vostra clau de visualització es pot utilitzar per monitoritzar les transaccions entrants al vostre portamonedes sense donar-ne permís per gastar els fons a dins seu.
<h2>Clau de Despesa</h2>
@ -75,13 +75,13 @@
<h1>Llista de Portamonedes</h1>
<h2>Node</h2>
<p>Monerujo utilitza un node remot per comunicar-se amb la xarxa Monero sense necessitat
         de descarregar i emmagatzemar una còpia de tota la blockchain sencera. Podeu trobar una llista dels nodes remots més populars o aprendre a configurar el vostre propi node remot aquí https://moneroworld.com/<p>
de descarregar i emmagatzemar una còpia de tota la blockchain sencera. Podeu trobar una llista dels nodes remots més populars o aprendre a configurar el vostre propi node remot aquí https://moneroworld.com/<p>
<p>Monerujo té alguns Nodes remots incorporats. Sen recorda dels últims cinc nodes empleats.</p>
<h2>Portamonedes</h2>
<p>Aquí podeu veure els portamonedes. Es troben a la carpeta <tt> monerujo </tt>
         dins lemmagatzematge intern del dispositiu. Podeu utilitzar una aplicació dexploració darxius per veurels. Haurieu de fer còpies de seguretat daquesta carpeta de manera regular en un emmagatzematge extern al dispositiu en cas que el vostre dispositiu exploti o el robin.</p>
dins lemmagatzematge intern del dispositiu. Podeu utilitzar una aplicació dexploració darxius per veurels. Haurieu de fer còpies de seguretat daquesta carpeta de manera regular en un emmagatzematge extern al dispositiu en cas que el vostre dispositiu exploti o el robin.</p>
<p>Seleccioneu una portamonedes per obrir-lo o premeu el botó "+" per crear-ne un de nou.
         O seleccioneu una de les operacions del portamonedes:</p>
O seleccioneu una de les operacions del portamonedes:</p>
<h3>Detalls</h3>
<p>Mostra els detalls del portamonedes, la llavor i les seves claus.</p>
<h3>Rebre</h3>
@ -90,7 +90,7 @@
<p>Canvia el nom del portamonedes. El canvi de nom no afecta a les còpies de seguretat.</p>
<h3>Còpia de Seguretat</h3>
<p>Feu una còpia del portamonedes en la carpeta <tt> backups </tt> dins del <tt> monerujo </tt>
         per a sobreescriure còpies anteriors.</p>
per a sobreescriure còpies anteriors.</p>
<h3>Arxiu</h3>
<p>Feu una còpia de seguretat i a continuació elimineu el portamonedes. La còpia es mantindrà a la carpeta <tt> backups </tt>. Si ja no necessiteu les vostres còpies de seguretat les haureu deliminar amb un explorador darxius o una aplicació segura.</p>
]]></string>
@ -122,14 +122,14 @@
<h1>Enviant BTC</h1>
<h2>SideShift.ai</h2>
<p>SideShift.ai és un servei de tercers que fa proporciona el canvi de Monero a Bitcoin.
         Nosaltres fem servir lAPI SideShift.ai per integrar els pagaments de Bitcoin a Monerujo. Si us plau, doneu un cop dull a https://sideshift.ai i decidiu vosaltres mateixos si és una cosa que volgueu utilitzar. Lequip de Monerujo no està associat amb SideShift.ai i no pot oferir assistència amb el seu servei.</p>
Nosaltres fem servir lAPI SideShift.ai per integrar els pagaments de Bitcoin a Monerujo. Si us plau, doneu un cop dull a https://sideshift.ai i decidiu vosaltres mateixos si és una cosa que volgueu utilitzar. Lequip de Monerujo no està associat amb SideShift.ai i no pot oferir assistència amb el seu servei.</p>
<h2>Tipus de Canvi SideShift.ai<h2>
<p>A la pantalla \"Quantitat\" es mostraran els paràmetres actuals del servei SideShift.ai. Aquests
         inclouen el tipus de canvi actual, així com els límits de BTC superiors i inferiors. Tingueu en compte que la tarifa no està garantida en aquell mateix moment.</p>
inclouen el tipus de canvi actual, així com els límits de BTC superiors i inferiors. Tingueu en compte que la tarifa no està garantida en aquell mateix moment.</p>
<h2>Ordre de compra SideShift.ai<h2>
<p>A la pantalla \"Confirmar\", veureu lordre de compra SideShift.ai real. Aquesta comanda és vàlida per a
         un temps limitat: és possible que veieu un compte enrere en el botó \"Gastar\". El tipus de canvi pot
         ser diferent del mostrat en pantalles anteriors.</p>
un temps limitat: és possible que veieu un compte enrere en el botó \"Gastar\". El tipus de canvi pot
ser diferent del mostrat en pantalles anteriors.</p>
<h2>Clau Secreta SideShift.ai<h2>
<p>Com que Monerujo només gestiona la part Monero de la vostra transacció, la vostra clau secreta per SideShift.ai es pot utilitzar per fer el seguiment de la part de Bitcoin de la vostra comanda a la pàgina principal de SideShift.ai.</p>
<h2>Compte enrere SideShift.ai!</h2>
@ -140,14 +140,14 @@
<h1>Enviant BTC</h1>
<h2>SideShift.ai</h2>
<p>SideShift.ai és un servei de tercers que fa proporciona el canvi de Monero a Bitcoin.
         Nosaltres fem servir lAPI SideShift.ai per integrar els pagaments de Bitcoin a Monerujo. Si us plau, doneu un cop dull a https://sideshift.ai i decidiu vosaltres mateixos si és una cosa que volgueu utilitzar. Lequip de Monerujo no està associat amb SideShift.ai i no pot oferir assistència amb el seu servei.</p>
Nosaltres fem servir lAPI SideShift.ai per integrar els pagaments de Bitcoin a Monerujo. Si us plau, doneu un cop dull a https://sideshift.ai i decidiu vosaltres mateixos si és una cosa que volgueu utilitzar. Lequip de Monerujo no està associat amb SideShift.ai i no pot oferir assistència amb el seu servei.</p>
<h2>Tipus de Canvi SideShift.ai<h2>
<p>A la pantalla \"Quantitat\" es mostraran els paràmetres actuals del servei SideShift.ai. Aquests
         inclouen el tipus de canvi actual, així com els límits de BTC superiors i inferiors. Tingueu en compte que la tarifa no està garantida en aquell mateix moment.</p>
inclouen el tipus de canvi actual, així com els límits de BTC superiors i inferiors. Tingueu en compte que la tarifa no està garantida en aquell mateix moment.</p>
<h2>Ordre de compra SideShift.ai<h2>
<p>A la pantalla \"Confirmar\", veureu lordre de compra SideShift.ai real. Aquesta comanda és vàlida per a
         un temps limitat: és possible que veieu un compte enrere en el botó \"Gastar\". El tipus de canvi pot
         ser diferent del mostrat en pantalles anteriors.</p>
un temps limitat: és possible que veieu un compte enrere en el botó \"Gastar\". El tipus de canvi pot
ser diferent del mostrat en pantalles anteriors.</p>
<h2>Clau Secreta SideShift.ai<h2>
<p>Com que Monerujo només gestiona la part Monero de la vostra transacció, la vostra clau secreta per SideShift.ai es pot utilitzar per fer el seguiment de la part de Bitcoin de la vostra comanda a la pàgina principal de SideShift.ai.</p>
<h2>Compte enrere SideShift.ai!</h2>
@ -164,7 +164,7 @@
<p><b>Ajuda! El balanç del meu portamonedes ha desaparegut o consta com a no confirmat!</b><br/>
No patiu! Quan envieu fons desde el vostre portamonedes part del balanç apareixerà com a no confirmat de forma temporal.
Això succeeix pel fet de com Monero és intercanviat a través de la blockchain i com es produeix el canvi.
        Podeu llegir més sobre el canvi a https://getmonero.org/resources/moneropedia/change.html
Podeu llegir més sobre el canvi a https://getmonero.org/resources/moneropedia/change.html
<h2>Llista de Transacció</h2>
<p>Llistat de les transaccions del portamonedes. Els portamonedes de visualització només mostraran les transaccions entrants.</p>
]]></string>
@ -173,49 +173,49 @@
<h1>Nodes</h1>
<h2>TL;DR</h2>
<p>Actualitzeu la llista de nodes prement cap avall; marqueu 3&#8211;5 nodes per permetre a Monerujo
         triar el millor per a tu!</p>
triar el millor per a tu!</p>
<h2>Què és un Node?</h2>
<p>Monerujo utilitza un Node Remot (de vegades també anomenat daemon) per comunicar-se
         la xarxa Monero sense haver de descarregar i emmagatzemar una còpia de
         tota la blockchain mateixa.<p>
la xarxa Monero sense haver de descarregar i emmagatzemar una còpia de
tota la blockchain mateixa.<p>
<h2>Llista de Nodes</h2>
<p>Si la llista està buida, podeu afegir nous nodes manualment o deixar que Monerujo
         escanegi la xarxa per vostè. O ambdós. Llegiu &#8230;</p>
escanegi la xarxa per vostè. O ambdós. Llegiu &#8230;</p>
<p>La llista de nodes mostra tots els nodes coneguts. A més, la marca de temps
         de lúltim bloc conegut per a cada node es mostra sota el nom del node. La icona
         que representa el temps de resposta del node
         (que indica el nivell de connectivitat estimat)
         es mostra al costat de cada node.</p>
de lúltim bloc conegut per a cada node es mostra sota el nom del node. La icona
que representa el temps de resposta del node
(que indica el nivell de connectivitat estimat)
es mostra al costat de cada node.</p>
<p>Es pot marcar qualsevol node de la llista per utilitzar-lo més endevant.
         Es descartaràn els nodes que no hagin estat seleccionats.<p>
Es descartaràn els nodes que no hagin estat seleccionats.<p>
<p>Monerujo escollirà el node òptim (marcat) cada vegada que lutilitzeu.
         Això ho fa mitjançant la comprovació de lalçada de bloc (com dactualitzat
         està el node?), així com el temps de resposta (què tan ràpidament respon el node a les peticions?).</p>
Això ho fa mitjançant la comprovació de lalçada de bloc (com dactualitzat
està el node?), així com el temps de resposta (què tan ràpidament respon el node a les peticions?).</p>
<p>La llista sordena per aquestes característiques, de manera que el node superior seria el que Monerujo
         triaria ara mateix. La part inferior de la llista mostraria els nodes més lents o no disponibles.</p>
triaria ara mateix. La part inferior de la llista mostraria els nodes més lents o no disponibles.</p>
<h2>Afegir Node</h2>
<p>Si premeu el botó &quot;Afegir Node&quot; a la part inferior, se us demanarà
        que introduïu els detalls del node al següent diàleg.
        El &quot;Adreça&quot; és el nom del servidor o adreça IP del node - aquesta és la única
        entrada obligatòria.
        Introduïu el &quot;Port&quot; si el node sexecuta en un port no predeterminat (per exemple, 18089).
        També podeu anomenar opcionalment el node, de manera que el pugueu identificar més fàcilment més endavant.
        Alguns nodes necessiten credencials per utilitzar-los. Introduïu el nom dusuari i
        contrasenya proporcionats als camps corresponents. Ara podeu &quot;Test&quot; aquesta configuració.
        Els &quot;Resultats de les Proves&quot; mostraran lalçada de bloc, el temps de resposta i lIP real.
        El resultat també pot ser un error - generalment perquè el nom del servidor proporcionat no és
        accessible dins dun temps raonable o les credencials són incorrectes.
        O la combinació de nom del servidor/port no apunta cap a un node real de Monero!
        Un cop aprovada la prova (sense error), ja estás llest per prémer &quot;Dacord&quot; per desar iamp;
        marcar aquest node.</p>
que introduïu els detalls del node al següent diàleg.
El &quot;Adreça&quot; és el nom del servidor o adreça IP del node - aquesta és la única
entrada obligatòria.
Introduïu el &quot;Port&quot; si el node sexecuta en un port no predeterminat (per exemple, 18089).
També podeu anomenar opcionalment el node, de manera que el pugueu identificar més fàcilment més endavant.
Alguns nodes necessiten credencials per utilitzar-los. Introduïu el nom dusuari i
contrasenya proporcionats als camps corresponents. Ara podeu &quot;Test&quot; aquesta configuració.
Els &quot;Resultats de les Proves&quot; mostraran lalçada de bloc, el temps de resposta i lIP real.
El resultat també pot ser un error - generalment perquè el nom del servidor proporcionat no és
accessible dins dun temps raonable o les credencials són incorrectes.
O la combinació de nom del servidor/port no apunta cap a un node real de Monero!
Un cop aprovada la prova (sense error), ja estás llest per prémer &quot;Dacord&quot; per desar iamp;
marcar aquest node.</p>
<h2>Escanejar Nodes</h2>
<p>A més, podeu escanejar la xarxa per buscar nodes. Monerujo començarà
         escanejant la xarxa per als nodes remots al port 18089. Començarà per preguntar als vostres
         nodes marcats per altres companys de la xarxa P2P de Monero, i després continuarà
         preguntant-los per als seus companys, etc. Si no teniu cap node marcat
         (o no ens informen sobre els seus companys),
         Monerujo anirà directament als nodes de llavor de Monero codificats a dins de Monero.
         Lescaneig satura quan troba un total de 10 nodes remots.</p>
escanejant la xarxa per als nodes remots al port 18089. Començarà per preguntar als vostres
nodes marcats per altres companys de la xarxa P2P de Monero, i després continuarà
preguntant-los per als seus companys, etc. Si no teniu cap node marcat
(o no ens informen sobre els seus companys),
Monerujo anirà directament als nodes de llavor de Monero codificats a dins de Monero.
Lescaneig satura quan troba un total de 10 nodes remots.</p>
]]></string>
<string name="help_uri"><![CDATA[
@ -230,4 +230,25 @@
]]></string>
<string name="help_ok">Ja ho tinc!</string> <!-- Note: "Got it" as in "I understand this" -->
<string name="help_nok">Nah…</string> <!-- Note: "Nah..." as in "I don't want this" -->
<string name="help_getorbot">Get Orbot!</string>
<string name="help_tor"><![CDATA[
<h1>Tor</h1>
<p>Tor, short for The Onion Router, is free and open-source software for enabling anonymous
communication.</p>
<p>Enabling Tor will route your connection through several relays and hide your IP address
from the node. Keep in mind this is more private but also <b>slower</b>.</p>
<p>In order to use Tor with Monerujo, you\'ll need Orbot installed on your phone. After
installing Orbot, make sure to enable it by clicking the network icon on the wallet list
screen.</p>
<p>If you have issues connecting with Tor, try to get a new Identity in the Orbot App (icon
on the top right).</p>
]]></string>
<string name="help_tor_enable"><![CDATA[
<h1>Tor Node</h1>
<p>This is an .onion node. In order to use it, you must enable Tor mode by touching the
<img src="ic_network_clearnet"/> icon near the top of the Wallet List page.</p>
]]></string>
</resources>

View File

@ -13,7 +13,7 @@
<string name="menu_changepw">Canvi de contrasenya</string>
<string name="password_weak">Segueix escrivint &#8230;</string>
<string name="password_fair">Més o menys... &#8230;</string>
<string name="password_fair">Més o menys</string>
<string name="password_good">Vinga, ho pots fer millor!</string>
<string name="password_strong">Força bé, pero millorbale &#8230;</string>
<string name="password_very_strong">Genial, ets tot un hacker!</string>
@ -23,7 +23,7 @@
<string name="label_ok">D\'acord</string>
<string name="label_cancel">Cancel·lar</string>
<string name="label_close">Tancar</string>
<string name="label_wallet_advanced_details">Premi aquí per informació més detallada</string>
<string name="label_wallet_advanced_details">Informació més detallada</string>
<string name="label_send_success">Enviat correctament!</string>
<string name="label_send_done">Fet</string>
@ -236,7 +236,7 @@
<string name="send_create_tx_error_title">Error creant la transacció</string>
<string name="tx_list_fee">- Comissió %1$s</string>
<string name="tx_list_fee">Comissió %1$s</string>
<string name="tx_list_amount_failed">(%1$s)</string>
<string name="tx_list_failed_text">fallit</string>
<string name="tx_list_amount_negative">- %1$s</string>
@ -425,8 +425,20 @@
<string name="restore_failed">Import failed!</string>
<string name="menu_deletecache">Reset wallet!</string>
<<<<<<< HEAD
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, ...)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="send_address_resolve_ud">Resolving ENS / UD&#8230;</string>
<string name="send_address_no_ud_records">No address found for ENS / UD domain</string>
=======
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, &#8230;)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="node_tor_error">Tor required</string>
<string name="node_waiting">\u00A0WAITING FOR NODE\u00A0</string>
<string name="tor_enable_background">"Allow Background Starts" in Orbot Settings to use Tor!</string>
<string name="tor_noshift">SideShift.ai doesn\'t support Tor.\nDisable Tor to swap XMR.</string>
<string name="label_seed_offset_encrypt">Seed encryption (EXPERIMENTAL)</string>
<string name="seed_offset_hint">Seed Offset Phrase (optional)</string>
>>>>>>> 7b96baeca7f216c943ad5d376e6838f9679e74b0
</resources>

View File

@ -290,4 +290,25 @@
]]></string>
<string name="help_ok">Hab\'s verstanden!</string> <!-- Note: "Got it" as in "I understand this" -->
<string name="help_nok">Nah…</string> <!-- Note: "Nah..." as in "I don't want this" -->
<string name="help_getorbot">Get Orbot!</string>
<string name="help_tor"><![CDATA[
<h1>Tor</h1>
<p>Tor, short for The Onion Router, is free and open-source software for enabling anonymous
communication.</p>
<p>Enabling Tor will route your connection through several relays and hide your IP address
from the node. Keep in mind this is more private but also <b>slower</b>.</p>
<p>In order to use Tor with Monerujo, you\'ll need Orbot installed on your phone. After
installing Orbot, make sure to enable it by clicking the network icon on the wallet list
screen.</p>
<p>If you have issues connecting with Tor, try to get a new Identity in the Orbot App (icon
on the top right).</p>
]]></string>
<string name="help_tor_enable"><![CDATA[
<h1>Tor Node</h1>
<p>This is an .onion node. In order to use it, you must enable Tor mode by touching the
<img src="ic_network_clearnet"/> icon near the top of the Wallet List page.</p>
]]></string>
</resources>

View File

@ -24,7 +24,7 @@
<string name="label_ok">OK</string>
<string name="label_cancel">Abbrechen</string>
<string name="label_close">Schließen</string>
<string name="label_wallet_advanced_details">Berühren für Detailinfos</string>
<string name="label_wallet_advanced_details">Detailinfos</string>
<string name="label_send_success">Erfolgreich gesendet</string>
<string name="label_send_done">Fertig</string>
@ -232,7 +232,7 @@
<string name="send_create_tx_error_title">Fehler bei Transaktionserstellung</string>
<string name="tx_list_fee">- Gebühr %1$s</string>
<string name="tx_list_fee">Gebühr %1$s</string>
<string name="tx_list_amount_failed">(%1$s)</string>
<string name="tx_list_failed_text">fehlgeschlagen</string>
<string name="tx_list_amount_negative">- %1$s</string>
@ -426,8 +426,20 @@
<string name="restore_failed">Import failed!</string>
<string name="menu_deletecache">Reset wallet!</string>
<<<<<<< HEAD
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, ...)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="send_address_resolve_ud">Resolving ENS / UD&#8230;</string>
<string name="send_address_no_ud_records">No address found for ENS / UD domain</string>
=======
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, &#8230;)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="node_tor_error">Tor required</string>
<string name="node_waiting">\u00A0WAITING FOR NODE\u00A0</string>
<string name="tor_enable_background">"Allow Background Starts" in Orbot Settings to use Tor!</string>
<string name="tor_noshift">SideShift.ai doesn\'t support Tor.\nDisable Tor to swap XMR.</string>
<string name="label_seed_offset_encrypt">Seed encryption (EXPERIMENTAL)</string>
<string name="seed_offset_hint">Seed Offset Phrase (optional)</string>
>>>>>>> 7b96baeca7f216c943ad5d376e6838f9679e74b0
</resources>

View File

@ -272,4 +272,25 @@
]]></string>
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
<string name="help_nok">Nah…</string> <!-- Note: "Nah..." as in "I don't want this" -->
<string name="help_getorbot">Get Orbot!</string>
<string name="help_tor"><![CDATA[
<h1>Tor</h1>
<p>Tor, short for The Onion Router, is free and open-source software for enabling anonymous
communication.</p>
<p>Enabling Tor will route your connection through several relays and hide your IP address
from the node. Keep in mind this is more private but also <b>slower</b>.</p>
<p>In order to use Tor with Monerujo, you\'ll need Orbot installed on your phone. After
installing Orbot, make sure to enable it by clicking the network icon on the wallet list
screen.</p>
<p>If you have issues connecting with Tor, try to get a new Identity in the Orbot App (icon
on the top right).</p>
]]></string>
<string name="help_tor_enable"><![CDATA[
<h1>Tor Node</h1>
<p>This is an .onion node. In order to use it, you must enable Tor mode by touching the
<img src="ic_network_clearnet"/> icon near the top of the Wallet List page.</p>
]]></string>
</resources>

View File

@ -22,7 +22,7 @@
<string name="label_ok">OK</string>
<string name="label_cancel">Άκυρο</string>
<string name="label_close">Κλείσιμο</string>
<string name="label_wallet_advanced_details">Πάτησε για λεπτομερείς πληροφορίες</string>
<string name="label_wallet_advanced_details">Λεπτομερείς πληροφορίες</string>
<string name="label_send_success">Αποστολή με επιτυχία</string>
<string name="label_send_done">Έγινε</string>
@ -205,7 +205,7 @@
<string name="send_create_tx_error_title">Σφάλμα Δημιουργίας Συναλλαγής</string>
<string name="tx_list_fee">- Κόμιστρο %1$s</string>
<string name="tx_list_fee">Κόμιστρο %1$s</string>
<string name="tx_list_amount_failed">(%1$s)</string>
<string name="tx_list_failed_text">απέτυχε</string>
<string name="tx_list_amount_negative">- %1$s</string>
@ -427,8 +427,20 @@
<string name="restore_failed">Import failed!</string>
<string name="menu_deletecache">Reset wallet!</string>
<<<<<<< HEAD
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, ...)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="send_address_resolve_ud">Resolving ENS / UD&#8230;</string>
<string name="send_address_no_ud_records">No address found for ENS / UD domain</string>
=======
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, &#8230;)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="node_tor_error">Tor required</string>
<string name="node_waiting">\u00A0WAITING FOR NODE\u00A0</string>
<string name="tor_enable_background">"Allow Background Starts" in Orbot Settings to use Tor!</string>
<string name="tor_noshift">SideShift.ai doesn\'t support Tor.\nDisable Tor to swap XMR.</string>
<string name="label_seed_offset_encrypt">Seed encryption (EXPERIMENTAL)</string>
<string name="seed_offset_hint">Seed Offset Phrase (optional)</string>
>>>>>>> 7b96baeca7f216c943ad5d376e6838f9679e74b0
</resources>

View File

@ -316,4 +316,25 @@
]]></string>
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
<string name="help_nok">Nah…</string> <!-- Note: "Nah..." as in "I don't want this" -->
<string name="help_getorbot">Get Orbot!</string>
<string name="help_tor"><![CDATA[
<h1>Tor</h1>
<p>Tor, short for The Onion Router, is free and open-source software for enabling anonymous
communication.</p>
<p>Enabling Tor will route your connection through several relays and hide your IP address
from the node. Keep in mind this is more private but also <b>slower</b>.</p>
<p>In order to use Tor with Monerujo, you\'ll need Orbot installed on your phone. After
installing Orbot, make sure to enable it by clicking the network icon on the wallet list
screen.</p>
<p>If you have issues connecting with Tor, try to get a new Identity in the Orbot App (icon
on the top right).</p>
]]></string>
<string name="help_tor_enable"><![CDATA[
<h1>Tor Node</h1>
<p>This is an .onion node. In order to use it, you must enable Tor mode by touching the
<img src="ic_network_clearnet"/> icon near the top of the Wallet List page.</p>
]]></string>
</resources>

View File

@ -23,7 +23,7 @@
<string name="label_ok">OK</string>
<string name="label_cancel">Nuligi</string>
<string name="label_close">Fermi</string>
<string name="label_wallet_advanced_details">Tuŝi por pli detalaj informoj.</string>
<string name="label_wallet_advanced_details">Detalaj informoj</string>
<string name="label_send_success">Sukcese sendis</string>
<string name="label_send_done">Farite</string>
@ -236,7 +236,7 @@
<string name="send_create_tx_error_title">Krei transakci-eraron</string>
<string name="tx_list_fee">- Kosto %1$s</string>
<string name="tx_list_fee">Kosto %1$s</string>
<string name="tx_list_amount_failed">(%1$s)</string>
<string name="tx_list_failed_text">masukcesis</string>
<string name="tx_list_amount_negative">- %1$s</string>
@ -427,8 +427,20 @@
<string name="restore_failed">Import failed!</string>
<string name="menu_deletecache">Reset wallet!</string>
<<<<<<< HEAD
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, ...)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="send_address_resolve_ud">Resolving ENS / UD&#8230;</string>
<string name="send_address_no_ud_records">No address found for ENS / UD domain</string>
=======
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, &#8230;)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="node_tor_error">Tor required</string>
<string name="node_waiting">\u00A0WAITING FOR NODE\u00A0</string>
<string name="tor_enable_background">"Allow Background Starts" in Orbot Settings to use Tor!</string>
<string name="tor_noshift">SideShift.ai doesn\'t support Tor.\nDisable Tor to swap XMR.</string>
<string name="label_seed_offset_encrypt">Seed encryption (EXPERIMENTAL)</string>
<string name="seed_offset_hint">Seed Offset Phrase (optional)</string>
>>>>>>> 7b96baeca7f216c943ad5d376e6838f9679e74b0
</resources>

View File

@ -312,4 +312,25 @@
]]></string>
<string name="help_ok">¡Entendido!</string> <!-- Note: "Got it" as in "I understand this" -->
<string name="help_nok">Nah…</string> <!-- Note: "Nah..." as in "I don't want this" -->
<string name="help_getorbot">Get Orbot!</string>
<string name="help_tor"><![CDATA[
<h1>Tor</h1>
<p>Tor, short for The Onion Router, is free and open-source software for enabling anonymous
communication.</p>
<p>Enabling Tor will route your connection through several relays and hide your IP address
from the node. Keep in mind this is more private but also <b>slower</b>.</p>
<p>In order to use Tor with Monerujo, you\'ll need Orbot installed on your phone. After
installing Orbot, make sure to enable it by clicking the network icon on the wallet list
screen.</p>
<p>If you have issues connecting with Tor, try to get a new Identity in the Orbot App (icon
on the top right).</p>
]]></string>
<string name="help_tor_enable"><![CDATA[
<h1>Tor Node</h1>
<p>This is an .onion node. In order to use it, you must enable Tor mode by touching the
<img src="ic_network_clearnet"/> icon near the top of the Wallet List page.</p>
]]></string>
</resources>

View File

@ -23,7 +23,7 @@
<string name="label_ok">Aceptar</string>
<string name="label_cancel">Cancelar</string>
<string name="label_close">Cerrar</string>
<string name="label_wallet_advanced_details">Toca para información más detallada</string>
<string name="label_wallet_advanced_details">Información más detallada</string>
<string name="label_send_success">¡Éxito!</string>
<string name="label_send_done">Hecho</string>
@ -173,7 +173,7 @@
<string name="send_create_tx_error_title">Error creando la transacción</string>
<string name="tx_list_fee">- Comisión %1$s</string>
<string name="tx_list_fee">Comisión %1$s</string>
<string name="tx_list_amount_failed">(%1$s)</string>
<string name="tx_list_failed_text">fallido</string>
<string name="tx_list_amount_negative">- %1$s</string>
@ -418,8 +418,20 @@
<string name="restore_failed">Import failed!</string>
<string name="menu_deletecache">Reset wallet!</string>
<<<<<<< HEAD
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, ...)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="send_address_resolve_ud">Resolving ENS / UD&#8230;</string>
<string name="send_address_no_ud_records">No address found for ENS / UD domain</string>
=======
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, &#8230;)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="node_tor_error">Tor required</string>
<string name="node_waiting">\u00A0WAITING FOR NODE\u00A0</string>
<string name="tor_enable_background">"Allow Background Starts" in Orbot Settings to use Tor!</string>
<string name="tor_noshift">SideShift.ai doesn\'t support Tor.\nDisable Tor to swap XMR.</string>
<string name="label_seed_offset_encrypt">Seed encryption (EXPERIMENTAL)</string>
<string name="seed_offset_hint">Seed Offset Phrase (optional)</string>
>>>>>>> 7b96baeca7f216c943ad5d376e6838f9679e74b0
</resources>

View File

@ -292,4 +292,25 @@
]]></string>
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
<string name="help_nok">Nah…</string> <!-- Note: "Nah..." as in "I don't want this" -->
<string name="help_getorbot">Get Orbot!</string>
<string name="help_tor"><![CDATA[
<h1>Tor</h1>
<p>Tor, short for The Onion Router, is free and open-source software for enabling anonymous
communication.</p>
<p>Enabling Tor will route your connection through several relays and hide your IP address
from the node. Keep in mind this is more private but also <b>slower</b>.</p>
<p>In order to use Tor with Monerujo, you\'ll need Orbot installed on your phone. After
installing Orbot, make sure to enable it by clicking the network icon on the wallet list
screen.</p>
<p>If you have issues connecting with Tor, try to get a new Identity in the Orbot App (icon
on the top right).</p>
]]></string>
<string name="help_tor_enable"><![CDATA[
<h1>Tor Node</h1>
<p>This is an .onion node. In order to use it, you must enable Tor mode by touching the
<img src="ic_network_clearnet"/> icon near the top of the Wallet List page.</p>
]]></string>
</resources>

View File

@ -23,7 +23,7 @@
<string name="label_ok">OK</string>
<string name="label_cancel">Katkesta</string>
<string name="label_close">Sulge</string>
<string name="label_wallet_advanced_details">Puuduta lisainfo saamiseks</string>
<string name="label_wallet_advanced_details">Lisainfo</string>
<string name="label_send_success">Edukalt saadetud</string>
<string name="label_send_done">Tehtud</string>
@ -231,7 +231,7 @@
<string name="send_create_tx_error_title">Viga ülekande genereerimisel</string>
<string name="tx_list_fee">- teenustasu %1$s</string>
<string name="tx_list_fee">teenustasu %1$s</string>
<string name="tx_list_amount_failed">(%1$s)</string>
<string name="tx_list_failed_text">ebaõnnestus</string>
<string name="tx_list_amount_negative">- %1$s</string>
@ -425,8 +425,20 @@
<string name="restore_failed">Import failed!</string>
<string name="menu_deletecache">Reset wallet!</string>
<<<<<<< HEAD
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, ...)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="send_address_resolve_ud">Resolving ENS / UD&#8230;</string>
<string name="send_address_no_ud_records">No address found for ENS / UD domain</string>
=======
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, &#8230;)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="node_tor_error">Tor required</string>
<string name="node_waiting">\u00A0WAITING FOR NODE\u00A0</string>
<string name="tor_enable_background">"Allow Background Starts" in Orbot Settings to use Tor!</string>
<string name="tor_noshift">SideShift.ai doesn\'t support Tor.\nDisable Tor to swap XMR.</string>
<string name="label_seed_offset_encrypt">Seed encryption (EXPERIMENTAL)</string>
<string name="seed_offset_hint">Seed Offset Phrase (optional)</string>
>>>>>>> 7b96baeca7f216c943ad5d376e6838f9679e74b0
</resources>

View File

@ -310,4 +310,25 @@
]]></string>
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
<string name="help_nok">Nah…</string> <!-- Note: "Nah..." as in "I don't want this" -->
<string name="help_getorbot">Get Orbot!</string>
<string name="help_tor"><![CDATA[
<h1>Tor</h1>
<p>Tor, short for The Onion Router, is free and open-source software for enabling anonymous
communication.</p>
<p>Enabling Tor will route your connection through several relays and hide your IP address
from the node. Keep in mind this is more private but also <b>slower</b>.</p>
<p>In order to use Tor with Monerujo, you\'ll need Orbot installed on your phone. After
installing Orbot, make sure to enable it by clicking the network icon on the wallet list
screen.</p>
<p>If you have issues connecting with Tor, try to get a new Identity in the Orbot App (icon
on the top right).</p>
]]></string>
<string name="help_tor_enable"><![CDATA[
<h1>Tor Node</h1>
<p>This is an .onion node. In order to use it, you must enable Tor mode by touching the
<img src="ic_network_clearnet"/> icon near the top of the Wallet List page.</p>
]]></string>
</resources>

View File

@ -23,7 +23,7 @@
<string name="label_ok">OK</string>
<string name="label_cancel">Annuler</string>
<string name="label_close">Fermer</string>
<string name="label_wallet_advanced_details">Toucher pour plus d\'infos</string>
<string name="label_wallet_advanced_details">Plus d\'infos</string>
<string name="label_send_success">Envoi réussi</string>
<string name="label_send_done">Fait</string>
@ -233,7 +233,7 @@
<string name="send_create_tx_error_title">Erreur de Création de Transaction</string>
<string name="tx_list_fee">- Frais %1$s</string>
<string name="tx_list_fee">Frais %1$s</string>
<string name="tx_list_amount_failed">(%1$s)</string>
<string name="tx_list_failed_text">Echoué</string>
<string name="tx_list_amount_negative">- %1$s</string>
@ -431,8 +431,20 @@
<string name="restore_failed">Import failed!</string>
<string name="menu_deletecache">Reset wallet!</string>
<<<<<<< HEAD
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, ...)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="send_address_resolve_ud">Resolving ENS / UD&#8230;</string>
<string name="send_address_no_ud_records">No address found for ENS / UD domain</string>
=======
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, &#8230;)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="node_tor_error">Tor required</string>
<string name="node_waiting">\u00A0WAITING FOR NODE\u00A0</string>
<string name="tor_enable_background">"Allow Background Starts" in Orbot Settings to use Tor!</string>
<string name="tor_noshift">SideShift.ai doesn\'t support Tor.\nDisable Tor to swap XMR.</string>
<string name="label_seed_offset_encrypt">Seed encryption (EXPERIMENTAL)</string>
<string name="seed_offset_hint">Seed Offset Phrase (optional)</string>
>>>>>>> 7b96baeca7f216c943ad5d376e6838f9679e74b0
</resources>

View File

@ -294,4 +294,25 @@
]]></string>
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
<string name="help_nok">Nah…</string> <!-- Note: "Nah..." as in "I don't want this" -->
<string name="help_getorbot">Get Orbot!</string>
<string name="help_tor"><![CDATA[
<h1>Tor</h1>
<p>Tor, short for The Onion Router, is free and open-source software for enabling anonymous
communication.</p>
<p>Enabling Tor will route your connection through several relays and hide your IP address
from the node. Keep in mind this is more private but also <b>slower</b>.</p>
<p>In order to use Tor with Monerujo, you\'ll need Orbot installed on your phone. After
installing Orbot, make sure to enable it by clicking the network icon on the wallet list
screen.</p>
<p>If you have issues connecting with Tor, try to get a new Identity in the Orbot App (icon
on the top right).</p>
]]></string>
<string name="help_tor_enable"><![CDATA[
<h1>Tor Node</h1>
<p>This is an .onion node. In order to use it, you must enable Tor mode by touching the
<img src="ic_network_clearnet"/> icon near the top of the Wallet List page.</p>
]]></string>
</resources>

View File

@ -23,7 +23,7 @@
<string name="label_ok">OK</string>
<string name="label_cancel">Mégsem</string>
<string name="label_close">Bezárás</string>
<string name="label_wallet_advanced_details">Koppints a részletes informcáióért</string>
<string name="label_wallet_advanced_details">Részletes információk</string>
<string name="label_send_success">Sikeresen elküldve</string>
<string name="label_send_done">Kész</string>
@ -230,7 +230,7 @@
<string name="send_create_tx_error_title">Tranzakciólétrehozási hiba</string>
<string name="tx_list_fee">- %1$s díj</string>
<string name="tx_list_fee">%1$s díj</string>
<string name="tx_list_amount_failed">(%1$s)</string>
<string name="tx_list_failed_text">sikertelen</string>
<string name="tx_list_amount_negative">- %1$s</string>
@ -429,8 +429,20 @@
<string name="restore_failed">Import failed!</string>
<string name="menu_deletecache">Reset wallet!</string>
<<<<<<< HEAD
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, ...)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="send_address_resolve_ud">Resolving ENS / UD&#8230;</string>
<string name="send_address_no_ud_records">No address found for ENS / UD domain</string>
=======
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, &#8230;)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="node_tor_error">Tor required</string>
<string name="node_waiting">\u00A0WAITING FOR NODE\u00A0</string>
<string name="tor_enable_background">"Allow Background Starts" in Orbot Settings to use Tor!</string>
<string name="tor_noshift">SideShift.ai doesn\'t support Tor.\nDisable Tor to swap XMR.</string>
<string name="label_seed_offset_encrypt">Seed encryption (EXPERIMENTAL)</string>
<string name="seed_offset_hint">Seed Offset Phrase (optional)</string>
>>>>>>> 7b96baeca7f216c943ad5d376e6838f9679e74b0
</resources>

View File

@ -148,13 +148,12 @@
<p>Questo è l&apos;indirizzo pubblico del portafoglio cui stai inviando Moneroj, puoi incollare qui un indirizzo
che hai precededentemente copiato sul blocco appunti, scansionare un codice QR o inserire un indirizzo
manualmente. Accertati più volte che sia l&apos;indirizzo corretto e che tu non stia inviando Moneroj ad un indirizzo sbagliato.</p>
<p>In addition to using an XMR address, you can also use
<p>In alternativa a un indirizzo XMR, puoi anche usare
<ul>
<li>an OpenAlias for XMR or BTC</li>
<li>a BTC address</li>
<li>un OpenAlias per XMR o BTC</li>
<li>un indirizzo BTC</li>
</u>
Please note, that sending BTC is processed through the SideShift.ai service (see https://sideshift.ai
for details). See the section on sending BTC below.</p>
L&apos;invio di BTC è processato tramite il servizio SideShift.ai. (per dettagli: https://sideshift.ai). Vedi la sezione sull&apos;invio di BTC in basso.</p>
<h1>Inviare BTC</h1>
<h2>SideShift.ai</h2>
<p>SideShift.ai è un servizio di terze parti che funziona come cambiavaluta da Monero a Bitcoin.
@ -285,15 +284,36 @@
<!-- Note for translators: new/changed text also in help_send -->
<string name="help_uri"><![CDATA[
<h1>Using a payment link</h1>
<p>You have started monerujo with a payment link. In order to send funds, please do the following:</p>
<h1>Uso di un link di pagamento</h1>
<p>Hai avviato monerujo con un link di pagamento. Per inviare fondi, procedi in questo modo:</p>
<p>
1. Open the wallet you want to spend from<br>
2. Wait until the wallet is synced &amp; the "Give" button appears<br>
3. Touch the "Give" button
1. Apri il portafogli da cui vuoi spendere<br>
2. Attendi la sincronizzazione del portafogli; apparirà il pulsante "Invia"<br>
3. Tocca il pulsante "Invia"
</p>
<p>The payment details will be filled in. Check them and proceed like for any other transaction.</p>
<p>I dettagli del pagamento saranno auto-inseriti. Controllali e procedi come per qualsiasi altra transazione.</p>
]]></string>
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
<string name="help_nok">Nah…</string> <!-- Note: "Nah..." as in "I don't want this" -->
<string name="help_getorbot">Get Orbot!</string>
<string name="help_tor"><![CDATA[
<h1>Tor</h1>
<p>Tor, short for The Onion Router, is free and open-source software for enabling anonymous
communication.</p>
<p>Enabling Tor will route your connection through several relays and hide your IP address
from the node. Keep in mind this is more private but also <b>slower</b>.</p>
<p>In order to use Tor with Monerujo, you\'ll need Orbot installed on your phone. After
installing Orbot, make sure to enable it by clicking the network icon on the wallet list
screen.</p>
<p>If you have issues connecting with Tor, try to get a new Identity in the Orbot App (icon
on the top right).</p>
]]></string>
<string name="help_tor_enable"><![CDATA[
<h1>Tor Node</h1>
<p>This is an .onion node. In order to use it, you must enable Tor mode by touching the
<img src="ic_network_clearnet"/> icon near the top of the Wallet List page.</p>
]]></string>
</resources>

View File

@ -23,7 +23,7 @@
<string name="label_ok">OK</string>
<string name="label_cancel">Cancella</string>
<string name="label_close">Chiudi</string>
<string name="label_wallet_advanced_details">Tocca per informazioni dettagliate</string>
<string name="label_wallet_advanced_details">Informazioni dettagliate</string>
<string name="label_send_success">Invio riuscito</string>
<string name="label_send_done">Fatto</string>
@ -232,7 +232,7 @@
<string name="send_create_tx_error_title">Errore nella creazione della transazione</string>
<string name="tx_list_fee">- Commissione %1$s</string>
<string name="tx_list_fee">Commissione %1$s</string>
<string name="tx_list_amount_failed">(%1$s)</string>
<string name="tx_list_failed_text">fallita</string>
<string name="tx_list_amount_negative">- %1$s</string>
@ -362,76 +362,89 @@
<string name="label_restoreheight">Altezza di ripristino</string> <!-- Restore Height -->
<string name="toast_ledger_start_app">Start Monero App on %1$s</string>
<string name="toast_ledger_start_app">Avvia app Monero su %1$s</string>
<string name="menu_rescan">Rescan!</string>
<string name="menu_rescan">Riscansiona!</string>
<string name="onboarding_agree">Ho capito!</string>
<string name="onboarding_button_next">Next</string>
<string name="onboarding_button_ready">I\'m ready!</string>
<string name="onboarding_button_ready">Sono pronto!</string>
<string name="onboarding_welcome_title">Welcome to Monerujo!</string>
<string name="onboarding_welcome_information">This app allows you to create and use Monero wallets. You can store your sweet moneroj in them.</string>
<string name="onboarding_seed_title">Keep your seed safe</string>
<string name="onboarding_seed_information">The seed grants full access to whoever has it. If you lose it, we cannot help you recover it and you lose your beloved moneroj.</string>
<string name="onboarding_xmrto_title">Send Crypto</string>
<string name="onboarding_xmrto_information">Monerujo has SideShift.ai support built-in. Just paste or scan a BTC, LTC, ETH, DASH or DOGE address and you\'ll be sending these cryptos by spending XMR.</string>
<string name="onboarding_nodes_title">Nodes, your way</string>
<string name="onboarding_nodes_information">Nodes connect you to the Monero network. Choose between public nodes or go full cypherpunk using your own.</string>
<string name="onboarding_fpsend_title">Send with fingerprint</string>
<string name="onboarding_fpsend_information">You\'re now able to send XMR with just your fingerprint if you enabled it. To request the password, just disable fingerprint access.</string>
<string name="onboarding_welcome_title">Benvenuto su Monerujo!</string>
<string name="onboarding_welcome_information">Questa app ti permette di creare ed usare portafogli di Monero. Puoi conservare i tuoi bei moneroj all\'interno.</string>
<string name="onboarding_seed_title">Tieni al sicuro il tuo seed</string>
<string name="onboarding_seed_information">Il seed permette l\'accesso al portafogli a chiunque lo abbia. Se lo perdi, non possiamo aiutarti a recuperarlo.</string>
<string name="onboarding_xmrto_title">Invia altre crypto</string>
<string name="onboarding_xmrto_information">Monerujo supporta SideShift.ai. Copia o scansiona un indirizzo BTC, LTC, ETH, DASH o DOGE per inviare una di queste crypto spendendo XMR.</string>
<string name="onboarding_nodes_title">Nodi, a modo tuo</string>
<string name="onboarding_nodes_information">I nodi ti connettono alla rete di Monero. Scegli tra i vari nodi pubblici oppure usa il tuo.</string>
<string name="onboarding_fpsend_title">Invia con impronta</string>
<string name="onboarding_fpsend_information">Ora puoi inviare XMR con la tua impronta digitale. Per richiedere la password, disabilita l\'accesso all\'impronta.</string>
<string name="menu_daynight">Dark Mode</string>
<string name="menu_daynight">Modalità scura</string>
<string-array name="daynight_themes">
<item>Auto</item>
<item>Day</item>
<item>Night</item>
<item>Giorno</item>
<item>Notte</item>
</string-array>
<string name="gunther_says">There is nothing here\nPlease create or restore a wallet</string>
<string name="gunther_says">Non c\'è niente qui\n Crea o ripristina un portafogli</string>
<string name="menu_default_nodes">Restore default nodes</string>
<string name="toast_default_nodes">Restoring already in progress</string>
<string name="menu_default_nodes">Ripristina i nodi predefiniti</string>
<string name="toast_default_nodes">Ripristino già in corso</string>
<string name="node_updated_now">Last Block: %1$d seconds ago</string>
<string name="node_updated_mins">Last Block: %1$d minutes ago</string>
<string name="node_updated_hours">Last Block: %1$d hours ago</string>
<string name="node_updated_days">Last Block: %1$d days ago</string>
<string name="node_updated_now">Ultimo blocco: %1$d secondi fa</string>
<string name="node_updated_mins">Ultimo blocco: %1$d minuti fa</string>
<string name="node_updated_hours">Ultimo blocco: %1$d ore fa</string>
<string name="node_updated_days">Ultimo blocco: %1$d giorni fa</string>
<string name="shift_noquote">Cannot get quote</string>
<string name="shift_checkamount">Check amount and try again</string>
<string name="shift_noquote">Impossibile ottenere la quota</string>
<string name="shift_checkamount">Controlla l\'ammontare e riprova</string>
<string name="info_xmrto_ambiguous"><![CDATA[
<b>Ambiguous address.</b><br/>
<i>Please select the type above.</i>
<b>Indirizzo ambiguo.</b><br/>
<i>Si prega di inserire il tipo selezionato.</i>
]]></string>
<string name="info_xmrto_help"><![CDATA[
<b>Please enter or scan a %1$s address.</b><br/>
<i>You&apos;ll send XMR and the receiver will get %2$s using the <b>SideShift.ai</b> service.</i>
<b>Inserisci o scansiona un indirizzo %1$s.</b><br/>
<i>Invierai XMR e il destinatario otterrà %2$s tramite il servizio <b>SideShift.ai</b>.</i>
]]></string>
<string name="info_xmrto_help_xmr"><![CDATA[
<b>Please enter or scan a Monero address.</b>
<b>Inserisci o scansiona un indirizzo di Monero.</b>
]]></string>
<string name="subbaddress_title">Subaddresses</string>
<string name="subbaddress_name_hint">Subaddress Name</string>
<string name="max_subaddress_warning">Too many unused addresses - use some to enable creating more!</string>
<string name="max_account_warning">Too many unused accounts - use some to enable creating more!</string>
<string name="subaddress_tx_label">Transactions for this subaddress:</string>
<string name="subaddress_notx_label">No transactions for this subaddress yet</string>
<string name="subaddress_select_label">Select a subaddress</string>
<string name="subaddress_details_hint">Long-press for details</string>
<string name="subbaddress_title">Sottoindirizzi</string>
<string name="subbaddress_name_hint">Nome sottoindirizzo</string>
<string name="max_subaddress_warning">Troppi indirizzi non usati - usane qualcuno per poterne creare altri!</string>
<string name="max_account_warning">Troppi account non usati - usane qualcuno per poterne creare altri!</string>
<string name="subaddress_tx_label">Transazioni per questo sottoindirizzo:</string>
<string name="subaddress_notx_label">Nessuna transazione per questo sottoindirizzo</string>
<string name="subaddress_select_label">Seleziona un sottoindirizzo</string>
<string name="subaddress_details_hint">Tieni premuto per i dettagli</string>
<string name="menu_delete">Delete</string><!-- like: "Delete wallet!" -->
<string name="delete_failed">Delete failed!</string>
<string name="menu_delete">Elimina</string><!-- like: "Delete wallet!" -->
<string name="delete_failed">Eliminazione fallita!</string>
<string name="menu_restore">Import wallet</string>
<string name="restore_failed">Import failed!</string>
<string name="menu_restore">Importa portafogli</string>
<string name="restore_failed">Importazione fallita!</string>
<<<<<<< HEAD
<string name="menu_deletecache">Reset wallet!</string>
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, ...)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="send_address_resolve_ud">Resolving ENS / UD&#8230;</string>
<string name="send_address_no_ud_records">No address found for ENS / UD domain</string>
=======
<string name="menu_deletecache">Resetta portafogli!</string>
<string name="deletecache_alert_message"><![CDATA[Il reset del portafogli cancellerà tutte le informazioni locali (note, nomi di account & sottoindirizzi, chiavi di transazione private, …)! Procedi solo se il portafogli è corrotto e non si carica!]]></string>
<string name="node_tor_error">Tor required</string>
<string name="node_waiting">\u00A0WAITING FOR NODE\u00A0</string>
<string name="tor_enable_background">"Allow Background Starts" in Orbot Settings to use Tor!</string>
<string name="tor_noshift">SideShift.ai doesn\'t support Tor.\nDisable Tor to swap XMR.</string>
<string name="label_seed_offset_encrypt">Seed encryption (EXPERIMENTAL)</string>
<string name="seed_offset_hint">Seed Offset Phrase (optional)</string>
>>>>>>> 7b96baeca7f216c943ad5d376e6838f9679e74b0
</resources>

View File

@ -423,4 +423,25 @@
]]></string>
<string name="help_ok">分かりました!</string> <!-- Note: "Got it" as in "I understand this" -->
<string name="help_nok">Nah…</string> <!-- Note: "Nah..." as in "I don't want this" -->
<string name="help_getorbot">Get Orbot!</string>
<string name="help_tor"><![CDATA[
<h1>Tor</h1>
<p>Tor, short for The Onion Router, is free and open-source software for enabling anonymous
communication.</p>
<p>Enabling Tor will route your connection through several relays and hide your IP address
from the node. Keep in mind this is more private but also <b>slower</b>.</p>
<p>In order to use Tor with Monerujo, you\'ll need Orbot installed on your phone. After
installing Orbot, make sure to enable it by clicking the network icon on the wallet list
screen.</p>
<p>If you have issues connecting with Tor, try to get a new Identity in the Orbot App (icon
on the top right).</p>
]]></string>
<string name="help_tor_enable"><![CDATA[
<h1>Tor Node</h1>
<p>This is an .onion node. In order to use it, you must enable Tor mode by touching the
<img src="ic_network_clearnet"/> icon near the top of the Wallet List page.</p>
]]></string>
</resources>

View File

@ -23,7 +23,6 @@
<string name="label_ok">OK</string>
<string name="label_cancel">キャンセル</string>
<string name="label_close">閉じる</string>
<string name="label_wallet_advanced_details">タッチして詳細情報を見る</string>
<string name="label_send_success">送金成功</string>
<string name="label_send_done">完了</string>
@ -236,7 +235,7 @@
<string name="send_create_tx_error_title">取引作成エラー</string>
<string name="tx_list_fee">- 手数料 %1$s</string>
<string name="tx_list_fee">手数料 %1$s</string>
<string name="tx_list_amount_failed">(%1$s)</string>
<string name="tx_list_failed_text">失敗</string>
<string name="tx_list_amount_negative">- %1$s</string>
@ -430,8 +429,21 @@
<string name="restore_failed">Import failed!</string>
<string name="menu_deletecache">Reset wallet!</string>
<<<<<<< HEAD
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, ...)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="send_address_resolve_ud">Resolving ENS / UD&#8230;</string>
<string name="send_address_no_ud_records">No address found for ENS / UD domain</string>
=======
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, &#8230;)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="node_tor_error">Tor required</string>
<string name="node_waiting">\u00A0WAITING FOR NODE\u00A0</string>
<string name="tor_enable_background">"Allow Background Starts" in Orbot Settings to use Tor!</string>
<string name="tor_noshift">SideShift.ai doesn\'t support Tor.\nDisable Tor to swap XMR.</string>
<string name="label_wallet_advanced_details">タッチして詳細情報を見る</string> <!-- Please chnage to "Detailed information" -->
<string name="label_seed_offset_encrypt">Seed encryption (EXPERIMENTAL)</string>
<string name="seed_offset_hint">Seed Offset Phrase (optional)</string>
>>>>>>> 7b96baeca7f216c943ad5d376e6838f9679e74b0
</resources>

View File

@ -292,4 +292,25 @@
]]></string>
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
<string name="help_nok">Nah…</string> <!-- Note: "Nah..." as in "I don't want this" -->
<string name="help_getorbot">Get Orbot!</string>
<string name="help_tor"><![CDATA[
<h1>Tor</h1>
<p>Tor, short for The Onion Router, is free and open-source software for enabling anonymous
communication.</p>
<p>Enabling Tor will route your connection through several relays and hide your IP address
from the node. Keep in mind this is more private but also <b>slower</b>.</p>
<p>In order to use Tor with Monerujo, you\'ll need Orbot installed on your phone. After
installing Orbot, make sure to enable it by clicking the network icon on the wallet list
screen.</p>
<p>If you have issues connecting with Tor, try to get a new Identity in the Orbot App (icon
on the top right).</p>
]]></string>
<string name="help_tor_enable"><![CDATA[
<h1>Tor Node</h1>
<p>This is an .onion node. In order to use it, you must enable Tor mode by touching the
<img src="ic_network_clearnet"/> icon near the top of the Wallet List page.</p>
]]></string>
</resources>

View File

@ -23,7 +23,7 @@
<string name="label_ok">OK</string>
<string name="label_cancel">Avbryt</string>
<string name="label_close">Lukk</string>
<string name="label_wallet_advanced_details">Trykk for detaljert informasjon</string>
<string name="label_wallet_advanced_details">Detaljert informasjon</string>
<string name="label_send_success">Sendt suksessfullt!</string>
<string name="label_send_done">Ferdig</string>
@ -230,7 +230,7 @@
<string name="send_create_tx_error_title">Error med å lage transaksjon</string>
<string name="tx_list_fee">- Avgift %1$s</string>
<string name="tx_list_fee">Avgift %1$s</string>
<string name="tx_list_amount_failed">(%1$s)</string>
<string name="tx_list_failed_text">feila</string>
<string name="tx_list_amount_negative">- %1$s</string>
@ -427,8 +427,20 @@
<string name="restore_failed">Import failed!</string>
<string name="menu_deletecache">Reset wallet!</string>
<<<<<<< HEAD
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, ...)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="send_address_resolve_ud">Resolving ENS / UD&#8230;</string>
<string name="send_address_no_ud_records">No address found for ENS / UD domain</string>
=======
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, &#8230;)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="node_tor_error">Tor required</string>
<string name="node_waiting">\u00A0WAITING FOR NODE\u00A0</string>
<string name="tor_enable_background">"Allow Background Starts" in Orbot Settings to use Tor!</string>
<string name="tor_noshift">SideShift.ai doesn\'t support Tor.\nDisable Tor to swap XMR.</string>
<string name="label_seed_offset_encrypt">Seed encryption (EXPERIMENTAL)</string>
<string name="seed_offset_hint">Seed Offset Phrase (optional)</string>
>>>>>>> 7b96baeca7f216c943ad5d376e6838f9679e74b0
</resources>

View File

@ -29,7 +29,6 @@
<style name="AppCard" parent="Widget.MaterialComponents.CardView">
<item name="cardElevation">0dp</item>
<item name="cardCornerRadius">1dp</item>
</style>
</resources>

View File

@ -230,4 +230,25 @@
]]></string>
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
<string name="help_nok">Nah…</string> <!-- Note: "Nah..." as in "I don't want this" -->
<string name="help_getorbot">Get Orbot!</string>
<string name="help_tor"><![CDATA[
<h1>Tor</h1>
<p>Tor, short for The Onion Router, is free and open-source software for enabling anonymous
communication.</p>
<p>Enabling Tor will route your connection through several relays and hide your IP address
from the node. Keep in mind this is more private but also <b>slower</b>.</p>
<p>In order to use Tor with Monerujo, you\'ll need Orbot installed on your phone. After
installing Orbot, make sure to enable it by clicking the network icon on the wallet list
screen.</p>
<p>If you have issues connecting with Tor, try to get a new Identity in the Orbot App (icon
on the top right).</p>
]]></string>
<string name="help_tor_enable"><![CDATA[
<h1>Tor Node</h1>
<p>This is an .onion node. In order to use it, you must enable Tor mode by touching the
<img src="ic_network_clearnet"/> icon near the top of the Wallet List page.</p>
]]></string>
</resources>

View File

@ -23,7 +23,7 @@
<string name="label_ok">OK</string>
<string name="label_cancel">Annuleren</string>
<string name="label_close">Sluiten</string>
<string name="label_wallet_advanced_details">Tik voor meer informatie</string>
<string name="label_wallet_advanced_details">Meer informatie</string>
<string name="label_send_success">Verzonden</string>
<string name="label_send_done">Klaar</string>
@ -227,7 +227,7 @@
<string name="send_create_tx_error_title">Fout bij transactie maken</string>
<string name="tx_list_fee">- kosten %1$s</string>
<string name="tx_list_fee">kosten %1$s</string>
<string name="tx_list_amount_failed">(%1$s)</string>
<string name="tx_list_failed_text">mislukt</string>
<string name="tx_list_amount_negative">- %1$s</string>
@ -427,8 +427,20 @@
<string name="restore_failed">Import failed!</string>
<string name="menu_deletecache">Reset wallet!</string>
<<<<<<< HEAD
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, ...)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="send_address_resolve_ud">Resolving ENS / UD&#8230;</string>
<string name="send_address_no_ud_records">No address found for ENS / UD domain</string>
=======
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, &#8230;)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="node_tor_error">Tor required</string>
<string name="node_waiting">\u00A0WAITING FOR NODE\u00A0</string>
<string name="tor_enable_background">"Allow Background Starts" in Orbot Settings to use Tor!</string>
<string name="tor_noshift">SideShift.ai doesn\'t support Tor.\nDisable Tor to swap XMR.</string>
<string name="label_seed_offset_encrypt">Seed encryption (EXPERIMENTAL)</string>
<string name="seed_offset_hint">Seed Offset Phrase (optional)</string>
>>>>>>> 7b96baeca7f216c943ad5d376e6838f9679e74b0
</resources>

View File

@ -291,4 +291,25 @@
]]></string>
<string name="help_ok">Entendi!</string> <!-- Note: "Got it" as in "I understand this" -->
<string name="help_nok">Nah…</string> <!-- Note: "Nah..." as in "I don't want this" -->
<string name="help_getorbot">Get Orbot!</string>
<string name="help_tor"><![CDATA[
<h1>Tor</h1>
<p>Tor, short for The Onion Router, is free and open-source software for enabling anonymous
communication.</p>
<p>Enabling Tor will route your connection through several relays and hide your IP address
from the node. Keep in mind this is more private but also <b>slower</b>.</p>
<p>In order to use Tor with Monerujo, you\'ll need Orbot installed on your phone. After
installing Orbot, make sure to enable it by clicking the network icon on the wallet list
screen.</p>
<p>If you have issues connecting with Tor, try to get a new Identity in the Orbot App (icon
on the top right).</p>
]]></string>
<string name="help_tor_enable"><![CDATA[
<h1>Tor Node</h1>
<p>This is an .onion node. In order to use it, you must enable Tor mode by touching the
<img src="ic_network_clearnet"/> icon near the top of the Wallet List page.</p>
]]></string>
</resources>

View File

@ -23,7 +23,7 @@
<string name="label_ok">OK</string>
<string name="label_cancel">Cancelar</string>
<string name="label_close">Fechar</string>
<string name="label_wallet_advanced_details">Toque para mais detalhes</string>
<string name="label_wallet_advanced_details">Mais detalhes</string>
<string name="label_send_success">Enviado com sucesso</string>
<string name="label_send_done">Concluído</string>
@ -74,7 +74,7 @@
<string name="text_send_btc_amount">%1$s %3$s = %2$s XMR</string>
<string name="text_send_btc_rate">(Cotação: %1$s %2$s/XMR)</string>
<string name="label_send_btc_xmrto_info">Visite o SideShift.ai para suporte &amp; rastreio da ordem</string>
<string name="label_send_btc_xmrto_info">Visite SideShift.ai para suporte &amp; rastreio da ordem</string>
<string name="label_send_btc_xmrto_key_lb">Chave secreta\nSideShift.ai</string>
<string name="label_send_btc_xmrto_key">Chave secreta SideShift.ai</string>
<string name="label_send_btc_address">Endereço %1$s de destino</string>
@ -156,9 +156,9 @@
<string name="message_exchange_failed">Não foi possível obter a cotação!\nUse XMR/XMR ou tente novamente</string>
<string name="generate_title">Criar Carteira</string>
<string name="generate_name_hint">Nome da Carteira</string>
<string name="generate_password_hint">Senha da Carteira</string>
<string name="generate_title">Criar carteira</string>
<string name="generate_name_hint">Nome da carteira</string>
<string name="generate_password_hint">Senha da carteira</string>
<string name="generate_fingerprint_hint">Permitir abrir a carteira com impressão digital</string>
<string name="generate_fingerprint_warn"><![CDATA[
<strong>Autenticação por impressão digital</strong>
@ -229,7 +229,7 @@
<string name="send_create_tx_error_title">Erro ao criar a transação</string>
<string name="tx_list_fee">- taxa de %1$s</string>
<string name="tx_list_fee">taxa de %1$s</string>
<string name="tx_list_amount_failed">(%1$s)</string>
<string name="tx_list_failed_text">falhou</string>
<string name="tx_list_amount_negative">- %1$s</string>
@ -358,12 +358,13 @@
<string name="onboarding_button_next">Próximo</string>
<string name="onboarding_button_ready">Estou pronto!</string>
<string name="onboarding_welcome_title">Bem-vindo a Monerujo!</string>
<string name="onboarding_welcome_information">Esse aplicativo permite que você crie e use carteiras Monero. Você poderá guardar seus queridos moneroj aqui.</string>
<string name="onboarding_welcome_title">Bem-vindo à Monerujo!</string>
<string name="onboarding_welcome_information">Este aplicativo permite que você crie e use carteiras Monero. Você poderá guardar seus queridos moneroj
aqui.</string>
<string name="onboarding_seed_title">Mantenha sua semente em segurança</string>
<string name="onboarding_seed_information">A semente dá acesso total a qualquer pessoa que a tenha. Se você perdê-la, nós não conseguiremos lhe ajudar a recuperá-la e você perderá seus amados moneroj.</string>
<string name="onboarding_xmrto_title">Enviar Crypto</string>
<string name="onboarding_xmrto_information">A Monerujo possui o SideShift.ai integrado. Basta colar ou escaner um endereço BTC, LTC, ETH, DASH ou DOGE e você estará enviando cripto, mas gastando em XMR.</string>
<string name="onboarding_xmrto_title">Enviar Cripto</string>
<string name="onboarding_xmrto_information">A Monerujo possui o SideShift.ai integrado. Basta colar ou escanear um endereço BTC, LTC, ETH, DASH ou DOGE e você estará enviando cripto, mas gastando em XMR.</string>
<string name="onboarding_nodes_title">"Nós", do seu jeito</string>
<string name="onboarding_nodes_information">Os nós conectam você à rede Monero. Escolha entre nós públicos ou seja completamente "cypherpunk" e utilize seu próprio nó.</string>
<string name="onboarding_fpsend_title">Enviar usando a digital</string>
@ -411,16 +412,29 @@
<string name="subaddress_select_label">Selecione um subendereço</string>
<string name="subaddress_details_hint">Toque e segure para mais detalhes</string>
<string name="delete_alert_message">This wallet will be deleted. Your funds will be gone forever unless you have your seed or a working backup to recover it.</string>
<string name="menu_delete">Delete</string><!-- like: "Delete wallet!" -->
<string name="delete_failed">Delete failed!</string>
<string name="delete_alert_message">Esta carteira será excluída. Seus fundos desaparecerão para sempre, a não ser que você tenha sua semente guardada ou um backup funcional para recuperá-la.</string>
<string name="menu_delete">Excluir</string><!-- like: "Delete wallet!" -->
<string name="delete_failed">Exclusão falhou!</string>
<string name="menu_restore">Import wallet</string>
<string name="restore_failed">Import failed!</string>
<string name="menu_restore">Importar carteira</string>
<string name="restore_failed">Importação falhou!</string>
<<<<<<< HEAD
<string name="menu_deletecache">Reset wallet!</string>
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, ...)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="send_address_resolve_ud">Resolving ENS / UD&#8230;</string>
<string name="send_address_no_ud_records">No address found for ENS / UD domain</string>
=======
<string name="menu_deletecache">Resetar carteira!</string>
<string name="deletecache_alert_message"><![CDATA[Esta carteira será resetada, perdendo todos os dados "off-chain" (como notas, contas & nomes de subendereços, chaves de transações privadas, …)! Use isso SOMENTE se esta carteira estiver corrompida e não carrega!]]></string>
<string name="node_tor_error">Tor required</string>
<string name="node_waiting">\u00A0WAITING FOR NODE\u00A0</string>
<string name="tor_enable_background">"Allow Background Starts" in Orbot Settings to use Tor!</string>
<string name="tor_noshift">SideShift.ai doesn\'t support Tor.\nDisable Tor to swap XMR.</string>
<string name="label_seed_offset_encrypt">Seed encryption (EXPERIMENTAL)</string>
<string name="seed_offset_hint">Seed Offset Phrase (optional)</string>
>>>>>>> 7b96baeca7f216c943ad5d376e6838f9679e74b0
</resources>

View File

@ -291,4 +291,25 @@
]]></string>
<string name="help_ok">Entendido!</string> <!-- Note: "Got it" as in "I understand this" -->
<string name="help_nok">Nah…</string> <!-- Note: "Nah..." as in "I don't want this" -->
<string name="help_getorbot">Get Orbot!</string>
<string name="help_tor"><![CDATA[
<h1>Tor</h1>
<p>Tor, short for The Onion Router, is free and open-source software for enabling anonymous
communication.</p>
<p>Enabling Tor will route your connection through several relays and hide your IP address
from the node. Keep in mind this is more private but also <b>slower</b>.</p>
<p>In order to use Tor with Monerujo, you\'ll need Orbot installed on your phone. After
installing Orbot, make sure to enable it by clicking the network icon on the wallet list
screen.</p>
<p>If you have issues connecting with Tor, try to get a new Identity in the Orbot App (icon
on the top right).</p>
]]></string>
<string name="help_tor_enable"><![CDATA[
<h1>Tor Node</h1>
<p>This is an .onion node. In order to use it, you must enable Tor mode by touching the
<img src="ic_network_clearnet"/> icon near the top of the Wallet List page.</p>
]]></string>
</resources>

View File

@ -23,7 +23,7 @@
<string name="label_ok">OK</string>
<string name="label_cancel">Cancelar</string>
<string name="label_close">Fechar</string>
<string name="label_wallet_advanced_details">Toca para informação detalhada</string>
<string name="label_wallet_advanced_details">Informação detalhada</string>
<string name="label_send_success">Enviado com sucesso</string>
<string name="label_send_done">Feito</string>
@ -229,7 +229,7 @@
<string name="send_create_tx_error_title">Erro ao criar a transacção</string>
<string name="tx_list_fee">- Taxa %1$s</string>
<string name="tx_list_fee">Taxa %1$s</string>
<string name="tx_list_amount_failed">(%1$s)</string>
<string name="tx_list_failed_text">falhou</string>
<string name="tx_list_amount_negative">- %1$s</string>
@ -431,8 +431,20 @@
<string name="restore_failed">Import failed!</string>
<string name="menu_deletecache">Reset wallet!</string>
<<<<<<< HEAD
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, ...)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="send_address_resolve_ud">Resolving ENS / UD&#8230;</string>
<string name="send_address_no_ud_records">No address found for ENS / UD domain</string>
=======
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, &#8230;)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="node_tor_error">Tor required</string>
<string name="node_waiting">\u00A0WAITING FOR NODE\u00A0</string>
<string name="tor_enable_background">"Allow Background Starts" in Orbot Settings to use Tor!</string>
<string name="tor_noshift">SideShift.ai doesn\'t support Tor.\nDisable Tor to swap XMR.</string>
<string name="label_seed_offset_encrypt">Seed encryption (EXPERIMENTAL)</string>
<string name="seed_offset_hint">Seed Offset Phrase (optional)</string>
>>>>>>> 7b96baeca7f216c943ad5d376e6838f9679e74b0
</resources>

View File

@ -298,4 +298,25 @@
]]></string>
<string name="help_ok">Am înțeles!</string> <!-- Note: "Got it" as in "I understand this" -->
<string name="help_nok">Nah…</string> <!-- Note: "Nah..." as in "I don't want this" -->
<string name="help_getorbot">Get Orbot!</string>
<string name="help_tor"><![CDATA[
<h1>Tor</h1>
<p>Tor, short for The Onion Router, is free and open-source software for enabling anonymous
communication.</p>
<p>Enabling Tor will route your connection through several relays and hide your IP address
from the node. Keep in mind this is more private but also <b>slower</b>.</p>
<p>In order to use Tor with Monerujo, you\'ll need Orbot installed on your phone. After
installing Orbot, make sure to enable it by clicking the network icon on the wallet list
screen.</p>
<p>If you have issues connecting with Tor, try to get a new Identity in the Orbot App (icon
on the top right).</p>
]]></string>
<string name="help_tor_enable"><![CDATA[
<h1>Tor Node</h1>
<p>This is an .onion node. In order to use it, you must enable Tor mode by touching the
<img src="ic_network_clearnet"/> icon near the top of the Wallet List page.</p>
]]></string>
</resources>

View File

@ -22,7 +22,7 @@
<string name="label_ok">OK</string>
<string name="label_cancel">Anulează</string>
<string name="label_close">Închide</string>
<string name="label_wallet_advanced_details">Atinge pentru informații detaliate</string>
<string name="label_wallet_advanced_details">Informații detaliate</string>
<string name="label_send_success">Trimis cu succes</string>
<string name="label_send_done">Gata</string>
@ -205,7 +205,7 @@
<string name="send_create_tx_error_title">Eroare creare tranzacție</string>
<string name="tx_list_fee">- Comision %1$s</string>
<string name="tx_list_fee">Comision %1$s</string>
<string name="tx_list_amount_failed">(%1$s)</string>
<string name="tx_list_failed_text">eșuat</string>
<string name="tx_list_amount_negative">- %1$s</string>
@ -427,8 +427,20 @@
<string name="restore_failed">Import failed!</string>
<string name="menu_deletecache">Reset wallet!</string>
<<<<<<< HEAD
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, ...)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="send_address_resolve_ud">Resolving ENS / UD&#8230;</string>
<string name="send_address_no_ud_records">No address found for ENS / UD domain</string>
=======
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, &#8230;)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="node_tor_error">Tor required</string>
<string name="node_waiting">\u00A0WAITING FOR NODE\u00A0</string>
<string name="tor_enable_background">"Allow Background Starts" in Orbot Settings to use Tor!</string>
<string name="tor_noshift">SideShift.ai doesn\'t support Tor.\nDisable Tor to swap XMR.</string>
<string name="label_seed_offset_encrypt">Seed encryption (EXPERIMENTAL)</string>
<string name="seed_offset_hint">Seed Offset Phrase (optional)</string>
>>>>>>> 7b96baeca7f216c943ad5d376e6838f9679e74b0
</resources>

View File

@ -297,4 +297,23 @@
]]></string>
<string name="help_ok">Я понял!</string> <!-- Note: "Got it" as in "I understand this" -->
<string name="help_nok">Не…</string> <!-- Note: "Nah..." as in "I don't want this" -->
<string name="help_getorbot">Скачать Orbot!</string>
<string name="help_tor"><![CDATA[
<h1>Tor</h1>
<p>Tor, сокр. от The Onion Router, бесплатное и программное обеспечение с открытым исходным кодом для обеспечения анонимного общения.</p>
<p>Включение Tor перенаправит подключение к нескольким узлам и скроет IP-адрес от узла.
Имейте в виду, что это более приватно, но и <b>медленнее</b>.</p>
<p>Для того, чтобы использовать Tor с Monerujo, вам понадобится Orbot на вашем телефоне. После установки Orbot убедитесь,
что вы включили его, нажав значок сети на экране списка кошельков.</p>
<p>Если у вас есть проблемы с подключением к Tor, попробуйте получить новую идентичность в приложении Orbot (значок
в правом верхнем углу).</p>
]]></string>
<string name="help_tor_enable"><![CDATA[
<h1>Tor узел</h1>
<p>Это .onion узел. Для того, чтобы использовать его, вы должны включить Tor, нажав
<img src="ic_network_clearnet"/> значок в верхней части страницы списка кошельков.</p>
]]></string>
</resources>

View File

@ -23,7 +23,7 @@
<string name="label_ok">Ок</string>
<string name="label_cancel">Отмена</string>
<string name="label_close">Закрыть</string>
<string name="label_wallet_advanced_details">Нажмите для доп. информации</string>
<string name="label_wallet_advanced_details">Дополнительная информация</string>
<string name="label_send_success">Успешно отправлено</string>
<string name="label_send_done">Готово</string>
@ -231,7 +231,7 @@
<string name="send_create_tx_error_title">Ошибка создания транзакции</string>
<string name="tx_list_fee">- Комиссия %1$s</string>
<string name="tx_list_fee">Комиссия %1$s</string>
<string name="tx_list_amount_failed">(%1$s)</string>
<string name="tx_list_failed_text">Не удалось</string>
<string name="tx_list_amount_negative">- %1$s</string>
@ -431,8 +431,20 @@
<string name="restore_failed">Ошибка импорта!</string>
<string name="menu_deletecache">Сбросить кошелек</string>
<<<<<<< HEAD
<string name="deletecache_alert_message">Этот кошелек будет сброшен, вы потеряете все данные, которые не находятся в блокчейне (например примечания, имена подадресов, приватные ключи транзакций, ...)! Используйте это ТОЛЬКО если ваш кошелек поврежден и не загружается!</string>
<string name="send_address_resolve_ud">Resolving ENS / UD&#8230;</string>
<string name="send_address_no_ud_records">No address found for ENS / UD domain</string>
=======
<string name="deletecache_alert_message">Этот кошелек будет сброшен, потеряв всю локальную информацию (например: заметки, имена адресов, приватные ключи транзакций, &#8230;)! Используйте это ТОЛЬКО если кошелек поврежден и не загружается!</string>
<string name="node_tor_error">Необходим Tor</string>
<string name="node_waiting">\u00A0ОЖИДАНИЕ УЗЛА\u00A0</string>
<string name="tor_enable_background">Необходимо выбрать "Allow Background Starts" в настройках Orbot для использования Tor!</string>
<string name="tor_noshift">SideShift.ai не поддерживает Tor.\nОтключите Tor для обмена XMR.</string>
<string name="label_seed_offset_encrypt">Seed encryption (EXPERIMENTAL)</string>
<string name="seed_offset_hint">Seed Offset Phrase (optional)</string>
>>>>>>> 7b96baeca7f216c943ad5d376e6838f9679e74b0
</resources>

View File

@ -259,4 +259,25 @@
]]></string>
<string name="help_ok">Rozumiem!</string> <!-- Note: "Got it" as in "I understand this" -->
<string name="help_nok">Nah…</string> <!-- Note: "Nah..." as in "I don't want this" -->
<string name="help_getorbot">Get Orbot!</string>
<string name="help_tor"><![CDATA[
<h1>Tor</h1>
<p>Tor, short for The Onion Router, is free and open-source software for enabling anonymous
communication.</p>
<p>Enabling Tor will route your connection through several relays and hide your IP address
from the node. Keep in mind this is more private but also <b>slower</b>.</p>
<p>In order to use Tor with Monerujo, you\'ll need Orbot installed on your phone. After
installing Orbot, make sure to enable it by clicking the network icon on the wallet list
screen.</p>
<p>If you have issues connecting with Tor, try to get a new Identity in the Orbot App (icon
on the top right).</p>
]]></string>
<string name="help_tor_enable"><![CDATA[
<h1>Tor Node</h1>
<p>This is an .onion node. In order to use it, you must enable Tor mode by touching the
<img src="ic_network_clearnet"/> icon near the top of the Wallet List page.</p>
]]></string>
</resources>

View File

@ -23,7 +23,7 @@
<string name="label_ok">OK</string>
<string name="label_cancel">Zrušiť</string>
<string name="label_close">Zatvoriť</string>
<string name="label_wallet_advanced_details">Klepni pre viac info</string>
<string name="label_wallet_advanced_details">Viac info</string>
<string name="label_send_success">úspešne odoslané</string>
<string name="label_send_done">Hotovo</string>
@ -228,7 +228,7 @@
<string name="send_create_tx_error_title">Vytvor Chybu Transakcie</string>
<string name="tx_list_fee">- poplatok %1$s</string>
<string name="tx_list_fee">poplatok %1$s</string>
<string name="tx_list_amount_failed">(%1$s)</string>
<string name="tx_list_failed_text">zlyhala</string>
<string name="tx_list_amount_negative">- %1$s</string>
@ -428,8 +428,20 @@
<string name="restore_failed">Import failed!</string>
<string name="menu_deletecache">Reset wallet!</string>
<<<<<<< HEAD
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, ...)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="send_address_resolve_ud">Resolving ENS / UD&#8230;</string>
<string name="send_address_no_ud_records">No address found for ENS / UD domain</string>
=======
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, &#8230;)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="node_tor_error">Tor required</string>
<string name="node_waiting">\u00A0WAITING FOR NODE\u00A0</string>
<string name="tor_enable_background">"Allow Background Starts" in Orbot Settings to use Tor!</string>
<string name="tor_noshift">SideShift.ai doesn\'t support Tor.\nDisable Tor to swap XMR.</string>
<string name="label_seed_offset_encrypt">Seed encryption (EXPERIMENTAL)</string>
<string name="seed_offset_hint">Seed Offset Phrase (optional)</string>
>>>>>>> 7b96baeca7f216c943ad5d376e6838f9679e74b0
</resources>

View File

@ -290,4 +290,25 @@
]]></string>
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
<string name="help_nok">Nah…</string> <!-- Note: "Nah..." as in "I don't want this" -->
<string name="help_getorbot">Get Orbot!</string>
<string name="help_tor"><![CDATA[
<h1>Tor</h1>
<p>Tor, short for The Onion Router, is free and open-source software for enabling anonymous
communication.</p>
<p>Enabling Tor will route your connection through several relays and hide your IP address
from the node. Keep in mind this is more private but also <b>slower</b>.</p>
<p>In order to use Tor with Monerujo, you\'ll need Orbot installed on your phone. After
installing Orbot, make sure to enable it by clicking the network icon on the wallet list
screen.</p>
<p>If you have issues connecting with Tor, try to get a new Identity in the Orbot App (icon
on the top right).</p>
]]></string>
<string name="help_tor_enable"><![CDATA[
<h1>Tor Node</h1>
<p>This is an .onion node. In order to use it, you must enable Tor mode by touching the
<img src="ic_network_clearnet"/> icon near the top of the Wallet List page.</p>
]]></string>
</resources>

View File

@ -23,7 +23,7 @@
<string name="label_ok">OK</string>
<string name="label_cancel">Otkaži</string>
<string name="label_close">Zatvori</string>
<string name="label_wallet_advanced_details">Takni za detaljne informacije</string>
<string name="label_wallet_advanced_details">Detaljne informacije</string>
<string name="label_send_success">Uspešno poslato</string>
<string name="label_send_done">Gotovo</string>
@ -237,7 +237,7 @@
<string name="send_create_tx_error_title">Kreiraj transakcijsku grešku</string>
<string name="tx_list_fee">- naknada %1$s</string>
<string name="tx_list_fee">naknada %1$s</string>
<string name="tx_list_amount_failed">(%1$s)</string>
<string name="tx_list_failed_text">neuspelo</string>
<string name="tx_list_amount_negative">- %1$s</string>
@ -426,8 +426,20 @@
<string name="restore_failed">Import failed!</string>
<string name="menu_deletecache">Reset wallet!</string>
<<<<<<< HEAD
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, ...)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="send_address_resolve_ud">Resolving ENS / UD&#8230;</string>
<string name="send_address_no_ud_records">No address found for ENS / UD domain</string>
=======
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, &#8230;)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="node_tor_error">Tor required</string>
<string name="node_waiting">\u00A0WAITING FOR NODE\u00A0</string>
<string name="tor_enable_background">"Allow Background Starts" in Orbot Settings to use Tor!</string>
<string name="tor_noshift">SideShift.ai doesn\'t support Tor.\nDisable Tor to swap XMR.</string>
<string name="label_seed_offset_encrypt">Seed encryption (EXPERIMENTAL)</string>
<string name="seed_offset_hint">Seed Offset Phrase (optional)</string>
>>>>>>> 7b96baeca7f216c943ad5d376e6838f9679e74b0
</resources>

View File

@ -279,4 +279,25 @@
]]></string>
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
<string name="help_nok">Nah…</string> <!-- Note: "Nah..." as in "I don't want this" -->
<string name="help_getorbot">Get Orbot!</string>
<string name="help_tor"><![CDATA[
<h1>Tor</h1>
<p>Tor, short for The Onion Router, is free and open-source software for enabling anonymous
communication.</p>
<p>Enabling Tor will route your connection through several relays and hide your IP address
from the node. Keep in mind this is more private but also <b>slower</b>.</p>
<p>In order to use Tor with Monerujo, you\'ll need Orbot installed on your phone. After
installing Orbot, make sure to enable it by clicking the network icon on the wallet list
screen.</p>
<p>If you have issues connecting with Tor, try to get a new Identity in the Orbot App (icon
on the top right).</p>
]]></string>
<string name="help_tor_enable"><![CDATA[
<h1>Tor Node</h1>
<p>This is an .onion node. In order to use it, you must enable Tor mode by touching the
<img src="ic_network_clearnet"/> icon near the top of the Wallet List page.</p>
]]></string>
</resources>

View File

@ -23,7 +23,7 @@
<string name="label_ok">OK</string>
<string name="label_cancel">Avbryt</string>
<string name="label_close">Stäng</string>
<string name="label_wallet_advanced_details">Tryck för detaljerad information</string>
<string name="label_wallet_advanced_details">Detaljerad information</string>
<string name="label_send_success">Har skickats</string>
<string name="label_send_done">Färdig</string>
@ -218,7 +218,7 @@
<string name="send_create_tx_error_title">Ett fel uppstod när transaktion skapades</string>
<string name="tx_list_fee">- Avgift %1$s</string>
<string name="tx_list_fee">Avgift %1$s</string>
<string name="tx_list_amount_failed">(%1$s)</string>
<string name="tx_list_failed_text">misslyckades</string>
<string name="tx_list_amount_negative">- %1$s</string>
@ -419,8 +419,20 @@
<string name="restore_failed">Importeringen misslyckad!</string>
<string name="menu_deletecache">Återställ plånbok!</string>
<<<<<<< HEAD
<string name="deletecache_alert_message">Denna plånbok kommer att återställas och förlorar all off-chain data (som anteckningar, konto- och subadresser, privata transaktionsnycklar, ...)! Använd ENDAST detta om den här plånboken är skadad och inte laddas!</string>
<string name="send_address_resolve_ud">Resolving ENS / UD&#8230;</string>
<string name="send_address_no_ud_records">No address found for ENS / UD domain</string>
=======
<string name="deletecache_alert_message">This wallet will be reset, losing all off-chain data (like notes, account &amp; subaddress names, private transaction keys, &#8230;)! Use this ONLY if this wallet is corrupt and does not load!</string>
<string name="node_tor_error">Tor required</string>
<string name="node_waiting">\u00A0WAITING FOR NODE\u00A0</string>
<string name="tor_enable_background">"Allow Background Starts" in Orbot Settings to use Tor!</string>
<string name="tor_noshift">SideShift.ai doesn\'t support Tor.\nDisable Tor to swap XMR.</string>
<string name="label_seed_offset_encrypt">Seed encryption (EXPERIMENTAL)</string>
<string name="seed_offset_hint">Seed Offset Phrase (optional)</string>
>>>>>>> 7b96baeca7f216c943ad5d376e6838f9679e74b0
</resources>

View File

@ -4,18 +4,18 @@
<h1>Створити гаманець - Новий</h1>
<p>Якщо вам потрібна нова адреса Monero!</p>
<p>Введіть унікальне і\'мя та пароль гаманця.
        Пароль використовується для захисту даних вашого гаманця на Android пристрої.
Пароль використовується для захисту даних вашого гаманця на Android пристрої.
Необхідно використовувати надійний пароль. Краще навіть використовувати фразу-пароль.
</p>
<h2>Запишіть вашу мнемонічну фразу!</h2>
<p>Наступний екран буде містити вашу \"мнемонічну фразу\", що складається з 25 слів.
        Це єдині дані, які необхідні для відновлення вашого гаманця в
        майбутньому і отримання доступу до ваших коштів.
        Підтримувати її безпеку і конфіденційність дуже важливо, так як це
     гарантує, що ніхто не зможе отримати доступ до ваших коштів!</p>
Це єдині дані, які необхідні для відновлення вашого гаманця в
майбутньому і отримання доступу до ваших коштів.
Підтримувати її безпеку і конфіденційність дуже важливо, так як це
гарантує, що ніхто не зможе отримати доступ до ваших коштів!</p>
<p>Якщо ви втратите пароль від вашого гаманця, ви зможете відновити його, використовуючи мнемонічну фразу.</p>
<p>Спосіб відновлення мнемонічної фрази відсутній. У разі її втрати - будуть втрачені
     і всі ваші кошти! Також ви ніколи не зможете змінити мнемонічну фразу, і якщо вона
і всі ваші кошти! Також ви ніколи не зможете змінити мнемонічну фразу, і якщо вона
буде вкрадена або розкрита будь-яким іншим чином, то вам доведеться перенести ваші кошти
в новий гаманець (з новою мнемонічною фразою). Тому рекомендується створити резервну копію
вашої мнемонічною фрази, записавши її, і зберігати декілька копій в безпечному місці.</p>
@ -61,7 +61,7 @@
не боячись втратити свої Monero. Monero відправлятимуть на ваш гаманець, використовуючи саме цю адресу.
<h2>Мнемонічна фраза</h2>
Це єдині дані, які необхідні для відновлення вашого гаманця в майбутньому, і отримання
        доступу до ваших коштів. Підтримувати її безпеку і конфіденційність дуже важливо,
доступу до ваших коштів. Підтримувати її безпеку і конфіденційність дуже важливо,
так як це гарантує, що <em>ніхто</em> не зможе отримати доступ до ваших коштів!
Якщо ви не записали цю фразу, і не зберегли її в безпечному місці, зробіть це негайно!
<h2>Файли відновлення паролю гаманця</h2>
@ -207,10 +207,10 @@
<p>Ваші секретні ключі ніколи не покинуть пристрій Ledger. Вам потрібен
пристрій кожен раз, коли ви хочете отримати доступ до свого гаманця.</p>
<p>Необхідно ввести унікальні і&apos:мя і пароль гаманця. Пароль використовується для захисту даних вашого
         гаманця на пристрої. Необхідно використовувати надійний пароль. Краще навіть використовувати фразу-пароль.</p>
гаманця на пристрої. Необхідно використовувати надійний пароль. Краще навіть використовувати фразу-пароль.</p>
<p>Якщо вам відомий номер блоку першої транзакції, який використовувався з цією адресою, слід
         ввести його в поле \"Відновити висоту\". Ви також можете використовувати дату в форматі YYYY-MM-DD.
  Якщо ви не впевнені, введіть приблизну дату/висоту блоку <em>до</em> того, як ви вперше використали цей гаманець.</p>
ввести його в поле \"Відновити висоту\". Ви також можете використовувати дату в форматі YYYY-MM-DD.
Якщо ви не впевнені, введіть приблизну дату/висоту блоку <em>до</em> того, як ви вперше використали цей гаманець.</p>
]]></string>
<string name="help_wallet"><![CDATA[
@ -229,7 +229,7 @@
<p><b>Допоможіть! Баланс мого гаманця кудись зник або не підтверджений!</b><br/>
Не панікуйте! Якщо ви відправляєте кошти з вашого гаманця, ваш баланс тимчасово залишається
непідтвердженим. Це відбувається в результаті процесу обміну Monero в блокчейні, і роботи механізму
        решти. Подробиці обміну можна дізнатися за посиланням:
решти. Подробиці обміну можна дізнатися за посиланням:
https://getmonero.org/resources/moneropedia/change.html
<h2>Список транзакцій</h2>
<p>Список транзакцій, проведених з використанням цього гаманця. У гаманцях перегляду можна побачити
@ -278,8 +278,6 @@
Сканування зупиниться, як тільки буде знайдено 10 віддалених вузлів.</p>
]]></string>
<string name="help_uri"><![CDATA[
<h1>Використання плажіного посилання</h1>
<p>Ви почали використовувати Monerujo з платіжним посиланням. Для надсилання коштів, будь ласка, виконайте найступне:</p>
@ -292,4 +290,25 @@
]]></string>
<string name="help_ok">Я зрозумів!</string> <!-- Note: "Got it" as in "I understand this" -->
<string name="help_nok">Nah…</string> <!-- Note: "Nah..." as in "I don't want this" -->
<string name="help_getorbot">Get Orbot!</string>
<string name="help_tor"><![CDATA[
<h1>Tor</h1>
<p>Tor, short for The Onion Router, is free and open-source software for enabling anonymous
communication.</p>
<p>Enabling Tor will route your connection through several relays and hide your IP address
from the node. Keep in mind this is more private but also <b>slower</b>.</p>
<p>In order to use Tor with Monerujo, you\'ll need Orbot installed on your phone. After
installing Orbot, make sure to enable it by clicking the network icon on the wallet list
screen.</p>
<p>If you have issues connecting with Tor, try to get a new Identity in the Orbot App (icon
on the top right).</p>
]]></string>
<string name="help_tor_enable"><![CDATA[
<h1>Tor Node</h1>
<p>This is an .onion node. In order to use it, you must enable Tor mode by touching the
<img src="ic_network_clearnet"/> icon near the top of the Wallet List page.</p>
]]></string>
</resources>

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