diff --git a/src/main/java/com/sparrowwallet/sparrow/MainApp.java b/src/main/java/com/sparrowwallet/sparrow/MainApp.java index 0c239e1c..8cd81b4e 100644 --- a/src/main/java/com/sparrowwallet/sparrow/MainApp.java +++ b/src/main/java/com/sparrowwallet/sparrow/MainApp.java @@ -3,7 +3,6 @@ package com.sparrowwallet.sparrow; import com.beust.jcommander.JCommander; import com.sparrowwallet.drongo.Network; import com.sparrowwallet.drongo.wallet.Wallet; -import com.sparrowwallet.sparrow.control.WelcomeDialog; import com.sparrowwallet.sparrow.glyphfont.FontAwesome5; import com.sparrowwallet.sparrow.glyphfont.FontAwesome5Brands; import com.sparrowwallet.sparrow.io.Config; @@ -52,7 +51,7 @@ public class MainApp extends Application { boolean createNewWallet = false; Mode mode = Config.get().getMode(); if(mode == null) { - WelcomeDialog welcomeDialog = new WelcomeDialog(getHostServices()); + WelcomeDialog welcomeDialog = new WelcomeDialog(); Optional optionalMode = welcomeDialog.showAndWait(); if(optionalMode.isPresent()) { mode = optionalMode.get(); diff --git a/src/main/java/com/sparrowwallet/sparrow/WelcomeController.java b/src/main/java/com/sparrowwallet/sparrow/WelcomeController.java new file mode 100644 index 00000000..42d4982d --- /dev/null +++ b/src/main/java/com/sparrowwallet/sparrow/WelcomeController.java @@ -0,0 +1,130 @@ +package com.sparrowwallet.sparrow; + +import com.sparrowwallet.sparrow.control.UnlabeledToggleSwitch; +import javafx.animation.PauseTransition; +import javafx.application.Platform; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.event.ActionEvent; +import javafx.event.Event; +import javafx.fxml.FXML; +import javafx.scene.input.MouseButton; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.VBox; +import javafx.util.Duration; +import org.controlsfx.control.StatusBar; + +public class WelcomeController { + @FXML + private VBox welcomeBox; + + @FXML + private VBox step1; + + @FXML + private VBox step2; + + @FXML + private VBox step3; + + @FXML + private VBox step4; + + @FXML + private StatusBar serverStatus; + + @FXML + private UnlabeledToggleSwitch serverToggle; + + public void initializeView() { + step1.managedProperty().bind(step1.visibleProperty()); + step2.managedProperty().bind(step2.visibleProperty()); + step3.managedProperty().bind(step3.visibleProperty()); + step4.managedProperty().bind(step4.visibleProperty()); + + step2.setVisible(false); + step3.setVisible(false); + step4.setVisible(false); + + welcomeBox.getStyleClass().add("offline"); + serverStatus.setText("Offline"); + serverToggle.selectedProperty().addListener((observable, oldValue, newValue) -> { + serverStatus.setText(newValue ? "Connected" : "Offline"); + }); + } + + public boolean next() { + if(step1.isVisible()) { + step1.setVisible(false); + step2.setVisible(true); + welcomeBox.getStyleClass().clear(); + welcomeBox.getStyleClass().add("public-electrum"); + PauseTransition wait = new PauseTransition(Duration.millis(200)); + wait.setOnFinished((e) -> { + serverToggle.setSelected(true); + serverStatus.setText("Connected to a Public Server"); + }); + wait.play(); + return true; + } + + if(step2.isVisible()) { + step2.setVisible(false); + step3.setVisible(true); + welcomeBox.getStyleClass().clear(); + welcomeBox.getStyleClass().add("bitcoin-core"); + serverToggle.setSelected(true); + serverStatus.setText("Connected to Bitcoin Core"); + return true; + } + + if(step3.isVisible()) { + step3.setVisible(false); + step4.setVisible(true); + welcomeBox.getStyleClass().clear(); + welcomeBox.getStyleClass().add("private-electrum"); + serverToggle.setSelected(true); + serverStatus.setText("Connected to a Private Electrum Server"); + } + + return false; + } + + public boolean back() { + if(step2.isVisible()) { + step2.setVisible(false); + step1.setVisible(true); + welcomeBox.getStyleClass().clear(); + welcomeBox.getStyleClass().add("offline"); + PauseTransition wait = new PauseTransition(Duration.millis(200)); + wait.setOnFinished((e) -> { + serverToggle.setSelected(false); + serverStatus.setText("Offline"); + }); + wait.play(); + return false; + } + + if(step3.isVisible()) { + step3.setVisible(false); + step2.setVisible(true); + welcomeBox.getStyleClass().clear(); + welcomeBox.getStyleClass().add("public-electrum"); + serverToggle.setSelected(true); + serverStatus.setText("Connected to a Public Server"); + return true; + } + + if(step4.isVisible()) { + step4.setVisible(false); + step3.setVisible(true); + welcomeBox.getStyleClass().clear(); + welcomeBox.getStyleClass().add("bitcoin-core"); + serverToggle.setSelected(true); + serverStatus.setText("Connected to Bitcoin Core"); + return true; + } + + return false; + } +} diff --git a/src/main/java/com/sparrowwallet/sparrow/WelcomeDialog.java b/src/main/java/com/sparrowwallet/sparrow/WelcomeDialog.java new file mode 100644 index 00000000..c64321bf --- /dev/null +++ b/src/main/java/com/sparrowwallet/sparrow/WelcomeDialog.java @@ -0,0 +1,69 @@ +package com.sparrowwallet.sparrow; + +import javafx.event.ActionEvent; +import javafx.fxml.FXMLLoader; +import javafx.scene.control.*; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; + +import java.io.IOException; + +public class WelcomeDialog extends Dialog { + public WelcomeDialog() { + final DialogPane dialogPane = getDialogPane(); + AppServices.setStageIcon(dialogPane.getScene().getWindow()); + + try { + FXMLLoader welcomeLoader = new FXMLLoader(AppServices.class.getResource("welcome.fxml")); + dialogPane.setContent(welcomeLoader.load()); + WelcomeController welcomeController = welcomeLoader.getController(); + welcomeController.initializeView(); + + dialogPane.setPrefWidth(600); + dialogPane.setPrefHeight(520); + + dialogPane.getStylesheets().add(AppServices.class.getResource("welcome.css").toExternalForm()); + + final ButtonType nextButtonType = new javafx.scene.control.ButtonType("Next", ButtonBar.ButtonData.OK_DONE); + final ButtonType backButtonType = new javafx.scene.control.ButtonType("Back", ButtonBar.ButtonData.LEFT); + final ButtonType onlineButtonType = new javafx.scene.control.ButtonType("Configure Server", ButtonBar.ButtonData.APPLY); + final ButtonType offlineButtonType = new javafx.scene.control.ButtonType("Later or Offline Mode", ButtonBar.ButtonData.CANCEL_CLOSE); + dialogPane.getButtonTypes().addAll(nextButtonType, backButtonType, onlineButtonType, offlineButtonType); + + Button nextButton = (Button)dialogPane.lookupButton(nextButtonType); + Button backButton = (Button)dialogPane.lookupButton(backButtonType); + Button onlineButton = (Button)dialogPane.lookupButton(onlineButtonType); + Button offlineButton = (Button)dialogPane.lookupButton(offlineButtonType); + + nextButton.managedProperty().bind(nextButton.visibleProperty()); + backButton.managedProperty().bind(backButton.visibleProperty()); + onlineButton.managedProperty().bind(onlineButton.visibleProperty()); + offlineButton.managedProperty().bind(offlineButton.visibleProperty()); + + backButton.setDisable(true); + onlineButton.visibleProperty().bind(nextButton.visibleProperty().not()); + offlineButton.visibleProperty().bind(nextButton.visibleProperty().not()); + + nextButton.addEventFilter(ActionEvent.ACTION, event -> { + if(!welcomeController.next()) { + nextButton.setVisible(false); + onlineButton.setDefaultButton(true); + } + backButton.setDisable(false); + event.consume(); + }); + + backButton.addEventFilter(ActionEvent.ACTION, event -> { + nextButton.setVisible(true); + if(!welcomeController.back()) { + backButton.setDisable(true); + } + event.consume(); + }); + + setResultConverter(dialogButton -> dialogButton == onlineButtonType ? Mode.ONLINE : Mode.OFFLINE); + } catch(IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/com/sparrowwallet/sparrow/control/WelcomeDialog.java b/src/main/java/com/sparrowwallet/sparrow/control/WelcomeDialog.java deleted file mode 100644 index 80117413..00000000 --- a/src/main/java/com/sparrowwallet/sparrow/control/WelcomeDialog.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.sparrowwallet.sparrow.control; - -import com.sparrowwallet.sparrow.AppServices; -import com.sparrowwallet.sparrow.Mode; -import com.sparrowwallet.sparrow.net.ServerType; -import javafx.application.HostServices; -import javafx.geometry.Insets; -import javafx.scene.control.*; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import javafx.scene.layout.VBox; -import org.controlsfx.control.StatusBar; -import org.controlsfx.control.ToggleSwitch; - -public class WelcomeDialog extends Dialog { - private final HostServices hostServices; - - private ServerType serverType = ServerType.ELECTRUM_SERVER; - - public WelcomeDialog(HostServices services) { - this.hostServices = services; - - final DialogPane dialogPane = getDialogPane(); - - setTitle("Welcome to Sparrow"); - dialogPane.setHeaderText("Welcome to Sparrow!"); - dialogPane.getStylesheets().add(AppServices.class.getResource("app.css").toExternalForm()); - dialogPane.getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm()); - AppServices.setStageIcon(dialogPane.getScene().getWindow()); - dialogPane.setPrefWidth(600); - dialogPane.setPrefHeight(520); - - Image image = new Image("image/sparrow-small.png", 50, 50, false, false); - if (!image.isError()) { - ImageView imageView = new ImageView(); - imageView.setSmooth(false); - imageView.setImage(image); - dialogPane.setGraphic(imageView); - } - - final ButtonType onlineButtonType = new javafx.scene.control.ButtonType("Configure Server", ButtonBar.ButtonData.OK_DONE); - final ButtonType offlineButtonType = new javafx.scene.control.ButtonType("Later or Offline Mode", ButtonBar.ButtonData.CANCEL_CLOSE); - dialogPane.getButtonTypes().addAll(onlineButtonType, offlineButtonType); - - final VBox content = new VBox(20); - content.setPadding(new Insets(20, 20, 20, 20)); - content.getChildren().add(createParagraph("Sparrow can operate in both an online and offline mode. In the online mode it connects to your Bitcoin Core node or Electrum server to display transaction history. In the offline mode it is useful as a transaction editor and as an airgapped multisig coordinator.")); - content.getChildren().add(createParagraph("Connecting Sparrow to your Bitcoin Core node ensures your privacy, while connecting Sparrow to your own Electrum server ensures wallets load quicker, you have access to a full blockchain explorer, and your public keys are always encrypted on disk. Examples of Electrum servers include ElectrumX and electrs.")); - content.getChildren().add(createParagraph("Sparrow can also be configured to connect to a public Electrum server, but be aware that this configuration means that server can see your transactions.")); - content.getChildren().add(createParagraph("You can change your mode at any time using the toggle in the status bar. A blue toggle indicates you are connected to an Electrum server, while a green toggle indicates you are connected to a Bitcoin Code node, and a yellow toggle means you are using a public server.")); - content.getChildren().add(createStatusBar(onlineButtonType, offlineButtonType)); - - dialogPane.setContent(content); - - setResultConverter(dialogButton -> dialogButton == onlineButtonType ? Mode.ONLINE : Mode.OFFLINE); - } - - private Label createParagraph(String text) { - Label label = new Label(text); - label.setWrapText(true); - - return label; - } - - private StatusBar createStatusBar(ButtonType onlineButtonType, ButtonType offlineButtonType) { - StatusBar statusBar = new StatusBar(); - statusBar.setText("Online Mode"); - statusBar.getRightItems().add(createToggle(statusBar, onlineButtonType, offlineButtonType)); - - return statusBar; - } - - private ToggleSwitch createToggle(StatusBar statusBar, ButtonType onlineButtonType, ButtonType offlineButtonType) { - ToggleSwitch toggleSwitch = new UnlabeledToggleSwitch(); - toggleSwitch.setStyle("-fx-padding: 1px 0 0 0"); - - toggleSwitch.selectedProperty().addListener((observable, oldValue, newValue) -> { - Button onlineButton = (Button) getDialogPane().lookupButton(onlineButtonType); - onlineButton.setDefaultButton(newValue); - Button offlineButton = (Button) getDialogPane().lookupButton(offlineButtonType); - offlineButton.setDefaultButton(!newValue); - - if(!newValue) { - serverType = (serverType == ServerType.BITCOIN_CORE ? ServerType.PUBLIC_ELECTRUM_SERVER : (serverType == ServerType.PUBLIC_ELECTRUM_SERVER ? ServerType.ELECTRUM_SERVER : ServerType.BITCOIN_CORE)); - - if(serverType == ServerType.PUBLIC_ELECTRUM_SERVER && !toggleSwitch.getStyleClass().contains("public-server")) { - toggleSwitch.getStyleClass().add("public-server"); - } else { - toggleSwitch.getStyleClass().remove("public-server"); - } - - if(serverType == ServerType.BITCOIN_CORE && !toggleSwitch.getStyleClass().contains("core-server")) { - toggleSwitch.getStyleClass().add("core-server"); - } else { - toggleSwitch.getStyleClass().remove("core-server"); - } - } - - statusBar.setText(newValue ? "Online Mode: " + serverType.getName() : "Offline Mode"); - }); - - toggleSwitch.setSelected(true); - return toggleSwitch; - } -} diff --git a/src/main/resources/com/sparrowwallet/sparrow/preferences/server.fxml b/src/main/resources/com/sparrowwallet/sparrow/preferences/server.fxml index c2274548..e8328380 100644 --- a/src/main/resources/com/sparrowwallet/sparrow/preferences/server.fxml +++ b/src/main/resources/com/sparrowwallet/sparrow/preferences/server.fxml @@ -38,7 +38,7 @@ - + @@ -69,20 +69,7 @@
-
- - - - - - - - - - - - - +