diff --git a/src/main/java/bisq/desktop/bisq.css b/src/main/java/bisq/desktop/bisq.css index a01697a134..ae7a42c387 100644 --- a/src/main/java/bisq/desktop/bisq.css +++ b/src/main/java/bisq/desktop/bisq.css @@ -1316,6 +1316,13 @@ textfield */ -fx-font-size: 0.846em; } +.my-message-header { + -fx-text-fill: -fx-accent; + -fx-fill: -fx-accent; + -fx-font-size: 0.846em; +} + + /******************************************************************************************************************** * * * DAO * diff --git a/src/main/java/bisq/desktop/components/TextFieldWithIcon.java b/src/main/java/bisq/desktop/components/TextFieldWithIcon.java new file mode 100644 index 0000000000..eac40793e0 --- /dev/null +++ b/src/main/java/bisq/desktop/components/TextFieldWithIcon.java @@ -0,0 +1,78 @@ +/* + * 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.components; + +import de.jensd.fx.fontawesome.AwesomeDude; +import de.jensd.fx.fontawesome.AwesomeIcon; + +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.layout.AnchorPane; +import javafx.scene.text.TextAlignment; + +import javafx.geometry.Pos; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import lombok.Getter; + +public class TextFieldWithIcon extends AnchorPane { + public static final Logger log = LoggerFactory.getLogger(TextFieldWithIcon.class); + @Getter + private final Label iconLabel; + private final TextField textField; + private final Label dummyTextField; + + public TextFieldWithIcon() { + textField = new TextField(); + textField.setEditable(false); + textField.setMouseTransparent(true); + textField.setFocusTraversable(false); + setLeftAnchor(textField, 0d); + setRightAnchor(textField, 0d); + + dummyTextField = new Label(); + dummyTextField.setWrapText(true); + dummyTextField.setAlignment(Pos.CENTER_LEFT); + dummyTextField.setTextAlignment(TextAlignment.LEFT); + dummyTextField.setMouseTransparent(true); + dummyTextField.setFocusTraversable(false); + setLeftAnchor(dummyTextField, 0d); + dummyTextField.setVisible(false); + + iconLabel = new Label(); + iconLabel.setLayoutX(0); + iconLabel.setLayoutY(3); + + dummyTextField.widthProperty().addListener((observable, oldValue, newValue) -> { + iconLabel.setLayoutX(dummyTextField.widthProperty().get() + 20); + }); + + getChildren().addAll(textField, dummyTextField, iconLabel); + } + + public void setIcon(AwesomeIcon iconLabel) { + AwesomeDude.setIcon(this.iconLabel, iconLabel); + } + + public void setText(String text) { + textField.setText(text); + dummyTextField.setText(text); + } +} diff --git a/src/main/java/bisq/desktop/components/paymentmethods/MoneyGramForm.java b/src/main/java/bisq/desktop/components/paymentmethods/MoneyGramForm.java new file mode 100644 index 0000000000..ca78e5230c --- /dev/null +++ b/src/main/java/bisq/desktop/components/paymentmethods/MoneyGramForm.java @@ -0,0 +1,269 @@ +/* + * 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.components.paymentmethods; + +import bisq.desktop.components.InputTextField; +import bisq.desktop.util.BSFormatter; +import bisq.desktop.util.FormBuilder; +import bisq.desktop.util.Layout; +import bisq.desktop.util.validation.EmailValidator; + +import bisq.core.locale.BankUtil; +import bisq.core.locale.Country; +import bisq.core.locale.CountryUtil; +import bisq.core.locale.CurrencyUtil; +import bisq.core.locale.Region; +import bisq.core.locale.Res; +import bisq.core.payment.AccountAgeWitnessService; +import bisq.core.payment.MoneyGramAccount; +import bisq.core.payment.PaymentAccount; +import bisq.core.payment.payload.MoneyGramAccountPayload; +import bisq.core.payment.payload.PaymentAccountPayload; +import bisq.core.util.validation.InputValidator; + +import bisq.common.util.Tuple2; +import bisq.common.util.Tuple3; + +import org.apache.commons.lang3.StringUtils; + +import javafx.scene.control.CheckBox; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Label; +import javafx.scene.control.Tooltip; +import javafx.scene.layout.FlowPane; +import javafx.scene.layout.GridPane; + +import javafx.geometry.Insets; +import javafx.geometry.VPos; + +import javafx.collections.FXCollections; + +import javafx.util.StringConverter; + +import lombok.extern.slf4j.Slf4j; + +import static bisq.desktop.util.FormBuilder.addLabel; +import static bisq.desktop.util.FormBuilder.addLabelTextFieldWithCopyIcon; + +@Slf4j +public class MoneyGramForm extends PaymentMethodForm { + + public static int addFormForBuyer(GridPane gridPane, int gridRow, + PaymentAccountPayload paymentAccountPayload) { + final MoneyGramAccountPayload payload = (MoneyGramAccountPayload) paymentAccountPayload; + addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, Res.getWithCol("payment.account.fullName"), + payload.getHolderName()); + FormBuilder.addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, + Res.getWithCol("payment.bank.country"), + CountryUtil.getNameAndCode(((MoneyGramAccountPayload) paymentAccountPayload).getCountryCode())); + if (BankUtil.isStateRequired(payload.getCountryCode())) + addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, Res.get("payment.account.state"), + payload.getState()); + addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, Res.get("payment.email"), + payload.getEmail()); + + return gridRow; + } + + protected final MoneyGramAccountPayload moneyGramAccountPayload; + protected InputTextField holderNameInputTextField, emailInputTextField, stateInputTextField; + private Label stateLabel; + private final EmailValidator emailValidator; + + public MoneyGramForm(PaymentAccount paymentAccount, AccountAgeWitnessService accountAgeWitnessService, InputValidator inputValidator, + GridPane gridPane, int gridRow, BSFormatter formatter) { + super(paymentAccount, accountAgeWitnessService, inputValidator, gridPane, gridRow, formatter); + this.moneyGramAccountPayload = (MoneyGramAccountPayload) paymentAccount.paymentAccountPayload; + + emailValidator = new EmailValidator(); + } + + @Override + public void addFormForDisplayAccount() { + gridRowFrom = gridRow; + final Country country = getMoneyGramPaymentAccount().getCountry(); + FormBuilder.addLabelTextField(gridPane, gridRow, Res.get("payment.account.name"), paymentAccount.getAccountName(), Layout.FIRST_ROW_AND_GROUP_DISTANCE); + FormBuilder.addLabelTextField(gridPane, ++gridRow, Res.getWithCol("shared.paymentMethod"), + Res.get(paymentAccount.getPaymentMethod().getId())); + FormBuilder.addLabelTextField(gridPane, ++gridRow, Res.get("payment.country"), country != null ? country.name : ""); + FormBuilder.addLabelTextField(gridPane, ++gridRow, Res.getWithCol("payment.account.fullName"), + moneyGramAccountPayload.getHolderName()); + if (BankUtil.isStateRequired(moneyGramAccountPayload.getCountryCode())) + FormBuilder.addLabelTextField(gridPane, ++gridRow, Res.get("payment.account.state"), + moneyGramAccountPayload.getState()).second.setMouseTransparent(false); + FormBuilder.addLabelTextField(gridPane, ++gridRow, Res.get("payment.email"), + moneyGramAccountPayload.getEmail()); + addLimitations(); + addCurrenciesGrid(false); + } + + @Override + public void addFormForAddAccount() { + gridRowFrom = gridRow + 1; + + Tuple3 tuple3 = FormBuilder.addLabelComboBoxComboBox(gridPane, ++gridRow, Res.get("payment.country")); + + //noinspection unchecked,unchecked,unchecked + ComboBox regionComboBox = tuple3.second; + regionComboBox.setPromptText(Res.get("payment.select.region")); + regionComboBox.setConverter(new StringConverter() { + @Override + public String toString(Region region) { + return region.name; + } + + @Override + public Region fromString(String s) { + return null; + } + }); + regionComboBox.setItems(FXCollections.observableArrayList(CountryUtil.getAllRegions())); + + //noinspection unchecked,unchecked,unchecked + ComboBox countryComboBox = tuple3.third; + countryComboBox.setVisibleRowCount(15); + countryComboBox.setDisable(true); + countryComboBox.setPromptText(Res.get("payment.select.country")); + countryComboBox.setConverter(new StringConverter() { + @Override + public String toString(Country country) { + return country.name + " (" + country.code + ")"; + } + + @Override + public Country fromString(String s) { + return null; + } + }); + countryComboBox.setOnAction(e -> { + Country selectedItem = countryComboBox.getSelectionModel().getSelectedItem(); + if (selectedItem != null) { + getMoneyGramPaymentAccount().setCountry(selectedItem); + updateFromInputs(); + applyIsStateRequired(); + stateInputTextField.setText(""); + } + }); + + regionComboBox.setOnAction(e -> { + Region selectedItem = regionComboBox.getSelectionModel().getSelectedItem(); + if (selectedItem != null) { + countryComboBox.setDisable(false); + countryComboBox.setItems(FXCollections.observableArrayList(CountryUtil.getAllCountriesForRegion(selectedItem))); + } + }); + + holderNameInputTextField = FormBuilder.addLabelInputTextField(gridPane, + ++gridRow, Res.getWithCol("payment.account.fullName")).second; + holderNameInputTextField.textProperty().addListener((ov, oldValue, newValue) -> { + moneyGramAccountPayload.setHolderName(newValue); + updateFromInputs(); + }); + holderNameInputTextField.setValidator(inputValidator); + + final Tuple2 tuple2 = FormBuilder.addLabelInputTextField(gridPane, ++gridRow, Res.get("payment.account.state")); + stateLabel = tuple2.first; + stateInputTextField = tuple2.second; + stateInputTextField.textProperty().addListener((ov, oldValue, newValue) -> { + moneyGramAccountPayload.setState(newValue); + updateFromInputs(); + + }); + applyIsStateRequired(); + + emailInputTextField = FormBuilder.addLabelInputTextField(gridPane, ++gridRow, Res.get("payment.email")).second; + emailInputTextField.textProperty().addListener((ov, oldValue, newValue) -> { + moneyGramAccountPayload.setEmail(newValue); + updateFromInputs(); + }); + emailInputTextField.setValidator(emailValidator); + + addCurrenciesGrid(true); + addLimitations(); + addAccountNameTextFieldWithAutoFillCheckBox(); + + updateFromInputs(); + } + + private void addCurrenciesGrid(boolean isEditable) { + Label label = addLabel(gridPane, ++gridRow, Res.get("payment.supportedCurrencies"), 0); + GridPane.setValignment(label, VPos.TOP); + FlowPane flowPane = new FlowPane(); + flowPane.setPadding(new Insets(10, 10, 10, 10)); + flowPane.setVgap(10); + flowPane.setHgap(10); + + if (isEditable) + flowPane.setId("flow-pane-checkboxes-bg"); + else + flowPane.setId("flow-pane-checkboxes-non-editable-bg"); + + CurrencyUtil.getAllMoneyGramCurrencies().forEach(e -> { + CheckBox checkBox = new CheckBox(e.getCode()); + checkBox.setMouseTransparent(!isEditable); + checkBox.setSelected(paymentAccount.getTradeCurrencies().contains(e)); + checkBox.setMinWidth(60); + checkBox.setMaxWidth(checkBox.getMinWidth()); + checkBox.setTooltip(new Tooltip(e.getName())); + checkBox.setOnAction(event -> { + if (checkBox.isSelected()) + paymentAccount.addCurrency(e); + else + paymentAccount.removeCurrency(e); + + updateAllInputsValid(); + }); + flowPane.getChildren().add(checkBox); + }); + + GridPane.setRowIndex(flowPane, gridRow); + GridPane.setColumnIndex(flowPane, 1); + gridPane.getChildren().add(flowPane); + } + + private void applyIsStateRequired() { + final boolean stateRequired = BankUtil.isStateRequired(moneyGramAccountPayload.getCountryCode()); + stateLabel.setManaged(stateRequired); + stateLabel.setVisible(stateRequired); + stateInputTextField.setManaged(stateRequired); + stateInputTextField.setVisible(stateRequired); + } + + private MoneyGramAccount getMoneyGramPaymentAccount() { + return (MoneyGramAccount) this.paymentAccount; + } + + @Override + protected void autoFillNameTextField() { + if (useCustomAccountNameCheckBox != null && !useCustomAccountNameCheckBox.isSelected()) { + accountNameTextField.setText(Res.get(paymentAccount.getPaymentMethod().getId()) + .concat(": ") + .concat(StringUtils.abbreviate(holderNameInputTextField.getText(), 9))); + } + } + + @Override + public void updateAllInputsValid() { + boolean result = isAccountNameValid() + && getMoneyGramPaymentAccount().getCountry() != null + && inputValidator.validate(moneyGramAccountPayload.getHolderName()).isValid + && emailValidator.validate(moneyGramAccountPayload.getEmail()).isValid + && paymentAccount.getTradeCurrencies().size() > 0; + allInputsValid.set(result); + } +} diff --git a/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsView.java b/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsView.java index 076da95972..6c4109074d 100644 --- a/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsView.java +++ b/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsView.java @@ -30,6 +30,7 @@ import bisq.desktop.components.paymentmethods.ClearXchangeForm; import bisq.desktop.components.paymentmethods.FasterPaymentsForm; import bisq.desktop.components.paymentmethods.InteracETransferForm; import bisq.desktop.components.paymentmethods.MoneyBeamForm; +import bisq.desktop.components.paymentmethods.MoneyGramForm; import bisq.desktop.components.paymentmethods.NationalBankForm; import bisq.desktop.components.paymentmethods.OKPayForm; import bisq.desktop.components.paymentmethods.PaymentMethodForm; @@ -72,6 +73,7 @@ import bisq.core.app.BisqEnvironment; import bisq.core.locale.Res; import bisq.core.payment.AccountAgeWitnessService; import bisq.core.payment.ClearXchangeAccount; +import bisq.core.payment.MoneyGramAccount; import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccountFactory; import bisq.core.payment.WesternUnionAccount; @@ -252,6 +254,13 @@ public class FiatAccountsView extends ActivatableViewAndModel doSaveNewAccount(paymentAccount)) .show(); + } else if (paymentAccount instanceof MoneyGramAccount) { + new Popup<>().information(Res.get("payment.moneyGram.info")) + .width(700) + .closeButtonText(Res.get("shared.cancel")) + .actionButtonText(Res.get("shared.iUnderstand")) + .onAction(() -> doSaveNewAccount(paymentAccount)) + .show(); } else { doSaveNewAccount(paymentAccount); } @@ -467,6 +476,8 @@ public class FiatAccountsView extends ActivatableViewAndModel { private VBox messagesInputBox; private BusyAnimation sendMsgBusyAnimation; private Label sendMsgInfoLabel; - private ChangeListener arrivedPropertyListener; - private ChangeListener storedInMailboxPropertyListener; + private ChangeListener storedInMailboxPropertyListener, arrivedPropertyListener; + private ChangeListener sendMessageErrorPropertyListener; @Nullable private DisputeCommunicationMessage disputeCommunicationMessage; private ListChangeListener disputeDirectMessageListListener; @@ -488,6 +488,7 @@ public class TraderDisputeView extends ActivatableView { if (disputeCommunicationMessage != null) { disputeCommunicationMessage.arrivedProperty().removeListener(arrivedPropertyListener); disputeCommunicationMessage.storedInMailboxProperty().removeListener(storedInMailboxPropertyListener); + disputeCommunicationMessage.sendMessageErrorProperty().removeListener(sendMessageErrorPropertyListener); } disputeCommunicationMessage = disputeManager.sendDisputeDirectMessage(dispute, inputText, new ArrayList<>(tempAttachments)); @@ -510,8 +511,6 @@ public class TraderDisputeView extends ActivatableView { hideSendMsgInfo(timer); } }; - if (disputeCommunicationMessage != null && disputeCommunicationMessage.arrivedProperty() != null) - disputeCommunicationMessage.arrivedProperty().addListener(arrivedPropertyListener); storedInMailboxPropertyListener = (observable, oldValue, newValue) -> { if (newValue) { sendMsgInfoLabel.setVisible(true); @@ -520,8 +519,19 @@ public class TraderDisputeView extends ActivatableView { hideSendMsgInfo(timer); } }; - if (disputeCommunicationMessage != null) + sendMessageErrorPropertyListener = (observable, oldValue, newValue) -> { + if (newValue != null) { + sendMsgInfoLabel.setVisible(true); + sendMsgInfoLabel.setManaged(true); + sendMsgInfoLabel.setText(Res.get("support.sendMessageError", newValue)); + hideSendMsgInfo(timer); + } + }; + if (disputeCommunicationMessage != null) { + disputeCommunicationMessage.arrivedProperty().addListener(arrivedPropertyListener); disputeCommunicationMessage.storedInMailboxProperty().addListener(storedInMailboxPropertyListener); + disputeCommunicationMessage.sendMessageErrorProperty().addListener(sendMessageErrorPropertyListener); + } } private void hideSendMsgInfo(Timer timer) { @@ -734,7 +744,7 @@ public class TraderDisputeView extends ActivatableView { @Override public ListCell call(ListView list) { return new ListCell() { - public ChangeListener sendMsgBusyAnimationListener; + ChangeListener sendMsgBusyAnimationListener; final Pane bg = new Pane(); final ImageView arrow = new ImageView(); final Label headerLabel = new AutoTooltipLabel(); @@ -743,6 +753,8 @@ public class TraderDisputeView extends ActivatableView { final HBox attachmentsBox = new HBox(); final AnchorPane messageAnchorPane = new AnchorPane(); final Label statusIcon = new Label(); + final Label statusInfoLabel = new Label(); + final HBox statusHBox = new HBox(); final double arrowWidth = 15d; final double attachmentsBoxHeight = 20d; final double border = 10d; @@ -756,25 +768,26 @@ public class TraderDisputeView extends ActivatableView { headerLabel.setTextAlignment(TextAlignment.CENTER); attachmentsBox.setSpacing(5); statusIcon.getStyleClass().add("small-text"); + statusInfoLabel.getStyleClass().add("small-text"); + statusInfoLabel.setPadding(new Insets(3, 0, 0, 0)); copyIcon.setTooltip(new Tooltip(Res.get("shared.copyToClipboard"))); - messageAnchorPane.getChildren().addAll(bg, arrow, headerLabel, messageLabel, copyIcon, attachmentsBox, statusIcon); - messageLabel.setOnMouseClicked(event -> { - if (2 > event.getClickCount()) { - return; - } - GUIUtil.showSelectableTextModal(headerLabel.getText(), messageLabel.getText()); - }); + statusHBox.setSpacing(5); + statusHBox.getChildren().addAll(statusIcon, statusInfoLabel); + messageAnchorPane.getChildren().addAll(bg, arrow, headerLabel, messageLabel, copyIcon, attachmentsBox, statusHBox); } @Override - public void updateItem(final DisputeCommunicationMessage item, boolean empty) { - super.updateItem(item, empty); - - if (item != null && !empty) { + public void updateItem(final DisputeCommunicationMessage message, boolean empty) { + super.updateItem(message, empty); + if (message != null && !empty) { copyIcon.setOnMouseClicked(e -> Utilities.copyToClipboard(messageLabel.getText())); + messageLabel.setOnMouseClicked(event -> { + if (2 > event.getClickCount()) { + return; + } + GUIUtil.showSelectableTextModal(headerLabel.getText(), messageLabel.getText()); + }); - /* messageAnchorPane.prefWidthProperty().bind(EasyBind.map(messageListView.widthProperty(), - w -> (double) w - padding - GUIUtil.getScrollbarWidth(messageListView)));*/ if (!messageAnchorPane.prefWidthProperty().isBound()) messageAnchorPane.prefWidthProperty() .bind(messageListView.widthProperty().subtract(padding + GUIUtil.getScrollbarWidth(messageListView))); @@ -787,25 +800,27 @@ public class TraderDisputeView extends ActivatableView { AnchorPane.setTopAnchor(copyIcon, 25d); AnchorPane.setBottomAnchor(attachmentsBox, bottomBorder + 10); - boolean senderIsTrader = item.isSenderIsTrader(); + boolean senderIsTrader = message.isSenderIsTrader(); boolean isMyMsg = isTrader ? senderIsTrader : !senderIsTrader; - arrow.setVisible(!item.isSystemMessage()); - arrow.setManaged(!item.isSystemMessage()); - statusIcon.setVisible(false); + arrow.setVisible(!message.isSystemMessage()); + arrow.setManaged(!message.isSystemMessage()); + statusHBox.setVisible(false); - headerLabel.getStyleClass().removeAll("message-header", "success-text", + headerLabel.getStyleClass().removeAll("message-header", "my-message-header", "success-text", "highlight-static"); messageLabel.getStyleClass().removeAll("my-message", "message"); copyIcon.getStyleClass().removeAll("my-message", "message"); - if (item.isSystemMessage()) { + if (message.isSystemMessage()) { headerLabel.getStyleClass().addAll("message-header", "success-text"); bg.setId("message-bubble-green"); messageLabel.getStyleClass().add("my-message"); copyIcon.getStyleClass().add("my-message"); + message.addWeakMessageStateListener(() -> updateMsgState(message)); + updateMsgState(message); } else if (isMyMsg) { - headerLabel.getStyleClass().add("highlight-static"); + headerLabel.getStyleClass().add("my-message-header"); bg.setId("message-bubble-blue"); messageLabel.getStyleClass().add("my-message"); copyIcon.getStyleClass().add("my-message"); @@ -818,22 +833,13 @@ public class TraderDisputeView extends ActivatableView { sendMsgBusyAnimation.isRunningProperty().removeListener(sendMsgBusyAnimationListener); sendMsgBusyAnimationListener = (observable, oldValue, newValue) -> { - if (!newValue) { - if (item.arrivedProperty().get()) - showArrivedIcon(); - else if (item.storedInMailboxProperty().get()) - showMailboxIcon(); - } + if (!newValue) + updateMsgState(message); }; - sendMsgBusyAnimation.isRunningProperty().addListener(sendMsgBusyAnimationListener); - if (item.arrivedProperty().get()) - showArrivedIcon(); - else if (item.storedInMailboxProperty().get()) - showMailboxIcon(); - //TODO show that icon on error - /*else if (sendMsgProgressIndicator.getProgress() == 0) - showNotArrivedIcon();*/ + sendMsgBusyAnimation.isRunningProperty().addListener(sendMsgBusyAnimationListener); + message.addWeakMessageStateListener(() -> updateMsgState(message)); + updateMsgState(message); } else { headerLabel.getStyleClass().add("message-header"); bg.setId("message-bubble-grey"); @@ -845,7 +851,7 @@ public class TraderDisputeView extends ActivatableView { arrow.setId("bubble_arrow_grey_left"); } - if (item.isSystemMessage()) { + if (message.isSystemMessage()) { AnchorPane.setLeftAnchor(headerLabel, padding); AnchorPane.setRightAnchor(headerLabel, padding); AnchorPane.setLeftAnchor(bg, border); @@ -855,6 +861,8 @@ public class TraderDisputeView extends ActivatableView { AnchorPane.setRightAnchor(copyIcon, padding); AnchorPane.setLeftAnchor(attachmentsBox, padding); AnchorPane.setRightAnchor(attachmentsBox, padding); + AnchorPane.clearConstraints(statusHBox); + AnchorPane.setLeftAnchor(statusHBox, padding); } else if (senderIsTrader) { AnchorPane.setLeftAnchor(headerLabel, padding + arrowWidth); AnchorPane.setLeftAnchor(bg, border + arrowWidth); @@ -865,7 +873,8 @@ public class TraderDisputeView extends ActivatableView { AnchorPane.setRightAnchor(copyIcon, padding); AnchorPane.setLeftAnchor(attachmentsBox, padding + arrowWidth); AnchorPane.setRightAnchor(attachmentsBox, padding); - AnchorPane.setRightAnchor(statusIcon, padding); + AnchorPane.clearConstraints(statusHBox); + AnchorPane.setRightAnchor(statusHBox, padding); } else { AnchorPane.setRightAnchor(headerLabel, padding + arrowWidth); AnchorPane.setLeftAnchor(bg, border); @@ -876,14 +885,14 @@ public class TraderDisputeView extends ActivatableView { AnchorPane.setRightAnchor(copyIcon, padding + arrowWidth); AnchorPane.setLeftAnchor(attachmentsBox, padding); AnchorPane.setRightAnchor(attachmentsBox, padding + arrowWidth); - AnchorPane.setLeftAnchor(statusIcon, padding); + AnchorPane.clearConstraints(statusHBox); + AnchorPane.setLeftAnchor(statusHBox, padding); } - - AnchorPane.setBottomAnchor(statusIcon, 7d); - headerLabel.setText(formatter.formatDateTime(new Date(item.getDate()))); - messageLabel.setText(item.getMessage()); + AnchorPane.setBottomAnchor(statusHBox, 7d); + headerLabel.setText(formatter.formatDateTime(new Date(message.getDate()))); + messageLabel.setText(message.getMessage()); attachmentsBox.getChildren().clear(); - if (item.getAttachments() != null && item.getAttachments().size() > 0) { + if (message.getAttachments() != null && message.getAttachments().size() > 0) { AnchorPane.setBottomAnchor(messageLabel, bottomBorder + attachmentsBoxHeight + 10); attachmentsBox.getChildren().add(new AutoTooltipLabel(Res.get("support.attachments") + " ") {{ setPadding(new Insets(0, 0, 3, 0)); @@ -892,7 +901,7 @@ public class TraderDisputeView extends ActivatableView { else getStyleClass().add("message"); }}); - item.getAttachments().stream().forEach(attachment -> { + message.getAttachments().forEach(attachment -> { final Label icon = new Label(); setPadding(new Insets(0, 0, 3, 0)); if (isMyMsg) @@ -927,33 +936,56 @@ public class TraderDisputeView extends ActivatableView { AnchorPane.clearConstraints(arrow); AnchorPane.clearConstraints(messageLabel); AnchorPane.clearConstraints(copyIcon); - AnchorPane.clearConstraints(statusIcon); + AnchorPane.clearConstraints(statusHBox); AnchorPane.clearConstraints(attachmentsBox); copyIcon.setOnMouseClicked(null); + messageLabel.setOnMouseClicked(null); setGraphic(null); } } - /* private void showNotArrivedIcon() { - statusIcon.setVisible(true); - AwesomeDude.setIcon(statusIcon, AwesomeIcon.WARNING_SIGN, "14"); - Tooltip.install(statusIcon, new Tooltip("Message did not arrive. Please try to send again.")); - statusIcon.setTextFill(Paint.valueOf("#dd0000")); - }*/ - - private void showMailboxIcon() { - statusIcon.setVisible(true); - AwesomeDude.setIcon(statusIcon, AwesomeIcon.ENVELOPE_ALT, "14"); - statusIcon.setTooltip(new Tooltip(Res.get("support.savedInMailbox"))); + private void updateMsgState(DisputeCommunicationMessage message) { + boolean visible; + AwesomeIcon icon = null; + String text = null; statusIcon.setTextFill(Paint.valueOf("#0f87c3")); - } + statusInfoLabel.setTextFill(Paint.valueOf("#0f87c3")); + statusHBox.setOpacity(1); + log.debug("updateMsgState msg-{}, ack={}, arrived={}", message.getMessage(), + message.acknowledgedProperty().get(), message.arrivedProperty().get()); + if (message.acknowledgedProperty().get()) { + visible = true; + icon = AwesomeIcon.OK_SIGN; + text = Res.get("support.acknowledged"); - private void showArrivedIcon() { - statusIcon.setVisible(true); - AwesomeDude.setIcon(statusIcon, AwesomeIcon.OK, "14"); - statusIcon.setTooltip(new Tooltip(Res.get("support.arrived"))); - statusIcon.setTextFill(Paint.valueOf("#0f87c3")); + } else if (message.ackErrorProperty().get() != null) { + visible = true; + icon = AwesomeIcon.EXCLAMATION_SIGN; + text = Res.get("support.error", message.ackErrorProperty().get()); + statusIcon.setTextFill(Paint.valueOf("#dd0000")); + statusInfoLabel.setTextFill(Paint.valueOf("#dd0000")); + } else if (message.arrivedProperty().get()) { + visible = true; + icon = AwesomeIcon.OK; + text = Res.get("support.arrived"); + statusHBox.setOpacity(0.5); + } else if (message.storedInMailboxProperty().get()) { + visible = true; + icon = AwesomeIcon.ENVELOPE; + text = Res.get("support.savedInMailbox"); + statusHBox.setOpacity(0.5); + } else { + visible = false; + log.debug("updateMsgState called but no msg state available. message={}", message); + } + + statusHBox.setVisible(visible); + if (visible) { + AwesomeDude.setIcon(statusIcon, icon, "14"); + statusIcon.setTooltip(new Tooltip(text)); + statusInfoLabel.setText(text); + } } }; } diff --git a/src/main/java/bisq/desktop/main/offer/EditableOfferViewModel.java b/src/main/java/bisq/desktop/main/offer/EditableOfferViewModel.java index 2cfc28f3d8..ac7cbaa38d 100644 --- a/src/main/java/bisq/desktop/main/offer/EditableOfferViewModel.java +++ b/src/main/java/bisq/desktop/main/offer/EditableOfferViewModel.java @@ -221,7 +221,7 @@ public abstract class EditableOfferViewModel e switch (BisqEnvironment.getBaseCurrencyNetwork().getCurrencyCode()) { case "BTC": amount.set("0.0001"); - price.set("11029"); + price.set("6700"); break; case "LTC": amount.set("50"); diff --git a/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferDataModel.java b/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferDataModel.java index 15b93bb79b..1573015a16 100644 --- a/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferDataModel.java +++ b/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferDataModel.java @@ -213,8 +213,8 @@ class TakeOfferDataModel extends OfferDataModel { calculateTotalToPay(); log.info("Completed requestTxFee: txFeeFromFeeService={}", txFeeFromFeeService); } else { - log.warn("We received the tx fee respnse after we have shown the funding screen and ignore that " + - "to avoid that the total funds to pay changes due cahnged tx fees."); + log.debug("We received the tx fee response after we have shown the funding screen and ignore that " + + "to avoid that the total funds to pay changes due changed tx fees."); } }, null); diff --git a/src/main/java/bisq/desktop/main/overlays/windows/DisputeSummaryWindow.java b/src/main/java/bisq/desktop/main/overlays/windows/DisputeSummaryWindow.java index 7ae46e45bb..232b757f99 100644 --- a/src/main/java/bisq/desktop/main/overlays/windows/DisputeSummaryWindow.java +++ b/src/main/java/bisq/desktop/main/overlays/windows/DisputeSummaryWindow.java @@ -23,7 +23,6 @@ import bisq.desktop.components.InputTextField; import bisq.desktop.main.overlays.Overlay; import bisq.desktop.main.overlays.popups.Popup; import bisq.desktop.util.Layout; -import bisq.desktop.util.Transitions; import bisq.core.arbitration.Dispute; import bisq.core.arbitration.DisputeManager; @@ -566,7 +565,7 @@ public class DisputeSummaryWindow extends Overlay { if (!finalPeersDispute.isClosed()) UserThread.runAfter(() -> new Popup<>().attention(Res.get("disputeSummaryWindow.close.closePeer")).show(), - Transitions.DEFAULT_DURATION, TimeUnit.MILLISECONDS); + 200, TimeUnit.MILLISECONDS); hide(); diff --git a/src/main/java/bisq/desktop/main/overlays/windows/SendPrivateNotificationWindow.java b/src/main/java/bisq/desktop/main/overlays/windows/SendPrivateNotificationWindow.java index a20ba2ec64..b8b64f76b9 100644 --- a/src/main/java/bisq/desktop/main/overlays/windows/SendPrivateNotificationWindow.java +++ b/src/main/java/bisq/desktop/main/overlays/windows/SendPrivateNotificationWindow.java @@ -139,21 +139,24 @@ public class SendPrivateNotificationWindow extends Overlay().feedback(Res.get("shared.messageArrived")) .onClose(SendPrivateNotificationWindow.this::hide).show(); } @Override public void onStoredInMailbox() { - log.info("PrivateNotificationMessage was stored in mailbox."); + log.info("{} stored in mailbox for peer {}.", + message.getClass().getSimpleName(), nodeAddress); new Popup<>().feedback(Res.get("shared.messageStoredInMailbox")) .onClose(SendPrivateNotificationWindow.this::hide).show(); } @Override public void onFault(String errorMessage) { - log.error("sendEncryptedMailboxMessage failed. message=" + message); + log.error("{} failed: Peer {}, errorMessage={}", + message.getClass().getSimpleName(), nodeAddress, errorMessage); new Popup<>().feedback(Res.get("shared.messageSendingFailed", errorMessage)) .onClose(SendPrivateNotificationWindow.this::hide).show(); } diff --git a/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java b/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java index ea87cf9e86..2e6f9dbc80 100644 --- a/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java +++ b/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java @@ -23,6 +23,7 @@ import bisq.desktop.util.GUIUtil; import bisq.desktop.util.validation.BtcAddressValidator; import bisq.core.locale.Res; +import bisq.core.network.MessageState; import bisq.core.offer.Offer; import bisq.core.payment.AccountAgeWitnessService; import bisq.core.payment.payload.PaymentMethod; @@ -52,12 +53,15 @@ import javafx.beans.property.SimpleObjectProperty; import java.util.Date; import java.util.stream.Collectors; +import lombok.Getter; + import javax.annotation.Nullable; import static bisq.desktop.main.portfolio.pendingtrades.PendingTradesViewModel.SellerState.UNDEFINED; public class PendingTradesViewModel extends ActivatableWithDataModel implements ViewModel { - private Subscription tradeStateSubscription; + + @Getter @Nullable private Trade trade; @@ -90,6 +94,11 @@ public class PendingTradesViewModel extends ActivatableWithDataModel buyerState = new SimpleObjectProperty<>(); private final ObjectProperty sellerState = new SimpleObjectProperty<>(); + @Getter + private final ObjectProperty messageStateProperty = new SimpleObjectProperty<>(MessageState.UNDEFINED); + private Subscription tradeStateSubscription; + private Subscription messageStateSubscription; + /////////////////////////////////////////////////////////////////////////////////////////// // Constructor, initialization @@ -115,8 +124,18 @@ public class PendingTradesViewModel extends ActivatableWithDataModel errorMessageListener; + protected Label infoLabel; + /////////////////////////////////////////////////////////////////////////////////////////// // Constructor, Initialisation @@ -144,6 +146,9 @@ public abstract class TradeStepView extends AnchorPane { }); model.clock.addListener(clockListener); + + if (infoLabel != null) + infoLabel.setText(getInfoText()); } public void deactivate() { @@ -211,7 +216,7 @@ public abstract class TradeStepView extends AnchorPane { protected void addInfoBlock() { FormBuilder.addTitledGroupBg(gridPane, ++gridRow, 1, getInfoBlockTitle(), Layout.GROUP_DISTANCE); - FormBuilder.addMultilineLabel(gridPane, gridRow, getInfoText(), Layout.FIRST_ROW_AND_GROUP_DISTANCE); + infoLabel = FormBuilder.addMultilineLabel(gridPane, gridRow, "", Layout.FIRST_ROW_AND_GROUP_DISTANCE); } protected String getInfoText() { diff --git a/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java b/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java index fd4f7c953c..3bf5c82a48 100644 --- a/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java +++ b/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java @@ -29,6 +29,7 @@ import bisq.desktop.components.paymentmethods.CryptoCurrencyForm; import bisq.desktop.components.paymentmethods.FasterPaymentsForm; import bisq.desktop.components.paymentmethods.InteracETransferForm; import bisq.desktop.components.paymentmethods.MoneyBeamForm; +import bisq.desktop.components.paymentmethods.MoneyGramForm; import bisq.desktop.components.paymentmethods.NationalBankForm; import bisq.desktop.components.paymentmethods.OKPayForm; import bisq.desktop.components.paymentmethods.PerfectMoneyForm; @@ -51,8 +52,10 @@ import bisq.desktop.util.Layout; import bisq.core.locale.CurrencyUtil; import bisq.core.locale.Res; +import bisq.core.network.MessageState; import bisq.core.payment.payload.CashDepositAccountPayload; import bisq.core.payment.payload.CryptoCurrencyAccountPayload; +import bisq.core.payment.payload.MoneyGramAccountPayload; import bisq.core.payment.payload.PaymentAccountPayload; import bisq.core.payment.payload.PaymentMethod; import bisq.core.payment.payload.USPostalMoneyOrderAccountPayload; @@ -111,7 +114,7 @@ public class BuyerStep2View extends TradeStepView { busyAnimation.play(); confirmButton.setDisable(true); statusLabel.setText(Res.get("shared.sendingConfirmation")); - + model.setMessageStateProperty(MessageState.SENT); timeoutTimer = UserThread.runAfter(() -> { busyAnimation.stop(); confirmButton.setDisable(false); @@ -121,16 +124,19 @@ public class BuyerStep2View extends TradeStepView { case BUYER_SAW_ARRIVED_FIAT_PAYMENT_INITIATED_MSG: busyAnimation.stop(); statusLabel.setText(Res.get("shared.messageArrived")); + model.setMessageStateProperty(MessageState.ARRIVED); break; case BUYER_STORED_IN_MAILBOX_FIAT_PAYMENT_INITIATED_MSG: busyAnimation.stop(); statusLabel.setText(Res.get("shared.messageStoredInMailbox")); + model.setMessageStateProperty(MessageState.STORED_IN_MAILBOX); break; case BUYER_SEND_FAILED_FIAT_PAYMENT_INITIATED_MSG: // We get a popup and the trade closed, so we dont need to show anything here busyAnimation.stop(); confirmButton.setDisable(false); statusLabel.setText(""); + model.setMessageStateProperty(MessageState.FAILED); break; default: log.warn("Unexpected case: State={}, tradeId={} " + state.name(), trade.getId()); @@ -245,6 +251,9 @@ public class BuyerStep2View extends TradeStepView { case PaymentMethod.CASH_DEPOSIT_ID: gridRow = CashDepositForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload); break; + case PaymentMethod.MONEY_GRAM_ID: + gridRow = MoneyGramForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload); + break; case PaymentMethod.WESTERN_UNION_ID: gridRow = WesternUnionForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload); break; @@ -338,6 +347,24 @@ public class BuyerStep2View extends TradeStepView { } else { showConfirmPaymentStartedPopup(); } + } else if (model.dataModel.getSellersPaymentAccountPayload() instanceof MoneyGramAccountPayload) { + //noinspection UnusedAssignment + //noinspection ConstantConditions + String key = "moneyGramMTCNSent"; + if (!DevEnv.isDevMode() && DontShowAgainLookup.showAgain(key)) { + String email = ((MoneyGramAccountPayload) model.dataModel.getSellersPaymentAccountPayload()).getEmail(); + Popup popup = new Popup<>(); + popup.headLine(Res.get("portfolio.pending.step2_buyer.moneyGramMTCNInfo.headline")) + .feedback(Res.get("portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg", email)) + .onAction(this::showConfirmPaymentStartedPopup) + .actionButtonText(Res.get("shared.yes")) + .closeButtonText(Res.get("shared.no")) + .onClose(popup::hide) + .dontShowAgainId(key) + .show(); + } else { + showConfirmPaymentStartedPopup(); + } } else { showConfirmPaymentStartedPopup(); } @@ -432,6 +459,15 @@ public class BuyerStep2View extends TradeStepView { paymentDetailsForTradePopup + ".\n" + copyPaste + "\n\n" + extra; + } else if (paymentAccountPayload instanceof MoneyGramAccountPayload) { + final String email = ((MoneyGramAccountPayload) paymentAccountPayload).getEmail(); + final String extra = Res.get("portfolio.pending.step2_buyer.moneyGram.extra", email); + message += Res.get("portfolio.pending.step2_buyer.moneyGram", + amount) + + accountDetails + + paymentDetailsForTradePopup + ".\n" + + copyPaste + "\n\n" + + extra; } else if (paymentAccountPayload instanceof USPostalMoneyOrderAccountPayload) { //noinspection UnusedAssignment message += Res.get("portfolio.pending.step2_buyer.postal", amount) + diff --git a/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep3View.java b/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep3View.java index 51871944c7..c523dcb85a 100644 --- a/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep3View.java +++ b/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep3View.java @@ -17,12 +17,26 @@ package bisq.desktop.main.portfolio.pendingtrades.steps.buyer; +import bisq.desktop.components.TextFieldWithIcon; import bisq.desktop.main.portfolio.pendingtrades.PendingTradesViewModel; import bisq.desktop.main.portfolio.pendingtrades.steps.TradeStepView; +import bisq.desktop.util.FormBuilder; +import bisq.desktop.util.Layout; import bisq.core.locale.Res; +import bisq.core.network.MessageState; + +import de.jensd.fx.fontawesome.AwesomeIcon; + +import javafx.scene.control.Label; +import javafx.scene.paint.Paint; + +import javafx.beans.value.ChangeListener; public class BuyerStep3View extends TradeStepView { + private final ChangeListener messageStateChangeListener; + private TextFieldWithIcon textFieldWithIconWithIcon; + /////////////////////////////////////////////////////////////////////////////////////////// // Constructor, Initialisation @@ -30,12 +44,40 @@ public class BuyerStep3View extends TradeStepView { public BuyerStep3View(PendingTradesViewModel model) { super(model); + + messageStateChangeListener = (observable, oldValue, newValue) -> { + updateMessageStateInfo(); + }; } + @Override + public void activate() { + super.activate(); + + model.getMessageStateProperty().addListener(messageStateChangeListener); + + updateMessageStateInfo(); + } + + public void deactivate() { + super.deactivate(); + + model.getMessageStateProperty().removeListener(messageStateChangeListener); + } + + /////////////////////////////////////////////////////////////////////////////////////////// // Info /////////////////////////////////////////////////////////////////////////////////////////// + @Override + protected void addInfoBlock() { + FormBuilder.addTitledGroupBg(gridPane, ++gridRow, 2, getInfoBlockTitle(), Layout.GROUP_DISTANCE); + infoLabel = FormBuilder.addMultilineLabel(gridPane, gridRow, "", Layout.FIRST_ROW_AND_GROUP_DISTANCE); + textFieldWithIconWithIcon = FormBuilder.addLabelTextFieldWithIcon(gridPane, ++gridRow, + Res.get("portfolio.pending.step3_buyer.wait.msgStateInfo.label"), 0).second; + } + @Override protected String getInfoBlockTitle() { return Res.get("portfolio.pending.step3_buyer.wait.headline"); @@ -46,6 +88,39 @@ public class BuyerStep3View extends TradeStepView { return Res.get("portfolio.pending.step3_buyer.wait.info", model.dataModel.getCurrencyCode()); } + private void updateMessageStateInfo() { + MessageState messageState = model.getMessageStateProperty().get(); + textFieldWithIconWithIcon.setText(Res.get("message.state." + messageState.name())); + Label iconLabel = textFieldWithIconWithIcon.getIconLabel(); + switch (messageState) { + case UNDEFINED: + textFieldWithIconWithIcon.setIcon(AwesomeIcon.QUESTION); + iconLabel.setTextFill(Paint.valueOf("#e9a20a")); + break; + case SENT: + textFieldWithIconWithIcon.setIcon(AwesomeIcon.ARROW_RIGHT); + iconLabel.setTextFill(Paint.valueOf("#afe193")); + break; + case ARRIVED: + textFieldWithIconWithIcon.setIcon(AwesomeIcon.OK); + iconLabel.setTextFill(Paint.valueOf("#0793ad")); + break; + case STORED_IN_MAILBOX: + textFieldWithIconWithIcon.setIcon(AwesomeIcon.ENVELOPE_ALT); + iconLabel.setTextFill(Paint.valueOf("#91B6E9")); + break; + case ACKNOWLEDGED: + textFieldWithIconWithIcon.setIcon(AwesomeIcon.OK_SIGN); + iconLabel.setTextFill(Paint.valueOf("#009900")); + break; + case FAILED: + textFieldWithIconWithIcon.setIcon(AwesomeIcon.EXCLAMATION_SIGN); + iconLabel.setTextFill(Paint.valueOf("#dd0000")); + break; + } + } + + /////////////////////////////////////////////////////////////////////////////////////////// // Warning /////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java b/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java index 5bcc0e826e..f89da41fbf 100644 --- a/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java +++ b/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java @@ -30,6 +30,7 @@ import bisq.core.locale.Res; import bisq.core.payment.payload.BankAccountPayload; import bisq.core.payment.payload.CashDepositAccountPayload; import bisq.core.payment.payload.CryptoCurrencyAccountPayload; +import bisq.core.payment.payload.MoneyGramAccountPayload; import bisq.core.payment.payload.PaymentAccountPayload; import bisq.core.payment.payload.SepaAccountPayload; import bisq.core.payment.payload.SepaInstantAccountPayload; @@ -315,6 +316,8 @@ public class SellerStep3View extends TradeStepView { message = message + Res.get("portfolio.pending.step3_seller.cash", part); else if (paymentAccountPayload instanceof WesternUnionAccountPayload) message = message + Res.get("portfolio.pending.step3_seller.westernUnion", part); + else if (paymentAccountPayload instanceof MoneyGramAccountPayload) + message = message + Res.get("portfolio.pending.step3_seller.moneyGram", part); Optional optionalHolderName = getOptionalHolderName(); if (optionalHolderName.isPresent()) { diff --git a/src/main/java/bisq/desktop/util/FormBuilder.java b/src/main/java/bisq/desktop/util/FormBuilder.java index 5e406a445d..7b5d2049ae 100644 --- a/src/main/java/bisq/desktop/util/FormBuilder.java +++ b/src/main/java/bisq/desktop/util/FormBuilder.java @@ -33,6 +33,7 @@ import bisq.desktop.components.InputTextField; import bisq.desktop.components.PasswordTextField; import bisq.desktop.components.SearchComboBox; import bisq.desktop.components.TextFieldWithCopyIcon; +import bisq.desktop.components.TextFieldWithIcon; import bisq.desktop.components.TitledGroupBg; import bisq.desktop.components.TxIdTextField; @@ -44,6 +45,8 @@ import bisq.common.util.Tuple4; import de.jensd.fx.fontawesome.AwesomeDude; import de.jensd.fx.fontawesome.AwesomeIcon; +import de.jensd.fx.glyphs.GlyphIcons; +import de.jensd.fx.glyphs.materialdesignicons.utils.MaterialDesignIconFactory; import javafx.scene.Node; import javafx.scene.control.Button; @@ -74,16 +77,7 @@ import javafx.geometry.VPos; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - - -import de.jensd.fx.glyphs.GlyphIcons; -import de.jensd.fx.glyphs.materialdesignicons.utils.MaterialDesignIconFactory; - public class FormBuilder { - private static final Logger log = LoggerFactory.getLogger(FormBuilder.class); public static final String MATERIAL_DESIGN_ICONS = "'Material Design Icons'"; public static final String FONTAWESOME_ICONS = "FontAwesome"; @@ -211,6 +205,27 @@ public class FormBuilder { return new Tuple2<>(label, textField); } + + /////////////////////////////////////////////////////////////////////////////////////////// + // Label + TextFieldWithIcon + /////////////////////////////////////////////////////////////////////////////////////////// + + + public static Tuple2 addLabelTextFieldWithIcon(GridPane gridPane, int rowIndex, String title, double top) { + Label label = addLabel(gridPane, rowIndex, title, top); + + TextFieldWithIcon textFieldWithIcon = new TextFieldWithIcon(); + textFieldWithIcon.setMouseTransparent(true); + textFieldWithIcon.setFocusTraversable(false); + GridPane.setRowIndex(textFieldWithIcon, rowIndex); + GridPane.setColumnIndex(textFieldWithIcon, 1); + GridPane.setMargin(textFieldWithIcon, new Insets(top, 0, 0, 0)); + gridPane.getChildren().add(textFieldWithIcon); + + return new Tuple2<>(label, textFieldWithIcon); + } + + /////////////////////////////////////////////////////////////////////////////////////////// // HyperlinkWithIcon /////////////////////////////////////////////////////////////////////////////////////////// @@ -873,6 +888,7 @@ public class FormBuilder { /////////////////////////////////////////////////////////////////////////////////////////// // Label + InfoTextField /////////////////////////////////////////////////////////////////////////////////////////// + public static Tuple2 addLabelInfoTextfield(GridPane gridPane, int rowIndex, String labelText, String fieldText) { return addLabelInfoTextfield(gridPane, rowIndex, labelText, fieldText, 0); diff --git a/src/test/java/bisq/desktop/AwesomeFontDemo.java b/src/test/java/bisq/desktop/AwesomeFontDemo.java index 188e91a3fe..30cbf688e1 100644 --- a/src/test/java/bisq/desktop/AwesomeFontDemo.java +++ b/src/test/java/bisq/desktop/AwesomeFontDemo.java @@ -59,7 +59,7 @@ public class AwesomeFontDemo extends Application { root.getChildren().add(button); } - primaryStage.setScene(new Scene(root, 900, 850)); + primaryStage.setScene(new Scene(root, 1200, 950)); primaryStage.show(); } }