From 5caa401999170d764dce18c3903fee74aa8f2757 Mon Sep 17 00:00:00 2001
From: jmacxx <47253594+jmacxx@users.noreply.github.com>
Date: Sun, 23 Oct 2022 22:53:01 -0500
Subject: [PATCH] Refactor the Support Tool UI.
This is the tool used for Manual Payouts and message sign/verify.
Replaces the monolithic code with a class for each tab in the UI.
This refactoring was necessary in preparation for adding a new tab.
---
.../main/java/bisq/desktop/app/BisqApp.java | 4 +-
.../windows/ManualPayoutTxWindow.java | 823 ------------------
.../windows/supporttool/BuildPane.java | 178 ++++
.../windows/supporttool/CommonPane.java | 61 ++
.../windows/supporttool/ExportPane.java | 49 ++
.../windows/supporttool/ImportPane.java | 148 ++++
.../windows/supporttool/InputsPane.java | 259 ++++++
.../windows/supporttool/SignPane.java | 146 ++++
.../windows/supporttool/SignVerifyPane.java | 109 +++
.../supporttool/SupportToolWindow.java | 173 ++++
10 files changed, 1125 insertions(+), 825 deletions(-)
delete mode 100644 desktop/src/main/java/bisq/desktop/main/overlays/windows/ManualPayoutTxWindow.java
create mode 100644 desktop/src/main/java/bisq/desktop/main/overlays/windows/supporttool/BuildPane.java
create mode 100644 desktop/src/main/java/bisq/desktop/main/overlays/windows/supporttool/CommonPane.java
create mode 100644 desktop/src/main/java/bisq/desktop/main/overlays/windows/supporttool/ExportPane.java
create mode 100644 desktop/src/main/java/bisq/desktop/main/overlays/windows/supporttool/ImportPane.java
create mode 100644 desktop/src/main/java/bisq/desktop/main/overlays/windows/supporttool/InputsPane.java
create mode 100644 desktop/src/main/java/bisq/desktop/main/overlays/windows/supporttool/SignPane.java
create mode 100644 desktop/src/main/java/bisq/desktop/main/overlays/windows/supporttool/SignVerifyPane.java
create mode 100644 desktop/src/main/java/bisq/desktop/main/overlays/windows/supporttool/SupportToolWindow.java
diff --git a/desktop/src/main/java/bisq/desktop/app/BisqApp.java b/desktop/src/main/java/bisq/desktop/app/BisqApp.java
index 6dfc7727716..bd627c8b3c9 100644
--- a/desktop/src/main/java/bisq/desktop/app/BisqApp.java
+++ b/desktop/src/main/java/bisq/desktop/app/BisqApp.java
@@ -26,7 +26,7 @@
import bisq.desktop.main.overlays.windows.BsqEmptyWalletWindow;
import bisq.desktop.main.overlays.windows.BtcEmptyWalletWindow;
import bisq.desktop.main.overlays.windows.FilterWindow;
-import bisq.desktop.main.overlays.windows.ManualPayoutTxWindow;
+import bisq.desktop.main.overlays.windows.supporttool.SupportToolWindow;
import bisq.desktop.main.overlays.windows.SendAlertMessageWindow;
import bisq.desktop.main.overlays.windows.ShowWalletDataWindow;
import bisq.desktop.main.overlays.windows.WalletPasswordWindow;
@@ -354,7 +354,7 @@ private void addSceneKeyEventHandler(Scene scene, Injector injector) {
new Popup().warning(Res.get("popup.warning.walletNotInitialized")).show();
} else if (Utilities.isAltOrCtrlPressed(KeyCode.G, keyEvent)) {
if (injector.getInstance(BtcWalletService.class).isWalletReady())
- injector.getInstance(ManualPayoutTxWindow.class).show();
+ injector.getInstance(SupportToolWindow.class).show();
else
new Popup().warning(Res.get("popup.warning.walletNotInitialized")).show();
} else if (DevEnv.isDevMode()) {
diff --git a/desktop/src/main/java/bisq/desktop/main/overlays/windows/ManualPayoutTxWindow.java b/desktop/src/main/java/bisq/desktop/main/overlays/windows/ManualPayoutTxWindow.java
deleted file mode 100644
index f36c5c5d583..00000000000
--- a/desktop/src/main/java/bisq/desktop/main/overlays/windows/ManualPayoutTxWindow.java
+++ /dev/null
@@ -1,823 +0,0 @@
-/*
- * This file is part of Bisq.
- *
- * Bisq is free software: you can redistribute it and/or modify it
- * under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at
- * your option) any later version.
- *
- * Bisq is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with Bisq. If not, see .
- */
-
-package bisq.desktop.main.overlays.windows;
-
-import bisq.desktop.components.AutoTooltipButton;
-import bisq.desktop.components.BisqTextArea;
-import bisq.desktop.components.InputTextField;
-import bisq.desktop.main.overlays.Overlay;
-import bisq.desktop.main.overlays.popups.Popup;
-import bisq.desktop.util.GUIUtil;
-import bisq.desktop.util.validation.LengthValidator;
-import bisq.desktop.util.validation.PercentageNumberValidator;
-
-import bisq.core.btc.exceptions.TransactionVerificationException;
-import bisq.core.btc.exceptions.TxBroadcastException;
-import bisq.core.btc.exceptions.WalletException;
-import bisq.core.btc.setup.WalletsSetup;
-import bisq.core.btc.wallet.TradeWalletService;
-import bisq.core.btc.wallet.TxBroadcaster;
-import bisq.core.btc.wallet.WalletsManager;
-import bisq.core.locale.Res;
-import bisq.core.support.dispute.Dispute;
-import bisq.core.support.dispute.mediation.MediationManager;
-
-import bisq.network.p2p.P2PService;
-
-import bisq.common.UserThread;
-import bisq.common.config.Config;
-import bisq.common.util.Base64;
-import bisq.common.util.Tuple2;
-import bisq.common.util.Utilities;
-
-import org.bitcoinj.core.Address;
-import org.bitcoinj.core.AddressFormatException;
-import org.bitcoinj.core.Coin;
-import org.bitcoinj.core.SignatureDecodeException;
-import org.bitcoinj.core.Transaction;
-import org.bitcoinj.core.Utils;
-import org.bitcoinj.core.VerificationException;
-import org.bitcoinj.core.ECKey;
-import org.bitcoinj.script.Script;
-
-import javax.inject.Inject;
-
-import de.jensd.fx.fontawesome.AwesomeDude;
-import de.jensd.fx.fontawesome.AwesomeIcon;
-
-import javafx.scene.Scene;
-import javafx.scene.control.Button;
-import javafx.scene.control.CheckBox;
-import javafx.scene.control.ComboBox;
-import javafx.scene.control.Label;
-import javafx.scene.control.Separator;
-import javafx.scene.control.TextArea;
-import javafx.scene.control.Tooltip;
-import javafx.scene.input.KeyCode;
-import javafx.scene.layout.ColumnConstraints;
-import javafx.scene.layout.GridPane;
-import javafx.scene.layout.HBox;
-import javafx.scene.layout.VBox;
-
-import javafx.geometry.Insets;
-import javafx.geometry.Orientation;
-import javafx.geometry.Pos;
-
-import javafx.beans.value.ChangeListener;
-
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableList;
-
-import java.security.SignatureException;
-
-import java.time.Instant;
-
-import java.nio.charset.Charset;
-
-import java.util.ArrayList;
-import java.util.Optional;
-import java.util.concurrent.TimeUnit;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.annotation.Nullable;
-
-import static bisq.desktop.util.FormBuilder.*;
-
-// We don't translate here as it is for dev only purpose
-public class ManualPayoutTxWindow extends Overlay {
- private static final int HEX_HASH_LENGTH = 32 * 2;
- private static final int HEX_PUBKEY_LENGTH = 33 * 2;
- private static final Logger log = LoggerFactory.getLogger(ManualPayoutTxWindow.class);
- private final TradeWalletService tradeWalletService;
- private final P2PService p2PService;
- private final MediationManager mediationManager;
- private final WalletsSetup walletsSetup;
- private final WalletsManager walletsManager;
- GridPane inputsGridPane;
- GridPane importTxGridPane;
- GridPane exportTxGridPane;
- GridPane signTxGridPane;
- GridPane buildTxGridPane;
- GridPane signVerifyMsgGridPane;
- CheckBox depositTxLegacy, recentTickets;
- ComboBox mediationDropDown;
- ObservableList disputeObservableList;
- InputTextField depositTxHex;
- InputTextField amountInMultisig;
- InputTextField buyerPayoutAmount;
- InputTextField sellerPayoutAmount;
- InputTextField txFee;
- InputTextField txFeePct;
- InputTextField buyerAddressString;
- InputTextField sellerAddressString;
- InputTextField buyerPubKeyAsHex;
- InputTextField sellerPubKeyAsHex;
- InputTextField buyerSignatureAsHex;
- InputTextField sellerSignatureAsHex;
- InputTextField privateKeyHex;
- InputTextField signatureHex;
- TextArea importHex;
- TextArea exportHex;
- TextArea finalSignedTxHex;
- private ChangeListener txFeeListener, amountInMultisigListener, buyerPayoutAmountListener, sellerPayoutAmountListener;
-
- ///////////////////////////////////////////////////////////////////////////////////////////
- // Public API
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- @Inject
- public ManualPayoutTxWindow(TradeWalletService tradeWalletService,
- P2PService p2PService,
- MediationManager mediationManager,
- WalletsSetup walletsSetup,
- WalletsManager walletsManager) {
- this.tradeWalletService = tradeWalletService;
- this.p2PService = p2PService;
- this.mediationManager = mediationManager;
- this.walletsSetup = walletsSetup;
- this.walletsManager = walletsManager;
- type = Type.Attention;
- }
-
- public void show() {
- if (headLine == null)
- headLine = "Emergency MultiSig payout tool"; // We dont translate here as it is for dev only purpose
-
- width = 1068;
- createGridPane();
- addHeadLine();
- addContent();
- addButtons();
- applyStyles();
- txFeeListener = (observable, oldValue, newValue) -> {
- calculateTxFee();
- };
- buyerPayoutAmountListener = (observable, oldValue, newValue) -> {
- calculateTxFee();
- };
- sellerPayoutAmountListener = (observable, oldValue, newValue) -> {
- calculateTxFee();
- };
- amountInMultisigListener = (observable, oldValue, newValue) -> {
- calculateTxFee();
- };
- txFee.focusedProperty().addListener(txFeeListener);
- buyerPayoutAmount.focusedProperty().addListener(buyerPayoutAmountListener);
- sellerPayoutAmount.focusedProperty().addListener(sellerPayoutAmountListener);
- amountInMultisig.focusedProperty().addListener(amountInMultisigListener);
- display();
- }
-
- ///////////////////////////////////////////////////////////////////////////////////////////
- // Protected
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- @Override
- protected void setupKeyHandler(Scene scene) {
- if (!hideCloseButton) {
- scene.setOnKeyPressed(e -> {
- if (e.getCode() == KeyCode.ESCAPE) {
- e.consume();
- doClose();
- }
- });
- }
- }
-
- @Override
- protected void createGridPane() {
- gridPane = new GridPane();
- gridPane.setHgap(15);
- gridPane.setVgap(15);
- gridPane.setPadding(new Insets(64, 64, 64, 64));
- gridPane.setPrefWidth(width);
- ColumnConstraints columnConstraints1 = new ColumnConstraints();
- ColumnConstraints columnConstraints2 = new ColumnConstraints();
- columnConstraints1.setPercentWidth(25);
- columnConstraints2.setPercentWidth(75);
- gridPane.getColumnConstraints().addAll(columnConstraints1, columnConstraints2);
- }
-
- @Override
- protected void cleanup() {
- txFee.focusedProperty().removeListener(txFeeListener);
- buyerPayoutAmount.focusedProperty().removeListener(buyerPayoutAmountListener);
- sellerPayoutAmount.focusedProperty().removeListener(sellerPayoutAmountListener);
- amountInMultisig.focusedProperty().removeListener(amountInMultisigListener);
- super.cleanup();
- }
-
- private void addContent() {
- rowIndex = 1;
- this.disableActionButton = true;
- addLeftPanelButtons();
- addInputsPane();
- addImportPane();
- addExportPane();
- addSignPane();
- addBuildPane();
- signVerifyMsgGridPane = addSignVerifyMsgPane(new GridPane());
- hideAllPanes();
- inputsGridPane.setVisible(true);
-
- // Notes:
- // Open with alt+g
- // Priv key is only visible if pw protection is removed (wallet details data (alt+j))
- // Take missing buyerPubKeyAsHex and sellerPubKeyAsHex from contract data!
- // Lookup sellerPrivateKeyAsHex associated with sellerPubKeyAsHex (or buyers) in wallet details data
- // sellerPubKeys/buyerPubKeys are auto generated if used the fields below
- }
-
- private void addLeftPanelButtons() {
- Button buttonInputs = new AutoTooltipButton("Inputs");
- Button buttonImport = new AutoTooltipButton("Import");
- Button buttonExport = new AutoTooltipButton("Export");
- Button buttonSign = new AutoTooltipButton("Sign");
- Button buttonBuild = new AutoTooltipButton("Build");
- Button buttonSignVerifyMsg = new AutoTooltipButton("Sign/Verify Msg");
- VBox vBox = new VBox(12, buttonInputs, buttonImport, buttonExport, buttonSign, buttonBuild, buttonSignVerifyMsg);
- vBox.getChildren().forEach(button -> ((Button) button).setPrefWidth(500));
- gridPane.add(vBox, 0, rowIndex);
- buttonInputs.getStyleClass().add("action-button");
- buttonInputs.setOnAction(e -> { // just show the inputs pane
- hideAllPanes();
- vBox.getChildren().forEach(button -> button.getStyleClass().remove("action-button"));
- buttonInputs.getStyleClass().add("action-button");
- inputsGridPane.setVisible(true);
- });
- buttonImport.setOnAction(e -> { // just show the import pane
- hideAllPanes();
- vBox.getChildren().forEach(button -> button.getStyleClass().remove("action-button"));
- buttonImport.getStyleClass().add("action-button");
- importTxGridPane.setVisible(true);
- importHex.setText("");
- });
- buttonExport.setOnAction(e -> { // show export pane and fill in the data
- hideAllPanes();
- vBox.getChildren().forEach(button -> button.getStyleClass().remove("action-button"));
- buttonExport.getStyleClass().add("action-button");
- exportTxGridPane.setVisible(true);
- exportHex.setText(generateExportText());
- });
- buttonSign.setOnAction(e -> { // just show the sign pane
- hideAllPanes();
- vBox.getChildren().forEach(button -> button.getStyleClass().remove("action-button"));
- buttonSign.getStyleClass().add("action-button");
- signTxGridPane.setVisible(true);
- privateKeyHex.setText("");
- signatureHex.setText("");
- });
- buttonBuild.setOnAction(e -> { // just show the build pane
- hideAllPanes();
- vBox.getChildren().forEach(button -> button.getStyleClass().remove("action-button"));
- buttonBuild.getStyleClass().add("action-button");
- buildTxGridPane.setVisible(true);
- finalSignedTxHex.setText("");
- });
- buttonSignVerifyMsg.setOnAction(e -> { // just show the sign msg pane
- hideAllPanes();
- vBox.getChildren().forEach(button -> button.getStyleClass().remove("action-button"));
- buttonSignVerifyMsg.getStyleClass().add("action-button");
- signVerifyMsgGridPane.setVisible(true);
- });
- }
-
- private void addInputsPane() {
- inputsGridPane = new GridPane();
- gridPane.add(inputsGridPane, 1, rowIndex);
- int rowIndexA = 0;
-
- depositTxLegacy = addCheckBox(inputsGridPane, rowIndexA, "depositTxLegacy");
-
- Tooltip tooltip = new Tooltip(Res.get("txIdTextField.blockExplorerIcon.tooltip"));
- Label blockExplorerIcon = new Label();
- blockExplorerIcon.getStyleClass().addAll("icon", "highlight");
- blockExplorerIcon.setTooltip(tooltip);
- AwesomeDude.setIcon(blockExplorerIcon, AwesomeIcon.EXTERNAL_LINK);
- blockExplorerIcon.setMinWidth(20);
- blockExplorerIcon.setOnMouseClicked(mouseEvent -> {
- if (depositTxHex.getText().length() == HEX_HASH_LENGTH) {
- GUIUtil.openTxInBlockExplorer(depositTxHex.getText());
- }
- });
- depositTxHex = addInputTextField(inputsGridPane, rowIndexA, "depositTxId");
- HBox hBoxTx = new HBox(12, depositTxHex, blockExplorerIcon);
- hBoxTx.setAlignment(Pos.BASELINE_LEFT);
- hBoxTx.setPrefWidth(800);
- inputsGridPane.add(new Label(""), 0, ++rowIndexA); // spacer
- inputsGridPane.add(hBoxTx, 0, ++rowIndexA);
-
- amountInMultisig = addInputTextField(inputsGridPane, ++rowIndexA, "amountInMultisig");
- inputsGridPane.add(new Label(""), 0, ++rowIndexA); // spacer
- buyerPayoutAmount = addInputTextField(inputsGridPane, rowIndexA, "buyerPayoutAmount");
- sellerPayoutAmount = addInputTextField(inputsGridPane, rowIndexA, "sellerPayoutAmount");
- txFee = addInputTextField(inputsGridPane, rowIndexA, "Tx fee");
- txFee.setEditable(false);
- txFeePct = addInputTextField(inputsGridPane, rowIndexA, "Tx fee %");
- txFeePct.setEditable(false);
- PercentageNumberValidator validator = new PercentageNumberValidator();
- validator.setMaxValue(10D);
- txFeePct.setValidator(validator);
-
- HBox hBox = new HBox(12, buyerPayoutAmount, sellerPayoutAmount, txFee, txFeePct);
- hBox.setAlignment(Pos.BASELINE_LEFT);
- hBox.setPrefWidth(800);
- inputsGridPane.add(hBox, 0, ++rowIndexA);
- buyerAddressString = addInputTextField(inputsGridPane, ++rowIndexA, "buyerPayoutAddress");
- sellerAddressString = addInputTextField(inputsGridPane, ++rowIndexA, "sellerPayoutAddress");
- buyerPubKeyAsHex = addInputTextField(inputsGridPane, ++rowIndexA, "buyerPubKeyAsHex");
- sellerPubKeyAsHex = addInputTextField(inputsGridPane, ++rowIndexA, "sellerPubKeyAsHex");
- depositTxHex.setPrefWidth(800);
- depositTxLegacy.setAllowIndeterminate(false);
- depositTxLegacy.setSelected(false);
- depositTxHex.setValidator(new LengthValidator(HEX_HASH_LENGTH, HEX_HASH_LENGTH));
- buyerAddressString.setValidator(new LengthValidator(20, 80));
- sellerAddressString.setValidator(new LengthValidator(20, 80));
- buyerPubKeyAsHex.setValidator(new LengthValidator(HEX_PUBKEY_LENGTH, HEX_PUBKEY_LENGTH));
- sellerPubKeyAsHex.setValidator(new LengthValidator(HEX_PUBKEY_LENGTH, HEX_PUBKEY_LENGTH));
- }
-
- private void addImportPane() {
- int rowIndexB = 0;
- importTxGridPane = new GridPane();
- gridPane.add(importTxGridPane, 1, rowIndex);
- importHex = new BisqTextArea();
- importHex.setEditable(true);
- importHex.setWrapText(true);
- importHex.setPrefSize(800, 150);
- importTxGridPane.add(importHex, 0, ++rowIndexB);
- importTxGridPane.add(new Label(""), 0, ++rowIndexB); // spacer
- Button buttonImport = new AutoTooltipButton("Import From String");
- buttonImport.setOnAction(e -> {
- // here we need to populate the "inputs" fields from the data contained in the TextArea
- if (doImport(importHex.getText())) {
- // switch back to the inputs pane
- hideAllPanes();
- inputsGridPane.setVisible(true);
- }
- });
- HBox hBox = new HBox(12, buttonImport);
- hBox.setAlignment(Pos.BASELINE_CENTER);
- hBox.setPrefWidth(800);
- importTxGridPane.add(hBox, 0, ++rowIndexB);
- importTxGridPane.add(new Label(""), 0, ++rowIndexB); // spacer
-
- final Separator separator = new Separator(Orientation.HORIZONTAL);
- separator.setPadding(new Insets(10, 10, 10, 10));
- importTxGridPane.add(separator, 0, ++rowIndexB);
-
- importTxGridPane.add(new Label(""), 0, ++rowIndexB); // spacer
- final Tuple2