Merge branch 'master' into refactoring-mainviewmodel

This commit is contained in:
Manfred Karrer 2018-06-26 15:20:20 +02:00
commit 1d8a6fe24e
No known key found for this signature in database
GPG Key ID: 401250966A6B2C46
16 changed files with 663 additions and 94 deletions

View File

@ -1316,6 +1316,13 @@ textfield */
-fx-font-size: 0.846em; -fx-font-size: 0.846em;
} }
.my-message-header {
-fx-text-fill: -fx-accent;
-fx-fill: -fx-accent;
-fx-font-size: 0.846em;
}
/******************************************************************************************************************** /********************************************************************************************************************
* * * *
* DAO * * DAO *

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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);
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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<Label, ComboBox, ComboBox> tuple3 = FormBuilder.addLabelComboBoxComboBox(gridPane, ++gridRow, Res.get("payment.country"));
//noinspection unchecked,unchecked,unchecked
ComboBox<Region> regionComboBox = tuple3.second;
regionComboBox.setPromptText(Res.get("payment.select.region"));
regionComboBox.setConverter(new StringConverter<Region>() {
@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<Country> countryComboBox = tuple3.third;
countryComboBox.setVisibleRowCount(15);
countryComboBox.setDisable(true);
countryComboBox.setPromptText(Res.get("payment.select.country"));
countryComboBox.setConverter(new StringConverter<Country>() {
@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<Label, InputTextField> 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);
}
}

View File

@ -30,6 +30,7 @@ import bisq.desktop.components.paymentmethods.ClearXchangeForm;
import bisq.desktop.components.paymentmethods.FasterPaymentsForm; import bisq.desktop.components.paymentmethods.FasterPaymentsForm;
import bisq.desktop.components.paymentmethods.InteracETransferForm; import bisq.desktop.components.paymentmethods.InteracETransferForm;
import bisq.desktop.components.paymentmethods.MoneyBeamForm; import bisq.desktop.components.paymentmethods.MoneyBeamForm;
import bisq.desktop.components.paymentmethods.MoneyGramForm;
import bisq.desktop.components.paymentmethods.NationalBankForm; import bisq.desktop.components.paymentmethods.NationalBankForm;
import bisq.desktop.components.paymentmethods.OKPayForm; import bisq.desktop.components.paymentmethods.OKPayForm;
import bisq.desktop.components.paymentmethods.PaymentMethodForm; import bisq.desktop.components.paymentmethods.PaymentMethodForm;
@ -72,6 +73,7 @@ import bisq.core.app.BisqEnvironment;
import bisq.core.locale.Res; import bisq.core.locale.Res;
import bisq.core.payment.AccountAgeWitnessService; import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.ClearXchangeAccount; import bisq.core.payment.ClearXchangeAccount;
import bisq.core.payment.MoneyGramAccount;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.payment.PaymentAccountFactory; import bisq.core.payment.PaymentAccountFactory;
import bisq.core.payment.WesternUnionAccount; import bisq.core.payment.WesternUnionAccount;
@ -252,6 +254,13 @@ public class FiatAccountsView extends ActivatableViewAndModel<GridPane, FiatAcco
.actionButtonText(Res.get("shared.iUnderstand")) .actionButtonText(Res.get("shared.iUnderstand"))
.onAction(() -> doSaveNewAccount(paymentAccount)) .onAction(() -> doSaveNewAccount(paymentAccount))
.show(); .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 { } else {
doSaveNewAccount(paymentAccount); doSaveNewAccount(paymentAccount);
} }
@ -467,6 +476,8 @@ public class FiatAccountsView extends ActivatableViewAndModel<GridPane, FiatAcco
return new InteracETransferForm(paymentAccount, accountAgeWitnessService, interacETransferValidator, inputValidator, root, gridRow, formatter); return new InteracETransferForm(paymentAccount, accountAgeWitnessService, interacETransferValidator, inputValidator, root, gridRow, formatter);
case PaymentMethod.US_POSTAL_MONEY_ORDER_ID: case PaymentMethod.US_POSTAL_MONEY_ORDER_ID:
return new USPostalMoneyOrderForm(paymentAccount, accountAgeWitnessService, usPostalMoneyOrderValidator, inputValidator, root, gridRow, formatter); return new USPostalMoneyOrderForm(paymentAccount, accountAgeWitnessService, usPostalMoneyOrderValidator, inputValidator, root, gridRow, formatter);
case PaymentMethod.MONEY_GRAM_ID:
return new MoneyGramForm(paymentAccount, accountAgeWitnessService, inputValidator, root, gridRow, formatter);
case PaymentMethod.WESTERN_UNION_ID: case PaymentMethod.WESTERN_UNION_ID:
return new WesternUnionForm(paymentAccount, accountAgeWitnessService, inputValidator, root, gridRow, formatter); return new WesternUnionForm(paymentAccount, accountAgeWitnessService, inputValidator, root, gridRow, formatter);
case PaymentMethod.CASH_DEPOSIT_ID: case PaymentMethod.CASH_DEPOSIT_ID:

View File

@ -157,8 +157,8 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
private VBox messagesInputBox; private VBox messagesInputBox;
private BusyAnimation sendMsgBusyAnimation; private BusyAnimation sendMsgBusyAnimation;
private Label sendMsgInfoLabel; private Label sendMsgInfoLabel;
private ChangeListener<Boolean> arrivedPropertyListener; private ChangeListener<Boolean> storedInMailboxPropertyListener, arrivedPropertyListener;
private ChangeListener<Boolean> storedInMailboxPropertyListener; private ChangeListener<String> sendMessageErrorPropertyListener;
@Nullable @Nullable
private DisputeCommunicationMessage disputeCommunicationMessage; private DisputeCommunicationMessage disputeCommunicationMessage;
private ListChangeListener<DisputeCommunicationMessage> disputeDirectMessageListListener; private ListChangeListener<DisputeCommunicationMessage> disputeDirectMessageListListener;
@ -488,6 +488,7 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
if (disputeCommunicationMessage != null) { if (disputeCommunicationMessage != null) {
disputeCommunicationMessage.arrivedProperty().removeListener(arrivedPropertyListener); disputeCommunicationMessage.arrivedProperty().removeListener(arrivedPropertyListener);
disputeCommunicationMessage.storedInMailboxProperty().removeListener(storedInMailboxPropertyListener); disputeCommunicationMessage.storedInMailboxProperty().removeListener(storedInMailboxPropertyListener);
disputeCommunicationMessage.sendMessageErrorProperty().removeListener(sendMessageErrorPropertyListener);
} }
disputeCommunicationMessage = disputeManager.sendDisputeDirectMessage(dispute, inputText, new ArrayList<>(tempAttachments)); disputeCommunicationMessage = disputeManager.sendDisputeDirectMessage(dispute, inputText, new ArrayList<>(tempAttachments));
@ -510,8 +511,6 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
hideSendMsgInfo(timer); hideSendMsgInfo(timer);
} }
}; };
if (disputeCommunicationMessage != null && disputeCommunicationMessage.arrivedProperty() != null)
disputeCommunicationMessage.arrivedProperty().addListener(arrivedPropertyListener);
storedInMailboxPropertyListener = (observable, oldValue, newValue) -> { storedInMailboxPropertyListener = (observable, oldValue, newValue) -> {
if (newValue) { if (newValue) {
sendMsgInfoLabel.setVisible(true); sendMsgInfoLabel.setVisible(true);
@ -520,8 +519,19 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
hideSendMsgInfo(timer); 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.storedInMailboxProperty().addListener(storedInMailboxPropertyListener);
disputeCommunicationMessage.sendMessageErrorProperty().addListener(sendMessageErrorPropertyListener);
}
} }
private void hideSendMsgInfo(Timer timer) { private void hideSendMsgInfo(Timer timer) {
@ -734,7 +744,7 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
@Override @Override
public ListCell<DisputeCommunicationMessage> call(ListView<DisputeCommunicationMessage> list) { public ListCell<DisputeCommunicationMessage> call(ListView<DisputeCommunicationMessage> list) {
return new ListCell<DisputeCommunicationMessage>() { return new ListCell<DisputeCommunicationMessage>() {
public ChangeListener<Boolean> sendMsgBusyAnimationListener; ChangeListener<Boolean> sendMsgBusyAnimationListener;
final Pane bg = new Pane(); final Pane bg = new Pane();
final ImageView arrow = new ImageView(); final ImageView arrow = new ImageView();
final Label headerLabel = new AutoTooltipLabel(); final Label headerLabel = new AutoTooltipLabel();
@ -743,6 +753,8 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
final HBox attachmentsBox = new HBox(); final HBox attachmentsBox = new HBox();
final AnchorPane messageAnchorPane = new AnchorPane(); final AnchorPane messageAnchorPane = new AnchorPane();
final Label statusIcon = new Label(); final Label statusIcon = new Label();
final Label statusInfoLabel = new Label();
final HBox statusHBox = new HBox();
final double arrowWidth = 15d; final double arrowWidth = 15d;
final double attachmentsBoxHeight = 20d; final double attachmentsBoxHeight = 20d;
final double border = 10d; final double border = 10d;
@ -756,25 +768,26 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
headerLabel.setTextAlignment(TextAlignment.CENTER); headerLabel.setTextAlignment(TextAlignment.CENTER);
attachmentsBox.setSpacing(5); attachmentsBox.setSpacing(5);
statusIcon.getStyleClass().add("small-text"); 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"))); copyIcon.setTooltip(new Tooltip(Res.get("shared.copyToClipboard")));
messageAnchorPane.getChildren().addAll(bg, arrow, headerLabel, messageLabel, copyIcon, attachmentsBox, statusIcon); statusHBox.setSpacing(5);
messageLabel.setOnMouseClicked(event -> { statusHBox.getChildren().addAll(statusIcon, statusInfoLabel);
if (2 > event.getClickCount()) { messageAnchorPane.getChildren().addAll(bg, arrow, headerLabel, messageLabel, copyIcon, attachmentsBox, statusHBox);
return;
}
GUIUtil.showSelectableTextModal(headerLabel.getText(), messageLabel.getText());
});
} }
@Override @Override
public void updateItem(final DisputeCommunicationMessage item, boolean empty) { public void updateItem(final DisputeCommunicationMessage message, boolean empty) {
super.updateItem(item, empty); super.updateItem(message, empty);
if (message != null && !empty) {
if (item != null && !empty) {
copyIcon.setOnMouseClicked(e -> Utilities.copyToClipboard(messageLabel.getText())); 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()) if (!messageAnchorPane.prefWidthProperty().isBound())
messageAnchorPane.prefWidthProperty() messageAnchorPane.prefWidthProperty()
.bind(messageListView.widthProperty().subtract(padding + GUIUtil.getScrollbarWidth(messageListView))); .bind(messageListView.widthProperty().subtract(padding + GUIUtil.getScrollbarWidth(messageListView)));
@ -787,25 +800,27 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
AnchorPane.setTopAnchor(copyIcon, 25d); AnchorPane.setTopAnchor(copyIcon, 25d);
AnchorPane.setBottomAnchor(attachmentsBox, bottomBorder + 10); AnchorPane.setBottomAnchor(attachmentsBox, bottomBorder + 10);
boolean senderIsTrader = item.isSenderIsTrader(); boolean senderIsTrader = message.isSenderIsTrader();
boolean isMyMsg = isTrader ? senderIsTrader : !senderIsTrader; boolean isMyMsg = isTrader ? senderIsTrader : !senderIsTrader;
arrow.setVisible(!item.isSystemMessage()); arrow.setVisible(!message.isSystemMessage());
arrow.setManaged(!item.isSystemMessage()); arrow.setManaged(!message.isSystemMessage());
statusIcon.setVisible(false); statusHBox.setVisible(false);
headerLabel.getStyleClass().removeAll("message-header", "success-text", headerLabel.getStyleClass().removeAll("message-header", "my-message-header", "success-text",
"highlight-static"); "highlight-static");
messageLabel.getStyleClass().removeAll("my-message", "message"); messageLabel.getStyleClass().removeAll("my-message", "message");
copyIcon.getStyleClass().removeAll("my-message", "message"); copyIcon.getStyleClass().removeAll("my-message", "message");
if (item.isSystemMessage()) { if (message.isSystemMessage()) {
headerLabel.getStyleClass().addAll("message-header", "success-text"); headerLabel.getStyleClass().addAll("message-header", "success-text");
bg.setId("message-bubble-green"); bg.setId("message-bubble-green");
messageLabel.getStyleClass().add("my-message"); messageLabel.getStyleClass().add("my-message");
copyIcon.getStyleClass().add("my-message"); copyIcon.getStyleClass().add("my-message");
message.addWeakMessageStateListener(() -> updateMsgState(message));
updateMsgState(message);
} else if (isMyMsg) { } else if (isMyMsg) {
headerLabel.getStyleClass().add("highlight-static"); headerLabel.getStyleClass().add("my-message-header");
bg.setId("message-bubble-blue"); bg.setId("message-bubble-blue");
messageLabel.getStyleClass().add("my-message"); messageLabel.getStyleClass().add("my-message");
copyIcon.getStyleClass().add("my-message"); copyIcon.getStyleClass().add("my-message");
@ -818,22 +833,13 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
sendMsgBusyAnimation.isRunningProperty().removeListener(sendMsgBusyAnimationListener); sendMsgBusyAnimation.isRunningProperty().removeListener(sendMsgBusyAnimationListener);
sendMsgBusyAnimationListener = (observable, oldValue, newValue) -> { sendMsgBusyAnimationListener = (observable, oldValue, newValue) -> {
if (!newValue) { if (!newValue)
if (item.arrivedProperty().get()) updateMsgState(message);
showArrivedIcon();
else if (item.storedInMailboxProperty().get())
showMailboxIcon();
}
}; };
sendMsgBusyAnimation.isRunningProperty().addListener(sendMsgBusyAnimationListener);
if (item.arrivedProperty().get()) sendMsgBusyAnimation.isRunningProperty().addListener(sendMsgBusyAnimationListener);
showArrivedIcon(); message.addWeakMessageStateListener(() -> updateMsgState(message));
else if (item.storedInMailboxProperty().get()) updateMsgState(message);
showMailboxIcon();
//TODO show that icon on error
/*else if (sendMsgProgressIndicator.getProgress() == 0)
showNotArrivedIcon();*/
} else { } else {
headerLabel.getStyleClass().add("message-header"); headerLabel.getStyleClass().add("message-header");
bg.setId("message-bubble-grey"); bg.setId("message-bubble-grey");
@ -845,7 +851,7 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
arrow.setId("bubble_arrow_grey_left"); arrow.setId("bubble_arrow_grey_left");
} }
if (item.isSystemMessage()) { if (message.isSystemMessage()) {
AnchorPane.setLeftAnchor(headerLabel, padding); AnchorPane.setLeftAnchor(headerLabel, padding);
AnchorPane.setRightAnchor(headerLabel, padding); AnchorPane.setRightAnchor(headerLabel, padding);
AnchorPane.setLeftAnchor(bg, border); AnchorPane.setLeftAnchor(bg, border);
@ -855,6 +861,8 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
AnchorPane.setRightAnchor(copyIcon, padding); AnchorPane.setRightAnchor(copyIcon, padding);
AnchorPane.setLeftAnchor(attachmentsBox, padding); AnchorPane.setLeftAnchor(attachmentsBox, padding);
AnchorPane.setRightAnchor(attachmentsBox, padding); AnchorPane.setRightAnchor(attachmentsBox, padding);
AnchorPane.clearConstraints(statusHBox);
AnchorPane.setLeftAnchor(statusHBox, padding);
} else if (senderIsTrader) { } else if (senderIsTrader) {
AnchorPane.setLeftAnchor(headerLabel, padding + arrowWidth); AnchorPane.setLeftAnchor(headerLabel, padding + arrowWidth);
AnchorPane.setLeftAnchor(bg, border + arrowWidth); AnchorPane.setLeftAnchor(bg, border + arrowWidth);
@ -865,7 +873,8 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
AnchorPane.setRightAnchor(copyIcon, padding); AnchorPane.setRightAnchor(copyIcon, padding);
AnchorPane.setLeftAnchor(attachmentsBox, padding + arrowWidth); AnchorPane.setLeftAnchor(attachmentsBox, padding + arrowWidth);
AnchorPane.setRightAnchor(attachmentsBox, padding); AnchorPane.setRightAnchor(attachmentsBox, padding);
AnchorPane.setRightAnchor(statusIcon, padding); AnchorPane.clearConstraints(statusHBox);
AnchorPane.setRightAnchor(statusHBox, padding);
} else { } else {
AnchorPane.setRightAnchor(headerLabel, padding + arrowWidth); AnchorPane.setRightAnchor(headerLabel, padding + arrowWidth);
AnchorPane.setLeftAnchor(bg, border); AnchorPane.setLeftAnchor(bg, border);
@ -876,14 +885,14 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
AnchorPane.setRightAnchor(copyIcon, padding + arrowWidth); AnchorPane.setRightAnchor(copyIcon, padding + arrowWidth);
AnchorPane.setLeftAnchor(attachmentsBox, padding); AnchorPane.setLeftAnchor(attachmentsBox, padding);
AnchorPane.setRightAnchor(attachmentsBox, padding + arrowWidth); AnchorPane.setRightAnchor(attachmentsBox, padding + arrowWidth);
AnchorPane.setLeftAnchor(statusIcon, padding); AnchorPane.clearConstraints(statusHBox);
AnchorPane.setLeftAnchor(statusHBox, padding);
} }
AnchorPane.setBottomAnchor(statusHBox, 7d);
AnchorPane.setBottomAnchor(statusIcon, 7d); headerLabel.setText(formatter.formatDateTime(new Date(message.getDate())));
headerLabel.setText(formatter.formatDateTime(new Date(item.getDate()))); messageLabel.setText(message.getMessage());
messageLabel.setText(item.getMessage());
attachmentsBox.getChildren().clear(); 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); AnchorPane.setBottomAnchor(messageLabel, bottomBorder + attachmentsBoxHeight + 10);
attachmentsBox.getChildren().add(new AutoTooltipLabel(Res.get("support.attachments") + " ") {{ attachmentsBox.getChildren().add(new AutoTooltipLabel(Res.get("support.attachments") + " ") {{
setPadding(new Insets(0, 0, 3, 0)); setPadding(new Insets(0, 0, 3, 0));
@ -892,7 +901,7 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
else else
getStyleClass().add("message"); getStyleClass().add("message");
}}); }});
item.getAttachments().stream().forEach(attachment -> { message.getAttachments().forEach(attachment -> {
final Label icon = new Label(); final Label icon = new Label();
setPadding(new Insets(0, 0, 3, 0)); setPadding(new Insets(0, 0, 3, 0));
if (isMyMsg) if (isMyMsg)
@ -927,33 +936,56 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
AnchorPane.clearConstraints(arrow); AnchorPane.clearConstraints(arrow);
AnchorPane.clearConstraints(messageLabel); AnchorPane.clearConstraints(messageLabel);
AnchorPane.clearConstraints(copyIcon); AnchorPane.clearConstraints(copyIcon);
AnchorPane.clearConstraints(statusIcon); AnchorPane.clearConstraints(statusHBox);
AnchorPane.clearConstraints(attachmentsBox); AnchorPane.clearConstraints(attachmentsBox);
copyIcon.setOnMouseClicked(null); copyIcon.setOnMouseClicked(null);
messageLabel.setOnMouseClicked(null);
setGraphic(null); setGraphic(null);
} }
} }
/* private void showNotArrivedIcon() { private void updateMsgState(DisputeCommunicationMessage message) {
statusIcon.setVisible(true); boolean visible;
AwesomeDude.setIcon(statusIcon, AwesomeIcon.WARNING_SIGN, "14"); AwesomeIcon icon = null;
Tooltip.install(statusIcon, new Tooltip("Message did not arrive. Please try to send again.")); String text = null;
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")));
statusIcon.setTextFill(Paint.valueOf("#0f87c3")); 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() { } else if (message.ackErrorProperty().get() != null) {
statusIcon.setVisible(true); visible = true;
AwesomeDude.setIcon(statusIcon, AwesomeIcon.OK, "14"); icon = AwesomeIcon.EXCLAMATION_SIGN;
statusIcon.setTooltip(new Tooltip(Res.get("support.arrived"))); text = Res.get("support.error", message.ackErrorProperty().get());
statusIcon.setTextFill(Paint.valueOf("#0f87c3")); 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);
}
} }
}; };
} }

View File

@ -221,7 +221,7 @@ public abstract class EditableOfferViewModel<M extends EditableOfferDataModel> e
switch (BisqEnvironment.getBaseCurrencyNetwork().getCurrencyCode()) { switch (BisqEnvironment.getBaseCurrencyNetwork().getCurrencyCode()) {
case "BTC": case "BTC":
amount.set("0.0001"); amount.set("0.0001");
price.set("11029"); price.set("6700");
break; break;
case "LTC": case "LTC":
amount.set("50"); amount.set("50");

View File

@ -213,8 +213,8 @@ class TakeOfferDataModel extends OfferDataModel {
calculateTotalToPay(); calculateTotalToPay();
log.info("Completed requestTxFee: txFeeFromFeeService={}", txFeeFromFeeService); log.info("Completed requestTxFee: txFeeFromFeeService={}", txFeeFromFeeService);
} else { } else {
log.warn("We received the tx fee respnse after we have shown the funding screen and ignore that " + 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 cahnged tx fees."); "to avoid that the total funds to pay changes due changed tx fees.");
} }
}, null); }, null);

View File

@ -23,7 +23,6 @@ import bisq.desktop.components.InputTextField;
import bisq.desktop.main.overlays.Overlay; import bisq.desktop.main.overlays.Overlay;
import bisq.desktop.main.overlays.popups.Popup; import bisq.desktop.main.overlays.popups.Popup;
import bisq.desktop.util.Layout; import bisq.desktop.util.Layout;
import bisq.desktop.util.Transitions;
import bisq.core.arbitration.Dispute; import bisq.core.arbitration.Dispute;
import bisq.core.arbitration.DisputeManager; import bisq.core.arbitration.DisputeManager;
@ -566,7 +565,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
if (!finalPeersDispute.isClosed()) if (!finalPeersDispute.isClosed())
UserThread.runAfter(() -> UserThread.runAfter(() ->
new Popup<>().attention(Res.get("disputeSummaryWindow.close.closePeer")).show(), new Popup<>().attention(Res.get("disputeSummaryWindow.close.closePeer")).show(),
Transitions.DEFAULT_DURATION, TimeUnit.MILLISECONDS); 200, TimeUnit.MILLISECONDS);
hide(); hide();

View File

@ -139,21 +139,24 @@ public class SendPrivateNotificationWindow extends Overlay<SendPrivateNotificati
new SendMailboxMessageListener() { new SendMailboxMessageListener() {
@Override @Override
public void onArrived() { public void onArrived() {
log.info("PrivateNotificationMessage arrived at peer."); log.info("{} arrived at peer {}.",
message.getClass().getSimpleName(), nodeAddress);
new Popup<>().feedback(Res.get("shared.messageArrived")) new Popup<>().feedback(Res.get("shared.messageArrived"))
.onClose(SendPrivateNotificationWindow.this::hide).show(); .onClose(SendPrivateNotificationWindow.this::hide).show();
} }
@Override @Override
public void onStoredInMailbox() { 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")) new Popup<>().feedback(Res.get("shared.messageStoredInMailbox"))
.onClose(SendPrivateNotificationWindow.this::hide).show(); .onClose(SendPrivateNotificationWindow.this::hide).show();
} }
@Override @Override
public void onFault(String errorMessage) { 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)) new Popup<>().feedback(Res.get("shared.messageSendingFailed", errorMessage))
.onClose(SendPrivateNotificationWindow.this::hide).show(); .onClose(SendPrivateNotificationWindow.this::hide).show();
} }

View File

@ -23,6 +23,7 @@ import bisq.desktop.util.GUIUtil;
import bisq.desktop.util.validation.BtcAddressValidator; import bisq.desktop.util.validation.BtcAddressValidator;
import bisq.core.locale.Res; import bisq.core.locale.Res;
import bisq.core.network.MessageState;
import bisq.core.offer.Offer; import bisq.core.offer.Offer;
import bisq.core.payment.AccountAgeWitnessService; import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.payload.PaymentMethod; import bisq.core.payment.payload.PaymentMethod;
@ -52,12 +53,15 @@ import javafx.beans.property.SimpleObjectProperty;
import java.util.Date; import java.util.Date;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import lombok.Getter;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static bisq.desktop.main.portfolio.pendingtrades.PendingTradesViewModel.SellerState.UNDEFINED; import static bisq.desktop.main.portfolio.pendingtrades.PendingTradesViewModel.SellerState.UNDEFINED;
public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTradesDataModel> implements ViewModel { public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTradesDataModel> implements ViewModel {
private Subscription tradeStateSubscription;
@Getter
@Nullable @Nullable
private Trade trade; private Trade trade;
@ -90,6 +94,11 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
private final ObjectProperty<BuyerState> buyerState = new SimpleObjectProperty<>(); private final ObjectProperty<BuyerState> buyerState = new SimpleObjectProperty<>();
private final ObjectProperty<SellerState> sellerState = new SimpleObjectProperty<>(); private final ObjectProperty<SellerState> sellerState = new SimpleObjectProperty<>();
@Getter
private final ObjectProperty<MessageState> messageStateProperty = new SimpleObjectProperty<>(MessageState.UNDEFINED);
private Subscription tradeStateSubscription;
private Subscription messageStateSubscription;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, initialization // Constructor, initialization
@ -115,8 +124,18 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
this.clock = clock; this.clock = clock;
} }
@Override @Override
protected void activate() { protected void deactivate() {
if (tradeStateSubscription != null) {
tradeStateSubscription.unsubscribe();
tradeStateSubscription = null;
}
if (messageStateSubscription != null) {
messageStateSubscription.unsubscribe();
messageStateSubscription = null;
}
} }
// Don't set own listener as we need to control the order of the calls // Don't set own listener as we need to control the order of the calls
@ -126,20 +145,36 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
sellerState.set(SellerState.UNDEFINED); sellerState.set(SellerState.UNDEFINED);
buyerState.set(BuyerState.UNDEFINED); buyerState.set(BuyerState.UNDEFINED);
} }
if (messageStateSubscription != null) {
messageStateSubscription.unsubscribe();
messageStateProperty.set(MessageState.UNDEFINED);
}
if (selectedItem != null) { if (selectedItem != null) {
this.trade = selectedItem.getTrade(); this.trade = selectedItem.getTrade();
tradeStateSubscription = EasyBind.subscribe(trade.stateProperty(), this::onTradeStateChanged); tradeStateSubscription = EasyBind.subscribe(trade.stateProperty(), this::onTradeStateChanged);
messageStateSubscription = EasyBind.subscribe(trade.getProcessModel().getPaymentStartedMessageStateProperty(), this::onMessageStateChanged);
} }
} }
@Override public void setMessageStateProperty(MessageState messageState) {
protected void deactivate() { if (messageStateProperty.get() == MessageState.ACKNOWLEDGED) {
if (tradeStateSubscription != null) { log.warn("We have already an ACKNOWLEDGED message received. " +
tradeStateSubscription.unsubscribe(); "We would not expect any other message after that. Received messageState={}", messageState);
tradeStateSubscription = null; return;
} }
if (trade != null)
trade.getProcessModel().setPaymentStartedMessageState(messageState);
} }
private void onMessageStateChanged(MessageState messageState) {
messageStateProperty.set(messageState);
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Getters // Getters
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////

View File

@ -78,6 +78,8 @@ public abstract class TradeStepView extends AnchorPane {
private Subscription txIdSubscription; private Subscription txIdSubscription;
private Clock.Listener clockListener; private Clock.Listener clockListener;
private final ChangeListener<String> errorMessageListener; private final ChangeListener<String> errorMessageListener;
protected Label infoLabel;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, Initialisation // Constructor, Initialisation
@ -144,6 +146,9 @@ public abstract class TradeStepView extends AnchorPane {
}); });
model.clock.addListener(clockListener); model.clock.addListener(clockListener);
if (infoLabel != null)
infoLabel.setText(getInfoText());
} }
public void deactivate() { public void deactivate() {
@ -211,7 +216,7 @@ public abstract class TradeStepView extends AnchorPane {
protected void addInfoBlock() { protected void addInfoBlock() {
FormBuilder.addTitledGroupBg(gridPane, ++gridRow, 1, getInfoBlockTitle(), Layout.GROUP_DISTANCE); 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() { protected String getInfoText() {

View File

@ -29,6 +29,7 @@ import bisq.desktop.components.paymentmethods.CryptoCurrencyForm;
import bisq.desktop.components.paymentmethods.FasterPaymentsForm; import bisq.desktop.components.paymentmethods.FasterPaymentsForm;
import bisq.desktop.components.paymentmethods.InteracETransferForm; import bisq.desktop.components.paymentmethods.InteracETransferForm;
import bisq.desktop.components.paymentmethods.MoneyBeamForm; import bisq.desktop.components.paymentmethods.MoneyBeamForm;
import bisq.desktop.components.paymentmethods.MoneyGramForm;
import bisq.desktop.components.paymentmethods.NationalBankForm; import bisq.desktop.components.paymentmethods.NationalBankForm;
import bisq.desktop.components.paymentmethods.OKPayForm; import bisq.desktop.components.paymentmethods.OKPayForm;
import bisq.desktop.components.paymentmethods.PerfectMoneyForm; import bisq.desktop.components.paymentmethods.PerfectMoneyForm;
@ -51,8 +52,10 @@ import bisq.desktop.util.Layout;
import bisq.core.locale.CurrencyUtil; import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res; import bisq.core.locale.Res;
import bisq.core.network.MessageState;
import bisq.core.payment.payload.CashDepositAccountPayload; import bisq.core.payment.payload.CashDepositAccountPayload;
import bisq.core.payment.payload.CryptoCurrencyAccountPayload; import bisq.core.payment.payload.CryptoCurrencyAccountPayload;
import bisq.core.payment.payload.MoneyGramAccountPayload;
import bisq.core.payment.payload.PaymentAccountPayload; import bisq.core.payment.payload.PaymentAccountPayload;
import bisq.core.payment.payload.PaymentMethod; import bisq.core.payment.payload.PaymentMethod;
import bisq.core.payment.payload.USPostalMoneyOrderAccountPayload; import bisq.core.payment.payload.USPostalMoneyOrderAccountPayload;
@ -111,7 +114,7 @@ public class BuyerStep2View extends TradeStepView {
busyAnimation.play(); busyAnimation.play();
confirmButton.setDisable(true); confirmButton.setDisable(true);
statusLabel.setText(Res.get("shared.sendingConfirmation")); statusLabel.setText(Res.get("shared.sendingConfirmation"));
model.setMessageStateProperty(MessageState.SENT);
timeoutTimer = UserThread.runAfter(() -> { timeoutTimer = UserThread.runAfter(() -> {
busyAnimation.stop(); busyAnimation.stop();
confirmButton.setDisable(false); confirmButton.setDisable(false);
@ -121,16 +124,19 @@ public class BuyerStep2View extends TradeStepView {
case BUYER_SAW_ARRIVED_FIAT_PAYMENT_INITIATED_MSG: case BUYER_SAW_ARRIVED_FIAT_PAYMENT_INITIATED_MSG:
busyAnimation.stop(); busyAnimation.stop();
statusLabel.setText(Res.get("shared.messageArrived")); statusLabel.setText(Res.get("shared.messageArrived"));
model.setMessageStateProperty(MessageState.ARRIVED);
break; break;
case BUYER_STORED_IN_MAILBOX_FIAT_PAYMENT_INITIATED_MSG: case BUYER_STORED_IN_MAILBOX_FIAT_PAYMENT_INITIATED_MSG:
busyAnimation.stop(); busyAnimation.stop();
statusLabel.setText(Res.get("shared.messageStoredInMailbox")); statusLabel.setText(Res.get("shared.messageStoredInMailbox"));
model.setMessageStateProperty(MessageState.STORED_IN_MAILBOX);
break; break;
case BUYER_SEND_FAILED_FIAT_PAYMENT_INITIATED_MSG: case BUYER_SEND_FAILED_FIAT_PAYMENT_INITIATED_MSG:
// We get a popup and the trade closed, so we dont need to show anything here // We get a popup and the trade closed, so we dont need to show anything here
busyAnimation.stop(); busyAnimation.stop();
confirmButton.setDisable(false); confirmButton.setDisable(false);
statusLabel.setText(""); statusLabel.setText("");
model.setMessageStateProperty(MessageState.FAILED);
break; break;
default: default:
log.warn("Unexpected case: State={}, tradeId={} " + state.name(), trade.getId()); log.warn("Unexpected case: State={}, tradeId={} " + state.name(), trade.getId());
@ -245,6 +251,9 @@ public class BuyerStep2View extends TradeStepView {
case PaymentMethod.CASH_DEPOSIT_ID: case PaymentMethod.CASH_DEPOSIT_ID:
gridRow = CashDepositForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload); gridRow = CashDepositForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload);
break; break;
case PaymentMethod.MONEY_GRAM_ID:
gridRow = MoneyGramForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload);
break;
case PaymentMethod.WESTERN_UNION_ID: case PaymentMethod.WESTERN_UNION_ID:
gridRow = WesternUnionForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload); gridRow = WesternUnionForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload);
break; break;
@ -338,6 +347,24 @@ public class BuyerStep2View extends TradeStepView {
} else { } else {
showConfirmPaymentStartedPopup(); 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 { } else {
showConfirmPaymentStartedPopup(); showConfirmPaymentStartedPopup();
} }
@ -432,6 +459,15 @@ public class BuyerStep2View extends TradeStepView {
paymentDetailsForTradePopup + ".\n" + paymentDetailsForTradePopup + ".\n" +
copyPaste + "\n\n" + copyPaste + "\n\n" +
extra; 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) { } else if (paymentAccountPayload instanceof USPostalMoneyOrderAccountPayload) {
//noinspection UnusedAssignment //noinspection UnusedAssignment
message += Res.get("portfolio.pending.step2_buyer.postal", amount) + message += Res.get("portfolio.pending.step2_buyer.postal", amount) +

View File

@ -17,12 +17,26 @@
package bisq.desktop.main.portfolio.pendingtrades.steps.buyer; 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.PendingTradesViewModel;
import bisq.desktop.main.portfolio.pendingtrades.steps.TradeStepView; 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.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 { public class BuyerStep3View extends TradeStepView {
private final ChangeListener<MessageState> messageStateChangeListener;
private TextFieldWithIcon textFieldWithIconWithIcon;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, Initialisation // Constructor, Initialisation
@ -30,12 +44,40 @@ public class BuyerStep3View extends TradeStepView {
public BuyerStep3View(PendingTradesViewModel model) { public BuyerStep3View(PendingTradesViewModel model) {
super(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 // 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 @Override
protected String getInfoBlockTitle() { protected String getInfoBlockTitle() {
return Res.get("portfolio.pending.step3_buyer.wait.headline"); 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()); 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 // Warning
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////

View File

@ -30,6 +30,7 @@ import bisq.core.locale.Res;
import bisq.core.payment.payload.BankAccountPayload; import bisq.core.payment.payload.BankAccountPayload;
import bisq.core.payment.payload.CashDepositAccountPayload; import bisq.core.payment.payload.CashDepositAccountPayload;
import bisq.core.payment.payload.CryptoCurrencyAccountPayload; import bisq.core.payment.payload.CryptoCurrencyAccountPayload;
import bisq.core.payment.payload.MoneyGramAccountPayload;
import bisq.core.payment.payload.PaymentAccountPayload; import bisq.core.payment.payload.PaymentAccountPayload;
import bisq.core.payment.payload.SepaAccountPayload; import bisq.core.payment.payload.SepaAccountPayload;
import bisq.core.payment.payload.SepaInstantAccountPayload; 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); message = message + Res.get("portfolio.pending.step3_seller.cash", part);
else if (paymentAccountPayload instanceof WesternUnionAccountPayload) else if (paymentAccountPayload instanceof WesternUnionAccountPayload)
message = message + Res.get("portfolio.pending.step3_seller.westernUnion", part); 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<String> optionalHolderName = getOptionalHolderName(); Optional<String> optionalHolderName = getOptionalHolderName();
if (optionalHolderName.isPresent()) { if (optionalHolderName.isPresent()) {

View File

@ -33,6 +33,7 @@ import bisq.desktop.components.InputTextField;
import bisq.desktop.components.PasswordTextField; import bisq.desktop.components.PasswordTextField;
import bisq.desktop.components.SearchComboBox; import bisq.desktop.components.SearchComboBox;
import bisq.desktop.components.TextFieldWithCopyIcon; import bisq.desktop.components.TextFieldWithCopyIcon;
import bisq.desktop.components.TextFieldWithIcon;
import bisq.desktop.components.TitledGroupBg; import bisq.desktop.components.TitledGroupBg;
import bisq.desktop.components.TxIdTextField; 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.AwesomeDude;
import de.jensd.fx.fontawesome.AwesomeIcon; 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.Node;
import javafx.scene.control.Button; import javafx.scene.control.Button;
@ -74,16 +77,7 @@ import javafx.geometry.VPos;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet; 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 { 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 MATERIAL_DESIGN_ICONS = "'Material Design Icons'";
public static final String FONTAWESOME_ICONS = "FontAwesome"; public static final String FONTAWESOME_ICONS = "FontAwesome";
@ -211,6 +205,27 @@ public class FormBuilder {
return new Tuple2<>(label, textField); return new Tuple2<>(label, textField);
} }
///////////////////////////////////////////////////////////////////////////////////////////
// Label + TextFieldWithIcon
///////////////////////////////////////////////////////////////////////////////////////////
public static Tuple2<Label, TextFieldWithIcon> 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 // HyperlinkWithIcon
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -873,6 +888,7 @@ public class FormBuilder {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Label + InfoTextField // Label + InfoTextField
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public static Tuple2<Label, InfoTextField> addLabelInfoTextfield(GridPane gridPane, int rowIndex, String labelText, public static Tuple2<Label, InfoTextField> addLabelInfoTextfield(GridPane gridPane, int rowIndex, String labelText,
String fieldText) { String fieldText) {
return addLabelInfoTextfield(gridPane, rowIndex, labelText, fieldText, 0); return addLabelInfoTextfield(gridPane, rowIndex, labelText, fieldText, 0);

View File

@ -59,7 +59,7 @@ public class AwesomeFontDemo extends Application {
root.getChildren().add(button); root.getChildren().add(button);
} }
primaryStage.setScene(new Scene(root, 900, 850)); primaryStage.setScene(new Scene(root, 1200, 950));
primaryStage.show(); primaryStage.show();
} }
} }