From e17b0f8ec83122cc3be73910f4be85664081d548 Mon Sep 17 00:00:00 2001 From: woodser Date: Thu, 14 Jul 2022 11:31:41 -0400 Subject: [PATCH] remove input selection from withdraw view --- .../resources/i18n/displayStrings.properties | 2 +- .../main/funds/withdrawal/WithdrawalView.fxml | 8 - .../main/funds/withdrawal/WithdrawalView.java | 291 +----------------- 3 files changed, 10 insertions(+), 291 deletions(-) diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index ba89e6c2..02379063 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -127,7 +127,7 @@ shared.noDateAvailable=No date available shared.noDetailsAvailable=No details available shared.notUsedYet=Not used yet shared.date=Date -shared.sendFundsDetailsWithFee=Sending: {0}\nFrom address: {1}\nTo receiving address: {2}.\nRequired mining fee is: {3}\n\nThe recipient will receive: {4}\n\nAre you sure you want to withdraw this amount? +shared.sendFundsDetailsWithFee=Sending: {0}\nTo receiving address: {1}.\nRequired mining fee is: {2}\n\nThe recipient will receive: {3}\n\nAre you sure you want to withdraw this amount? # suppress inspection "TrailingSpacesInProperty" shared.sendFundsDetailsDust=Haveno detected that this transaction would create a change output which is below the minimum dust threshold (and therefore not allowed by Monero consensus rules). Instead, this dust ({0} satoshi{1}) will be added to the mining fee.\n\n\n shared.copyToClipboard=Copy to clipboard diff --git a/desktop/src/main/java/bisq/desktop/main/funds/withdrawal/WithdrawalView.fxml b/desktop/src/main/java/bisq/desktop/main/funds/withdrawal/WithdrawalView.fxml index 592bfc45..c6d31402 100644 --- a/desktop/src/main/java/bisq/desktop/main/funds/withdrawal/WithdrawalView.fxml +++ b/desktop/src/main/java/bisq/desktop/main/funds/withdrawal/WithdrawalView.fxml @@ -29,14 +29,6 @@ - - - - - - - - diff --git a/desktop/src/main/java/bisq/desktop/main/funds/withdrawal/WithdrawalView.java b/desktop/src/main/java/bisq/desktop/main/funds/withdrawal/WithdrawalView.java index 846b0b5e..29fe323f 100644 --- a/desktop/src/main/java/bisq/desktop/main/funds/withdrawal/WithdrawalView.java +++ b/desktop/src/main/java/bisq/desktop/main/funds/withdrawal/WithdrawalView.java @@ -19,10 +19,6 @@ package bisq.desktop.main.funds.withdrawal; import bisq.desktop.common.view.ActivatableView; import bisq.desktop.common.view.FxmlView; -import bisq.desktop.components.AutoTooltipCheckBox; -import bisq.desktop.components.AutoTooltipLabel; -import bisq.desktop.components.ExternalHyperlink; -import bisq.desktop.components.HyperlinkWithIcon; import bisq.desktop.components.InputTextField; import bisq.desktop.components.TitledGroupBg; import bisq.desktop.main.overlays.popups.Popup; @@ -30,7 +26,6 @@ import bisq.desktop.main.overlays.windows.TxDetails; import bisq.desktop.main.overlays.windows.WalletPasswordWindow; import bisq.desktop.util.GUIUtil; import bisq.desktop.util.Layout; - import bisq.core.btc.listeners.XmrBalanceListener; import bisq.core.btc.model.XmrAddressEntry; import bisq.core.btc.setup.WalletsSetup; @@ -40,7 +35,6 @@ import bisq.core.provider.fee.FeeService; import bisq.core.trade.Trade; import bisq.core.trade.TradeManager; import bisq.core.user.DontShowAgainLookup; -import bisq.core.user.Preferences; import bisq.core.util.FormattingUtils; import bisq.core.util.ParsingUtils; import bisq.core.util.coin.CoinFormatter; @@ -48,7 +42,6 @@ import bisq.core.util.validation.BtcAddressValidator; import bisq.network.p2p.P2PService; import bisq.common.util.Tuple2; -import bisq.common.util.Tuple3; import org.bitcoinj.core.Coin; @@ -57,46 +50,19 @@ import javax.inject.Named; import monero.wallet.model.MoneroTxConfig; import monero.wallet.model.MoneroTxWallet; -import org.apache.commons.lang3.StringUtils; - import javafx.fxml.FXML; import javafx.scene.control.Button; -import javafx.scene.control.CheckBox; import javafx.scene.control.Label; -import javafx.scene.control.RadioButton; -import javafx.scene.control.SelectionMode; -import javafx.scene.control.TableCell; -import javafx.scene.control.TableColumn; -import javafx.scene.control.TableView; import javafx.scene.control.TextField; -import javafx.scene.control.Toggle; -import javafx.scene.control.ToggleGroup; -import javafx.scene.control.Tooltip; import javafx.scene.layout.GridPane; import javafx.scene.layout.VBox; -import javafx.geometry.Pos; - -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.ReadOnlyObjectWrapper; -import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.value.ChangeListener; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.collections.transformation.SortedList; - -import javafx.util.Callback; - - import java.math.BigInteger; import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashSet; import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; import static bisq.desktop.util.FormBuilder.*; @@ -105,31 +71,18 @@ public class WithdrawalView extends ActivatableView { @FXML GridPane gridPane; - @FXML - TableView tableView; - @FXML - TableColumn addressColumn, balanceColumn, selectColumn; - private RadioButton useAllInputsRadioButton, useCustomInputsRadioButton; private Label amountLabel; - private TextField amountTextField, withdrawFromTextField, withdrawToTextField, withdrawMemoTextField; + private TextField amountTextField, withdrawToTextField, withdrawMemoTextField; private final XmrWalletService xmrWalletService; private final TradeManager tradeManager; private final P2PService p2PService; private final CoinFormatter formatter; - private final Preferences preferences; - private final ObservableList observableList = FXCollections.observableArrayList(); - private final SortedList sortedList = new SortedList<>(observableList); - private final Set selectedItems = new HashSet<>(); private XmrBalanceListener balanceListener; - private Coin totalAvailableAmountOfSelectedItems = Coin.ZERO; private Coin amountAsCoin = Coin.ZERO; private ChangeListener amountListener; private ChangeListener amountFocusListener; - private ChangeListener inputsToggleGroupListener; - private ToggleGroup inputsToggleGroup; - private final BooleanProperty useAllInputs = new SimpleBooleanProperty(true); private int rowIndex = 0; /////////////////////////////////////////////////////////////////////////////////////////// @@ -142,7 +95,6 @@ public class WithdrawalView extends ActivatableView { P2PService p2PService, WalletsSetup walletsSetup, @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter, - Preferences preferences, BtcAddressValidator btcAddressValidator, WalletPasswordWindow walletPasswordWindow, FeeService feeService) { @@ -150,7 +102,6 @@ public class WithdrawalView extends ActivatableView { this.tradeManager = tradeManager; this.p2PService = p2PService; this.formatter = formatter; - this.preferences = preferences; } @Override @@ -159,34 +110,14 @@ public class WithdrawalView extends ActivatableView { final TitledGroupBg titledGroupBg = addTitledGroupBg(gridPane, rowIndex, 4, Res.get("funds.deposit.withdrawFromWallet")); titledGroupBg.getStyleClass().add("last"); - inputsToggleGroup = new ToggleGroup(); - inputsToggleGroupListener = (observable, oldValue, newValue) -> { - useAllInputs.set(newValue == useAllInputsRadioButton); - - updateInputSelection(); - }; - - final Tuple3 labelRadioButtonRadioButtonTuple3 = - addTopLabelRadioButtonRadioButton(gridPane, rowIndex, inputsToggleGroup, - Res.get("funds.withdrawal.inputs"), - Res.get("funds.withdrawal.useAllInputs"), - Res.get("funds.withdrawal.useCustomInputs"), - Layout.FIRST_ROW_DISTANCE); - - useAllInputsRadioButton = labelRadioButtonRadioButtonTuple3.second; - useCustomInputsRadioButton = labelRadioButtonRadioButtonTuple3.third; - - final Tuple2 feeTuple3 = addTopLabelInputTextField(gridPane, ++rowIndex, + final Tuple2 amountTuple3 = addTopLabelInputTextField(gridPane, ++rowIndex, Res.get("funds.withdrawal.receiverAmount", Res.getBaseCurrencyCode()), - 0); + Layout.COMPACT_FIRST_ROW_DISTANCE); - amountLabel = feeTuple3.first; - amountTextField = feeTuple3.second; + amountLabel = amountTuple3.first; + amountTextField = amountTuple3.second; amountTextField.setMinWidth(180); - withdrawFromTextField = addTopLabelTextField(gridPane, ++rowIndex, - Res.get("funds.withdrawal.fromLabel", Res.getBaseCurrencyCode())).second; - withdrawToTextField = addTopLabelInputTextField(gridPane, ++rowIndex, Res.get("funds.withdrawal.toLabel", Res.getBaseCurrencyCode())).second; @@ -197,28 +128,10 @@ public class WithdrawalView extends ActivatableView { withdrawButton.setOnAction(event -> onWithdraw()); - addressColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.address"))); - balanceColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.balanceWithCur", Res.getBaseCurrencyCode()))); - selectColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.select"))); - - tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); - tableView.setMaxHeight(Double.MAX_VALUE); - tableView.setPlaceholder(new AutoTooltipLabel(Res.get("funds.withdrawal.noFundsAvailable"))); - tableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); - - setAddressColumnCellFactory(); - setBalanceColumnCellFactory(); - setSelectColumnCellFactory(); - - addressColumn.setComparator(Comparator.comparing(WithdrawalListItem::getAddressString)); - balanceColumn.setComparator(Comparator.comparing(WithdrawalListItem::getBalance)); - balanceColumn.setSortType(TableColumn.SortType.DESCENDING); - tableView.getSortOrder().add(balanceColumn); - balanceListener = new XmrBalanceListener() { @Override public void onBalanceChanged(BigInteger balance) { - updateList(); + } }; amountListener = (observable, oldValue, newValue) -> { @@ -241,42 +154,22 @@ public class WithdrawalView extends ActivatableView { amountLabel.setText(Res.get("funds.withdrawal.receiverAmount")); } - private void updateInputSelection() { - observableList.forEach(item -> { - item.setSelected(useAllInputs.get()); - selectForWithdrawal(item); - }); - tableView.refresh(); - } - @Override protected void activate() { - sortedList.comparatorProperty().bind(tableView.comparatorProperty()); - tableView.setItems(sortedList); - updateList(); - reset(); amountTextField.textProperty().addListener(amountListener); amountTextField.focusedProperty().addListener(amountFocusListener); xmrWalletService.addBalanceListener(balanceListener); - inputsToggleGroup.selectedToggleProperty().addListener(inputsToggleGroupListener); - if (inputsToggleGroup.getSelectedToggle() == null) - inputsToggleGroup.selectToggle(useAllInputsRadioButton); - - updateInputSelection(); GUIUtil.requestFocus(withdrawToTextField); } @Override protected void deactivate() { - sortedList.comparatorProperty().unbind(); - observableList.forEach(WithdrawalListItem::cleanup); xmrWalletService.removeBalanceListener(balanceListener); amountTextField.textProperty().removeListener(amountListener); amountTextField.focusedProperty().removeListener(amountFocusListener); - inputsToggleGroup.selectedToggleProperty().removeListener(inputsToggleGroupListener); } @@ -299,14 +192,14 @@ public class WithdrawalView extends ActivatableView { MoneroTxWallet tx = xmrWalletService.getWallet().createTx(new MoneroTxConfig() .setAccountIndex(0) .setAmount(ParsingUtils.coinToAtomicUnits(receiverAmount)) // TODO: rename to centinerosToAtomicUnits()? - .setAddress(withdrawToAddress)); + .setAddress(withdrawToAddress) + .setNote(withdrawMemoTextField.getText())); // create confirmation message Coin fee = ParsingUtils.atomicUnitsToCoin(tx.getFee()); Coin sendersAmount = receiverAmount.add(fee); String messageText = Res.get("shared.sendFundsDetailsWithFee", formatter.formatCoinWithCode(sendersAmount), - withdrawFromTextField.getText(), withdrawToAddress, formatter.formatCoinWithCode(fee), formatter.formatCoinWithCode(receiverAmount)); @@ -343,7 +236,7 @@ public class WithdrawalView extends ActivatableView { .closeButtonText(Res.get("shared.cancel")) .show(); } catch (Throwable e) { - if (e.getMessage().contains("enough")) new Popup().warning(Res.get("funds.withdrawal.warn.amountExceeds") + "\n\nError message:\n" + e.getMessage()).show(); + if (e.getMessage().contains("enough")) new Popup().warning(Res.get("funds.withdrawal.warn.amountExceeds")).show(); else { e.printStackTrace(); log.error(e.toString()); @@ -353,71 +246,12 @@ public class WithdrawalView extends ActivatableView { } } - private void selectForWithdrawal(WithdrawalListItem item) { - if (item.isSelected()) - selectedItems.add(item); - else - selectedItems.remove(item); - - if (!selectedItems.isEmpty()) { - totalAvailableAmountOfSelectedItems = Coin.valueOf(selectedItems.stream().mapToLong(e -> e.getBalance().getValue()).sum()); - if (totalAvailableAmountOfSelectedItems.isPositive()) { - amountAsCoin = totalAvailableAmountOfSelectedItems; - amountTextField.setText(formatter.formatCoin(amountAsCoin)); - } else { - amountAsCoin = Coin.ZERO; - totalAvailableAmountOfSelectedItems = Coin.ZERO; - amountTextField.setText(""); - withdrawFromTextField.setText(""); - } - - if (selectedItems.size() == 1) { - withdrawFromTextField.setText(selectedItems.stream().findAny().get().getAddressEntry().getAddressString()); - withdrawFromTextField.setTooltip(null); - } else { - int abbr = Math.max(10, 66 / selectedItems.size()); - String addressesShortened = selectedItems.stream() - .map(e -> StringUtils.abbreviate(e.getAddressString(), abbr)) - .collect(Collectors.joining(", ")); - String text = Res.get("funds.withdrawal.withdrawMultipleAddresses", addressesShortened); - withdrawFromTextField.setText(text); - - String addresses = selectedItems.stream() - .map(WithdrawalListItem::getAddressString) - .collect(Collectors.joining(",\n")); - String tooltipText = Res.get("funds.withdrawal.withdrawMultipleAddresses.tooltip", addresses); - withdrawFromTextField.setTooltip(new Tooltip(tooltipText)); - } - } else { - reset(); - } - } - - private void openBlockExplorer(WithdrawalListItem item) { - if (item.getAddressString() != null) - GUIUtil.openWebPage(preferences.getBlockChainExplorer().addressUrl + item.getAddressString(), false); - } - /////////////////////////////////////////////////////////////////////////////////////////// // Private /////////////////////////////////////////////////////////////////////////////////////////// - private void updateList() { - observableList.forEach(WithdrawalListItem::cleanup); - observableList.setAll(xmrWalletService.getAddressEntriesForAvailableBalanceStream() - .map(addressEntry -> new WithdrawalListItem(addressEntry, xmrWalletService, formatter)) - .collect(Collectors.toList())); - - updateInputSelection(); - } - private void reset() { - withdrawFromTextField.setText(""); - withdrawFromTextField.setPromptText(Res.get("funds.withdrawal.selectAddress")); - withdrawFromTextField.setTooltip(null); - - totalAvailableAmountOfSelectedItems = Coin.ZERO; amountAsCoin = Coin.ZERO; amountTextField.setText(""); amountTextField.setPromptText(Res.get("funds.withdrawal.setAmount")); @@ -427,113 +261,6 @@ public class WithdrawalView extends ActivatableView { withdrawMemoTextField.setText(""); withdrawMemoTextField.setPromptText(Res.get("funds.withdrawal.memo")); - - selectedItems.clear(); - tableView.getSelectionModel().clearSelection(); - } - - /////////////////////////////////////////////////////////////////////////////////////////// - // ColumnCellFactories - /////////////////////////////////////////////////////////////////////////////////////////// - - private void setAddressColumnCellFactory() { - addressColumn.setCellValueFactory((addressListItem) -> new ReadOnlyObjectWrapper<>(addressListItem.getValue())); - - addressColumn.setCellFactory( - new Callback<>() { - - @Override - public TableCell call(TableColumn column) { - return new TableCell<>() { - private HyperlinkWithIcon hyperlinkWithIcon; - - @Override - public void updateItem(final WithdrawalListItem item, boolean empty) { - super.updateItem(item, empty); - - if (item != null && !empty) { - String address = item.getAddressString(); - hyperlinkWithIcon = new ExternalHyperlink(address); - hyperlinkWithIcon.setOnAction(event -> openBlockExplorer(item)); - hyperlinkWithIcon.setTooltip(new Tooltip(Res.get("tooltip.openBlockchainForAddress", address))); - setAlignment(Pos.CENTER); - setGraphic(hyperlinkWithIcon); - } else { - setGraphic(null); - if (hyperlinkWithIcon != null) - hyperlinkWithIcon.setOnAction(null); - } - } - }; - } - }); - } - - private void setBalanceColumnCellFactory() { - balanceColumn.getStyleClass().add("last-column"); - balanceColumn.setCellValueFactory((addressListItem) -> new ReadOnlyObjectWrapper<>(addressListItem.getValue())); - balanceColumn.setCellFactory( - new Callback<>() { - - @Override - public TableCell call(TableColumn column) { - return new TableCell<>() { - @Override - public void updateItem(final WithdrawalListItem item, boolean empty) { - super.updateItem(item, empty); - setGraphic((item != null && !empty) ? item.getBalanceLabel() : null); - } - }; - } - }); - } - - private void setSelectColumnCellFactory() { - selectColumn.getStyleClass().add("first-column"); - selectColumn.setCellValueFactory((addressListItem) -> - new ReadOnlyObjectWrapper<>(addressListItem.getValue())); - selectColumn.setCellFactory( - new Callback<>() { - - @Override - public TableCell call(TableColumn column) { - return new TableCell<>() { - - CheckBox checkBox = new AutoTooltipCheckBox(); - - @Override - public void updateItem(final WithdrawalListItem item, boolean empty) { - super.updateItem(item, empty); - if (item != null && !empty) { - checkBox.setOnAction(e -> { - item.setSelected(checkBox.isSelected()); - selectForWithdrawal(item); - - // If all are selected we select useAllInputsRadioButton - if (observableList.size() == selectedItems.size()) { - inputsToggleGroup.selectToggle(useAllInputsRadioButton); - } else { - // We don't want to get deselected all when we activate the useCustomInputsRadioButton - // so we temporarily disable the listener - inputsToggleGroup.selectedToggleProperty().removeListener(inputsToggleGroupListener); - inputsToggleGroup.selectToggle(useCustomInputsRadioButton); - useAllInputs.set(false); - inputsToggleGroup.selectedToggleProperty().addListener(inputsToggleGroupListener); - } - }); - setGraphic(checkBox); - checkBox.setSelected(item.isSelected()); - } else { - checkBox.setOnAction(null); - setGraphic(null); - } - } - }; - } - }); } }