1
mirror of https://github.com/m2049r/xmrwallet synced 2025-09-04 00:53:36 +02:00

Compare commits

...

38 Commits

Author SHA1 Message Date
m2049r
67f3c5f948 bump version 2019-02-04 19:41:28 +01:00
m2049r
cd67a7e2bf 2019-02 height 2019-02-04 19:41:28 +01:00
0140454
fa5fe313ea Update zh-rTW translation (#529) 2019-02-03 07:54:41 +01:00
jaro Lee
ed4957a3cc sk strings update (#523) 2019-01-29 22:33:09 +01:00
jaro Lee
3e0eeebd51 sk help.xml update (#527)
sk-translation - help_send update
2019-01-29 22:32:40 +01:00
m2049r
0d213a1eb4 hide sweep amount in street mode (#526) 2019-01-28 01:16:00 +01:00
m2049r
39d048fd5e Feature bitpay (#525)
* support bitcoin payment protocol (BIP70/72)

* prep translations
2019-01-27 21:32:06 +01:00
m2049r
1a5d2d0399 Update Android Studio v3.3 (#522)
* Update Android Studio v3.3

* also update circleci script to accept licenses
2019-01-21 17:38:59 +01:00
m2049r
028057a672 bump version (#519) 2019-01-14 12:52:28 +01:00
TheFuzzStone
909ff8ca5e Ukranian translation for Monerujo (#517)
* Ukranian translation

* Update for Russian language (fixed small typos)
2019-01-12 19:56:59 +01:00
m2049r
ffd61e4495 remove getErrorString method (#516) 2019-01-11 19:24:33 +01:00
m2049r
003dee382e Merge pull request #515 from m2049r/fix_license
SwipeableRecyclerView license
2019-01-11 19:23:56 +01:00
m2049r
be0498c67d SwipeableRecyclerView license 2019-01-11 19:23:25 +01:00
m2049r
06227a4a83 Merge pull request #514 from m2049r/feature_dismissTx
Allow swipe-to-dismiss transactions in street mode
2019-01-10 19:33:26 +01:00
m2049r
4409087bd0 update dependencies 2019-01-10 19:31:34 +01:00
m2049r
965e52d8a5 allow to dismiss tx in streetmode 2019-01-10 19:31:15 +01:00
m2049r
beba0f497b Fix bech32 (#513)
* fix bech32 recognition

* bump version
2019-01-09 20:54:14 +01:00
m2049r
9d1827ff0d show current node (#511)
& bump version
2019-01-08 22:13:25 +01:00
m2049r
c04b192753 keep node once found (#510) 2019-01-06 10:57:25 +01:00
m2049r
888b5edaec height for jan19 (#509) 2019-01-06 09:56:00 +01:00
netrik182
5ee5a81926 updated pt-BR translation help and node strings (#491)
* updated pt-BR translation for #440

* update help.xml after review

* update strings.xml after review

* update help.xml after further peer review
2019-01-05 13:42:49 +01:00
m2049r
c4e361a873 allow bech32 segwit btc addresses (#508) 2019-01-05 13:42:22 +01:00
m2049r
dba6cb057e add restore height for december (#502) 2018-12-23 08:29:21 +01:00
m2049r
9e1167c5b9 read unsigned types & read payload_data (top_version...) (#501) 2018-12-23 08:12:50 +01:00
Hans
12546a1ade [Estonian] Some additional translations (#497) 2018-12-23 07:48:20 +01:00
BlackLotus64
e9313bc235 ES Translation of strings and help v2 (#490) 2018-12-08 18:26:20 +01:00
m2049r
7e9bf84640 tweaks to barcode/tag reading (#494)
- deal with empty payment_id
- use btc message as description
- BarcodeData is final
2018-12-02 10:23:07 +01:00
m2049r
94f87a5193 bump version 2018-11-28 22:03:24 +01:00
Lafudoci
8a8fc5ec9e Node-o-matiC translation in zh-tw (#488) 2018-11-28 19:47:29 +01:00
joshuamarques
036d4ebf6c Japanese translation added (#481) 2018-11-28 07:52:16 +01:00
m2049r
c6d4de8599 bump version 2018-11-26 23:39:01 +01:00
m2049r
2ef7f8571c adjust & tweak tx details layout (#489) 2018-11-26 23:08:32 +01:00
m2049r
d2612a26e5 show my tx (sub)address (#487) 2018-11-26 12:05:40 +01:00
m2049r
7e14572756 (optional) disable crazypass generation (#486)
* (optional) disable crazypass generation

* update FAQ about disabling crazypass
2018-11-26 12:05:25 +01:00
hrumag
6f840dcacf [IT-Translation] help.xml / strings.xml - First Issue (#480)
* [IT-Translation] help.xml / strings.xml

* [IT-Translation] Fixes from @erciccione and @serhack
2018-11-26 12:05:03 +01:00
m2049r
36b389cd0f USE_FINGERPRINT & bump version 2018-11-24 23:39:35 +01:00
m2049r
ed2b95ea37 Fix android9 permissions (#484)
* FOREGROUND_SERVICE for Android 9

* USE_BIOMETRIC for Android 9
2018-11-24 23:03:20 +01:00
m2049r
8d41d1d03e Stagenet build config (#483)
* combine gitignores

* stagenet build config
2018-11-24 22:28:33 +01:00
102 changed files with 3355 additions and 762 deletions

View File

@@ -3,11 +3,13 @@ jobs:
build:
working_directory: ~/code
docker:
- image: bitriseio/android-ndk
- image: circleci/android:api-28-ndk
environment:
JVM_OPTS: -Xmx3200m
steps:
- checkout
- run: yes | sdkmanager --licenses || exit 0
- run: yes | sdkmanager --update || exit 0
- restore_cache:
key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}
- run:

3
.gitignore vendored
View File

@@ -6,7 +6,10 @@
/captures
.externalNativeBuild
.DS_Store
/app/build
/app/release
/app/alpha
/app/prod
/app/alphaMainnet
/app/prodMainnet
/app/alphaStagenet

3
.idea/.gitignore generated vendored
View File

@@ -1,3 +0,0 @@
workspace.xml
markdown-*
misc.xml

1
.idea/.name generated
View File

@@ -1 +0,0 @@
xmrwallet

22
.idea/compiler.xml generated
View File

@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<resourceExtensions />
<wildcardResourcePatterns>
<entry name="!?*.java" />
<entry name="!?*.form" />
<entry name="!?*.class" />
<entry name="!?*.groovy" />
<entry name="!?*.scala" />
<entry name="!?*.flex" />
<entry name="!?*.kt" />
<entry name="!?*.clj" />
<entry name="!?*.aj" />
</wildcardResourcePatterns>
<annotationProcessing>
<profile default="true" name="Default" enabled="false">
<processorPath useClasspath="true" />
</profile>
</annotationProcessing>
</component>
</project>

View File

@@ -1,3 +0,0 @@
<component name="CopyrightManager">
<settings default="" />
</component>

19
.idea/gradle.xml generated
View File

@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="disableWrapperSourceDistributionNotification" value="true" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
</GradleProjectSettings>
</option>
</component>
</project>

9
.idea/modules.xml generated
View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
<module fileurl="file://$PROJECT_DIR$/xmrwallet.iml" filepath="$PROJECT_DIR$/xmrwallet.iml" />
</modules>
</component>
</project>

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
</set>
</option>
</component>
</project>

6
.idea/vcs.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

5
app/.gitignore vendored
View File

@@ -1,5 +0,0 @@
.externalNativeBuild
build
app.iml
prod
alpha

View File

@@ -7,8 +7,8 @@ android {
applicationId "com.m2049r.xmrwallet"
minSdkVersion 21
targetSdkVersion 28
versionCode 155
versionName "1.10.5 'Node-O-matiC'"
versionCode 165
versionName "1.10.15 'Node-O-matiC'"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
@@ -27,6 +27,7 @@ android {
stagenet {
dimension 'net'
applicationIdSuffix '.stage'
versionNameSuffix ' (stage)'
}
alpha {
dimension 'type'
@@ -112,10 +113,12 @@ dependencies {
implementation 'dnsjava:dnsjava:2.1.8'
implementation 'org.jitsi:dnssecjava:1.1.3'
implementation 'org.slf4j:slf4j-nop:1.7.25'
implementation 'com.github.brnunes:swipeablerecyclerview:1.0.2'
testImplementation "junit:junit:$rootProject.ext.junitVersion"
testImplementation "org.mockito:mockito-all:$rootProject.ext.mockitoVersion"
testImplementation "com.squareup.okhttp3:mockwebserver:$rootProject.ext.okHttpVersion"
testImplementation 'org.json:json:20140107'
testImplementation 'net.jodah:concurrentunit:0.4.2'
testImplementation 'org.json:json:20180813'
testImplementation 'net.jodah:concurrentunit:0.4.4'
}

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name" translatable="false">monerujo - Debug</string>
</resources>

View File

@@ -7,8 +7,10 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
android:name=".XmrWalletApplication"

View File

@@ -43,6 +43,9 @@ Copyright (c) 2014 Dushyanth Maguluru
<h3>AndroidLicensesPage (https://github.com/adamsp/AndroidLicensesPage)</h3>
Copyright (c) 2013 Adam Speakman
<h3>SwipeableRecyclerView (https://github.com/brnunes/SwipeableRecyclerView)</h3>
Copyright (c) 2015 Bruno R. Nunes
<h3>Apache License, Version 2.0, January 2004</h3>
http://www.apache.org/licenses/<br/>
<br/>

View File

@@ -417,8 +417,8 @@ Java_com_m2049r_xmrwallet_model_WalletManager_verifyWalletPassword(JNIEnv *env,
//virtual int queryWalletHardware(const std::string &keys_file_name, const std::string &password) const = 0;
JNIEXPORT jint JNICALL
Java_com_m2049r_xmrwallet_model_WalletManager_queryWalletDeviceJ(JNIEnv *env, jobject instance,
jstring keys_file_name,
jstring password) {
jstring keys_file_name,
jstring password) {
const char *_keys_file_name = env->GetStringUTFChars(keys_file_name, NULL);
const char *_password = env->GetStringUTFChars(password, NULL);
Bitmonero::Wallet::Device device_type;
@@ -442,12 +442,6 @@ Java_com_m2049r_xmrwallet_model_WalletManager_findWallets(JNIEnv *env, jobject i
return cpp2java(env, walletPaths);
}
JNIEXPORT jstring JNICALL
Java_com_m2049r_xmrwallet_model_WalletManager_getErrorString(JNIEnv *env, jobject instance) {
Bitmonero::Wallet *wallet = getHandle<Bitmonero::Wallet>(env, instance);
return env->NewStringUTF(wallet->errorString().c_str());
}
//TODO virtual bool checkPayment(const std::string &address, const std::string &txid, const std::string &txkey, const std::string &daemon_address, uint64_t &received, uint64_t &height, std::string &error) const = 0;
JNIEXPORT void JNICALL
@@ -1185,10 +1179,11 @@ jobject newTransferList(JNIEnv *env, Bitmonero::TransactionInfo *info) {
jobject newTransactionInfo(JNIEnv *env, Bitmonero::TransactionInfo *info) {
jmethodID c = env->GetMethodID(class_TransactionInfo, "<init>",
"(IZZJJJLjava/lang/String;JLjava/lang/String;IIJLjava/util/List;)V");
"(IZZJJJLjava/lang/String;JLjava/lang/String;IIJLjava/lang/String;Ljava/util/List;)V");
jobject transfers = newTransferList(env, info);
jstring _hash = env->NewStringUTF(info->hash().c_str());
jstring _paymentId = env->NewStringUTF(info->paymentId().c_str());
jstring _label = env->NewStringUTF(info->label().c_str());
uint32_t subaddrIndex = 0;
if (info->direction() == Bitmonero::TransactionInfo::Direction_In)
subaddrIndex = *(info->subaddrIndex().begin());
@@ -1205,6 +1200,7 @@ jobject newTransactionInfo(JNIEnv *env, Bitmonero::TransactionInfo *info) {
info->subaddrAccount(),
subaddrIndex,
info->confirmations(),
_label,
transfers);
env->DeleteLocalRef(transfers);
env->DeleteLocalRef(_hash);
@@ -1397,7 +1393,7 @@ Java_com_m2049r_xmrwallet_model_WalletManager_setLogLevel(JNIEnv *env, jclass cl
*
* @return length of received data in response or -1 if error
*/
int LedgerExchange(
int LedgerExchange(
unsigned char *command,
unsigned int cmd_len,
unsigned char *response,

View File

@@ -18,7 +18,6 @@ package com.m2049r.levin.scanner;
import com.m2049r.xmrwallet.data.NodeInfo;
import java.net.InetSocketAddress;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
@@ -176,9 +175,9 @@ public class Dispatcher implements PeerRetriever.OnGetPeers {
}
private void retrievePeers(PeerRetriever peer) {
for (InetSocketAddress socketAddress : peer.getPeers()) {
for (LevinPeer levinPeer : peer.getPeers()) {
if (getMorePeers())
retrievePeer(new NodeInfo(socketAddress));
retrievePeer(new NodeInfo(levinPeer));
else
break;
}

View File

@@ -0,0 +1,23 @@
package com.m2049r.levin.scanner;
import java.net.InetAddress;
import java.net.InetSocketAddress;
public class LevinPeer {
final public InetSocketAddress socketAddress;
final public int version;
final public long height;
final public String top;
public InetSocketAddress getSocketAddress() {
return socketAddress;
}
LevinPeer(InetAddress address, int port, int version, long height, String top) {
this.socketAddress = new InetSocketAddress(address, port);
this.version = version;
this.height = height;
this.top = top;
}
}

View File

@@ -28,7 +28,6 @@ import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Date;
@@ -45,7 +44,7 @@ public class PeerRetriever implements Callable<PeerRetriever> {
static final private byte[] HANDSHAKE = handshakeRequest().asByteArray();
static final private byte[] FLAGS_RESP = flagsResponse().asByteArray();
final private List<InetSocketAddress> peers = new ArrayList<>();
final private List<LevinPeer> peers = new ArrayList<>();
private NodeInfo nodeInfo;
private OnGetPeers onGetPeersCallback;
@@ -67,7 +66,7 @@ public class PeerRetriever implements Callable<PeerRetriever> {
return !peers.isEmpty();
}
public List<InetSocketAddress> getPeers() {
public List<LevinPeer> getPeers() {
return peers;
}
@@ -107,12 +106,18 @@ public class PeerRetriever implements Callable<PeerRetriever> {
}
private void readAddressList(Section section) {
Section data = (Section) section.get("payload_data");
int topVersion = (Integer) data.get("top_version");
long currentHeight = (Long) data.get("current_height");
String topId = HexHelper.bytesToHex((byte[]) data.get("top_id"));
Timber.d("PAYLOAD_DATA %d/%d/%s", topVersion, currentHeight, topId);
@SuppressWarnings("unchecked")
List<Section> peerList = (List<Section>) section.get("local_peerlist_new");
if (peerList != null) {
for (Section peer : peerList) {
Section adr = (Section) peer.get("adr");
Byte type = (Byte) adr.get("type");
Integer type = (Integer) adr.get("type");
if ((type == null) || (type != 1))
continue;
Section addr = (Section) adr.get("addr");
@@ -121,7 +126,7 @@ public class PeerRetriever implements Callable<PeerRetriever> {
Integer ip = (Integer) addr.get("m_ip");
if (ip == null)
continue;
Short sport = (Short) addr.get("m_port");
Integer sport = (Integer) addr.get("m_port");
if (sport == null)
continue;
int port = sport;
@@ -133,7 +138,7 @@ public class PeerRetriever implements Callable<PeerRetriever> {
&& !inet.isLoopbackAddress()
&& !inet.isMulticastAddress()
&& !inet.isLinkLocalAddress()) {
peers.add(new InetSocketAddress(inet, port));
peers.add(new LevinPeer(inet, port, topVersion, currentHeight, topId));
}
}
}

View File

@@ -83,9 +83,11 @@ public class LevinReader {
case Section.SERIALIZE_TYPE_INT32:
return in.readInt();
case Section.SERIALIZE_TYPE_UINT16:
return in.readUnsignedShort();
case Section.SERIALIZE_TYPE_INT16:
return in.readShort();
case Section.SERIALIZE_TYPE_UINT8:
return in.readUnsignedByte();
case Section.SERIALIZE_TYPE_INT8:
return in.readByte();
case Section.SERIALIZE_TYPE_OBJECT:

View File

@@ -92,6 +92,11 @@ public class LoginActivity extends BaseActivity
Set<NodeInfo> favouriteNodes = new HashSet<>();
@Override
public NodeInfo getNode() {
return node;
}
@Override
public void setNode(NodeInfo node) {
if ((node != null) && (node.getNetworkType() != WalletManager.getInstance().getNetworkType()))

View File

@@ -99,6 +99,8 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
void setNode(NodeInfo node);
NodeInfo getNode();
Set<NodeInfo> getFavouriteNodes();
boolean hasLedger();
@@ -128,7 +130,11 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
activityCallback.setTitle(null);
activityCallback.setToolbarButton(Toolbar.BUTTON_CREDITS);
activityCallback.showNet();
findBestNode();
NodeInfo node = activityCallback.getNode();
if (node == null)
findBestNode();
else
showNode(node);
}
@Override
@@ -181,7 +187,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
@Override
public void onClick(View v) {
if (activityCallback.getFavouriteNodes().isEmpty())
activityCallback.onNodePrefs();
startNodePrefs();
else
findBestNode();
}
@@ -191,8 +197,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
view.findViewById(R.id.ibOption).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (activityCallback != null)
activityCallback.onNodePrefs();
startNodePrefs();
}
});
@@ -476,4 +481,9 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
tvNodeAddress.setText(nodeInfo.getAddress());
tvNodeAddress.setVisibility(View.VISIBLE);
}
private void startNodePrefs() {
activityCallback.setNode(null);
activityCallback.onNodePrefs();
}
}

View File

@@ -36,7 +36,7 @@ import com.m2049r.xmrwallet.model.TransactionInfo;
import com.m2049r.xmrwallet.model.Transfer;
import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.UserNotes;
import com.m2049r.xmrwallet.data.UserNotes;
import com.m2049r.xmrwallet.widget.Toolbar;
import java.text.SimpleDateFormat;
@@ -60,6 +60,7 @@ public class TxFragment extends Fragment {
}
private TextView tvAccount;
private TextView tvAddress;
private TextView tvTxTimestamp;
private TextView tvTxId;
private TextView tvTxKey;
@@ -90,6 +91,7 @@ public class TxFragment extends Fragment {
tvTxAmountBtc = view.findViewById(R.id.tvTxAmountBtc);
tvAccount = view.findViewById(R.id.tvAccount);
tvAddress = view.findViewById(R.id.tvAddress);
tvTxTimestamp = view.findViewById(R.id.tvTxTimestamp);
tvTxId = view.findViewById(R.id.tvTxId);
tvTxKey = view.findViewById(R.id.tvTxKey);
@@ -219,12 +221,16 @@ public class TxFragment extends Fragment {
if (info.txKey == null) {
info.txKey = activityCallback.getTxKey(info.hash);
}
if (info.address == null) {
info.address = activityCallback.getTxAddress(info.account, info.subaddress);
}
loadNotes(info);
activityCallback.setSubtitle(getString(R.string.tx_title));
activityCallback.setToolbarButton(Toolbar.BUTTON_BACK);
tvAccount.setText(getString(R.string.tx_account_formatted, info.account, info.subaddress));
tvAddress.setText(info.address);
tvTxTimestamp.setText(TS_FORMATTER.format(new Date(info.timestamp * 1000)));
tvTxId.setText(info.hash);
@@ -331,6 +337,8 @@ public class TxFragment extends Fragment {
String getTxNotes(String hash);
String getTxAddress(int major, int minor);
void onSetNote(String txId, String notes);
void setToolbarButton(int type);

View File

@@ -59,7 +59,7 @@ import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.service.WalletService;
import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
import com.m2049r.xmrwallet.util.UserNotes;
import com.m2049r.xmrwallet.data.UserNotes;
import com.m2049r.xmrwallet.widget.Toolbar;
import java.util.ArrayList;
@@ -144,6 +144,9 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
} else {
streetMode = 0;
}
final WalletFragment walletFragment = (WalletFragment)
getSupportFragmentManager().findFragmentByTag(WalletFragment.class.getName());
if (walletFragment != null) walletFragment.resetDismissedTransactions();
updateAccountsBalance();
forceUpdate();
}
@@ -168,6 +171,11 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
return getWallet().getUserNote(txId);
}
@Override
public String getTxAddress(int major, int minor) {
return getWallet().getSubaddress(major, minor);
}
@Override
protected void onStart() {
super.onStart();
@@ -281,7 +289,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
showNet();
}
invalidateOptionsMenu();
}
private void onEnableStreetMode() {
@@ -951,8 +958,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
}
if (!processed || (onUriScannedListener == null)) {
Toast.makeText(this, getString(R.string.nfc_tag_read_what), Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, getString(R.string.nfc_tag_read_success), Toast.LENGTH_SHORT).show();
}
}

View File

@@ -38,6 +38,7 @@ import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.TextView;
import com.github.brnunes.swipeablerecyclerview.SwipeableRecyclerViewTouchListener;
import com.m2049r.xmrwallet.layout.TransactionInfoAdapter;
import com.m2049r.xmrwallet.model.TransactionInfo;
import com.m2049r.xmrwallet.model.Wallet;
@@ -73,6 +74,12 @@ public class WalletFragment extends Fragment
private Spinner sCurrency;
private List<String> dismissedTransactions = new ArrayList<>();
public void resetDismissedTransactions() {
dismissedTransactions.clear();
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -116,9 +123,44 @@ public class WalletFragment extends Fragment
RecyclerView recyclerView = view.findViewById(R.id.list);
this.adapter = new TransactionInfoAdapter(getActivity(), this);
adapter = new TransactionInfoAdapter(getActivity(), this);
recyclerView.setAdapter(adapter);
SwipeableRecyclerViewTouchListener swipeTouchListener =
new SwipeableRecyclerViewTouchListener(recyclerView,
new SwipeableRecyclerViewTouchListener.SwipeListener() {
@Override
public boolean canSwipeLeft(int position) {
return activityCallback.isStreetMode();
}
@Override
public boolean canSwipeRight(int position) {
return activityCallback.isStreetMode();
}
@Override
public void onDismissedBySwipeLeft(RecyclerView recyclerView, int[] reverseSortedPositions) {
for (int position : reverseSortedPositions) {
dismissedTransactions.add(adapter.getItem(position).hash);
adapter.removeItem(position);
}
adapter.notifyDataSetChanged();
}
@Override
public void onDismissedBySwipeRight(RecyclerView recyclerView, int[] reverseSortedPositions) {
for (int position : reverseSortedPositions) {
dismissedTransactions.add(adapter.getItem(position).hash);
adapter.removeItem(position);
}
adapter.notifyDataSetChanged();
}
});
recyclerView.addOnItemTouchListener(swipeTouchListener);
bSend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -294,7 +336,9 @@ public class WalletFragment extends Fragment
Timber.d("StreetHeight=%d", streetHeight);
for (TransactionInfo info : wallet.getHistory().getAll()) {
Timber.d("TxHeight=%d", info.blockheight);
if (info.isPending || (info.blockheight >= streetHeight)) list.add(info);
if ((info.isPending || (info.blockheight >= streetHeight))
&& !dismissedTransactions.contains(info.hash))
list.add(info);
}
adapter.setInfos(list);
adapter.notifyDataSetChanged();

View File

@@ -21,7 +21,10 @@ import android.net.Uri;
import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.util.BitcoinAddressValidator;
import com.m2049r.xmrwallet.util.OpenAliasHelper;
import com.m2049r.xmrwallet.util.PaymentProtocolHelper;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
@@ -37,8 +40,10 @@ public class BarcodeData {
public static final String OA_XMR_ASSET = "xmr";
public static final String OA_BTC_ASSET = "btc";
static final String BTC_SCHEME = "bitcoin:";
static final String BTC_SCHEME = "bitcoin";
static final String BTC_DESCRIPTION = "message";
static final String BTC_AMOUNT = "amount";
static final String BTC_BIP70_PARM = "r";
public enum Asset {
XMR, BTC
@@ -47,56 +52,55 @@ public class BarcodeData {
public enum Security {
NORMAL,
OA_NO_DNSSEC,
OA_DNSSEC
OA_DNSSEC,
BIP70
}
public Asset asset = null;
public String addressName = null;
public String address = null;
public String paymentId = null;
public String amount = null;
public String description = null;
public Security security = Security.NORMAL;
public BarcodeData(String uri) {
this.asset = asset;
this.address = address;
}
final public Asset asset;
final public String address;
final public String addressName;
final public String paymentId;
final public String amount;
final public String description;
final public Security security;
final public String bip70;
public BarcodeData(Asset asset, String address) {
this.asset = asset;
this.address = address;
this(asset, address, null, null, null, null, Security.NORMAL);
}
public BarcodeData(Asset asset, String address, String amount) {
this.asset = asset;
this.address = address;
this.amount = amount;
this(asset, address, null, null, null, amount, Security.NORMAL);
}
public BarcodeData(Asset asset, String address, String amount, String description, Security security) {
this(asset, address, null, null, description, amount, security);
}
public BarcodeData(Asset asset, String address, String paymentId, String amount) {
this.asset = asset;
this.address = address;
this.paymentId = paymentId;
this.amount = amount;
this(asset, address, null, paymentId, null, amount, Security.NORMAL);
}
public BarcodeData(Asset asset, String address, String paymentId, String description, String amount) {
this(asset, address, null, paymentId, description, amount, Security.NORMAL);
}
public BarcodeData(Asset asset, String address, String addressName, String paymentId, String description, String amount, Security security) {
this(asset, address, addressName, null, paymentId, description, amount, security);
}
public BarcodeData(Asset asset, String address, String addressName, String bip70, String paymentId, String description, String amount, Security security) {
this.asset = asset;
this.address = address;
this.bip70 = bip70;
this.addressName = addressName;
this.paymentId = paymentId;
this.description = description;
this.amount = amount;
}
public void setAddressName(String name) {
addressName = name;
}
public void setSecurity(Security security) {
this.security = security;
}
public Uri getUri() {
return Uri.parse(getUriString());
}
@@ -134,13 +138,17 @@ public class BarcodeData {
if (bcData == null) {
bcData = parseBitcoinUri(qrCode);
}
// check for btc payment uri (like bitpay)
if (bcData == null) {
bcData = parseBitcoinPaymentUrl(qrCode);
}
// check for naked btc address
if (bcData == null) {
bcData = parseBitcoinNaked(qrCode);
}
// check for OpenAlias
if (bcData == null) {
bcData = parseOpenAlias(qrCode);
bcData = parseOpenAlias(qrCode, false);
}
return bcData;
}
@@ -175,7 +183,11 @@ public class BarcodeData {
}
}
String address = monero.getPath();
String paymentId = parms.get(XMR_PAYMENTID);
// deal with empty payment_id created by non-spec-conforming apps
if ((paymentId != null) && paymentId.isEmpty()) paymentId = null;
String description = parms.get(XMR_DESCRIPTION);
String amount = parms.get(XMR_AMOUNT);
if (amount != null) {
@@ -212,19 +224,28 @@ public class BarcodeData {
}
// bitcoin:mpQ84J43EURZHkCnXbyQ4PpNDLLBqdsMW2?amount=0.01
static public BarcodeData parseBitcoinUri(String uri) {
Timber.d("parseBitcoinUri=%s", uri);
// bitcoin:?r=https://bitpay.com/i/xxx
static public BarcodeData parseBitcoinUri(String uriString) {
Timber.d("parseBitcoinUri=%s", uriString);
if (uri == null) return null;
if (uriString == null) return null;
URI uri;
try {
uri = new URI(uriString);
} catch (URISyntaxException ex) {
return null;
}
if (!uri.isOpaque() ||
!uri.getScheme().equals(BTC_SCHEME)) return null;
if (!uri.startsWith(BTC_SCHEME)) return null;
String noScheme = uri.substring(BTC_SCHEME.length());
Uri bitcoin = Uri.parse(noScheme);
String[] parts = uri.getRawSchemeSpecificPart().split("[?]");
if ((parts.length <= 0) || (parts.length > 2)) {
Timber.d("invalid number of parts %d", parts.length);
return null;
}
Map<String, String> parms = new HashMap<>();
String query = bitcoin.getQuery();
if (query != null) {
String[] args = query.split("&");
if (parts.length == 2) {
String[] args = parts[1].split("&");
for (String arg : args) {
String[] namevalue = arg.split("=");
if (namevalue.length == 0) {
@@ -234,9 +255,26 @@ public class BarcodeData {
namevalue.length > 1 ? Uri.decode(namevalue[1]) : "");
}
}
String address = bitcoin.getPath();
String description = parms.get(BTC_DESCRIPTION);
String address = parts[0]; // no need to decode as there can bo no special characters
if (address.isEmpty()) { // possibly a BIP72 uri
String bip70 = parms.get(BTC_BIP70_PARM);
if (bip70 == null) {
Timber.d("no address and can't find pp url");
return null;
}
if (!PaymentProtocolHelper.isHttp(bip70)) {
Timber.d("[%s] is not http url", bip70);
return null;
}
return new BarcodeData(BarcodeData.Asset.BTC, null, null, bip70, null, description, null, Security.NORMAL);
}
if (!BitcoinAddressValidator.validate(address)) {
Timber.d("BTC address (%s) invalid", address);
return null;
}
String amount = parms.get(BTC_AMOUNT);
if (amount != null) {
if ((amount != null) && (!amount.isEmpty())) {
try {
Double.parseDouble(amount);
} catch (NumberFormatException ex) {
@@ -244,11 +282,22 @@ public class BarcodeData {
return null; // we have an amount but its not a number!
}
}
if (!BitcoinAddressValidator.validate(address)) {
Timber.d("address invalid");
return new BarcodeData(BarcodeData.Asset.BTC, address, null, description, amount);
}
// https://bitpay.com/invoice?id=xxx
// https://bitpay.com/i/KbMdd4EhnLXSbpWGKsaeo6
static public BarcodeData parseBitcoinPaymentUrl(String url) {
Timber.d("parseBitcoinUri=%s", url);
if (url == null) return null;
if (!PaymentProtocolHelper.isHttp(url)) {
Timber.d("[%s] is not http url", url);
return null;
}
return new BarcodeData(BarcodeData.Asset.BTC, address, amount);
return new BarcodeData(Asset.BTC, url);
}
static public BarcodeData parseBitcoinNaked(String address) {
@@ -264,7 +313,7 @@ public class BarcodeData {
return new BarcodeData(BarcodeData.Asset.BTC, address);
}
static public BarcodeData parseOpenAlias(String oaString) {
static public BarcodeData parseOpenAlias(String oaString, boolean dnssec) {
Timber.d("parseOpenAlias=%s", oaString);
if (oaString == null) return null;
@@ -316,8 +365,8 @@ public class BarcodeData {
return null;
}
BarcodeData bc = new BarcodeData(asset, address, paymentId, description, amount);
bc.setAddressName(addressName);
return bc;
Security sec = dnssec ? BarcodeData.Security.OA_DNSSEC : BarcodeData.Security.OA_NO_DNSSEC;
return new BarcodeData(asset, address, addressName, paymentId, description, amount, sec);
}
}

View File

@@ -22,6 +22,7 @@ import com.burgstaller.okhttp.digest.CachingAuthenticator;
import com.burgstaller.okhttp.digest.Credentials;
import com.burgstaller.okhttp.digest.DigestAuthenticator;
import com.m2049r.levin.scanner.Dispatcher;
import com.m2049r.levin.scanner.LevinPeer;
import com.m2049r.xmrwallet.util.OkHttpHelper;
import org.json.JSONException;
@@ -99,21 +100,18 @@ public class NodeInfo extends Node {
super(nodeString);
}
public NodeInfo(InetSocketAddress socketAddress) {
super(socketAddress);
public NodeInfo(LevinPeer levinPeer) {
super(levinPeer.getSocketAddress());
}
public NodeInfo(InetSocketAddress address) {
super(address);
}
public NodeInfo() {
super();
}
public NodeInfo(InetSocketAddress peerAddress, long height, int majorVersion, double respTime) {
super(peerAddress);
this.height = height;
this.majorVersion = majorVersion;
this.responseTime = respTime;
}
public long getHeight() {
return height;
}

View File

@@ -20,9 +20,6 @@ import android.os.Parcel;
import android.os.Parcelable;
import com.m2049r.xmrwallet.model.PendingTransaction;
import com.m2049r.xmrwallet.util.UserNotes;
import timber.log.Timber;
// https://stackoverflow.com/questions/2139134/how-to-send-an-object-from-one-android-activity-to-another-using-intents
public class TxData implements Parcelable {

View File

@@ -18,12 +18,11 @@ package com.m2049r.xmrwallet.data;
import android.os.Parcel;
import com.m2049r.xmrwallet.model.PendingTransaction;
public class TxDataBtc extends TxData {
private String xmrtoUuid;
private String btcAddress;
private String bip70;
private double btcAmount;
public TxDataBtc() {
@@ -50,6 +49,14 @@ public class TxDataBtc extends TxData {
this.btcAddress = btcAddress;
}
public String getBip70() {
return bip70;
}
public void setBip70(String bip70) {
this.bip70 = bip70;
}
public double getBtcAmount() {
return btcAmount;
}
@@ -63,6 +70,7 @@ public class TxDataBtc extends TxData {
super.writeToParcel(out, flags);
out.writeString(xmrtoUuid);
out.writeString(btcAddress);
out.writeString(bip70);
out.writeDouble(btcAmount);
}
@@ -81,16 +89,19 @@ public class TxDataBtc extends TxData {
super(in);
xmrtoUuid = in.readString();
btcAddress = in.readString();
bip70 = in.readString();
btcAmount = in.readDouble();
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
StringBuilder sb = new StringBuilder();
sb.append(",xmrtoUuid:");
sb.append(xmrtoUuid);
sb.append(",btcAddress:");
sb.append(btcAddress);
sb.append(",bip70:");
sb.append(bip70);
sb.append(",btcAmount:");
sb.append(btcAmount);
return sb.toString();

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.m2049r.xmrwallet.util;
package com.m2049r.xmrwallet.data;
import com.m2049r.xmrwallet.xmrto.api.QueryOrderStatus;

View File

@@ -120,6 +120,15 @@ public class SendBtcAmountWizardFragment extends SendWizardFragment {
return true;
}
private void setBip70Mode() {
TxDataBtc txDataBtc = (TxDataBtc) sendListener.getTxData();
if (txDataBtc.getBip70() != null) {
numberPad.setVisibility(View.INVISIBLE);
} else {
numberPad.setVisibility(View.VISIBLE);
}
}
double maxBtc = 0;
double minBtc = 0;
@@ -141,12 +150,13 @@ public class SendBtcAmountWizardFragment extends SendWizardFragment {
tvFunds.setText(getString(R.string.send_available,
getString(R.string.unknown_amount)));
}
if ((evAmount.getAmount() == null) || evAmount.getAmount().isEmpty()) {
final BarcodeData data = sendListener.popBarcodeData();
if ((data != null) && (data.amount != null)) {
final BarcodeData data = sendListener.popBarcodeData();
if (data != null) {
if (data.amount != null) {
evAmount.setAmount(data.amount);
}
}
setBip70Mode();
callXmrTo();
}

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