mirror of
https://github.com/m2049r/xmrwallet
synced 2025-09-04 00:53:36 +02:00
Compare commits
38 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7f1796b12e | ||
![]() |
abe5c8afab | ||
![]() |
47f79b5269 | ||
![]() |
c9c07eaa15 | ||
![]() |
a490e3af0c | ||
![]() |
64d5b3bdea | ||
![]() |
bf91eaf22f | ||
![]() |
2c3e73b540 | ||
![]() |
830d9dadb9 | ||
![]() |
331d88ebba | ||
![]() |
7cc2f6fafb | ||
![]() |
9a3ee0eda8 | ||
![]() |
6e898939a3 | ||
![]() |
40ae39d647 | ||
![]() |
ca81e652e5 | ||
![]() |
796048be4e | ||
![]() |
441bf995c8 | ||
![]() |
e8860ab8eb | ||
![]() |
525b38ff53 | ||
![]() |
ba79bf87aa | ||
![]() |
3fe6571e7d | ||
![]() |
364e6a8137 | ||
![]() |
cb69ce99d6 | ||
![]() |
1f976872fc | ||
![]() |
27f266b6f7 | ||
![]() |
168928d54a | ||
![]() |
b3f61072aa | ||
![]() |
ccb64aded0 | ||
![]() |
e98fa089f2 | ||
![]() |
884878b7a7 | ||
![]() |
4e23f0ef3a | ||
![]() |
6ea4e3d998 | ||
![]() |
971c90f35b | ||
![]() |
f0523c403c | ||
![]() |
966ed23b87 | ||
![]() |
95f2ca74a6 | ||
![]() |
81d94478f2 | ||
![]() |
16ff779ebc |
@@ -137,7 +137,11 @@ set_target_properties(checkpoints PROPERTIES IMPORTED_LOCATION
|
||||
|
||||
add_library(device STATIC IMPORTED)
|
||||
set_target_properties(device PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libdevice.a)
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libdevice.a)
|
||||
|
||||
add_library(device_trezor STATIC IMPORTED)
|
||||
set_target_properties(device_trezor PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libdevice_trezor.a)
|
||||
|
||||
add_library(multisig STATIC IMPORTED)
|
||||
set_target_properties(multisig PROPERTIES IMPORTED_LOCATION
|
||||
@@ -147,6 +151,10 @@ add_library(version STATIC IMPORTED)
|
||||
set_target_properties(version PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libversion.a)
|
||||
|
||||
add_library(net STATIC IMPORTED)
|
||||
set_target_properties(net PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libnet.a)
|
||||
|
||||
#############
|
||||
# System
|
||||
#############
|
||||
@@ -166,6 +174,7 @@ target_link_libraries( monerujo
|
||||
mnemonics
|
||||
ringct
|
||||
ringct_basic
|
||||
net
|
||||
common
|
||||
cncrypto
|
||||
blockchain_db
|
||||
@@ -176,6 +185,7 @@ target_link_libraries( monerujo
|
||||
blocks
|
||||
checkpoints
|
||||
device
|
||||
device_trezor
|
||||
multisig
|
||||
version
|
||||
|
||||
|
@@ -7,8 +7,8 @@ android {
|
||||
applicationId "com.m2049r.xmrwallet"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 28
|
||||
versionCode 173
|
||||
versionName "1.11.3 'Chernushka'"
|
||||
versionCode 179
|
||||
versionName "1.11.9 'Chernushka'"
|
||||
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
externalNativeBuild {
|
||||
|
@@ -1,88 +0,0 @@
|
||||
// Copyright (c) 2017-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#if defined(HAVE_MONERUJO)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief LedgerFind - find Ledger Device and return it's name
|
||||
* @param buffer - buffer for name of found device
|
||||
* @param len - length of buffer
|
||||
* @return 0 - success
|
||||
* -1 - no device connected / found
|
||||
* -2 - JVM not found
|
||||
*/
|
||||
int LedgerFind(char *buffer, size_t len);
|
||||
|
||||
/**
|
||||
* @brief LedgerExchange - exchange data with Ledger Device
|
||||
* @param command - buffer for data to send
|
||||
* @param cmd_len - length of send to send
|
||||
* @param response - buffer for received data
|
||||
* @param max_resp_len - size of receive buffer
|
||||
*
|
||||
* @return length of received data in response or -1 if error
|
||||
*/
|
||||
int LedgerExchange(unsigned char *command, unsigned int cmd_len, unsigned char *response, unsigned int max_resp_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "device_io.hpp"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace hw {
|
||||
namespace io {
|
||||
class device_io_monerujo: device_io {
|
||||
public:
|
||||
device_io_monerujo() {};
|
||||
~device_io_monerujo() {};
|
||||
|
||||
void init() {};
|
||||
void release() {};
|
||||
|
||||
void connect(void *params) {};
|
||||
void disconnect() {};
|
||||
bool connected() const {return true;}; // monerujo is always connected before it gets here
|
||||
|
||||
// returns number of bytes read or -1 on error
|
||||
int exchange(unsigned char *command, unsigned int cmd_len, unsigned char *response, unsigned int max_resp_len) {
|
||||
return LedgerExchange(command, cmd_len, response, max_resp_len);
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#endif //#if defined(HAVE_MONERUJO)
|
@@ -39,6 +39,7 @@ static jclass class_WalletListener;
|
||||
static jclass class_TransactionInfo;
|
||||
static jclass class_Transfer;
|
||||
static jclass class_Ledger;
|
||||
static jclass class_WalletStatus;
|
||||
|
||||
std::mutex _listenerMutex;
|
||||
|
||||
@@ -61,6 +62,8 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
|
||||
jenv->FindClass("com/m2049r/xmrwallet/model/WalletListener")));
|
||||
class_Ledger = static_cast<jclass>(jenv->NewGlobalRef(
|
||||
jenv->FindClass("com/m2049r/xmrwallet/ledger/Ledger")));
|
||||
class_WalletStatus = static_cast<jclass>(jenv->NewGlobalRef(
|
||||
jenv->FindClass("com/m2049r/xmrwallet/model/Wallet$Status")));
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
#ifdef __cplusplus
|
||||
@@ -581,10 +584,25 @@ Java_com_m2049r_xmrwallet_model_Wallet_getStatusJ(JNIEnv *env, jobject instance)
|
||||
return wallet->status();
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_com_m2049r_xmrwallet_model_Wallet_getErrorString(JNIEnv *env, jobject instance) {
|
||||
jobject newWalletStatusInstance(JNIEnv *env, int status, const std::string &errorString) {
|
||||
jmethodID init = env->GetMethodID(class_WalletStatus, "<init>",
|
||||
"(ILjava/lang/String;)V");
|
||||
jstring _errorString = env->NewStringUTF(errorString.c_str());
|
||||
jobject instance = env->NewObject(class_WalletStatus, init, status, _errorString);
|
||||
env->DeleteLocalRef(_errorString);
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_com_m2049r_xmrwallet_model_Wallet_statusWithErrorString(JNIEnv *env, jobject instance) {
|
||||
Bitmonero::Wallet *wallet = getHandle<Bitmonero::Wallet>(env, instance);
|
||||
return env->NewStringUTF(wallet->errorString().c_str());
|
||||
|
||||
int status;
|
||||
std::string errorString;
|
||||
wallet->statusWithErrorString(status, errorString);
|
||||
|
||||
return newWalletStatusInstance(env, status, errorString);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
@@ -1382,8 +1400,6 @@ Java_com_m2049r_xmrwallet_model_WalletManager_setLogLevel(JNIEnv *env, jclass cl
|
||||
// Ledger Stuff
|
||||
//
|
||||
|
||||
#include "device_io_monerujo.hpp"
|
||||
|
||||
/**
|
||||
* @brief LedgerExchange - exchange data with Ledger Device
|
||||
* @param command - buffer for data to send
|
||||
@@ -1417,7 +1433,7 @@ int LedgerExchange(
|
||||
return -1;
|
||||
}
|
||||
jsize len = jenv->GetArrayLength(dataRecv);
|
||||
LOGD("LedgerExchange SCARD_S_SUCCESS %ld/%d", cmd_len, len);
|
||||
LOGD("LedgerExchange SCARD_S_SUCCESS %u/%d", cmd_len, len);
|
||||
if (len <= max_resp_len) {
|
||||
jenv->GetByteArrayRegion(dataRecv, 0, len, (jbyte *) response);
|
||||
jenv->DeleteLocalRef(dataRecv);
|
||||
|
@@ -192,7 +192,7 @@ public class GenerateReviewFragment extends Fragment {
|
||||
String viewKey;
|
||||
String spendKey;
|
||||
boolean isWatchOnly;
|
||||
Wallet.Status status;
|
||||
Wallet.Status walletStatus;
|
||||
|
||||
boolean dialogOpened = false;
|
||||
|
||||
@@ -224,9 +224,9 @@ public class GenerateReviewFragment extends Fragment {
|
||||
closeWallet = true;
|
||||
}
|
||||
name = wallet.getName();
|
||||
status = wallet.getStatus();
|
||||
if (status != Wallet.Status.Status_Ok) {
|
||||
Timber.e(wallet.getErrorString());
|
||||
walletStatus = wallet.getStatus();
|
||||
if (!walletStatus.isOk()) {
|
||||
Timber.e(walletStatus.getErrorString());
|
||||
if (closeWallet) wallet.close();
|
||||
return false;
|
||||
}
|
||||
@@ -287,10 +287,10 @@ public class GenerateReviewFragment extends Fragment {
|
||||
GenerateReviewFragment.VIEW_TYPE_ACCEPT.equals(type) ? Toolbar.BUTTON_NONE : Toolbar.BUTTON_BACK);
|
||||
} else {
|
||||
// TODO show proper error message and/or end the fragment?
|
||||
tvWalletAddress.setText(status.toString());
|
||||
tvWalletMnemonic.setText(status.toString());
|
||||
tvWalletViewKey.setText(status.toString());
|
||||
tvWalletSpendKey.setText(status.toString());
|
||||
tvWalletAddress.setText(walletStatus.toString());
|
||||
tvWalletMnemonic.setText(walletStatus.toString());
|
||||
tvWalletViewKey.setText(walletStatus.toString());
|
||||
tvWalletSpendKey.setText(walletStatus.toString());
|
||||
}
|
||||
hideProgress();
|
||||
}
|
||||
@@ -414,12 +414,13 @@ public class GenerateReviewFragment extends Fragment {
|
||||
}
|
||||
|
||||
boolean ok = false;
|
||||
if (wallet.getStatus() == Wallet.Status.Status_Ok) {
|
||||
Wallet.Status walletStatus = wallet.getStatus();
|
||||
if (walletStatus.isOk()) {
|
||||
wallet.setPassword(newPassword);
|
||||
wallet.store();
|
||||
ok = true;
|
||||
} else {
|
||||
Timber.e(wallet.getErrorString());
|
||||
Timber.e(walletStatus.getErrorString());
|
||||
}
|
||||
if (closeWallet) wallet.close();
|
||||
return ok;
|
||||
|
@@ -918,6 +918,16 @@ public class LoginActivity extends BaseActivity
|
||||
|
||||
}
|
||||
|
||||
boolean checkAndCloseWallet(Wallet aWallet) {
|
||||
Wallet.Status walletStatus = aWallet.getStatus();
|
||||
if (!walletStatus.isOk()) {
|
||||
Timber.e(walletStatus.getErrorString());
|
||||
toast(walletStatus.getErrorString());
|
||||
}
|
||||
aWallet.close();
|
||||
return walletStatus.isOk();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGenerate(final String name, final String password) {
|
||||
createWallet(name, password,
|
||||
@@ -929,15 +939,12 @@ public class LoginActivity extends BaseActivity
|
||||
|
||||
@Override
|
||||
public boolean createWallet(File aFile, String password) {
|
||||
NodeInfo currentNode = getNode();
|
||||
final long restoreHeight =
|
||||
(currentNode != null) ? currentNode.getHeight() - 20 : -1;
|
||||
Wallet newWallet = WalletManager.getInstance()
|
||||
.createWallet(aFile, password, MNEMONIC_LANGUAGE);
|
||||
boolean success = (newWallet.getStatus() == Wallet.Status.Status_Ok);
|
||||
if (!success) {
|
||||
Timber.e(newWallet.getErrorString());
|
||||
toast(newWallet.getErrorString());
|
||||
}
|
||||
newWallet.close();
|
||||
return success;
|
||||
.createWallet(aFile, password, MNEMONIC_LANGUAGE, restoreHeight);
|
||||
return checkAndCloseWallet(newWallet);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -956,13 +963,7 @@ public class LoginActivity extends BaseActivity
|
||||
public boolean createWallet(File aFile, String password) {
|
||||
Wallet newWallet = WalletManager.getInstance()
|
||||
.recoveryWallet(aFile, password, seed, restoreHeight);
|
||||
boolean success = (newWallet.getStatus() == Wallet.Status.Status_Ok);
|
||||
if (!success) {
|
||||
Timber.e(newWallet.getErrorString());
|
||||
toast(newWallet.getErrorString());
|
||||
}
|
||||
newWallet.close();
|
||||
return success;
|
||||
return checkAndCloseWallet(newWallet);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -982,13 +983,7 @@ public class LoginActivity extends BaseActivity
|
||||
Wallet newWallet = WalletManager.getInstance()
|
||||
.createWalletFromDevice(aFile, password,
|
||||
restoreHeight, "Ledger");
|
||||
boolean success = (newWallet.getStatus() == Wallet.Status.Status_Ok);
|
||||
if (!success) {
|
||||
Timber.e(newWallet.getErrorString());
|
||||
toast(newWallet.getErrorString());
|
||||
}
|
||||
newWallet.close();
|
||||
return success;
|
||||
return checkAndCloseWallet(newWallet);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1009,13 +1004,7 @@ public class LoginActivity extends BaseActivity
|
||||
Wallet newWallet = WalletManager.getInstance()
|
||||
.createWalletWithKeys(aFile, password, MNEMONIC_LANGUAGE, restoreHeight,
|
||||
address, viewKey, spendKey);
|
||||
boolean success = (newWallet.getStatus() == Wallet.Status.Status_Ok);
|
||||
if (!success) {
|
||||
Timber.e(newWallet.getErrorString());
|
||||
toast(newWallet.getErrorString());
|
||||
}
|
||||
newWallet.close();
|
||||
return success;
|
||||
return checkAndCloseWallet(newWallet);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@@ -440,7 +440,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
||||
Collections.sort(nodesToTest, NodeInfo.BestNodeComparator);
|
||||
NodeInfo bestNode = nodesToTest.get(0);
|
||||
if (bestNode.isValid())
|
||||
return nodesToTest.get(0);
|
||||
return bestNode;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
@@ -302,7 +302,7 @@ public class ReceiveFragment extends Fragment {
|
||||
File imagePath = new File(getActivity().getCacheDir(), "images");
|
||||
File png = new File(imagePath, "QR.png");
|
||||
Uri contentUri = FileProvider.getUriForFile(getActivity(),
|
||||
"com.m2049r.xmrwallet.fileprovider", png);
|
||||
BuildConfig.APPLICATION_ID + ".fileprovider", png);
|
||||
if (contentUri != null) {
|
||||
Intent shareIntent = new Intent();
|
||||
shareIntent.setAction(Intent.ACTION_SEND);
|
||||
@@ -574,6 +574,7 @@ public class ReceiveFragment extends Fragment {
|
||||
@Override
|
||||
public void onPause() {
|
||||
Timber.d("onPause()");
|
||||
Helper.hideKeyboard(getActivity());
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
|
@@ -71,7 +71,6 @@ public class TxFragment extends Fragment {
|
||||
private TextView tvTxFee;
|
||||
private TextView tvTxTransfers;
|
||||
private TextView etTxNotes;
|
||||
private Button bTxNotes;
|
||||
|
||||
// XMRTO stuff
|
||||
private View cvXmrTo;
|
||||
@@ -102,21 +101,9 @@ public class TxFragment extends Fragment {
|
||||
tvTxFee = view.findViewById(R.id.tvTxFee);
|
||||
tvTxTransfers = view.findViewById(R.id.tvTxTransfers);
|
||||
etTxNotes = view.findViewById(R.id.etTxNotes);
|
||||
bTxNotes = view.findViewById(R.id.bTxNotes);
|
||||
|
||||
etTxNotes.setRawInputType(InputType.TYPE_CLASS_TEXT);
|
||||
|
||||
bTxNotes.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
info.notes = null; // force reload on next view
|
||||
bTxNotes.setEnabled(false);
|
||||
etTxNotes.setEnabled(false);
|
||||
userNotes.setNote(etTxNotes.getText().toString());
|
||||
activityCallback.onSetNote(info.hash, userNotes.txNotes);
|
||||
}
|
||||
});
|
||||
|
||||
tvTxXmrToKey.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
@@ -131,14 +118,6 @@ public class TxFragment extends Fragment {
|
||||
return view;
|
||||
}
|
||||
|
||||
public void onNotesSet(boolean reload) {
|
||||
bTxNotes.setEnabled(true);
|
||||
etTxNotes.setEnabled(true);
|
||||
if (reload) {
|
||||
loadNotes(this.info);
|
||||
}
|
||||
}
|
||||
|
||||
void shareTxInfo() {
|
||||
if (this.info == null) return;
|
||||
StringBuffer sb = new StringBuffer();
|
||||
@@ -315,7 +294,6 @@ public class TxFragment extends Fragment {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@@ -337,9 +315,9 @@ public class TxFragment extends Fragment {
|
||||
|
||||
String getTxNotes(String hash);
|
||||
|
||||
String getTxAddress(int major, int minor);
|
||||
boolean setTxNotes(String txId, String txNotes);
|
||||
|
||||
void onSetNote(String txId, String notes);
|
||||
String getTxAddress(int major, int minor);
|
||||
|
||||
void setToolbarButton(int type);
|
||||
|
||||
@@ -357,4 +335,16 @@ public class TxFragment extends Fragment {
|
||||
+ " must implement Listener");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
if (!etTxNotes.getText().toString().equals(userNotes.note)) { // notes have changed
|
||||
// save them
|
||||
userNotes.setNote(etTxNotes.getText().toString());
|
||||
info.notes = userNotes.txNotes;
|
||||
activityCallback.setTxNotes(info.hash, info.notes);
|
||||
}
|
||||
Helper.hideKeyboard(getActivity());
|
||||
super.onPause();
|
||||
}
|
||||
}
|
@@ -150,8 +150,13 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
||||
final WalletFragment walletFragment = (WalletFragment)
|
||||
getSupportFragmentManager().findFragmentByTag(WalletFragment.class.getName());
|
||||
if (walletFragment != null) walletFragment.resetDismissedTransactions();
|
||||
updateAccountsBalance();
|
||||
forceUpdate();
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateAccountsBalance();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -174,6 +179,11 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
||||
return getWallet().getUserNote(txId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setTxNotes(String txId, String txNotes) {
|
||||
return getWallet().setUserNote(txId, txNotes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTxAddress(int major, int minor) {
|
||||
return getWallet().getSubaddress(major, minor);
|
||||
@@ -618,23 +628,22 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWalletStarted(final Wallet.ConnectionStatus connStatus) {
|
||||
public void onWalletStarted(final Wallet.Status walletStatus) {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
dismissProgressDialog();
|
||||
switch (connStatus) {
|
||||
case ConnectionStatus_Disconnected:
|
||||
Toast.makeText(WalletActivity.this, getString(R.string.status_wallet_connect_failed), Toast.LENGTH_LONG).show();
|
||||
break;
|
||||
case ConnectionStatus_WrongVersion:
|
||||
if (walletStatus == null) {
|
||||
// guess what went wrong
|
||||
Toast.makeText(WalletActivity.this, getString(R.string.status_wallet_connect_failed), Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
if (Wallet.ConnectionStatus.ConnectionStatus_WrongVersion == walletStatus.getConnectionStatus())
|
||||
Toast.makeText(WalletActivity.this, getString(R.string.status_wallet_connect_wrongversion), Toast.LENGTH_LONG).show();
|
||||
break;
|
||||
case ConnectionStatus_Connected:
|
||||
break;
|
||||
else if (!walletStatus.isOk())
|
||||
Toast.makeText(WalletActivity.this, walletStatus.getErrorString(), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
if (connStatus != Wallet.ConnectionStatus.ConnectionStatus_Connected) {
|
||||
if ((walletStatus == null) || (Wallet.ConnectionStatus.ConnectionStatus_Connected != walletStatus.getConnectionStatus())) {
|
||||
finish();
|
||||
} else {
|
||||
haveWallet = true;
|
||||
@@ -713,26 +722,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetNotes(final boolean success) {
|
||||
try {
|
||||
final TxFragment txFragment = (TxFragment)
|
||||
getSupportFragmentManager().findFragmentById(R.id.fragment_container);
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
if (!success) {
|
||||
Toast.makeText(WalletActivity.this, getString(R.string.tx_notes_set_failed), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
txFragment.onNotesSet(success);
|
||||
}
|
||||
});
|
||||
} catch (ClassCastException ex) {
|
||||
// not in tx fragment
|
||||
Timber.d(ex.getLocalizedMessage());
|
||||
// never mind
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgress(final String text) {
|
||||
try {
|
||||
@@ -794,21 +783,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetNote(String txId, String notes) {
|
||||
if (mIsBound) { // no point in talking to unbound service
|
||||
Intent intent = new Intent(getApplicationContext(), WalletService.class);
|
||||
intent.putExtra(WalletService.REQUEST, WalletService.REQUEST_CMD_SETNOTE);
|
||||
intent.putExtra(WalletService.REQUEST_CMD_SETNOTE_TX, txId);
|
||||
intent.putExtra(WalletService.REQUEST_CMD_SETNOTE_NOTES, notes);
|
||||
startService(intent);
|
||||
Timber.d("SET NOTE request sent");
|
||||
} else {
|
||||
Timber.e("Service not bound");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareSend(final String tag, final TxData txData) {
|
||||
if (mIsBound) { // no point in talking to unbound service
|
||||
@@ -1062,6 +1036,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
||||
} else {
|
||||
tvBalance.setText(null);
|
||||
}
|
||||
updateAccountsList();
|
||||
}
|
||||
|
||||
void updateAccountsHeader() {
|
||||
@@ -1075,8 +1050,11 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
||||
Menu menu = accountsView.getMenu();
|
||||
menu.removeGroup(R.id.accounts_list);
|
||||
final int n = wallet.getNumAccounts();
|
||||
final boolean showBalances = (n > 1) && !isStreetMode();
|
||||
for (int i = 0; i < n; i++) {
|
||||
final String label = wallet.getAccountLabel(i);
|
||||
final String label = (showBalances ?
|
||||
getString(R.string.label_account, wallet.getAccountLabel(i), Helper.getDisplayAmount(wallet.getBalance(i), 2))
|
||||
: wallet.getAccountLabel(i));
|
||||
final MenuItem item = menu.add(R.id.accounts_list, getAccountId(i), 2 * i, label);
|
||||
item.setIcon(R.drawable.ic_account_balance_wallet_black_24dp);
|
||||
if (i == wallet.getAccountIndex())
|
||||
|
@@ -219,7 +219,7 @@ public class WalletFragment extends Fragment
|
||||
if (isExchanging) return; // wait for exchange to finish - it will fire this itself then.
|
||||
// at this point selection is XMR in case of error
|
||||
String displayB;
|
||||
double amountA = Double.parseDouble(Wallet.getDisplayAmount(unlockedBalance)); // crash if this fails!
|
||||
double amountA = Helper.getDecimalAmount(unlockedBalance).doubleValue();
|
||||
if (!Helper.CRYPTO.equals(balanceCurrency)) { // not XMR
|
||||
double amountB = amountA * balanceRate;
|
||||
displayB = Helper.getFormattedAmount(amountB, false);
|
||||
@@ -235,10 +235,10 @@ public class WalletFragment extends Fragment
|
||||
private final ExchangeApi exchangeApi = Helper.getExchangeApi();
|
||||
|
||||
void refreshBalance() {
|
||||
double unconfirmedXmr = Double.parseDouble(Helper.getDisplayAmount(balance - unlockedBalance));
|
||||
double unconfirmedXmr = Helper.getDecimalAmount(balance - unlockedBalance).doubleValue();
|
||||
showUnconfirmed(unconfirmedXmr);
|
||||
if (sCurrency.getSelectedItemPosition() == 0) { // XMR
|
||||
double amountXmr = Double.parseDouble(Wallet.getDisplayAmount(unlockedBalance)); // assume this cannot fail!
|
||||
double amountXmr = Helper.getDecimalAmount(unlockedBalance).doubleValue();
|
||||
showBalance(Helper.getFormattedAmount(amountXmr, true));
|
||||
} else { // not XMR
|
||||
String currency = (String) sCurrency.getSelectedItem();
|
||||
@@ -294,7 +294,7 @@ public class WalletFragment extends Fragment
|
||||
|
||||
public void exchangeFailed() {
|
||||
sCurrency.setSelection(0, true); // default to XMR
|
||||
double amountXmr = Double.parseDouble(Wallet.getDisplayAmount(unlockedBalance)); // assume this cannot fail!
|
||||
double amountXmr = Helper.getDecimalAmount(unlockedBalance).doubleValue();
|
||||
showBalance(Helper.getFormattedAmount(amountXmr, true));
|
||||
hideExchanging();
|
||||
}
|
||||
|
@@ -46,7 +46,8 @@ import okhttp3.ResponseBody;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class NodeInfo extends Node {
|
||||
final static public int MIN_MAJOR_VERSION = 9;
|
||||
final static public int MIN_MAJOR_VERSION = 11;
|
||||
final static public String RPC_VERSION = "2.0";
|
||||
|
||||
private long height = 0;
|
||||
private long timestamp = 0;
|
||||
@@ -228,9 +229,12 @@ public class NodeInfo extends Node {
|
||||
responseCode = response.code();
|
||||
if (response.isSuccessful()) {
|
||||
ResponseBody respBody = response.body(); // closed through Response object
|
||||
if ((respBody != null) && (respBody.contentLength() < 1000)) { // sanity check
|
||||
if ((respBody != null) && (respBody.contentLength() < 2000)) { // sanity check
|
||||
final JSONObject json = new JSONObject(
|
||||
respBody.string());
|
||||
String rpcVersion = json.getString("jsonrpc");
|
||||
if (!RPC_VERSION.equals(rpcVersion))
|
||||
return false;
|
||||
final JSONObject header = json.getJSONObject(
|
||||
"result").getJSONObject("block_header");
|
||||
height = header.getLong("height");
|
||||
|
@@ -33,7 +33,9 @@ import android.view.ViewGroup;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.m2049r.xmrwallet.R;
|
||||
import com.m2049r.xmrwallet.data.BarcodeData;
|
||||
@@ -92,6 +94,7 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
||||
private View llPaymentId;
|
||||
private TextView tvXmrTo;
|
||||
private View llXmrTo;
|
||||
private ImageButton bPasteAddress;
|
||||
|
||||
private boolean resolvingOA = false;
|
||||
private boolean resolvingPP = false;
|
||||
@@ -197,6 +200,21 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
||||
}
|
||||
});
|
||||
|
||||
bPasteAddress = view.findViewById(R.id.bPasteAddress);
|
||||
bPasteAddress.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
final String clip = Helper.getClipBoardText(getActivity());
|
||||
if (clip == null) return;
|
||||
// clean it up
|
||||
final String address = clip.replaceAll("[^0-9A-Z-a-z]", "");
|
||||
if (Wallet.isAddressValid(address) || BitcoinAddressValidator.validate(address))
|
||||
etAddress.getEditText().setText(address);
|
||||
else
|
||||
Toast.makeText(getActivity(), getString(R.string.send_address_invalid), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
|
||||
etPaymentId = view.findViewById(R.id.etPaymentId);
|
||||
etPaymentId.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||
etPaymentId.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||
|
@@ -30,6 +30,7 @@ import com.m2049r.xmrwallet.model.TransactionInfo;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.data.UserNotes;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
@@ -154,7 +155,7 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
||||
}
|
||||
|
||||
if ((infoItem.fee > 0)) {
|
||||
String fee = Helper.getDisplayAmount(infoItem.fee, 5);
|
||||
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 {
|
||||
|
@@ -34,7 +34,7 @@ import java.io.IOException;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class Ledger {
|
||||
static final public boolean ENABLED = false;
|
||||
static final public boolean ENABLED = true;
|
||||
// 5:20 is same as wallet2.cpp::restore()
|
||||
static public final int LOOKAHEAD_ACCOUNTS = 5;
|
||||
static public final int LOOKAHEAD_SUBADDRESSES = 20;
|
||||
|
@@ -173,5 +173,4 @@ public class TransactionInfo implements Parcelable, Comparable<TransactionInfo>
|
||||
return this.hash.compareTo(another.hash);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -16,6 +16,9 @@
|
||||
|
||||
package com.m2049r.xmrwallet.model;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.m2049r.xmrwallet.data.TxData;
|
||||
|
||||
import java.io.File;
|
||||
@@ -32,6 +35,47 @@ public class Wallet {
|
||||
System.loadLibrary("monerujo");
|
||||
}
|
||||
|
||||
static public class Status {
|
||||
Status(int status, String errorString) {
|
||||
this.status = StatusEnum.values()[status];
|
||||
this.errorString = errorString;
|
||||
}
|
||||
|
||||
final private StatusEnum status;
|
||||
final private String errorString;
|
||||
@Nullable
|
||||
private ConnectionStatus connectionStatus; // optional
|
||||
|
||||
public StatusEnum getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public String getErrorString() {
|
||||
return errorString;
|
||||
}
|
||||
|
||||
public void setConnectionStatus(@Nullable ConnectionStatus connectionStatus) {
|
||||
this.connectionStatus = connectionStatus;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ConnectionStatus getConnectionStatus() {
|
||||
return connectionStatus;
|
||||
}
|
||||
|
||||
public boolean isOk() {
|
||||
return (getStatus() == StatusEnum.Status_Ok)
|
||||
&& ((getConnectionStatus() == null) ||
|
||||
(getConnectionStatus() == ConnectionStatus.ConnectionStatus_Connected));
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public String toString() {
|
||||
return "Wallet.Status: (" + status + "/" + errorString + ", " + connectionStatus;
|
||||
}
|
||||
}
|
||||
|
||||
private int accountIndex = 0;
|
||||
|
||||
public int getAccountIndex() {
|
||||
@@ -66,7 +110,7 @@ public class Wallet {
|
||||
Device_Ledger
|
||||
}
|
||||
|
||||
public enum Status {
|
||||
public enum StatusEnum {
|
||||
Status_Ok,
|
||||
Status_Error,
|
||||
Status_Critical
|
||||
@@ -85,12 +129,16 @@ public class Wallet {
|
||||
public native void setSeedLanguage(String language);
|
||||
|
||||
public Status getStatus() {
|
||||
return Wallet.Status.values()[getStatusJ()];
|
||||
return statusWithErrorString();
|
||||
}
|
||||
|
||||
private native int getStatusJ();
|
||||
public Status getFullStatus() {
|
||||
Wallet.Status walletStatus = statusWithErrorString();
|
||||
walletStatus.setConnectionStatus(getConnectionStatus());
|
||||
return walletStatus;
|
||||
}
|
||||
|
||||
public native String getErrorString();
|
||||
private native Status statusWithErrorString();
|
||||
|
||||
public native boolean setPassword(String password);
|
||||
|
||||
@@ -353,9 +401,10 @@ public class Wallet {
|
||||
if (label.equals(NEW_ACCOUNT_NAME)) {
|
||||
String address = getAddress(accountIndex);
|
||||
int len = address.length();
|
||||
return address.substring(0, 6) +
|
||||
label = address.substring(0, 6) +
|
||||
"\u2026" + address.substring(len - 6, len);
|
||||
} else return label;
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
public String getSubaddressLabel(int addressIndex) {
|
||||
|
@@ -91,14 +91,16 @@ public class WalletManager {
|
||||
managedWallet = null;
|
||||
}
|
||||
|
||||
public Wallet createWallet(File aFile, String password, String language) {
|
||||
public Wallet createWallet(File aFile, String password, String language, long height) {
|
||||
long walletHandle = createWalletJ(aFile.getAbsolutePath(), password, language, getNetworkType().getValue());
|
||||
Wallet wallet = new Wallet(walletHandle);
|
||||
manageWallet(wallet);
|
||||
if (wallet.getStatus() == Wallet.Status.Status_Ok) {
|
||||
if (wallet.getStatus().isOk()) {
|
||||
// (Re-)Estimate restore height based on what we know
|
||||
long oldHeight = wallet.getRestoreHeight();
|
||||
wallet.setRestoreHeight(RestoreHeight.getInstance().getHeight(new Date()));
|
||||
final long oldHeight = wallet.getRestoreHeight();
|
||||
final long restoreHeight =
|
||||
(height > -1) ? height : RestoreHeight.getInstance().getHeight(new Date());
|
||||
wallet.setRestoreHeight(restoreHeight);
|
||||
Timber.d("Changed Restore Height from %d to %d", oldHeight, wallet.getRestoreHeight());
|
||||
wallet.setPassword(password); // this rewrites the keys file (which contains the restore height)
|
||||
}
|
||||
|
@@ -31,6 +31,7 @@ import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Process;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
|
||||
@@ -69,10 +70,6 @@ public class WalletService extends Service {
|
||||
public static final String REQUEST_CMD_SEND = "send";
|
||||
public static final String REQUEST_CMD_SEND_NOTES = "notes";
|
||||
|
||||
public static final String REQUEST_CMD_SETNOTE = "setnote";
|
||||
public static final String REQUEST_CMD_SETNOTE_TX = "tx";
|
||||
public static final String REQUEST_CMD_SETNOTE_NOTES = "notes";
|
||||
|
||||
public static final int START_SERVICE = 1;
|
||||
public static final int STOP_SERVICE = 2;
|
||||
|
||||
@@ -224,9 +221,7 @@ public class WalletService extends Service {
|
||||
|
||||
void onSendTransactionFailed(String error);
|
||||
|
||||
void onSetNotes(boolean success);
|
||||
|
||||
void onWalletStarted(Wallet.ConnectionStatus walletStatus);
|
||||
void onWalletStarted(Wallet.Status walletStatus);
|
||||
|
||||
void onWalletOpen(Wallet.Device device);
|
||||
}
|
||||
@@ -293,9 +288,9 @@ public class WalletService extends Service {
|
||||
if (walletId != null) {
|
||||
showProgress(getString(R.string.status_wallet_loading));
|
||||
showProgress(10);
|
||||
Wallet.ConnectionStatus connStatus = start(walletId, walletPw);
|
||||
if (observer != null) observer.onWalletStarted(connStatus);
|
||||
if (connStatus != Wallet.ConnectionStatus.ConnectionStatus_Connected) {
|
||||
Wallet.Status walletStatus = start(walletId, walletPw);
|
||||
if (observer != null) observer.onWalletStarted(walletStatus);
|
||||
if (!walletStatus.isOk()) {
|
||||
errorState = true;
|
||||
stop();
|
||||
}
|
||||
@@ -306,7 +301,7 @@ public class WalletService extends Service {
|
||||
boolean rc = myWallet.store();
|
||||
Timber.d("wallet stored: %s with rc=%b", myWallet.getName(), rc);
|
||||
if (!rc) {
|
||||
Timber.w("Wallet store failed: %s", myWallet.getErrorString());
|
||||
Timber.w("Wallet store failed: %s", myWallet.getStatus().getErrorString());
|
||||
}
|
||||
if (observer != null) observer.onWalletStored(rc);
|
||||
} else if (cmd.equals(REQUEST_CMD_TX)) {
|
||||
@@ -368,7 +363,7 @@ public class WalletService extends Service {
|
||||
boolean rc = myWallet.store();
|
||||
Timber.d("wallet stored: %s with rc=%b", myWallet.getName(), rc);
|
||||
if (!rc) {
|
||||
Timber.w("Wallet store failed: %s", myWallet.getErrorString());
|
||||
Timber.w("Wallet store failed: %s", myWallet.getStatus().getErrorString());
|
||||
}
|
||||
if (observer != null) observer.onWalletStored(rc);
|
||||
listener.updated = true;
|
||||
@@ -378,26 +373,6 @@ public class WalletService extends Service {
|
||||
if (observer != null) observer.onSendTransactionFailed(error);
|
||||
return;
|
||||
}
|
||||
} else if (cmd.equals(REQUEST_CMD_SETNOTE)) {
|
||||
Wallet myWallet = getWallet();
|
||||
Timber.d("SET NOTE for wallet: %s", myWallet.getName());
|
||||
String txId = extras.getString(REQUEST_CMD_SETNOTE_TX);
|
||||
String notes = extras.getString(REQUEST_CMD_SETNOTE_NOTES);
|
||||
if ((txId != null) && (notes != null)) {
|
||||
boolean success = myWallet.setUserNote(txId, notes);
|
||||
if (!success) {
|
||||
Timber.e(myWallet.getErrorString());
|
||||
}
|
||||
if (observer != null) observer.onSetNotes(success);
|
||||
if (success) {
|
||||
boolean rc = myWallet.store();
|
||||
Timber.d("wallet stored: %s with rc=%b", myWallet.getName(), rc);
|
||||
if (!rc) {
|
||||
Timber.w("Wallet store failed: %s", myWallet.getErrorString());
|
||||
}
|
||||
if (observer != null) observer.onWalletStored(rc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -490,7 +465,8 @@ public class WalletService extends Service {
|
||||
return true; // true is important so that onUnbind is also called next time
|
||||
}
|
||||
|
||||
private Wallet.ConnectionStatus start(String walletName, String walletPassword) {
|
||||
@Nullable
|
||||
private Wallet.Status start(String walletName, String walletPassword) {
|
||||
Timber.d("start()");
|
||||
startNotfication();
|
||||
showProgress(getString(R.string.status_wallet_loading));
|
||||
@@ -498,11 +474,11 @@ public class WalletService extends Service {
|
||||
if (listener == null) {
|
||||
Timber.d("start() loadWallet");
|
||||
Wallet aWallet = loadWallet(walletName, walletPassword);
|
||||
Wallet.ConnectionStatus connStatus = Wallet.ConnectionStatus.ConnectionStatus_Disconnected;
|
||||
if (aWallet != null) connStatus = aWallet.getConnectionStatus();
|
||||
if (connStatus != Wallet.ConnectionStatus.ConnectionStatus_Connected) {
|
||||
if (aWallet != null) aWallet.close();
|
||||
return connStatus;
|
||||
if (aWallet == null) return null;
|
||||
Wallet.Status walletStatus = aWallet.getFullStatus();
|
||||
if (!walletStatus.isOk()) {
|
||||
aWallet.close();
|
||||
return walletStatus;
|
||||
}
|
||||
listener = new MyWalletListener();
|
||||
listener.start();
|
||||
@@ -513,7 +489,7 @@ public class WalletService extends Service {
|
||||
// if we try to refresh the history here we get occasional segfaults!
|
||||
// doesnt matter since we update as soon as we get a new block anyway
|
||||
Timber.d("start() done");
|
||||
return Wallet.ConnectionStatus.ConnectionStatus_Connected;
|
||||
return getWallet().getFullStatus();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
@@ -558,10 +534,9 @@ public class WalletService extends Service {
|
||||
wallet = walletMgr.openWallet(path, walletPassword);
|
||||
showProgress(60);
|
||||
Timber.d("wallet opened");
|
||||
Wallet.Status status = wallet.getStatus();
|
||||
Timber.d("wallet status is %s", status);
|
||||
if (status != Wallet.Status.Status_Ok) {
|
||||
Timber.d("wallet status is %s", status);
|
||||
Wallet.Status walletStatus = wallet.getStatus();
|
||||
if (!walletStatus.isOk()) {
|
||||
Timber.d("wallet status is %s", walletStatus);
|
||||
WalletManager.getInstance().close(wallet); // TODO close() failed?
|
||||
wallet = null;
|
||||
// TODO what do we do with the progress??
|
||||
|
@@ -21,6 +21,7 @@ import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipDescription;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
@@ -64,6 +65,7 @@ import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.SocketTimeoutException;
|
||||
@@ -186,28 +188,23 @@ public class Helper {
|
||||
act.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
|
||||
}
|
||||
|
||||
static public BigDecimal getDecimalAmount(long amount) {
|
||||
return new BigDecimal(amount).scaleByPowerOfTen(-12);
|
||||
}
|
||||
|
||||
static public String getDisplayAmount(long amount) {
|
||||
return getDisplayAmount(amount, 12);
|
||||
}
|
||||
|
||||
static public String getDisplayAmount(long amount, int maxDecimals) {
|
||||
return getDisplayAmount(Wallet.getDisplayAmount(amount), maxDecimals);
|
||||
}
|
||||
|
||||
// amountString must have '.' as decimal point
|
||||
private static String getDisplayAmount(String amountString, int maxDecimals) {
|
||||
int lastZero = 0;
|
||||
int decimal = 0;
|
||||
for (int i = amountString.length() - 1; i >= 0; i--) {
|
||||
if ((lastZero == 0) && (amountString.charAt(i) != '0')) lastZero = i + 1;
|
||||
// TODO i18n
|
||||
if (amountString.charAt(i) == '.') {
|
||||
decimal = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int cutoff = Math.min(Math.max(lastZero, decimal + 2), decimal + maxDecimals);
|
||||
return amountString.substring(0, cutoff);
|
||||
// a Java bug does not strip zeros properly if the value is 0
|
||||
if (amount == 0) return "0.00";
|
||||
BigDecimal d = getDecimalAmount(amount)
|
||||
.setScale(maxDecimals, BigDecimal.ROUND_HALF_UP)
|
||||
.stripTrailingZeros();
|
||||
if (d.scale() < 2)
|
||||
d = d.setScale(2, BigDecimal.ROUND_UNNECESSARY);
|
||||
return d.toPlainString();
|
||||
}
|
||||
|
||||
static public String getFormattedAmount(double amount, boolean isXmr) {
|
||||
@@ -285,6 +282,21 @@ public class Helper {
|
||||
clipboardManager.setPrimaryClip(clip);
|
||||
}
|
||||
|
||||
static public String getClipBoardText(Context context) {
|
||||
final ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
try {
|
||||
if (clipboardManager.hasPrimaryClip()
|
||||
&& clipboardManager.getPrimaryClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) {
|
||||
final ClipData.Item item = clipboardManager.getPrimaryClip().getItemAt(0);
|
||||
return item.getText().toString();
|
||||
}
|
||||
} catch (NullPointerException ex) {
|
||||
// if we have don't find a text in the clipboard
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static private Animation ShakeAnimation;
|
||||
|
||||
static public Animation getShakeAnimation(Context context) {
|
||||
@@ -556,6 +568,8 @@ public class Helper {
|
||||
tvOpenPrompt.setText(context.getText(R.string.prompt_fingerprint_auth));
|
||||
tvOpenPrompt.setVisibility(View.VISIBLE);
|
||||
FingerprintHelper.authenticate(context, cancelSignal, fingerprintAuthCallback);
|
||||
} else {
|
||||
etPassword.requestFocus();
|
||||
}
|
||||
Button button = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_POSITIVE);
|
||||
button.setOnClickListener(new View.OnClickListener() {
|
||||
|
@@ -101,6 +101,8 @@ public class RestoreHeight {
|
||||
blockheight.put("2019-01-01", 1738923L);
|
||||
blockheight.put("2019-02-01", 1761435L);
|
||||
blockheight.put("2019-03-01", 1781681L);
|
||||
blockheight.put("2019-04-01", 1803081L);
|
||||
blockheight.put("2019-05-01", 1824671L);
|
||||
}
|
||||
|
||||
public long getHeight(String date) {
|
||||
|
@@ -28,6 +28,7 @@ import java.security.spec.ECPoint;
|
||||
|
||||
public class ECsecp256k1 {
|
||||
static private final BigInteger TWO = new BigInteger("2");
|
||||
static private final BigInteger THREE = new BigInteger("3");
|
||||
static public final BigInteger p = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16);
|
||||
static public final BigInteger a = new BigInteger("0000000000000000000000000000000000000000000000000000000000000000", 16);
|
||||
static public final BigInteger b = new BigInteger("0000000000000000000000000000000000000000000000000000000000000007", 16);
|
||||
@@ -61,19 +62,18 @@ public class ECsecp256k1 {
|
||||
return s;
|
||||
else if (s.equals(ECPoint.POINT_INFINITY))
|
||||
return r;
|
||||
BigInteger slope = (r.getAffineY().subtract(s.getAffineY())).multiply(r.getAffineX().subtract(s.getAffineX()).modInverse(p)).mod(p);
|
||||
BigInteger slope = (r.getAffineY().subtract(s.getAffineY()))
|
||||
.multiply(r.getAffineX().subtract(s.getAffineX()).modInverse(p));
|
||||
BigInteger Xout = (slope.modPow(TWO, p).subtract(r.getAffineX())).subtract(s.getAffineX()).mod(p);
|
||||
BigInteger Yout = s.getAffineY().negate().mod(p);
|
||||
Yout = Yout.add(slope.multiply(s.getAffineX().subtract(Xout))).mod(p);
|
||||
BigInteger Yout = s.getAffineY().negate().add(slope.multiply(s.getAffineX().subtract(Xout))).mod(p);
|
||||
return new ECPoint(Xout, Yout);
|
||||
}
|
||||
|
||||
public static ECPoint doublePoint(ECPoint r) {
|
||||
if (r.equals(ECPoint.POINT_INFINITY))
|
||||
return r;
|
||||
BigInteger slope = (r.getAffineX().pow(2)).multiply(new BigInteger("3"));
|
||||
slope = slope.add(a);
|
||||
slope = slope.multiply((r.getAffineY().multiply(TWO)).modInverse(p));
|
||||
BigInteger slope = (r.getAffineX().pow(2)).multiply(THREE).add(a)
|
||||
.multiply((r.getAffineY().multiply(TWO)).modInverse(p));
|
||||
BigInteger Xout = slope.pow(2).subtract(r.getAffineX().multiply(TWO)).mod(p);
|
||||
BigInteger Yout = (r.getAffineY().negate()).add(slope.multiply(r.getAffineX().subtract(Xout))).mod(p);
|
||||
return new ECPoint(Xout, Yout);
|
||||
|
@@ -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="@color/gradientOrange"
|
||||
android:pathData="M19,2h-4.18C14.4,0.84 13.3,0 12,0c-1.3,0 -2.4,0.84 -2.82,2L5,2c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,4c0,-1.1 -0.9,-2 -2,-2zM12,2c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM19,20L5,20L5,4h2v3h10L17,4h2v16z" />
|
||||
</vector>
|
@@ -37,8 +37,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_toStartOf="@+id/ibOption"
|
||||
android:layout_toEndOf="@id/ibBookmark">
|
||||
android:layout_toStartOf="@+id/ibOption">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/pbNode"
|
||||
|
@@ -20,21 +20,46 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp" />
|
||||
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:id="@+id/etAddress"
|
||||
<RelativeLayout
|
||||
android:id="@+id/llAddress"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:errorEnabled="true">
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<android.support.design.widget.TextInputEditText
|
||||
style="@style/MoneroEdit"
|
||||
android:layout_width="match_parent"
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:id="@+id/etAddress"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/send_address_hint"
|
||||
android:imeOptions="actionNext"
|
||||
android:inputType="textMultiLine"
|
||||
android:textAlignment="textStart" />
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_toStartOf="@+id/bPasteAddress"
|
||||
app:counterEnabled="true"
|
||||
app:counterMaxLength="16"
|
||||
app:errorEnabled="true">
|
||||
|
||||
<android.support.design.widget.TextInputEditText
|
||||
style="@style/MoneroEdit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="10"
|
||||
android:hint="@string/send_address_hint"
|
||||
android:imeOptions="actionNext"
|
||||
android:inputType="textMultiLine"
|
||||
android:textAlignment="textStart" />
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/bPasteAddress"
|
||||
style="@style/MoneroText.Button.Small"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="56dp"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="8dp"
|
||||
android:background="?android:selectableItemBackgroundBorderless"
|
||||
android:src="@drawable/ic_content_paste_orange_24dp" />
|
||||
</RelativeLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
|
@@ -225,34 +225,14 @@
|
||||
android:padding="8sp"
|
||||
android:text="@string/tx_notes" />
|
||||
|
||||
<RelativeLayout
|
||||
<EditText
|
||||
android:id="@+id/etTxNotes"
|
||||
style="@style/MoneroEdit"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etTxNotes"
|
||||
style="@style/MoneroEdit"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_toStartOf="@+id/bTxNotes"
|
||||
android:backgroundTint="@color/moneroGray"
|
||||
android:hint="@string/tx_notes_hint"
|
||||
android:inputType="textMultiLine" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/bTxNotes"
|
||||
style="@style/MoneroButton.Small"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerInParent="true"
|
||||
android:enabled="true"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="@string/tx_button_notes" />
|
||||
</RelativeLayout>
|
||||
|
||||
android:layout_height="wrap_content"
|
||||
android:backgroundTint="@color/moneroGray"
|
||||
android:hint="@string/tx_notes_hint"
|
||||
android:inputType="textMultiLine" />
|
||||
</TableRow>
|
||||
|
||||
<TableRow>
|
||||
|
54
app/src/main/res/values-cat/about.xml
Normal file
54
app/src/main/res/values-cat/about.xml
Normal file
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="about_close">Tancar</string>
|
||||
<string name="about_whoami">Sóc en monerujo</string>
|
||||
<string name="about_version">Versió %1$s (%2$d)</string>
|
||||
|
||||
<string name="credits_text"><![CDATA[
|
||||
<b>Credits</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>Política de Privacitat</h1>
|
||||
<p>Aquesta pàgina us informa de les nostres polítiques relatives a la recopilació,
|
||||
ús i divulgació de la informació personal que rebem dels usuaris de la nostra
|
||||
aplicació (monerujo: Monero Wallet).
|
||||
</p>
|
||||
<p>Mitjançant l'ús d'aquesta aplicació vostè accepta la recopilació i l’ús de la informació d’acord amb aquesta política.
|
||||
</p>
|
||||
<h2>Dades Recopilades</h2>
|
||||
<p>Les dades personals són qualsevol tipus de dades que puguin identificar un individu.
|
||||
</p>
|
||||
<p>Les claus i les adreces públiques de Monero són recollides i processades per l’aplicació de forma local per tal de processar les transaccions i transmetre-les a la xarxa Monero de forma encriptada.
|
||||
</p>
|
||||
<p>L'aplicació no recopila altres dades personals.</p>
|
||||
<p>Si utilitzeu la funcionalitat d'intercanvi (opcional), monerujo obté el canvi
|
||||
a través de l’API pública de coinmarketcap.com.
|
||||
Consulteu la seva política de privacitat a https://coinmarketcap.com/privacy per a més detalls sobre com es recullen les dades de les vostres peticions</p>
|
||||
<p>Si utilitzeu l’aplicació per pagar a adreces BTC, utilitzareu el servei XMR.TO.
|
||||
Consulteu la seva política de privacitat a https://xmr.to/ per obtenir més informació. Monerujo els envia l'adreça de destinació de BTC i la quantitat. La vostra IP també podrà ser recollida.</p>
|
||||
<h2>Permisos de la App</h2>
|
||||
<ul>
|
||||
<li>INTERNET : Connectar a la xarxa Monero mitjançant un Node Daemon de Monero</li>
|
||||
<li>READ_EXTERNAL_STORAGE : Llegir els arxius del portamonedes emmagatzemats al dispositiu</li>
|
||||
<li>WRITE_EXTERNAL_STORAGE : Escriure els arxius del portamonedes emmagatzemats al dispositiu</li>
|
||||
<li>WAKE_LOCK : Mantenir el dispositiu despert durant la sincronització</li>
|
||||
<li>CAMERA : Escanejar codis QR per rebre Monero</li>
|
||||
</ul>
|
||||
<h2>Canvis en aquesta Política de Privacitat</h2>
|
||||
<p>És possible que actualitzem aquesta política de privacitat de tant en tant. Li notificarem de qualsevol canvi publicant la nova política de privacitat a l’aplicació i al lloc web (www.monerujo.io)
|
||||
Us recomanem que reviseu aquesta política de privacitat periòdicament per conèixer els canvis.
|
||||
<p>Aquesta Política de Privacitat es va actualitzar per darrer cop: 10th November, 2017.
|
||||
</p>
|
||||
<h2>Contacti amb nosaltres</h2>
|
||||
<p>Si teniu alguna consulta sobre la nostra política de privadesa,
|
||||
o com es recullen i processen les vostres dades,
|
||||
si us plau envieu un correu electrònic a privacy@monerujo.io.
|
||||
</p>
|
||||
]]></string>
|
||||
</resources>
|
244
app/src/main/res/values-cat/help.xml
Normal file
244
app/src/main/res/values-cat/help.xml
Normal file
@@ -0,0 +1,244 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="help_create_new"><![CDATA[
|
||||
<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 s’utilitza 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>
|
||||
<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 d'alguna 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>
|
||||
|
||||
<string name="help_create_seed"><![CDATA[
|
||||
<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 s’utilitza 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> d'haver fer servir aquesta adreça del portamonedes.</p>
|
||||
]]></string>
|
||||
|
||||
<string name="help_create_ledger"><![CDATA[
|
||||
<h1>Crear Portamonedes - Ledger</h1>
|
||||
<p>Si voleu recuperar el vostre portamonedes desde un dispositiu Ledger Nano S!</p>
|
||||
<p>Les vostres claus secretes no surten mai del dispositiu Ledger, de manera que necessiteu que estigui connectat sempre que vulgueu accedir aal vostre portamonedes.</p>
|
||||
<p>Introduïu un nom i contrasenya únics del portamonedes. La contrasenya s’utilitza per protegir les dades de la seva cartera al dispositiu Android. Utilitzeu una contrasenya sòlida - encara millor si utiliza una frase.</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> d'haver fer servir aquesta adreça del portamonedes.</p>
|
||||
]]></string>
|
||||
|
||||
<string name="help_create_keys"><![CDATA[
|
||||
<h1>Crear Portamonedes - Claus</h1>
|
||||
<p>Si voleu recuperar el vostre portamonedes fent servir les vostres claus!</p>
|
||||
<p>Introduïu un nom i contrasenya únics del portamonedes. La contrasenya s’utilitza 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> d'haver fer servir aquesta adreça del portamonedes.</p>
|
||||
]]></string>
|
||||
|
||||
<string name="help_create_view"><![CDATA[
|
||||
<h1>Crear Portamonedes - Només de Lectura</h1>
|
||||
<p>Si només voleu monitoritzar les transaccions entrants del portamonedes!</p>
|
||||
<p>Introduïu un nom i contrasenya únics del portamonedes. La contrasenya s’utilitza 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ó\".</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> d'haver fer servir aquesta adreça del portamonedes.</p>
|
||||
]]></string>
|
||||
|
||||
<string name="help_details"><![CDATA[
|
||||
<h1>Detalls del portamonedes</h1>
|
||||
<h2>Adreça pública</h2>
|
||||
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!
|
||||
<h2>Contrasenya de Recuperació d'Arxius del Portamonedes</h2>
|
||||
Assegureu-vos que heu escrit aquesta contrasenya. Si restabliu el dispositiu o desinstal·leu l’aplicació, 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/>
|
||||
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 s'utilitza la CrAzYsenya. Per solucionar-ho, seleccioneu \"Canviar Contrasenya\" des del menú. Després d'entrar una nova contrasenya (potser fins i tot la mateixa que abans) l’aplicació 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!
|
||||
<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>
|
||||
La vostra clau de despesa permet a qualsevol persona gastar els Monero associats al seu portamonedes, així que no ho compartiu amb ningú, mantingueu-la segura com la vostra Llavor Mnemotècnica.
|
||||
]]></string>
|
||||
|
||||
<string name="help_list"><![CDATA[
|
||||
<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>
|
||||
<p>Monerujo té alguns Nodes remots incorporats. Se'n 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 l’emmagatzematge intern del dispositiu. Podeu utilitzar una aplicació d’exploració d'arxius per veure'ls. Haurieu de fer còpies de seguretat d’aquesta 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>
|
||||
<h3>Detalls</h3>
|
||||
<p>Mostra els detalls del portamonedes, la llavor i les seves claus.</p>
|
||||
<h3>Rebre</h3>
|
||||
<p>Crea un codi QR per rebre Moneroj.</p>
|
||||
<h3>Canvi de Nom</h3>
|
||||
<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>
|
||||
<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 d’eliminar amb un explorador d'arxius o una aplicació segura.</p>
|
||||
]]></string>
|
||||
|
||||
<string name="help_tx_details"><![CDATA[
|
||||
<h1>Detalls de Transacció</h1>
|
||||
<h2>Destí</h2>
|
||||
Aquesta és l'adreça pública del portamonedes on esteu enviant els Monero.
|
||||
<h2>ID de Pagament</h2>
|
||||
Podeu utilitzar un ID de pagament per identificar el motiu pel qual heu enviat a Monero entre dues parts. Això és totalment opcional i privat. Per exemple, això pot permetre a una empresa associar la transacció amb un article que heu comprat.
|
||||
<h2>ID de Transacció</h2>
|
||||
Aquest és el vostre ID de transacció que podeu utilitzar per identificar la vostra transacció oculta en un Explorador de Blockchain de Monero com <a href="https:// xmrchain.net/"> https://xmrchain.net/ </a>
|
||||
<h2>Clau de Transacció</h2>
|
||||
Aquesta és la vostra clau privada de transacció, manteniu-la segureta ja que mostrar-la a tercers els revelia quina signatura dins un anell és la vostra, fent que la vostra transacció sigui transparent.
|
||||
<h2>Bloc</h2>
|
||||
Aquest és el bloc de la cadena de Monero on la vostra transacció ha estat inclosa.
|
||||
]]></string>
|
||||
|
||||
<string name="help_send"><![CDATA[
|
||||
<h1>Enviar</h1>
|
||||
<h2>Adreça del Receptor</h2>
|
||||
<p>Aquesta és l'adreça pública del portamonedes a la qual esteu enviant Moneroj. Podeu copiar-la al porta-retalls, escanejar un codi QR o introduir-la manualment. Assegureu- vos de confirmar-ho a consciencia i que no estigueu enviant monedes a la direcció incorrecta.</p>
|
||||
<p>A més d’utilitzar una adreça XMR, també podeu utilitzar
|
||||
<ul>
|
||||
<li>un OpenAlias per XMR o BTC</li>
|
||||
<li>una adreça BTC</li>
|
||||
<li>un bitcoin: URI (inclòs BIP70 com bitpay)</li>
|
||||
</u>
|
||||
Tingueu en compte que l’enviament de BTC es duu a terme a través del servei XMR.TO (consulteu https://xmr.to per a més detalls). Consulteu la secció sobre l’enviament de BTC més avall.</p>
|
||||
<h2>ID de Pagament</h2>
|
||||
<p>Podeu utilitzar un ID de pagament per identificar el motiu pel qual heu enviat a Monero entre dues parts. Això és totalment opcional i privat. Per exemple, això pot permetre a una empresa associar la transacció amb un article que heu comprat.<p>
|
||||
<h1>Enviant BTC</h1>
|
||||
<h2>XMR.TO</h2>
|
||||
<p>XMR.TO és un servei de tercers que fa proporciona el canvi de Monero a Bitcoin.
|
||||
Nosaltres fem servir l'API XMR.TO per integrar els pagaments de Bitcoin a Monerujo. Si us plau, doneu un cop d'ull a https://xmr.to i decidiu vosaltres mateixos si és una cosa que volgueu utilitzar. L'equip de Monerujo no està associat amb XMR.TO i no pot oferir assistència amb el seu servei.</p>
|
||||
<h2>Tipus de Canvi XMR.TO<h2>
|
||||
<p>A la pantalla \"Quantitat\" es mostraran els paràmetres actuals del servei XMR.TO. 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. També veureu
|
||||
la quantitat fins a la qual la transacció BTC s’executarà instantàniament sense esperar
|
||||
a confirmacions de XMR (consulteu les preguntes freqüents sobre XMR.TO per obtenir més informació). Tingueu en compte que el servei XMR.TO no suposa càrrecs addicionals: oi que mola?</p>
|
||||
<h2>Ordre de compra XMR.TO<h2>
|
||||
<p>A la pantalla \"Confirmar\", veureu l’ordre de compra XMR.TO 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>
|
||||
<h2>Clau Secreta XMR.TO<h2>
|
||||
<p>Com que Monerujo només gestiona la part Monero de la vostra transacció, la vostra clau secreta per XMR.TO es pot utilitzar per fer el seguiment de la part de Bitcoin de la vostra comanda a la pàgina principal de XMR.TO.</p>
|
||||
<p>Tingueu en compte que aquesta clau secreta només és vàlida durant 24 hores després que la transacció
|
||||
ha començat!</p>
|
||||
<h2>Compte enrere XMR.TO!</h2>
|
||||
<p>Una vegada el compte enrere arribi a zero haureu d’obtenir una nova sol·licitud de XMR.TO tornant enrere al pas anterior i després tornar a la pantalla de \"Confirmar\".</p>
|
||||
]]></string>
|
||||
|
||||
<string name="help_xmrto"><![CDATA[
|
||||
<h1>Enviant BTC</h1>
|
||||
<h2>XMR.TO</h2>
|
||||
<p>XMR.TO és un servei de tercers que fa proporciona el canvi de Monero a Bitcoin.
|
||||
Nosaltres fem servir l'API XMR.TO per integrar els pagaments de Bitcoin a Monerujo. Si us plau, doneu un cop d'ull a https://xmr.to i decidiu vosaltres mateixos si és una cosa que volgueu utilitzar. L'equip de Monerujo no està associat amb XMR.TO i no pot oferir assistència amb el seu servei.</p>
|
||||
<h2>Tipus de Canvi XMR.TO<h2>
|
||||
<p>A la pantalla \"Quantitat\" es mostraran els paràmetres actuals del servei XMR.TO. 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. També veureu
|
||||
la quantitat fins a la qual la transacció BTC s’executarà instantàniament sense esperar
|
||||
a confirmacions de XMR (consulteu les preguntes freqüents sobre XMR.TO per obtenir més informació). Tingueu en compte que el servei XMR.TO no suposa càrrecs addicionals: oi que mola?</p>
|
||||
<h2>Ordre de compra XMR.TO<h2>
|
||||
<p>A la pantalla \"Confirmar\", veureu l’ordre de compra XMR.TO 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>
|
||||
<h2>Clau Secreta XMR.TO<h2>
|
||||
<p>Com que Monerujo només gestiona la part Monero de la vostra transacció, la vostra clau secreta per XMR.TO es pot utilitzar per fer el seguiment de la part de Bitcoin de la vostra comanda a la pàgina principal de XMR.TO.</p>
|
||||
<p>Tingueu en compte que aquesta clau secreta només és vàlida durant 24 hores després que la transacció
|
||||
ha començat!</p>
|
||||
<h2>Compte enrere XMR.TO!</h2>
|
||||
<p>Una vegada el compte enrere arribi a zero haureu d’obtenir una nova sol·licitud de XMR.TO tornant enrere al pas anterior i després tornar a la pantalla de \"Confirmar\".</p>
|
||||
]]></string>
|
||||
|
||||
<string name="help_wallet"><![CDATA[
|
||||
<h1>El Portamonedes</h1>
|
||||
<h2>Mode de carrer</h2>
|
||||
<p>El mode de carrer es pot habilitar / desactivar des del menú o a la icona principal de Gunther. En aquest mode, el vostre balanç no es mostra a cap pantalla perquè pugueu utilitzar la vostra cartera amb seguretat al carrer, al pub o qualsevol lloc públic. Les transaccions anteriors també estan ocultes. Es mostraran les noves transaccions perquè pogueu veure que heu enviat / rebut els vostres estimats Moneroj!</p>
|
||||
<h2>Escanejant</h2>
|
||||
Perquè a Monero li agrada mantenir les coses privades, cada cop que obri un portamonedes Monerujo hem d'escanejar la blockchain per veure si s'han enviat nous moneroj al seu portamonedes. Això només emmagatzema l'informació al telèfon que pertany al seu portamonedes. De vegades pot trigar una estona perquè no s’ha sincronitzat en molt de temps.
|
||||
<h2>El Balanç</h2>
|
||||
<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
|
||||
<h2>Llista de Transacció</h2>
|
||||
<p>Llistat de les transaccions del portamonedes. Els portamonedes de visualització només mostraran les transaccions entrants.</p>
|
||||
]]></string>
|
||||
|
||||
<string name="help_node"><![CDATA[
|
||||
<h1>Nodes</h1>
|
||||
<h2>TL;DR</h2>
|
||||
<p>Actualitzeu la llista de nodes prement cap avall; marqueu 3–5 nodes per permetre a Monerujo
|
||||
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>
|
||||
<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 …</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>
|
||||
<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>
|
||||
<p>Monerujo escollirà el node òptim (marcat) cada vegada que l'utilitzeu.
|
||||
Això ho fa mitjançant la comprovació de l'alçada de bloc (com d'actualitzat
|
||||
està el node?), així com el temps de resposta (què tan ràpidament respon el node a les peticions?).</p>
|
||||
<p>La llista s’ordena 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>
|
||||
<h2>Afegir Node</h2>
|
||||
<p>Si premeu el botó "Afegir Node" a la part inferior, se us demanarà
|
||||
que introduïu els detalls del node al següent diàleg.
|
||||
El "Adreça" és el nom del servidor o adreça IP del node - aquesta és la única
|
||||
entrada obligatòria.
|
||||
Introduïu el "Port" si el node s'executa 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 d’usuari i
|
||||
contrasenya proporcionats als camps corresponents. Ara podeu "Test" aquesta configuració.
|
||||
Els "Resultats de les Proves" mostraran l'alçada de bloc, el temps de resposta i l'IP real.
|
||||
El resultat també pot ser un error - generalment perquè el nom del servidor proporcionat no és
|
||||
accessible dins d'un 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 "D'acord" 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.
|
||||
L’escaneig s’atura quan troba un total de 10 nodes remots.</p>
|
||||
]]></string>
|
||||
|
||||
<string name="help_uri"><![CDATA[
|
||||
<h1>Fer servir un enllaç de pagament</h1>
|
||||
<p>Heu iniciat monerujo amb un enllaç de pagament. Per enviar fons, feu el següent:</p>
|
||||
<p>
|
||||
1. Obrir el portamonedes desde la qual voleu gastar els fons<br>
|
||||
2. Espereu fins que es sincronitzi el portamonedes i el botó de "Donar" apareixi<br>
|
||||
3. Premeu el botó de "Donar"
|
||||
</p>
|
||||
<p>Els detalls de pagament es completaran. Comproveu-les i continueu com a qualsevol altra transacció.</p>
|
||||
]]></string>
|
||||
|
||||
<string name="help_ok">Ja ho tinc!</string> <!-- Note: "Got it" as in "I understand this" -->
|
||||
</resources>
|
382
app/src/main/res/values-cat/strings.xml
Normal file
382
app/src/main/res/values-cat/strings.xml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -17,7 +17,7 @@
|
||||
<h1>Datenschutzerklärung</h1>
|
||||
<p>Diese Seite informiert dich über unsere Richtlinien bezüglich der Sammlung,
|
||||
Nutzung und Weitergabe persönlicher Informationen, die wir von Nutzern unserer
|
||||
App erhalten (monerujo: Monero Wallet).
|
||||
App erhalten (monerujo: Monero-Wallet).
|
||||
</p>
|
||||
<p>Mit der Nutzung der App stimmst du der Erfassung und Nutzung von Informationen in
|
||||
Übereinstimmung mit dieser Erklärung zu.
|
||||
@@ -29,21 +29,21 @@
|
||||
von Transaktionen lokal gesammelt und verarbeitet und verschlüsselt in das Monero-Netzwerk übertragen.
|
||||
</p>
|
||||
<p>Andere persönliche Daten werden von der App nicht gesammelt.</p>
|
||||
<p>Wenn du den Umrechner (optional) nutzt fragt Monerujo
|
||||
<p>Wenn du den Umrechner (optional) nutzt, fragt Monerujo
|
||||
den aktuellen Kurs über die öffentliche Schnittstelle von coinmarketcap.com ab.
|
||||
Siehe dir ihre Datenschutzerklärung unter https://coinmarketcap.com/privacy für
|
||||
Details darüber an, wie Daten in deinen Anfragen gesammelt werden.</p>
|
||||
<p>Wenn du die App zum Bezahlen an BTC-Adressen verwendest, verwendest du den Dienst XMR.TO.
|
||||
Weitere Informationen findest du in den Datenschutzerklärung unter https://xmr.to/.
|
||||
Monerujo schickt dem Anbieter die BTC Zieladresse und den Betrag.
|
||||
Weitere Informationen findest du in der Datenschutzerklärung unter https://xmr.to/.
|
||||
Monerujo schickt dem Anbieter die BTC-Zieladresse und den Betrag.
|
||||
Deine IP-Adresse kann dabei aufgezeichnet werden.</p>
|
||||
<h2>App-Berechtigungen</h2>
|
||||
<ul>
|
||||
<li>INTERNET : Verbinde zum Monero Netzwerk über eine Monero Daemon Node</li>
|
||||
<li>READ_EXTERNAL_STORAGE : Liest die auf dem Gerät gespeicherten Wallet Dateien aus</li>
|
||||
<li>WRITE_EXTERNAL_STORAGE : Schreibt Wallet Dateien auf dem Gerät</li>
|
||||
<li>INTERNET : Verbinde zum Monero-Netzwerk über einen Monero-Hintergrunddienst-Node</li>
|
||||
<li>READ_EXTERNAL_STORAGE : Lese die auf dem Gerät gespeicherten Wallet-Dateien aus</li>
|
||||
<li>WRITE_EXTERNAL_STORAGE : Schreibe Wallet-Dateien auf das Gerät</li>
|
||||
<li>WAKE_LOCK : Halte das Gerät während der Synchronisation wach</li>
|
||||
<li>CAMERA : Scanne QR-Codes um Monero zu erhalten</li>
|
||||
<li>CAMERA : Scanne QR-Codes, um Monero zu erhalten</li>
|
||||
</ul>
|
||||
<h2>Änderungen an dieser Datenschutzerklärung</h2>
|
||||
<p>Wir können diese Datenschutzerklärung von Zeit zu Zeit aktualisieren.
|
||||
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user