refactor and cleanup importing

This commit is contained in:
Craig Raw 2020-05-13 18:15:46 +02:00
parent d516eaa9d6
commit 02258dea8d
13 changed files with 77 additions and 221 deletions

View file

@ -1,32 +0,0 @@
package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.io.Device;
import javafx.collections.ObservableList;
import javafx.scene.control.Accordion;
public class DeviceAccordion extends Accordion {
private ObservableList<Device> devices;
private DeviceOperation deviceOperation = DeviceOperation.IMPORT;
public void setDevices(Wallet wallet, ObservableList<Device> devices) {
this.devices = devices;
for(Device device : devices) {
DevicePane devicePane = new DevicePane(this, wallet, device);
this.getPanes().add(devicePane);
}
}
public DeviceOperation getDeviceOperation() {
return deviceOperation;
}
public void setDeviceOperation(DeviceOperation deviceOperation) {
this.deviceOperation = deviceOperation;
}
public enum DeviceOperation {
IMPORT;
}
}

View file

@ -12,14 +12,11 @@ import com.sparrowwallet.sparrow.io.Device;
import com.sparrowwallet.sparrow.io.Hwi; import com.sparrowwallet.sparrow.io.Hwi;
import com.sparrowwallet.drongo.wallet.WalletModel; import com.sparrowwallet.drongo.wallet.WalletModel;
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5; import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.geometry.Pos; import javafx.geometry.Pos;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.control.*; import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*; import javafx.scene.layout.*;
import org.controlsfx.control.textfield.CustomPasswordField; import org.controlsfx.control.textfield.CustomPasswordField;
import org.controlsfx.control.textfield.CustomTextField; import org.controlsfx.control.textfield.CustomTextField;
@ -32,115 +29,28 @@ import org.controlsfx.validation.decoration.StyleClassValidationDecoration;
import java.util.List; import java.util.List;
public class DevicePane extends TitledPane { public class DevicePane extends TitledDescriptionPane {
private final DeviceAccordion deviceAccordion; private final DeviceOperation deviceOperation;
private final Wallet wallet; private final Wallet wallet;
private final Device device; private final Device device;
private Label mainLabel;
private Label statusLabel;
private Hyperlink showHideLink;
private CustomPasswordField pinField; private CustomPasswordField pinField;
private CustomTextField passphraseField;
private Button unlockButton; private Button unlockButton;
private Button enterPinButton; private Button enterPinButton;
private Button setPassphraseButton; private Button setPassphraseButton;
private SplitMenuButton importButton; private SplitMenuButton importButton;
private final SimpleStringProperty status = new SimpleStringProperty("");
private final SimpleStringProperty passphrase = new SimpleStringProperty(""); private final SimpleStringProperty passphrase = new SimpleStringProperty("");
public DevicePane(DeviceAccordion deviceAccordion, Wallet wallet, Device device) { public DevicePane(DeviceOperation deviceOperation, Wallet wallet, Device device) {
super(); super(device.getModel().toDisplayString(), "", "", "image/" + device.getType() + ".png");
this.deviceAccordion = deviceAccordion; this.deviceOperation = deviceOperation;
this.wallet = wallet; this.wallet = wallet;
this.device = device; this.device = device;
setPadding(Insets.EMPTY);
setGraphic(getTitle());
getStyleClass().add("titled-description-pane");
setDefaultStatus(); setDefaultStatus();
removeArrow();
}
private void removeArrow() {
Platform.runLater(() -> {
Node arrow = this.lookup(".arrow");
if (arrow != null) {
arrow.setVisible(false);
arrow.setManaged(false);
} else {
removeArrow();
}
});
}
private void setDefaultStatus() {
setStatus(device.getNeedsPinSent() ? "Locked" : device.getNeedsPassphraseSent() ? "Passphrase Required" : "Unlocked");
}
private Node getTitle() {
HBox listItem = new HBox();
listItem.setPadding(new Insets(10, 20, 10, 10));
listItem.setSpacing(10);
HBox imageBox = new HBox();
imageBox.setMinWidth(50);
imageBox.setMinHeight(50);
listItem.getChildren().add(imageBox);
Image image = new Image("image/" + device.getType() + ".png", 50, 50, true, true);
if (!image.isError()) {
ImageView imageView = new ImageView();
imageView.setImage(image);
imageBox.getChildren().add(imageView);
}
VBox labelsBox = new VBox();
labelsBox.setSpacing(5);
labelsBox.setAlignment(Pos.CENTER_LEFT);
this.mainLabel = new Label();
mainLabel.setText(device.getModel().toDisplayString());
mainLabel.getStyleClass().add("main-label");
labelsBox.getChildren().add(mainLabel);
HBox statusBox = new HBox();
statusBox.setSpacing(7);
this.statusLabel = new Label();
statusLabel.getStyleClass().add("status-label");
statusLabel.textProperty().bind(status);
statusBox.getChildren().add(statusLabel);
showHideLink = new Hyperlink("Show details...");
showHideLink.managedProperty().bind(showHideLink.visibleProperty());
showHideLink.setVisible(false); showHideLink.setVisible(false);
showHideLink.setOnAction(event -> {
if(this.isExpanded()) {
setExpanded(false);
} else {
setExpanded(true);
}
});
this.expandedProperty().addListener((observable, oldValue, newValue) -> {
if(newValue) {
showHideLink.setText(showHideLink.getText().replace("Show", "Hide"));
} else {
showHideLink.setText(showHideLink.getText().replace("Hide", "Show"));
}
});
statusBox.getChildren().add(showHideLink);
labelsBox.getChildren().add(statusBox);
listItem.getChildren().add(labelsBox);
HBox.setHgrow(labelsBox, Priority.ALWAYS);
HBox buttonBox = new HBox();
buttonBox.setAlignment(Pos.CENTER_RIGHT);
createUnlockButton();
createSetPassphraseButton(); createSetPassphraseButton();
createImportButton(); createImportButton();
@ -152,15 +62,17 @@ public class DevicePane extends TitledPane {
showOperationButton(); showOperationButton();
} }
buttonBox.getChildren().addAll(unlockButton, setPassphraseButton, importButton); buttonBox.getChildren().addAll(setPassphraseButton, importButton);
listItem.getChildren().add(buttonBox); }
this.layoutBoundsProperty().addListener((observable, oldValue, newValue) -> { @Override
//Hack to force listItem to expand to full available width less border protected Control createButton() {
listItem.setPrefWidth(newValue.getWidth() - 2); createUnlockButton();
}); return unlockButton;
}
return listItem; private void setDefaultStatus() {
setDescription(device.getNeedsPinSent() ? "Locked" : device.getNeedsPassphraseSent() ? "Passphrase Required" : "Unlocked");
} }
private void createUnlockButton() { private void createUnlockButton() {
@ -256,7 +168,7 @@ public class DevicePane extends TitledPane {
} }
private Node getPassphraseEntry() { private Node getPassphraseEntry() {
passphraseField = (CustomTextField)TextFields.createClearableTextField(); CustomTextField passphraseField = (CustomTextField)TextFields.createClearableTextField();
passphrase.bind(passphraseField.textProperty()); passphrase.bind(passphraseField.textProperty());
HBox.setHgrow(passphraseField, Priority.ALWAYS); HBox.setHgrow(passphraseField, Priority.ALWAYS);
@ -284,12 +196,12 @@ public class DevicePane extends TitledPane {
setContent(getPinEntry()); setContent(getPinEntry());
setExpanded(true); setExpanded(true);
} else { } else {
setErrorStatus("Could not request PIN"); setError("Could not request PIN", null);
unlockButton.setDisable(false); unlockButton.setDisable(false);
} }
}); });
promptPinService.setOnFailed(workerStateEvent -> { promptPinService.setOnFailed(workerStateEvent -> {
setErrorStatus(promptPinService.getException().getMessage()); setError(promptPinService.getException().getMessage(), null);
unlockButton.setDisable(false); unlockButton.setDisable(false);
}); });
promptPinService.start(); promptPinService.start();
@ -314,7 +226,7 @@ public class DevicePane extends TitledPane {
showOperationButton(); showOperationButton();
} }
} else { } else {
setErrorStatus("Incorrect PIN"); setError("Incorrect PIN", null);
enterPinButton.setDisable(false); enterPinButton.setDisable(false);
if(pinField != null) { if(pinField != null) {
pinField.setText(""); pinField.setText("");
@ -322,7 +234,7 @@ public class DevicePane extends TitledPane {
} }
}); });
sendPinService.setOnFailed(workerStateEvent -> { sendPinService.setOnFailed(workerStateEvent -> {
setErrorStatus(sendPinService.getException().getMessage()); setError(sendPinService.getException().getMessage(), null);
enterPinButton.setDisable(false); enterPinButton.setDisable(false);
}); });
sendPinService.start(); sendPinService.start();
@ -344,13 +256,13 @@ public class DevicePane extends TitledPane {
setDefaultStatus(); setDefaultStatus();
showOperationButton(); showOperationButton();
} else { } else {
setErrorStatus("Passphrase send failed"); setError("Passphrase send failed", null);
setPassphraseButton.setDisable(false); setPassphraseButton.setDisable(false);
setPassphraseButton.setVisible(true); setPassphraseButton.setVisible(true);
} }
}); });
enumerateService.setOnFailed(workerStateEvent -> { enumerateService.setOnFailed(workerStateEvent -> {
setErrorStatus(enumerateService.getException().getMessage()); setError(enumerateService.getException().getMessage(), null);
setPassphraseButton.setDisable(false); setPassphraseButton.setDisable(false);
setPassphraseButton.setVisible(true); setPassphraseButton.setVisible(true);
}); });
@ -371,7 +283,7 @@ public class DevicePane extends TitledPane {
importXpub(derivation); importXpub(derivation);
}); });
enumerateService.setOnFailed(workerStateEvent -> { enumerateService.setOnFailed(workerStateEvent -> {
setErrorStatus(enumerateService.getException().getMessage()); setError(enumerateService.getException().getMessage(), null);
importButton.setDisable(false); importButton.setDisable(false);
}); });
enumerateService.start(); enumerateService.start();
@ -397,24 +309,14 @@ public class DevicePane extends TitledPane {
EventManager.get().post(new KeystoreImportEvent(keystore)); EventManager.get().post(new KeystoreImportEvent(keystore));
}); });
getXpubService.setOnFailed(workerStateEvent -> { getXpubService.setOnFailed(workerStateEvent -> {
setErrorStatus(getXpubService.getException().getMessage()); setError(getXpubService.getException().getMessage(), null);
importButton.setDisable(false); importButton.setDisable(false);
}); });
getXpubService.start(); getXpubService.start();
} }
private void setStatus(String statusMessage) {
statusLabel.getStyleClass().remove("status-error");
status.setValue(statusMessage);
}
private void setErrorStatus(String statusMessage) {
statusLabel.getStyleClass().add("status-error");
status.setValue(statusMessage);
}
private void showOperationButton() { private void showOperationButton() {
if(deviceAccordion.getDeviceOperation().equals(DeviceAccordion.DeviceOperation.IMPORT)) { if(deviceOperation.equals(DeviceOperation.IMPORT)) {
importButton.setVisible(true); importButton.setVisible(true);
showHideLink.setText("Show derivation..."); showHideLink.setText("Show derivation...");
showHideLink.setVisible(true); showHideLink.setVisible(true);
@ -459,4 +361,8 @@ public class DevicePane extends TitledPane {
return contentBox; return contentBox;
} }
public enum DeviceOperation {
IMPORT;
}
} }

View file

@ -1,32 +0,0 @@
package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.io.KeystoreFileImport;
import com.sparrowwallet.sparrow.io.KeystoreImport;
import com.sparrowwallet.sparrow.io.KeystoreMnemonicImport;
import javafx.collections.ObservableList;
import javafx.scene.control.Accordion;
import java.util.List;
public class KeystoreImportAccordion extends Accordion {
private List<KeystoreImport> importers;
public void setKeystoreImporters(Wallet wallet, ObservableList<KeystoreImport> importers) {
this.importers = importers;
for(KeystoreImport importer : importers) {
TitledDescriptionPane importPane = null;
if(importer instanceof KeystoreFileImport) {
importPane = new FileKeystoreImportPane(wallet, (KeystoreFileImport)importer);
} else if(importer instanceof KeystoreMnemonicImport) {
importPane = new MnemonicKeystoreImportPane(wallet, (KeystoreMnemonicImport)importer);
} else {
throw new IllegalArgumentException("Could not create ImportPane for importer of type " + importer.getClass());
}
this.getPanes().add(importPane);
}
}
}

View file

@ -106,9 +106,11 @@ public class TitledDescriptionPane extends TitledPane {
descriptionLabel.getStyleClass().remove("description-label"); descriptionLabel.getStyleClass().remove("description-label");
descriptionLabel.getStyleClass().add("description-error"); descriptionLabel.getStyleClass().add("description-error");
descriptionLabel.setText(title); descriptionLabel.setText(title);
if(detail != null && !detail.isEmpty()) {
setContent(getContentBox(detail)); setContent(getContentBox(detail));
setExpanded(true); setExpanded(true);
} }
}
protected Node getContentBox(String message) { protected Node getContentBox(String message) {
Label details = new Label(message); Label details = new Label(message);

View file

@ -26,8 +26,7 @@ public class WalletImportDialog extends Dialog<Wallet> {
stackPane.getChildren().add(anchorPane); stackPane.getChildren().add(anchorPane);
ScrollPane scrollPane = new ScrollPane(); ScrollPane scrollPane = new ScrollPane();
scrollPane.setPrefWidth(500); scrollPane.setPrefHeight(280);
scrollPane.setPrefHeight(500);
scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
anchorPane.getChildren().add(scrollPane); anchorPane.getChildren().add(scrollPane);
scrollPane.setFitToWidth(true); scrollPane.setFitToWidth(true);
@ -44,8 +43,8 @@ public class WalletImportDialog extends Dialog<Wallet> {
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); dialogPane.getButtonTypes().addAll(cancelButtonType);
dialogPane.setPrefWidth(650); dialogPane.setPrefWidth(500);
dialogPane.setPrefHeight(600); dialogPane.setPrefHeight(360);
setResultConverter(dialogButton -> dialogButton != cancelButtonType ? wallet : null); setResultConverter(dialogButton -> dialogButton != cancelButtonType ? wallet : null);
} }

View file

@ -46,7 +46,7 @@ public class ColdcardSinglesig implements KeystoreFileImport {
Map<String, JsonElement> map = gson.fromJson(new InputStreamReader(inputStream), stringStringMap); Map<String, JsonElement> map = gson.fromJson(new InputStreamReader(inputStream), stringStringMap);
if (map.get("xfp") == null) { if (map.get("xfp") == null) {
throw new ImportException("This is not a valid Coldcard wallet export"); throw new ImportException("File was not a valid Coldcard wallet export");
} }
String masterFingerprint = map.get("xfp").getAsString(); String masterFingerprint = map.get("xfp").getAsString();

View file

@ -43,7 +43,7 @@ public class Electrum implements KeystoreFileImport, WalletImport, WalletExport
Wallet wallet = importWallet(inputStream, password); Wallet wallet = importWallet(inputStream, password);
if(!wallet.getPolicyType().equals(PolicyType.SINGLE) || wallet.getKeystores().size() != 1) { if(!wallet.getPolicyType().equals(PolicyType.SINGLE) || wallet.getKeystores().size() != 1) {
throw new ImportException("Multisig wallet detected - import it using File > Import > Electrum"); throw new ImportException("Multisig wallet detected - import it using File > Import Wallet");
} }
if(!wallet.getScriptType().equals(scriptType)) { if(!wallet.getScriptType().equals(scriptType)) {
@ -71,7 +71,7 @@ public class Electrum implements KeystoreFileImport, WalletImport, WalletExport
ElectrumJsonWallet ew = new ElectrumJsonWallet(); ElectrumJsonWallet ew = new ElectrumJsonWallet();
if(map.get("wallet_type") == null) { if(map.get("wallet_type") == null) {
throw new ImportException("This is not a valid Electrum wallet"); throw new ImportException("File was not a valid Electrum wallet");
} }
ew.wallet_type = map.get("wallet_type").getAsString(); ew.wallet_type = map.get("wallet_type").getAsString();

View file

@ -1,28 +1,29 @@
package com.sparrowwallet.sparrow.keystoreimport; package com.sparrowwallet.sparrow.keystoreimport;
import com.sparrowwallet.drongo.policy.PolicyType; import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.sparrow.control.KeystoreImportAccordion; import com.sparrowwallet.sparrow.control.FileKeystoreImportPane;
import com.sparrowwallet.sparrow.io.ColdcardMultisig; import com.sparrowwallet.sparrow.io.*;
import com.sparrowwallet.sparrow.io.ColdcardSinglesig;
import com.sparrowwallet.sparrow.io.KeystoreImport;
import javafx.collections.FXCollections;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.control.Accordion;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
public class HwAirgappedController extends KeystoreImportDetailController { public class HwAirgappedController extends KeystoreImportDetailController {
@FXML @FXML
private KeystoreImportAccordion importAccordion; private Accordion importAccordion;
public void initializeView() { public void initializeView() {
List<KeystoreImport> importers = Collections.emptyList(); List<KeystoreFileImport> importers = Collections.emptyList();
if(getMasterController().getWallet().getPolicyType().equals(PolicyType.SINGLE)) { if(getMasterController().getWallet().getPolicyType().equals(PolicyType.SINGLE)) {
importers = List.of(new ColdcardSinglesig()); importers = List.of(new ColdcardSinglesig());
} else if(getMasterController().getWallet().getPolicyType().equals(PolicyType.MULTI)) { } else if(getMasterController().getWallet().getPolicyType().equals(PolicyType.MULTI)) {
importers = List.of(new ColdcardMultisig()); importers = List.of(new ColdcardMultisig());
} }
importAccordion.setKeystoreImporters(getMasterController().getWallet(), FXCollections.observableList(importers)); for(KeystoreImport importer : importers) {
FileKeystoreImportPane importPane = new FileKeystoreImportPane(getMasterController().getWallet(), (KeystoreFileImport)importer);;
importAccordion.getPanes().add(importPane);
}
} }
} }

View file

@ -1,18 +1,21 @@
package com.sparrowwallet.sparrow.keystoreimport; package com.sparrowwallet.sparrow.keystoreimport;
import com.sparrowwallet.sparrow.control.DeviceAccordion; import com.sparrowwallet.sparrow.control.DevicePane;
import com.sparrowwallet.sparrow.io.Device; import com.sparrowwallet.sparrow.io.Device;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.control.Accordion;
import java.util.List; import java.util.List;
public class HwUsbDevicesController extends KeystoreImportDetailController { public class HwUsbDevicesController extends KeystoreImportDetailController {
@FXML @FXML
private DeviceAccordion deviceAccordion; private Accordion deviceAccordion;
public void initializeView(List<Device> devices) { public void initializeView(List<Device> devices) {
deviceAccordion.setDeviceOperation(DeviceAccordion.DeviceOperation.IMPORT); for(Device device : devices) {
deviceAccordion.setDevices(getMasterController().getWallet(), FXCollections.observableList(devices)); DevicePane devicePane = new DevicePane(DevicePane.DeviceOperation.IMPORT, getMasterController().getWallet(), device);
deviceAccordion.getPanes().add(devicePane);
}
} }
} }

View file

@ -1,20 +1,33 @@
package com.sparrowwallet.sparrow.keystoreimport; package com.sparrowwallet.sparrow.keystoreimport;
import com.sparrowwallet.sparrow.control.KeystoreImportAccordion; import com.sparrowwallet.sparrow.control.FileKeystoreImportPane;
import com.sparrowwallet.sparrow.io.Bip39; import com.sparrowwallet.sparrow.control.MnemonicKeystoreImportPane;
import com.sparrowwallet.sparrow.io.Electrum; import com.sparrowwallet.sparrow.control.TitledDescriptionPane;
import com.sparrowwallet.sparrow.io.KeystoreImport; import com.sparrowwallet.sparrow.io.*;
import javafx.collections.FXCollections;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.control.Accordion;
import java.util.List; import java.util.List;
public class SwController extends KeystoreImportDetailController { public class SwController extends KeystoreImportDetailController {
@FXML @FXML
private KeystoreImportAccordion importAccordion; private Accordion importAccordion;
public void initializeView() { public void initializeView() {
List<KeystoreImport> importers = List.of(new Bip39(), new Electrum()); List<KeystoreImport> importers = List.of(new Bip39(), new Electrum());
importAccordion.setKeystoreImporters(getMasterController().getWallet(), FXCollections.observableList(importers));
for(KeystoreImport importer : importers) {
TitledDescriptionPane importPane = null;
if(importer instanceof KeystoreFileImport) {
importPane = new FileKeystoreImportPane(getMasterController().getWallet(), (KeystoreFileImport)importer);
} else if(importer instanceof KeystoreMnemonicImport) {
importPane = new MnemonicKeystoreImportPane(getMasterController().getWallet(), (KeystoreMnemonicImport)importer);
} else {
throw new IllegalArgumentException("Could not create ImportPane for importer of type " + importer.getClass());
}
importAccordion.getPanes().add(importPane);
}
} }
} }

View file

@ -6,10 +6,8 @@
<?import javafx.scene.control.*?> <?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
<?import com.sparrowwallet.sparrow.control.KeystoreImportAccordion?>
<AnchorPane stylesheets="@keystoreimport.css" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:controller="com.sparrowwallet.sparrow.keystoreimport.HwAirgappedController"> <AnchorPane stylesheets="@keystoreimport.css" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:controller="com.sparrowwallet.sparrow.keystoreimport.HwAirgappedController">
<ScrollPane AnchorPane.leftAnchor="0" AnchorPane.rightAnchor="0" fitToWidth="true"> <ScrollPane AnchorPane.leftAnchor="0" AnchorPane.rightAnchor="0" fitToWidth="true">
<KeystoreImportAccordion fx:id="importAccordion" /> <Accordion fx:id="importAccordion" />
</ScrollPane> </ScrollPane>
</AnchorPane> </AnchorPane>

View file

@ -5,10 +5,9 @@
<?import javafx.scene.*?> <?import javafx.scene.*?>
<?import javafx.scene.control.*?> <?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
<?import com.sparrowwallet.sparrow.control.DeviceAccordion?>
<AnchorPane stylesheets="@keystoreimport.css" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:controller="com.sparrowwallet.sparrow.keystoreimport.HwUsbDevicesController"> <AnchorPane stylesheets="@keystoreimport.css" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:controller="com.sparrowwallet.sparrow.keystoreimport.HwUsbDevicesController">
<ScrollPane AnchorPane.leftAnchor="0" AnchorPane.rightAnchor="0" fitToWidth="true"> <ScrollPane AnchorPane.leftAnchor="0" AnchorPane.rightAnchor="0" fitToWidth="true">
<DeviceAccordion fx:id="deviceAccordion" /> <Accordion fx:id="deviceAccordion" />
</ScrollPane> </ScrollPane>
</AnchorPane> </AnchorPane>

View file

@ -5,10 +5,9 @@
<?import javafx.scene.*?> <?import javafx.scene.*?>
<?import javafx.scene.control.*?> <?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
<?import com.sparrowwallet.sparrow.control.KeystoreImportAccordion?>
<AnchorPane stylesheets="@keystoreimport.css" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:controller="com.sparrowwallet.sparrow.keystoreimport.SwController"> <AnchorPane stylesheets="@keystoreimport.css" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:controller="com.sparrowwallet.sparrow.keystoreimport.SwController">
<ScrollPane AnchorPane.leftAnchor="0" AnchorPane.rightAnchor="0" fitToWidth="true"> <ScrollPane AnchorPane.leftAnchor="0" AnchorPane.rightAnchor="0" fitToWidth="true">
<KeystoreImportAccordion fx:id="importAccordion" /> <Accordion fx:id="importAccordion" />
</ScrollPane> </ScrollPane>
</AnchorPane> </AnchorPane>