mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-24 12:46:45 +00:00
scan and import connected devices from import wallet dialog
This commit is contained in:
parent
e1f405d886
commit
7c6daf2e11
2 changed files with 86 additions and 19 deletions
|
@ -4,16 +4,15 @@ import com.sparrowwallet.drongo.ExtendedKey;
|
||||||
import com.sparrowwallet.drongo.KeyDerivation;
|
import com.sparrowwallet.drongo.KeyDerivation;
|
||||||
import com.sparrowwallet.drongo.OutputDescriptor;
|
import com.sparrowwallet.drongo.OutputDescriptor;
|
||||||
import com.sparrowwallet.drongo.crypto.ChildNumber;
|
import com.sparrowwallet.drongo.crypto.ChildNumber;
|
||||||
|
import com.sparrowwallet.drongo.policy.Policy;
|
||||||
|
import com.sparrowwallet.drongo.policy.PolicyType;
|
||||||
import com.sparrowwallet.drongo.protocol.ScriptType;
|
import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||||
import com.sparrowwallet.drongo.psbt.PSBT;
|
import com.sparrowwallet.drongo.psbt.PSBT;
|
||||||
import com.sparrowwallet.drongo.wallet.Keystore;
|
import com.sparrowwallet.drongo.wallet.Keystore;
|
||||||
import com.sparrowwallet.drongo.wallet.KeystoreSource;
|
import com.sparrowwallet.drongo.wallet.KeystoreSource;
|
||||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||||
import com.sparrowwallet.sparrow.EventManager;
|
import com.sparrowwallet.sparrow.EventManager;
|
||||||
import com.sparrowwallet.sparrow.event.AddressDisplayedEvent;
|
import com.sparrowwallet.sparrow.event.*;
|
||||||
import com.sparrowwallet.sparrow.event.KeystoreImportEvent;
|
|
||||||
import com.sparrowwallet.sparrow.event.MessageSignedEvent;
|
|
||||||
import com.sparrowwallet.sparrow.event.PSBTSignedEvent;
|
|
||||||
import com.sparrowwallet.sparrow.io.Device;
|
import com.sparrowwallet.sparrow.io.Device;
|
||||||
import com.sparrowwallet.sparrow.io.Hwi;
|
import com.sparrowwallet.sparrow.io.Hwi;
|
||||||
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
||||||
|
@ -34,6 +33,7 @@ import org.controlsfx.validation.decoration.StyleClassValidationDecoration;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@ -197,18 +197,31 @@ public class DevicePane extends TitledDescriptionPane {
|
||||||
importButton.setText("Import Keystore");
|
importButton.setText("Import Keystore");
|
||||||
importButton.setOnAction(event -> {
|
importButton.setOnAction(event -> {
|
||||||
importButton.setDisable(true);
|
importButton.setDisable(true);
|
||||||
importKeystore(wallet.getScriptType().getDefaultDerivation());
|
importKeystore(wallet.getScriptType() == null ? ScriptType.P2WPKH.getDefaultDerivation() : wallet.getScriptType().getDefaultDerivation());
|
||||||
});
|
});
|
||||||
String[] accounts = new String[] {"Default Account #0", "Account #1", "Account #2", "Account #3", "Account #4", "Account #5", "Account #6", "Account #7", "Account #8", "Account #9"};
|
if(wallet.getScriptType() == null) {
|
||||||
int scriptAccountsLength = ScriptType.P2SH.equals(wallet.getScriptType()) ? 1 : accounts.length;
|
ScriptType[] scriptTypes = new ScriptType[] {ScriptType.P2WPKH, ScriptType.P2SH_P2WPKH, ScriptType.P2PKH};
|
||||||
for(int i = 0; i < scriptAccountsLength; i++) {
|
for(ScriptType scriptType : scriptTypes) {
|
||||||
MenuItem item = new MenuItem(accounts[i]);
|
MenuItem item = new MenuItem(scriptType.getDescription());
|
||||||
final List<ChildNumber> derivation = wallet.getScriptType().getDefaultDerivation(i);
|
final List<ChildNumber> derivation = scriptType.getDefaultDerivation();
|
||||||
item.setOnAction(event -> {
|
item.setOnAction(event -> {
|
||||||
importButton.setDisable(true);
|
importButton.setDisable(true);
|
||||||
importKeystore(derivation);
|
importKeystore(derivation);
|
||||||
});
|
});
|
||||||
importButton.getItems().add(item);
|
importButton.getItems().add(item);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String[] accounts = new String[] {"Default Account #0", "Account #1", "Account #2", "Account #3", "Account #4", "Account #5", "Account #6", "Account #7", "Account #8", "Account #9"};
|
||||||
|
int scriptAccountsLength = ScriptType.P2SH.equals(wallet.getScriptType()) ? 1 : accounts.length;
|
||||||
|
for(int i = 0; i < scriptAccountsLength; i++) {
|
||||||
|
MenuItem item = new MenuItem(accounts[i]);
|
||||||
|
final List<ChildNumber> derivation = wallet.getScriptType().getDefaultDerivation(i);
|
||||||
|
item.setOnAction(event -> {
|
||||||
|
importButton.setDisable(true);
|
||||||
|
importKeystore(derivation);
|
||||||
|
});
|
||||||
|
importButton.getItems().add(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
importButton.managedProperty().bind(importButton.visibleProperty());
|
importButton.managedProperty().bind(importButton.visibleProperty());
|
||||||
importButton.setVisible(false);
|
importButton.setVisible(false);
|
||||||
|
@ -450,7 +463,18 @@ public class DevicePane extends TitledDescriptionPane {
|
||||||
keystore.setKeyDerivation(new KeyDerivation(device.getFingerprint(), derivationPath));
|
keystore.setKeyDerivation(new KeyDerivation(device.getFingerprint(), derivationPath));
|
||||||
keystore.setExtendedPublicKey(ExtendedKey.fromDescriptor(xpub));
|
keystore.setExtendedPublicKey(ExtendedKey.fromDescriptor(xpub));
|
||||||
|
|
||||||
EventManager.get().post(new KeystoreImportEvent(keystore));
|
if(wallet.getScriptType() == null) {
|
||||||
|
ScriptType scriptType = Arrays.stream(ScriptType.SINGLE_HASH_TYPES).filter(type -> type.getDefaultDerivation().get(0).equals(derivation.get(0))).findFirst().orElse(ScriptType.P2PKH);
|
||||||
|
wallet.setName(device.getModel().toDisplayString());
|
||||||
|
wallet.setPolicyType(PolicyType.SINGLE);
|
||||||
|
wallet.setScriptType(scriptType);
|
||||||
|
wallet.getKeystores().add(keystore);
|
||||||
|
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, scriptType, wallet.getKeystores(), null));
|
||||||
|
|
||||||
|
EventManager.get().post(new WalletImportEvent(wallet));
|
||||||
|
} else {
|
||||||
|
EventManager.get().post(new KeystoreImportEvent(keystore));
|
||||||
|
}
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
setError("Could not retrieve xpub", e.getMessage());
|
setError("Could not retrieve xpub", e.getMessage());
|
||||||
}
|
}
|
||||||
|
@ -513,7 +537,7 @@ public class DevicePane extends TitledDescriptionPane {
|
||||||
importButton.setVisible(true);
|
importButton.setVisible(true);
|
||||||
showHideLink.setText("Show derivation...");
|
showHideLink.setText("Show derivation...");
|
||||||
showHideLink.setVisible(true);
|
showHideLink.setVisible(true);
|
||||||
setContent(getDerivationEntry(wallet.getScriptType().getDefaultDerivation()));
|
setContent(getDerivationEntry(wallet.getScriptType() == null ? ScriptType.P2WPKH.getDefaultDerivation() : wallet.getScriptType().getDefaultDerivation()));
|
||||||
} else if(deviceOperation.equals(DeviceOperation.SIGN)) {
|
} else if(deviceOperation.equals(DeviceOperation.SIGN)) {
|
||||||
signButton.setVisible(true);
|
signButton.setVisible(true);
|
||||||
showHideLink.setVisible(false);
|
showHideLink.setVisible(false);
|
||||||
|
@ -562,6 +586,10 @@ public class DevicePane extends TitledDescriptionPane {
|
||||||
return contentBox;
|
return contentBox;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Device getDevice() {
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
public enum DeviceOperation {
|
public enum DeviceOperation {
|
||||||
IMPORT, SIGN, DISPLAY_ADDRESS, SIGN_MESSAGE;
|
IMPORT, SIGN, DISPLAY_ADDRESS, SIGN_MESSAGE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,16 +4,24 @@ import com.google.common.eventbus.Subscribe;
|
||||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||||
import com.sparrowwallet.sparrow.AppServices;
|
import com.sparrowwallet.sparrow.AppServices;
|
||||||
import com.sparrowwallet.sparrow.EventManager;
|
import com.sparrowwallet.sparrow.EventManager;
|
||||||
|
import com.sparrowwallet.sparrow.event.UsbDeviceEvent;
|
||||||
import com.sparrowwallet.sparrow.event.WalletImportEvent;
|
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.io.*;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.event.ActionEvent;
|
||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
|
import org.controlsfx.glyphfont.Glyph;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class WalletImportDialog extends Dialog<Wallet> {
|
public class WalletImportDialog extends Dialog<Wallet> {
|
||||||
private Wallet wallet;
|
private Wallet wallet;
|
||||||
|
private final Accordion importAccordion;
|
||||||
|
private final Button scanButton;
|
||||||
|
|
||||||
public WalletImportDialog() {
|
public WalletImportDialog() {
|
||||||
EventManager.get().register(this);
|
EventManager.get().register(this);
|
||||||
|
@ -38,7 +46,7 @@ public class WalletImportDialog extends Dialog<Wallet> {
|
||||||
AnchorPane.setLeftAnchor(scrollPane, 0.0);
|
AnchorPane.setLeftAnchor(scrollPane, 0.0);
|
||||||
AnchorPane.setRightAnchor(scrollPane, 0.0);
|
AnchorPane.setRightAnchor(scrollPane, 0.0);
|
||||||
|
|
||||||
Accordion importAccordion = new Accordion();
|
importAccordion = new Accordion();
|
||||||
List<KeystoreFileImport> keystoreImporters = List.of(new ColdcardSinglesig(), new CoboVaultSinglesig(), new PassportSinglesig());
|
List<KeystoreFileImport> keystoreImporters = List.of(new ColdcardSinglesig(), new CoboVaultSinglesig(), new PassportSinglesig());
|
||||||
for(KeystoreFileImport importer : keystoreImporters) {
|
for(KeystoreFileImport importer : keystoreImporters) {
|
||||||
FileWalletKeystoreImportPane importPane = new FileWalletKeystoreImportPane(importer);
|
FileWalletKeystoreImportPane importPane = new FileWalletKeystoreImportPane(importer);
|
||||||
|
@ -53,7 +61,16 @@ public class WalletImportDialog extends Dialog<Wallet> {
|
||||||
scrollPane.setContent(importAccordion);
|
scrollPane.setContent(importAccordion);
|
||||||
|
|
||||||
final ButtonType cancelButtonType = new javafx.scene.control.ButtonType("Cancel", ButtonBar.ButtonData.CANCEL_CLOSE);
|
final ButtonType cancelButtonType = new javafx.scene.control.ButtonType("Cancel", ButtonBar.ButtonData.CANCEL_CLOSE);
|
||||||
dialogPane.getButtonTypes().addAll(cancelButtonType);
|
final ButtonType scanButtonType = new javafx.scene.control.ButtonType("Scan for Connected Devices", ButtonBar.ButtonData.LEFT);
|
||||||
|
dialogPane.getButtonTypes().addAll(scanButtonType, cancelButtonType);
|
||||||
|
|
||||||
|
scanButton = (Button) dialogPane.lookupButton(scanButtonType);
|
||||||
|
scanButton.setGraphic(new Glyph(FontAwesome5Brands.FONT_NAME, FontAwesome5Brands.Glyph.USB));
|
||||||
|
scanButton.addEventFilter(ActionEvent.ACTION, event -> {
|
||||||
|
scan();
|
||||||
|
event.consume();
|
||||||
|
});
|
||||||
|
|
||||||
dialogPane.setPrefWidth(500);
|
dialogPane.setPrefWidth(500);
|
||||||
dialogPane.setPrefHeight(500);
|
dialogPane.setPrefHeight(500);
|
||||||
|
|
||||||
|
@ -65,4 +82,26 @@ public class WalletImportDialog extends Dialog<Wallet> {
|
||||||
wallet = event.getWallet();
|
wallet = event.getWallet();
|
||||||
setResult(wallet);
|
setResult(wallet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void scan() {
|
||||||
|
Hwi.EnumerateService enumerateService = new Hwi.EnumerateService(null);
|
||||||
|
enumerateService.setOnSucceeded(workerStateEvent -> {
|
||||||
|
scanButton.setGraphic(new Glyph(FontAwesome5Brands.FONT_NAME, FontAwesome5Brands.Glyph.USB));
|
||||||
|
scanButton.setTooltip(null);
|
||||||
|
List<Device> devices = enumerateService.getValue();
|
||||||
|
importAccordion.getPanes().removeIf(titledPane -> titledPane instanceof DevicePane);
|
||||||
|
for(Device device : devices) {
|
||||||
|
DevicePane devicePane = new DevicePane(new Wallet(), device);
|
||||||
|
importAccordion.getPanes().add(0, devicePane);
|
||||||
|
}
|
||||||
|
Platform.runLater(() -> EventManager.get().post(new UsbDeviceEvent(devices)));
|
||||||
|
});
|
||||||
|
enumerateService.setOnFailed(workerStateEvent -> {
|
||||||
|
Glyph glyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.EXCLAMATION_CIRCLE);
|
||||||
|
glyph.getStyleClass().add("failure");
|
||||||
|
scanButton.setGraphic(glyph);
|
||||||
|
scanButton.setTooltip(new Tooltip(workerStateEvent.getSource().getException().getMessage()));
|
||||||
|
});
|
||||||
|
enumerateService.start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue