mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-24 12:46:45 +00:00
implement bip329 for importing and exporting wallet labels
This commit is contained in:
parent
8d584d1c48
commit
555260e954
12 changed files with 359 additions and 13 deletions
2
drongo
2
drongo
|
@ -1 +1 @@
|
|||
Subproject commit b487396417fbdf3c73c24399a778855c97a26584
|
||||
Subproject commit d48054ac6ba071b49180017fe12e3acb41635b9c
|
|
@ -1068,11 +1068,14 @@ public class AppController implements Initializable {
|
|||
}
|
||||
|
||||
public void importWallet(ActionEvent event) {
|
||||
WalletImportDialog dlg = new WalletImportDialog();
|
||||
List<WalletForm> selectedWalletForms = getSelectedWalletForms();
|
||||
WalletImportDialog dlg = new WalletImportDialog(selectedWalletForms);
|
||||
Optional<Wallet> optionalWallet = dlg.showAndWait();
|
||||
if(optionalWallet.isPresent()) {
|
||||
Wallet wallet = optionalWallet.get();
|
||||
addImportedWallet(wallet);
|
||||
if(selectedWalletForms.isEmpty() || wallet != selectedWalletForms.get(0).getWallet()) {
|
||||
addImportedWallet(wallet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1653,6 +1656,19 @@ public class AppController implements Initializable {
|
|||
return null;
|
||||
}
|
||||
|
||||
public List<WalletForm> getSelectedWalletForms() {
|
||||
Tab selectedTab = tabs.getSelectionModel().getSelectedItem();
|
||||
if(selectedTab != null) {
|
||||
TabData tabData = (TabData) selectedTab.getUserData();
|
||||
if(tabData instanceof WalletTabData) {
|
||||
TabPane subTabs = (TabPane) selectedTab.getContent();
|
||||
return subTabs.getTabs().stream().map(subTab -> ((WalletTabData) subTab.getUserData()).getWalletForm()).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private void addTransactionTab(String name, File file, String string) throws ParseException, PSBTParseException, TransactionParseException {
|
||||
if(Utils.isBase64(string) && !Utils.isHex(string)) {
|
||||
addTransactionTab(name, file, Base64.getDecoder().decode(string));
|
||||
|
|
|
@ -975,7 +975,7 @@ public class DevicePane extends TitledDescriptionPane {
|
|||
}
|
||||
importButton.setVisible(true);
|
||||
showHideLink.setText("Show derivation...");
|
||||
showHideLink.setVisible(true);
|
||||
showHideLink.setVisible(!device.isCard());
|
||||
List<ChildNumber> defaultDerivation = wallet.getScriptType() == null ? ScriptType.P2WPKH.getDefaultDerivation() : wallet.getScriptType().getDefaultDerivation();
|
||||
setContent(getDerivationEntry(keyDerivation == null ? defaultDerivation : keyDerivation.getDerivation()));
|
||||
} else if(deviceOperation.equals(DeviceOperation.SIGN)) {
|
||||
|
|
|
@ -42,9 +42,9 @@ public class WalletExportDialog extends Dialog<Wallet> {
|
|||
|
||||
List<WalletExport> exporters;
|
||||
if(wallet.getPolicyType() == PolicyType.SINGLE) {
|
||||
exporters = List.of(new Electrum(), new ElectrumPersonalServer(), new Descriptor(), new SpecterDesktop(), new Sparrow());
|
||||
exporters = List.of(new Electrum(), new ElectrumPersonalServer(), new Descriptor(), new SpecterDesktop(), new Sparrow(), new WalletLabels());
|
||||
} else if(wallet.getPolicyType() == PolicyType.MULTI) {
|
||||
exporters = List.of(new CaravanMultisig(), new ColdcardMultisig(), new CoboVaultMultisig(), new Electrum(), new ElectrumPersonalServer(), new KeystoneMultisig(), new Descriptor(), new JadeMultisig(), new PassportMultisig(), new SpecterDesktop(), new BlueWalletMultisig(), new SpecterDIY(), new Sparrow());
|
||||
exporters = List.of(new CaravanMultisig(), new ColdcardMultisig(), new CoboVaultMultisig(), new Electrum(), new ElectrumPersonalServer(), new KeystoneMultisig(), new Descriptor(), new JadeMultisig(), new PassportMultisig(), new SpecterDesktop(), new BlueWalletMultisig(), new SpecterDIY(), new Sparrow(), new WalletLabels());
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Cannot export wallet with policy type " + wallet.getPolicyType());
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import com.sparrowwallet.sparrow.event.WalletImportEvent;
|
|||
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
||||
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5Brands;
|
||||
import com.sparrowwallet.sparrow.io.*;
|
||||
import com.sparrowwallet.sparrow.wallet.WalletForm;
|
||||
import javafx.application.Platform;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.*;
|
||||
|
@ -16,6 +17,7 @@ import javafx.scene.layout.AnchorPane;
|
|||
import javafx.scene.layout.StackPane;
|
||||
import org.controlsfx.glyphfont.Glyph;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -24,7 +26,7 @@ public class WalletImportDialog extends Dialog<Wallet> {
|
|||
private final Accordion importAccordion;
|
||||
private final Button scanButton;
|
||||
|
||||
public WalletImportDialog() {
|
||||
public WalletImportDialog(List<WalletForm> selectedWalletForms) {
|
||||
EventManager.get().register(this);
|
||||
setOnCloseRequest(event -> {
|
||||
EventManager.get().unregister(this);
|
||||
|
@ -57,7 +59,10 @@ public class WalletImportDialog extends Dialog<Wallet> {
|
|||
}
|
||||
}
|
||||
|
||||
List<WalletImport> walletImporters = List.of(new CaravanMultisig(), new ColdcardMultisig(), new CoboVaultMultisig(), new Electrum(), new KeystoneMultisig(), new Descriptor(), new SpecterDesktop(), new BlueWalletMultisig(), new Sparrow());
|
||||
List<WalletImport> walletImporters = new ArrayList<>(List.of(new CaravanMultisig(), new ColdcardMultisig(), new CoboVaultMultisig(), new Electrum(), new KeystoneMultisig(), new Descriptor(), new SpecterDesktop(), new BlueWalletMultisig(), new Sparrow()));
|
||||
if(!selectedWalletForms.isEmpty()) {
|
||||
walletImporters.add(new WalletLabels(selectedWalletForms));
|
||||
}
|
||||
for(WalletImport importer : walletImporters) {
|
||||
if(!importer.isDeprecated() || Config.get().isShowDeprecatedImportExport()) {
|
||||
FileWalletImportPane importPane = new FileWalletImportPane(importer);
|
||||
|
|
|
@ -11,22 +11,29 @@ import java.util.*;
|
|||
public class WalletEntryLabelsChangedEvent extends WalletChangedEvent {
|
||||
//Contains the changed entry mapped to the entry that changed it, if changed recursively (otherwise null)
|
||||
private final Map<Entry, Entry> entrySourceMap;
|
||||
private final boolean propagate;
|
||||
|
||||
public WalletEntryLabelsChangedEvent(Wallet wallet, Entry entry) {
|
||||
this(wallet, List.of(entry));
|
||||
}
|
||||
|
||||
public WalletEntryLabelsChangedEvent(Wallet wallet, List<Entry> entries) {
|
||||
this(wallet, entries, true);
|
||||
}
|
||||
|
||||
public WalletEntryLabelsChangedEvent(Wallet wallet, List<Entry> entries, boolean propagate) {
|
||||
super(wallet);
|
||||
this.entrySourceMap = new LinkedHashMap<>();
|
||||
for(Entry entry : entries) {
|
||||
entrySourceMap.put(entry, null);
|
||||
}
|
||||
this.propagate = propagate;
|
||||
}
|
||||
|
||||
public WalletEntryLabelsChangedEvent(Wallet wallet, Map<Entry, Entry> entrySourceMap) {
|
||||
super(wallet);
|
||||
this.entrySourceMap = entrySourceMap;
|
||||
this.propagate = true;
|
||||
}
|
||||
|
||||
public Collection<Entry> getEntries() {
|
||||
|
@ -36,4 +43,8 @@ public class WalletEntryLabelsChangedEvent extends WalletChangedEvent {
|
|||
public Entry getSource(Entry entry) {
|
||||
return entrySourceMap.get(entry);
|
||||
}
|
||||
|
||||
public boolean propagate() {
|
||||
return propagate;
|
||||
}
|
||||
}
|
||||
|
|
296
src/main/java/com/sparrowwallet/sparrow/io/WalletLabels.java
Normal file
296
src/main/java/com/sparrowwallet/sparrow/io/WalletLabels.java
Normal file
|
@ -0,0 +1,296 @@
|
|||
package com.sparrowwallet.sparrow.io;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.sparrowwallet.drongo.KeyPurpose;
|
||||
import com.sparrowwallet.drongo.OutputDescriptor;
|
||||
import com.sparrowwallet.drongo.wallet.*;
|
||||
import com.sparrowwallet.sparrow.AppServices;
|
||||
import com.sparrowwallet.sparrow.EventManager;
|
||||
import com.sparrowwallet.sparrow.event.KeystoreLabelsChangedEvent;
|
||||
import com.sparrowwallet.sparrow.event.WalletEntryLabelsChangedEvent;
|
||||
import com.sparrowwallet.sparrow.wallet.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
public class WalletLabels implements WalletImport, WalletExport {
|
||||
private static final Logger log = LoggerFactory.getLogger(WalletLabels.class);
|
||||
|
||||
private final List<WalletForm> walletForms;
|
||||
|
||||
public WalletLabels() {
|
||||
this.walletForms = Collections.emptyList();
|
||||
}
|
||||
|
||||
public WalletLabels(List<WalletForm> walletForms) {
|
||||
this.walletForms = walletForms;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEncrypted(File file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Wallet Labels";
|
||||
}
|
||||
|
||||
@Override
|
||||
public WalletModel getWalletModel() {
|
||||
return WalletModel.LABELS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exportWallet(Wallet wallet, OutputStream outputStream) throws ExportException {
|
||||
List<Label> labels = new ArrayList<>();
|
||||
List<Wallet> allWallets = wallet.isMasterWallet() ? wallet.getAllWallets() : wallet.getMasterWallet().getAllWallets();
|
||||
for(Wallet exportWallet : allWallets) {
|
||||
OutputDescriptor outputDescriptor = OutputDescriptor.getOutputDescriptor(exportWallet);
|
||||
String origin = outputDescriptor.toString(true, false, false);
|
||||
|
||||
for(Keystore keystore : exportWallet.getKeystores()) {
|
||||
if(keystore.getLabel() != null && !keystore.getLabel().isEmpty()) {
|
||||
labels.add(new Label(Type.xpub, keystore.getExtendedPublicKey().toString(), keystore.getLabel(), null));
|
||||
}
|
||||
}
|
||||
|
||||
for(BlockTransaction blkTx : exportWallet.getWalletTransactions().values()) {
|
||||
if(blkTx.getLabel() != null && !blkTx.getLabel().isEmpty()) {
|
||||
labels.add(new Label(Type.tx, blkTx.getHashAsString(), blkTx.getLabel(), origin));
|
||||
}
|
||||
}
|
||||
|
||||
for(WalletNode addressNode : exportWallet.getWalletAddresses().values()) {
|
||||
if(addressNode.getLabel() != null && !addressNode.getLabel().isEmpty()) {
|
||||
labels.add(new Label(Type.addr, addressNode.getAddress().toString(), addressNode.getLabel(), null));
|
||||
}
|
||||
}
|
||||
|
||||
for(BlockTransactionHashIndex txo : exportWallet.getWalletTxos().keySet()) {
|
||||
if(txo.getLabel() != null && !txo.getLabel().isEmpty()) {
|
||||
labels.add(new Label(Type.output, txo.toString(), txo.getLabel(), null));
|
||||
}
|
||||
|
||||
if(txo.isSpent() && txo.getSpentBy().getLabel() != null && !txo.getSpentBy().getLabel().isEmpty()) {
|
||||
labels.add(new Label(Type.input, txo.getSpentBy().toString(), txo.getSpentBy().getLabel(), null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Gson gson = new Gson();
|
||||
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8));
|
||||
|
||||
for(Label label : labels) {
|
||||
writer.write(gson.toJson(label) + "\n");
|
||||
}
|
||||
|
||||
writer.flush();
|
||||
} catch(Exception e) {
|
||||
log.error("Error exporting labels", e);
|
||||
throw new ExportException("Error exporting labels", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWalletExportDescription() {
|
||||
return "Exports a file containing labels from this wallet in the BIP329 standard format.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExportFileExtension(Wallet wallet) {
|
||||
return "jsonl";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWalletExportScannable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean walletExportRequiresDecryption() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWalletImportDescription() {
|
||||
return "Imports a file containing labels in the BIP329 standard format to the currently selected wallet.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Wallet importWallet(InputStream inputStream, String password) throws ImportException {
|
||||
if(walletForms.isEmpty()) {
|
||||
throw new IllegalStateException("No wallets to import labels for");
|
||||
}
|
||||
|
||||
Gson gson = new Gson();
|
||||
List<Label> labels = new ArrayList<>();
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
|
||||
String line;
|
||||
while((line = reader.readLine()) != null) {
|
||||
Label label;
|
||||
try {
|
||||
label = gson.fromJson(line, Label.class);
|
||||
} catch(Exception e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(label == null || label.type == null || label.ref == null || label.label == null || label.label.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
labels.add(label);
|
||||
}
|
||||
} catch(Exception e) {
|
||||
throw new ImportException("Error importing labels file", e);
|
||||
}
|
||||
|
||||
Map<Wallet, List<Keystore>> changedWalletKeystores = new LinkedHashMap<>();
|
||||
Map<Wallet, List<Entry>> changedWalletEntries = new LinkedHashMap<>();
|
||||
|
||||
for(WalletForm walletForm : walletForms) {
|
||||
Wallet wallet = walletForm.getWallet();
|
||||
if(!wallet.isValid()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
OutputDescriptor outputDescriptor = OutputDescriptor.getOutputDescriptor(wallet);
|
||||
String origin = outputDescriptor.toString(true, false, false);
|
||||
|
||||
List<Entry> transactionEntries = walletForm.getWalletTransactionsEntry().getChildren();
|
||||
List<Entry> addressEntries = new ArrayList<>();
|
||||
addressEntries.addAll(walletForm.getNodeEntry(KeyPurpose.RECEIVE).getChildren());
|
||||
addressEntries.addAll(walletForm.getNodeEntry(KeyPurpose.CHANGE).getChildren());
|
||||
List<Entry> utxoEntries = walletForm.getWalletUtxosEntry().getChildren();
|
||||
|
||||
for(Label label : labels) {
|
||||
if(label.origin != null && !label.origin.equals(origin)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(label.type == Type.xpub) {
|
||||
for(Keystore keystore : wallet.getKeystores()) {
|
||||
if(keystore.getExtendedPublicKey().toString().equals(label.ref)) {
|
||||
keystore.setLabel(label.label);
|
||||
List<Keystore> changedKeystores = changedWalletKeystores.computeIfAbsent(wallet, w -> new ArrayList<>());
|
||||
changedKeystores.add(keystore);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(label.type == Type.tx) {
|
||||
for(Entry entry : transactionEntries) {
|
||||
if(entry instanceof TransactionEntry transactionEntry) {
|
||||
BlockTransaction blkTx = transactionEntry.getBlockTransaction();
|
||||
if(blkTx.getHashAsString().equals(label.ref)) {
|
||||
transactionEntry.getBlockTransaction().setLabel(label.label);
|
||||
transactionEntry.labelProperty().set(label.label);
|
||||
addChangedEntry(changedWalletEntries, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(label.type == Type.addr) {
|
||||
for(Entry addressEntry : addressEntries) {
|
||||
if(addressEntry instanceof NodeEntry nodeEntry) {
|
||||
WalletNode addressNode = nodeEntry.getNode();
|
||||
if(addressNode.getAddress().toString().equals(label.ref)) {
|
||||
nodeEntry.getNode().setLabel(label.label);
|
||||
nodeEntry.labelProperty().set(label.label);
|
||||
addChangedEntry(changedWalletEntries, addressEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(label.type == Type.output || label.type == Type.input) {
|
||||
for(Entry entry : transactionEntries) {
|
||||
for(Entry hashIndexEntry : entry.getChildren()) {
|
||||
if(hashIndexEntry instanceof TransactionHashIndexEntry txioEntry) {
|
||||
BlockTransactionHashIndex reference = txioEntry.getHashIndex();
|
||||
if((label.type == Type.output && txioEntry.getType() == HashIndexEntry.Type.OUTPUT && reference.toString().equals(label.ref))
|
||||
|| (label.type == Type.input && txioEntry.getType() == HashIndexEntry.Type.INPUT && reference.toString().equals(label.ref))) {
|
||||
txioEntry.getHashIndex().setLabel(label.label);
|
||||
txioEntry.labelProperty().set(label.label);
|
||||
addChangedEntry(changedWalletEntries, txioEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for(Entry addressEntry : addressEntries) {
|
||||
for(Entry entry : addressEntry.getChildren()) {
|
||||
updateHashIndexEntryLabel(label, entry);
|
||||
for(Entry spentEntry : entry.getChildren()) {
|
||||
updateHashIndexEntryLabel(label, spentEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
for(Entry entry : utxoEntries) {
|
||||
updateHashIndexEntryLabel(label, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(Map.Entry<Wallet, List<Keystore>> walletKeystores : changedWalletKeystores.entrySet()) {
|
||||
Wallet wallet = walletKeystores.getKey();
|
||||
Storage storage = AppServices.get().getOpenWallets().get(wallet);
|
||||
EventManager.get().post(new KeystoreLabelsChangedEvent(wallet, wallet, storage.getWalletId(wallet), walletKeystores.getValue()));
|
||||
}
|
||||
|
||||
for(Map.Entry<Wallet, List<Entry>> walletEntries : changedWalletEntries.entrySet()) {
|
||||
EventManager.get().post(new WalletEntryLabelsChangedEvent(walletEntries.getKey(), walletEntries.getValue(), false));
|
||||
}
|
||||
|
||||
return walletForms.get(0).getWallet();
|
||||
}
|
||||
|
||||
private static void updateHashIndexEntryLabel(Label label, Entry entry) {
|
||||
if(entry instanceof HashIndexEntry hashIndexEntry) {
|
||||
BlockTransactionHashIndex reference = hashIndexEntry.getHashIndex();
|
||||
if((label.type == Type.output && hashIndexEntry.getType() == HashIndexEntry.Type.OUTPUT && reference.toString().equals(label.ref))
|
||||
|| (label.type == Type.input && hashIndexEntry.getType() == HashIndexEntry.Type.INPUT && reference.toString().equals(label.ref))) {
|
||||
hashIndexEntry.labelProperty().set(label.label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void addChangedEntry(Map<Wallet, List<Entry>> changedEntries, Entry entry) {
|
||||
List<Entry> entries = changedEntries.computeIfAbsent(entry.getWallet(), wallet -> new ArrayList<>());
|
||||
entries.add(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWalletImportScannable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exportsAllWallets() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private enum Type {
|
||||
tx, addr, pubkey, input, output, xpub
|
||||
}
|
||||
|
||||
private static class Label {
|
||||
public Label(Type type, String ref, String label, String origin) {
|
||||
this.type = type;
|
||||
this.ref = ref;
|
||||
this.label = label;
|
||||
this.origin = origin;
|
||||
}
|
||||
|
||||
Type type;
|
||||
String ref;
|
||||
String label;
|
||||
String origin;
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ import com.sparrowwallet.sparrow.io.CardApi;
|
|||
import com.sparrowwallet.sparrow.io.Storage;
|
||||
import com.sparrowwallet.sparrow.keystoreimport.KeystoreImportDialog;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.concurrent.Service;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
|
@ -96,6 +97,11 @@ public class KeystoreController extends WalletFormController implements Initiali
|
|||
|
||||
private final ValidationSupport validationSupport = new ValidationSupport();
|
||||
|
||||
private final ChangeListener<String> labelChangeListener = (observable, oldValue, newValue) -> {
|
||||
keystore.setLabel(newValue);
|
||||
EventManager.get().post(new SettingsChangedEvent(walletForm.getWallet(), SettingsChangedEvent.Type.KEYSTORE_LABEL));
|
||||
};
|
||||
|
||||
@Override
|
||||
public void initialize(URL location, ResourceBundle resources) {
|
||||
EventManager.get().register(this);
|
||||
|
@ -152,10 +158,7 @@ public class KeystoreController extends WalletFormController implements Initiali
|
|||
keystore.setKeyDerivation(new KeyDerivation("",""));
|
||||
}
|
||||
|
||||
label.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||
keystore.setLabel(newValue);
|
||||
EventManager.get().post(new SettingsChangedEvent(walletForm.getWallet(), SettingsChangedEvent.Type.KEYSTORE_LABEL));
|
||||
});
|
||||
label.textProperty().addListener(labelChangeListener);
|
||||
fingerprint.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||
keystore.setKeyDerivation(new KeyDerivation(newValue, keystore.getKeyDerivation().getDerivationPath()));
|
||||
fingerprintIcon.setHex(newValue.length() == 8 ? newValue : null);
|
||||
|
@ -597,4 +600,18 @@ public class KeystoreController extends WalletFormController implements Initiali
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void keystoreLabelsChanged(KeystoreLabelsChangedEvent event) {
|
||||
if(event.getWalletId().equals(walletForm.getWalletId())) {
|
||||
for(Keystore changedKeystore : event.getChangedKeystores()) {
|
||||
if(xpub.getText().trim().equals(changedKeystore.getExtendedPublicKey().toString()) && !label.getText().equals(changedKeystore.getLabel())) {
|
||||
label.textProperty().removeListener(labelChangeListener);
|
||||
label.setText(changedKeystore.getLabel());
|
||||
keystore.setLabel(changedKeystore.getLabel());
|
||||
label.textProperty().addListener(labelChangeListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -488,7 +488,8 @@ public class WalletForm {
|
|||
public void walletLabelsChanged(WalletEntryLabelsChangedEvent event) {
|
||||
if(event.toThisOrNested(wallet)) {
|
||||
Map<Entry, Entry> labelChangedEntries = new LinkedHashMap<>();
|
||||
for(Entry entry : event.getEntries()) {
|
||||
Collection<Entry> entries = event.propagate() ? event.getEntries() : Collections.emptyList();
|
||||
for(Entry entry : entries) {
|
||||
if(entry.getLabel() != null && !entry.getLabel().isEmpty()) {
|
||||
if(entry instanceof TransactionEntry transactionEntry) {
|
||||
for(KeyPurpose keyPurpose : KeyPurpose.DEFAULT_PURPOSES) {
|
||||
|
|
BIN
src/main/resources/image/labels.png
Normal file
BIN
src/main/resources/image/labels.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 979 B |
BIN
src/main/resources/image/labels@2x.png
Normal file
BIN
src/main/resources/image/labels@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
BIN
src/main/resources/image/labels@3x.png
Normal file
BIN
src/main/resources/image/labels@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.9 KiB |
Loading…
Reference in a new issue