support searching on multiple addresses, txids and utxos in a search phrase separated by spaces

This commit is contained in:
Craig Raw 2024-04-17 09:22:31 +02:00
parent 2d0a94d024
commit fe7dba6d83

View file

@ -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,12 +156,21 @@ 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()) {
Set<String> searchWords = new LinkedHashSet<>(Arrays.stream(searchPhrase.split("\\s+"))
.filter(text -> isAddress(text) || isHash(text) || isHashIndex(text)).toList());
String freeText = removeOccurrences(searchPhrase, searchWords).trim();
if(!freeText.isEmpty()) {
searchWords.add(freeText);
}
for(String searchText : searchWords) {
Long searchValue = getSearchValue(searchText); Long searchValue = getSearchValue(searchText);
Address searchAddress = getSearchAddress(searchText); Address searchAddress = getSearchAddress(searchText);
searchText = searchText.toLowerCase(Locale.ROOT);
for(WalletForm walletForm : walletForms) { for(WalletForm walletForm : walletForms) {
WalletTransactionsEntry walletTransactionsEntry = walletForm.getWalletTransactionsEntry(); WalletTransactionsEntry walletTransactionsEntry = walletForm.getWalletTransactionsEntry();
@ -210,6 +217,7 @@ public class SearchWalletDialog extends Dialog<Entry> {
for(Entry entry : walletUtxosEntry.getChildren()) { for(Entry entry : walletUtxosEntry.getChildren()) {
if(entry instanceof HashIndexEntry hashIndexEntry) { if(entry instanceof HashIndexEntry hashIndexEntry) {
if(hashIndexEntry.getBlockTransaction().getHash().toString().toLowerCase(Locale.ROOT).equals(searchText) || 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.getLabel() != null && hashIndexEntry.getLabel().toLowerCase(Locale.ROOT).contains(searchText)) ||
(hashIndexEntry.getValue() != null && searchValue != null && Math.abs(hashIndexEntry.getValue()) == searchValue)) { (hashIndexEntry.getValue() != null && searchValue != null && Math.abs(hashIndexEntry.getValue()) == searchValue)) {
matchingEntries.add(entry); matchingEntries.add(entry);
@ -218,8 +226,9 @@ public class SearchWalletDialog extends Dialog<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);