mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-25 13:16:44 +00:00
support searching on multiple addresses, txids and utxos in a search phrase separated by spaces
This commit is contained in:
parent
2d0a94d024
commit
fe7dba6d83
1 changed files with 86 additions and 42 deletions
|
@ -1,6 +1,7 @@
|
||||||
package com.sparrowwallet.sparrow.control;
|
package com.sparrowwallet.sparrow.control;
|
||||||
|
|
||||||
import com.sparrowwallet.drongo.KeyPurpose;
|
import com.sparrowwallet.drongo.KeyPurpose;
|
||||||
|
import com.sparrowwallet.drongo.Utils;
|
||||||
import com.sparrowwallet.drongo.address.Address;
|
import com.sparrowwallet.drongo.address.Address;
|
||||||
import com.sparrowwallet.drongo.address.InvalidAddressException;
|
import com.sparrowwallet.drongo.address.InvalidAddressException;
|
||||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||||
|
@ -20,10 +21,7 @@ import tornadofx.control.Field;
|
||||||
import tornadofx.control.Fieldset;
|
import tornadofx.control.Fieldset;
|
||||||
import tornadofx.control.Form;
|
import tornadofx.control.Form;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public class SearchWalletDialog extends Dialog<Entry> {
|
public class SearchWalletDialog extends Dialog<Entry> {
|
||||||
private static final Logger log = LoggerFactory.getLogger(SearchWalletDialog.class);
|
private static final Logger log = LoggerFactory.getLogger(SearchWalletDialog.class);
|
||||||
|
@ -148,7 +146,7 @@ public class SearchWalletDialog extends Dialog<Entry> {
|
||||||
});
|
});
|
||||||
|
|
||||||
search.textProperty().addListener((observable, oldValue, newValue) -> {
|
search.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
searchWallets(newValue.toLowerCase(Locale.ROOT));
|
searchWallets(newValue);
|
||||||
});
|
});
|
||||||
|
|
||||||
setResizable(true);
|
setResizable(true);
|
||||||
|
@ -158,42 +156,37 @@ public class SearchWalletDialog extends Dialog<Entry> {
|
||||||
Platform.runLater(search::requestFocus);
|
Platform.runLater(search::requestFocus);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void searchWallets(String searchText) {
|
private void searchWallets(String searchPhrase) {
|
||||||
List<Entry> matchingEntries = new ArrayList<>();
|
Set<Entry> matchingEntries = new LinkedHashSet<>();
|
||||||
|
|
||||||
if(!searchText.isEmpty()) {
|
if(!searchPhrase.isEmpty()) {
|
||||||
Long searchValue = getSearchValue(searchText);
|
Set<String> searchWords = new LinkedHashSet<>(Arrays.stream(searchPhrase.split("\\s+"))
|
||||||
Address searchAddress = getSearchAddress(searchText);
|
.filter(text -> isAddress(text) || isHash(text) || isHashIndex(text)).toList());
|
||||||
|
String freeText = removeOccurrences(searchPhrase, searchWords).trim();
|
||||||
|
if(!freeText.isEmpty()) {
|
||||||
|
searchWords.add(freeText);
|
||||||
|
}
|
||||||
|
|
||||||
for(WalletForm walletForm : walletForms) {
|
for(String searchText : searchWords) {
|
||||||
WalletTransactionsEntry walletTransactionsEntry = walletForm.getWalletTransactionsEntry();
|
Long searchValue = getSearchValue(searchText);
|
||||||
for(Entry entry : walletTransactionsEntry.getChildren()) {
|
Address searchAddress = getSearchAddress(searchText);
|
||||||
if(entry instanceof TransactionEntry transactionEntry) {
|
searchText = searchText.toLowerCase(Locale.ROOT);
|
||||||
if(transactionEntry.getBlockTransaction().getHash().toString().equals(searchText) ||
|
|
||||||
(transactionEntry.getLabel() != null && transactionEntry.getLabel().toLowerCase(Locale.ROOT).contains(searchText)) ||
|
|
||||||
(transactionEntry.getValue() != null && searchValue != null && Math.abs(transactionEntry.getValue()) == searchValue) ||
|
|
||||||
(searchAddress != null && transactionEntry.getBlockTransaction().getTransaction().getOutputs().stream().map(output -> output.getScript().getToAddress()).filter(Objects::nonNull).anyMatch(address -> address.equals(searchAddress)))) {
|
|
||||||
matchingEntries.add(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(KeyPurpose keyPurpose : KeyPurpose.DEFAULT_PURPOSES) {
|
for(WalletForm walletForm : walletForms) {
|
||||||
NodeEntry purposeEntry = walletForm.getNodeEntry(keyPurpose);
|
WalletTransactionsEntry walletTransactionsEntry = walletForm.getWalletTransactionsEntry();
|
||||||
for(Entry entry : purposeEntry.getChildren()) {
|
for(Entry entry : walletTransactionsEntry.getChildren()) {
|
||||||
if(entry instanceof NodeEntry nodeEntry) {
|
if(entry instanceof TransactionEntry transactionEntry) {
|
||||||
if(nodeEntry.getAddress().toString().toLowerCase(Locale.ROOT).contains(searchText) ||
|
if(transactionEntry.getBlockTransaction().getHash().toString().equals(searchText) ||
|
||||||
(nodeEntry.getLabel() != null && nodeEntry.getLabel().toLowerCase(Locale.ROOT).contains(searchText)) ||
|
(transactionEntry.getLabel() != null && transactionEntry.getLabel().toLowerCase(Locale.ROOT).contains(searchText)) ||
|
||||||
(nodeEntry.getValue() != null && searchValue != null && Math.abs(nodeEntry.getValue()) == searchValue)) {
|
(transactionEntry.getValue() != null && searchValue != null && Math.abs(transactionEntry.getValue()) == searchValue) ||
|
||||||
|
(searchAddress != null && transactionEntry.getBlockTransaction().getTransaction().getOutputs().stream().map(output -> output.getScript().getToAddress()).filter(Objects::nonNull).anyMatch(address -> address.equals(searchAddress)))) {
|
||||||
matchingEntries.add(entry);
|
matchingEntries.add(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for(WalletForm nestedWalletForm : walletForm.getNestedWalletForms()) {
|
for(KeyPurpose keyPurpose : KeyPurpose.DEFAULT_PURPOSES) {
|
||||||
for(KeyPurpose keyPurpose : nestedWalletForm.getWallet().getWalletKeyPurposes()) {
|
NodeEntry purposeEntry = walletForm.getNodeEntry(keyPurpose);
|
||||||
NodeEntry purposeEntry = nestedWalletForm.getNodeEntry(keyPurpose);
|
|
||||||
for(Entry entry : purposeEntry.getChildren()) {
|
for(Entry entry : purposeEntry.getChildren()) {
|
||||||
if(entry instanceof NodeEntry nodeEntry) {
|
if(entry instanceof NodeEntry nodeEntry) {
|
||||||
if(nodeEntry.getAddress().toString().toLowerCase(Locale.ROOT).contains(searchText) ||
|
if(nodeEntry.getAddress().toString().toLowerCase(Locale.ROOT).contains(searchText) ||
|
||||||
|
@ -204,22 +197,38 @@ public class SearchWalletDialog extends Dialog<Entry> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
WalletUtxosEntry walletUtxosEntry = walletForm.getWalletUtxosEntry();
|
for(WalletForm nestedWalletForm : walletForm.getNestedWalletForms()) {
|
||||||
for(Entry entry : walletUtxosEntry.getChildren()) {
|
for(KeyPurpose keyPurpose : nestedWalletForm.getWallet().getWalletKeyPurposes()) {
|
||||||
if(entry instanceof HashIndexEntry hashIndexEntry) {
|
NodeEntry purposeEntry = nestedWalletForm.getNodeEntry(keyPurpose);
|
||||||
if(hashIndexEntry.getBlockTransaction().getHash().toString().toLowerCase(Locale.ROOT).equals(searchText) ||
|
for(Entry entry : purposeEntry.getChildren()) {
|
||||||
(hashIndexEntry.getLabel() != null && hashIndexEntry.getLabel().toLowerCase(Locale.ROOT).contains(searchText)) ||
|
if(entry instanceof NodeEntry nodeEntry) {
|
||||||
(hashIndexEntry.getValue() != null && searchValue != null && Math.abs(hashIndexEntry.getValue()) == searchValue)) {
|
if(nodeEntry.getAddress().toString().toLowerCase(Locale.ROOT).contains(searchText) ||
|
||||||
matchingEntries.add(entry);
|
(nodeEntry.getLabel() != null && nodeEntry.getLabel().toLowerCase(Locale.ROOT).contains(searchText)) ||
|
||||||
|
(nodeEntry.getValue() != null && searchValue != null && Math.abs(nodeEntry.getValue()) == searchValue)) {
|
||||||
|
matchingEntries.add(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WalletUtxosEntry walletUtxosEntry = walletForm.getWalletUtxosEntry();
|
||||||
|
for(Entry entry : walletUtxosEntry.getChildren()) {
|
||||||
|
if(entry instanceof HashIndexEntry hashIndexEntry) {
|
||||||
|
if(hashIndexEntry.getBlockTransaction().getHash().toString().toLowerCase(Locale.ROOT).equals(searchText) ||
|
||||||
|
hashIndexEntry.getHashIndex().toString().toLowerCase(Locale.ROOT).equals(searchText) ||
|
||||||
|
(hashIndexEntry.getLabel() != null && hashIndexEntry.getLabel().toLowerCase(Locale.ROOT).contains(searchText)) ||
|
||||||
|
(hashIndexEntry.getValue() != null && searchValue != null && Math.abs(hashIndexEntry.getValue()) == searchValue)) {
|
||||||
|
matchingEntries.add(entry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SearchWalletEntry rootEntry = new SearchWalletEntry(walletForms.iterator().next().getWallet(), matchingEntries);
|
SearchWalletEntry rootEntry = new SearchWalletEntry(walletForms.iterator().next().getWallet(), new ArrayList<>(matchingEntries));
|
||||||
RecursiveTreeItem<Entry> rootItem = new RecursiveTreeItem<>(rootEntry, Entry::getChildren);
|
RecursiveTreeItem<Entry> rootItem = new RecursiveTreeItem<>(rootEntry, Entry::getChildren);
|
||||||
results.setRoot(rootItem);
|
results.setRoot(rootItem);
|
||||||
}
|
}
|
||||||
|
@ -240,6 +249,41 @@ public class SearchWalletDialog extends Dialog<Entry> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isAddress(String text) {
|
||||||
|
try {
|
||||||
|
Address.fromString(text);
|
||||||
|
return true;
|
||||||
|
} catch(InvalidAddressException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isHash(String text) {
|
||||||
|
return text.length() == 64 && Utils.isHex(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isHashIndex(String text) {
|
||||||
|
String[] parts = text.split(":");
|
||||||
|
if(parts.length == 2 && isHash(parts[0])) {
|
||||||
|
try {
|
||||||
|
Integer.parseInt(parts[1]);
|
||||||
|
return true;
|
||||||
|
} catch(NumberFormatException e) {
|
||||||
|
//ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String removeOccurrences(String inputString, Collection<String> stringsToRemove) {
|
||||||
|
for(String str : stringsToRemove) {
|
||||||
|
inputString = inputString.replaceAll("(?i)" + str, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
return inputString;
|
||||||
|
}
|
||||||
|
|
||||||
private static class SearchWalletEntry extends Entry {
|
private static class SearchWalletEntry extends Entry {
|
||||||
public SearchWalletEntry(Wallet wallet, List<Entry> entries) {
|
public SearchWalletEntry(Wallet wallet, List<Entry> entries) {
|
||||||
super(wallet, wallet.getName(), entries);
|
super(wallet, wallet.getName(), entries);
|
||||||
|
|
Loading…
Reference in a new issue