diff --git a/src/main/java/bisq/desktop/bisq.css b/src/main/java/bisq/desktop/bisq.css
index ae7a42c387a..dfe4f17cc19 100644
--- a/src/main/java/bisq/desktop/bisq.css
+++ b/src/main/java/bisq/desktop/bisq.css
@@ -286,6 +286,10 @@ bg color of non edit textFields: fafafa
-fx-background-color: -bs-bg-light;
}
+.text-area {
+ -fx-prompt-text-fill: derive(-fx-control-inner-background, -30%);
+}
+
#label-url {
-fx-cursor: hand;
-fx-text-fill: -bs-blue;
diff --git a/src/main/java/bisq/desktop/components/paymentmethods/F2FForm.java b/src/main/java/bisq/desktop/components/paymentmethods/F2FForm.java
new file mode 100644
index 00000000000..305c9968a69
--- /dev/null
+++ b/src/main/java/bisq/desktop/components/paymentmethods/F2FForm.java
@@ -0,0 +1,263 @@
+/*
+ * 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.main.overlays.popups.Popup;
+import bisq.desktop.util.Layout;
+import bisq.desktop.util.validation.F2FValidator;
+
+import bisq.core.locale.Country;
+import bisq.core.locale.CountryUtil;
+import bisq.core.locale.CurrencyUtil;
+import bisq.core.locale.FiatCurrency;
+import bisq.core.locale.Region;
+import bisq.core.locale.Res;
+import bisq.core.locale.TradeCurrency;
+import bisq.core.offer.Offer;
+import bisq.core.payment.AccountAgeWitnessService;
+import bisq.core.payment.CountryBasedPaymentAccount;
+import bisq.core.payment.F2FAccount;
+import bisq.core.payment.PaymentAccount;
+import bisq.core.payment.payload.F2FAccountPayload;
+import bisq.core.payment.payload.PaymentAccountPayload;
+import bisq.core.util.BSFormatter;
+import bisq.core.util.validation.InputValidator;
+
+import bisq.common.util.Tuple3;
+
+import org.apache.commons.lang3.StringUtils;
+
+import javafx.scene.control.ComboBox;
+import javafx.scene.control.Label;
+import javafx.scene.control.TextArea;
+import javafx.scene.layout.GridPane;
+
+import javafx.collections.FXCollections;
+
+import javafx.util.StringConverter;
+
+import static bisq.desktop.util.FormBuilder.*;
+
+public class F2FForm extends PaymentMethodForm {
+ private final F2FAccount f2fAccount;
+ private final F2FValidator f2fValidator;
+ private TextArea extraTextArea;
+ private InputTextField cityInputTextField;
+
+ public static int addFormForBuyer(GridPane gridPane, int gridRow,
+ PaymentAccountPayload paymentAccountPayload, Offer offer) {
+ F2FAccountPayload f2fAccountPayload = (F2FAccountPayload) paymentAccountPayload;
+ addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, Res.getWithCol("shared.country"),
+ CountryUtil.getNameAndCode(f2fAccountPayload.getCountryCode()));
+ addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, Res.getWithCol("payment.f2f.contact"),
+ f2fAccountPayload.getContact());
+ addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, Res.getWithCol("payment.f2f.city"),
+ offer.getF2FCity());
+ TextArea textArea = addLabelTextArea(gridPane, ++gridRow, Res.getWithCol("payment.f2f.extra"), "").second;
+ textArea.setPrefHeight(60);
+ textArea.setEditable(false);
+ textArea.setId("text-area-disabled");
+ textArea.setText(offer.getF2FExtraInfo());
+ return gridRow;
+ }
+
+ public F2FForm(PaymentAccount paymentAccount,
+ AccountAgeWitnessService accountAgeWitnessService, F2FValidator f2fValidator,
+ InputValidator inputValidator, GridPane gridPane, int gridRow, BSFormatter formatter) {
+ super(paymentAccount, accountAgeWitnessService, inputValidator, gridPane, gridRow, formatter);
+
+ this.f2fAccount = (F2FAccount) paymentAccount;
+ this.f2fValidator = f2fValidator;
+ }
+
+
+ @Override
+ public void addFormForAddAccount() {
+ gridRowFrom = gridRow + 1;
+
+ Tuple3 tuple3 = 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) {
+ getCountryBasedPaymentAccount().setCountry(selectedItem);
+ String countryCode = selectedItem.code;
+ TradeCurrency currency = CurrencyUtil.getCurrencyByCountryCode(countryCode);
+ paymentAccount.setSingleTradeCurrency(currency);
+ currencyComboBox.setDisable(false);
+ currencyComboBox.getSelectionModel().select(currency);
+
+ updateFromInputs();
+ }
+ });
+
+ regionComboBox.setOnAction(e -> {
+ Region selectedItem = regionComboBox.getSelectionModel().getSelectedItem();
+ if (selectedItem != null) {
+ countryComboBox.setDisable(false);
+ countryComboBox.setItems(FXCollections.observableArrayList(CountryUtil.getAllCountriesForRegion(selectedItem)));
+ }
+ });
+
+ //noinspection unchecked
+ currencyComboBox = addLabelComboBox(gridPane, ++gridRow, Res.getWithCol("shared.currency")).second;
+ currencyComboBox.setPromptText(Res.get("list.currency.select"));
+ currencyComboBox.setItems(FXCollections.observableArrayList(CurrencyUtil.getAllSortedFiatCurrencies()));
+ currencyComboBox.setOnAction(e -> {
+ TradeCurrency selectedItem = currencyComboBox.getSelectionModel().getSelectedItem();
+ FiatCurrency defaultCurrency = CurrencyUtil.getCurrencyByCountryCode(countryComboBox.getSelectionModel().getSelectedItem().code);
+ if (!defaultCurrency.equals(selectedItem)) {
+ new Popup<>().warning(Res.get("payment.foreign.currency"))
+ .actionButtonText(Res.get("shared.yes"))
+ .onAction(() -> {
+ paymentAccount.setSingleTradeCurrency(selectedItem);
+ autoFillNameTextField();
+ })
+ .closeButtonText(Res.get("payment.restore.default"))
+ .onClose(() -> currencyComboBox.getSelectionModel().select(defaultCurrency))
+ .show();
+ } else {
+ paymentAccount.setSingleTradeCurrency(selectedItem);
+ autoFillNameTextField();
+ }
+ });
+ currencyComboBox.setConverter(new StringConverter() {
+ @Override
+ public String toString(TradeCurrency currency) {
+ return currency.getNameAndCode();
+ }
+
+ @Override
+ public TradeCurrency fromString(String string) {
+ return null;
+ }
+ });
+ currencyComboBox.setDisable(true);
+
+ InputTextField contactInputTextField = addLabelInputTextField(gridPane, ++gridRow,
+ Res.getWithCol("payment.f2f.contact")).second;
+ contactInputTextField.setPromptText(Res.get("payment.f2f.contact.prompt"));
+ contactInputTextField.setValidator(f2fValidator);
+ contactInputTextField.textProperty().addListener((ov, oldValue, newValue) -> {
+ f2fAccount.setContact(newValue);
+ updateFromInputs();
+ });
+
+ cityInputTextField = addLabelInputTextField(gridPane, ++gridRow,
+ Res.getWithCol("payment.f2f.city")).second;
+ cityInputTextField.setPromptText(Res.get("payment.f2f.city.prompt"));
+ cityInputTextField.setValidator(f2fValidator);
+ cityInputTextField.textProperty().addListener((ov, oldValue, newValue) -> {
+ f2fAccount.setCity(newValue);
+ updateFromInputs();
+ });
+
+ extraTextArea = addLabelTextArea(gridPane, ++gridRow,
+ Res.getWithCol("payment.f2f.optionalExtra"), "").second;
+ extraTextArea.setPromptText(Res.get("payment.f2f.extra.prompt"));
+ extraTextArea.setPrefHeight(60);
+ //extraTextArea.setValidator(f2fValidator);
+ extraTextArea.textProperty().addListener((ov, oldValue, newValue) -> {
+ f2fAccount.setExtraInfo(newValue);
+ updateFromInputs();
+ });
+
+ addLimitations();
+ addAccountNameTextFieldWithAutoFillCheckBox();
+ }
+
+ @Override
+ protected void autoFillNameTextField() {
+ if (useCustomAccountNameCheckBox != null && !useCustomAccountNameCheckBox.isSelected()) {
+ String city = cityInputTextField.getText();
+ city = StringUtils.abbreviate(city, 9);
+ String method = Res.get(paymentAccount.getPaymentMethod().getId());
+ accountNameTextField.setText(method.concat(": ").concat(city));
+ }
+ }
+
+ @Override
+ public void addFormForDisplayAccount() {
+ gridRowFrom = gridRow;
+
+ addLabelTextField(gridPane, gridRow, Res.get("payment.account.name"),
+ paymentAccount.getAccountName(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
+ addLabelTextField(gridPane, ++gridRow, Res.getWithCol("shared.paymentMethod"),
+ Res.get(paymentAccount.getPaymentMethod().getId()));
+ addLabelTextField(gridPane, ++gridRow, Res.get("payment.country"),
+ getCountryBasedPaymentAccount().getCountry() != null ? getCountryBasedPaymentAccount().getCountry().name : "");
+ TradeCurrency singleTradeCurrency = paymentAccount.getSingleTradeCurrency();
+ String nameAndCode = singleTradeCurrency != null ? singleTradeCurrency.getNameAndCode() : "null";
+ addLabelTextField(gridPane, ++gridRow, Res.getWithCol("shared.currency"), nameAndCode);
+ addLabelTextField(gridPane, ++gridRow, Res.getWithCol("payment.f2f.contact", f2fAccount.getContact()),
+ f2fAccount.getContact());
+ addLabelTextField(gridPane, ++gridRow, Res.getWithCol("payment.f2f.city", f2fAccount.getCity()),
+ f2fAccount.getCity());
+ TextArea textArea = addLabelTextArea(gridPane, ++gridRow, Res.get("payment.f2f.extra"), "").second;
+ textArea.setText(f2fAccount.getExtraInfo());
+ textArea.setPrefHeight(60);
+ textArea.setEditable(false);
+
+ addLimitations();
+ }
+
+ @Override
+ public void updateAllInputsValid() {
+ allInputsValid.set(isAccountNameValid()
+ && f2fValidator.validate(f2fAccount.getContact()).isValid
+ && f2fValidator.validate(f2fAccount.getCity()).isValid
+ && f2fAccount.getTradeCurrencies().size() > 0);
+ }
+
+ private CountryBasedPaymentAccount getCountryBasedPaymentAccount() {
+ return (CountryBasedPaymentAccount) this.paymentAccount;
+ }
+}
diff --git a/src/main/java/bisq/desktop/components/paymentmethods/USPostalMoneyOrderForm.java b/src/main/java/bisq/desktop/components/paymentmethods/USPostalMoneyOrderForm.java
index cfe680f389c..2cb7f50d81b 100644
--- a/src/main/java/bisq/desktop/components/paymentmethods/USPostalMoneyOrderForm.java
+++ b/src/main/java/bisq/desktop/components/paymentmethods/USPostalMoneyOrderForm.java
@@ -36,17 +36,12 @@
import javafx.scene.control.TextArea;
import javafx.scene.layout.GridPane;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import static bisq.desktop.util.FormBuilder.addLabelInputTextField;
import static bisq.desktop.util.FormBuilder.addLabelTextArea;
import static bisq.desktop.util.FormBuilder.addLabelTextField;
import static bisq.desktop.util.FormBuilder.addLabelTextFieldWithCopyIcon;
public class USPostalMoneyOrderForm extends PaymentMethodForm {
- private static final Logger log = LoggerFactory.getLogger(USPostalMoneyOrderForm.class);
-
private final USPostalMoneyOrderAccount usPostalMoneyOrderAccount;
private final USPostalMoneyOrderValidator usPostalMoneyOrderValidator;
private TextArea postalAddressTextArea;
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 6c4109074da..1127efc4587 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
@@ -27,6 +27,7 @@
import bisq.desktop.components.paymentmethods.CashDepositForm;
import bisq.desktop.components.paymentmethods.ChaseQuickPayForm;
import bisq.desktop.components.paymentmethods.ClearXchangeForm;
+import bisq.desktop.components.paymentmethods.F2FForm;
import bisq.desktop.components.paymentmethods.FasterPaymentsForm;
import bisq.desktop.components.paymentmethods.InteracETransferForm;
import bisq.desktop.components.paymentmethods.MoneyBeamForm;
@@ -49,6 +50,7 @@
import bisq.desktop.components.paymentmethods.WesternUnionForm;
import bisq.desktop.main.overlays.popups.Popup;
import bisq.desktop.util.FormBuilder;
+import bisq.desktop.util.GUIUtil;
import bisq.desktop.util.ImageUtil;
import bisq.desktop.util.Layout;
import bisq.desktop.util.validation.AliPayValidator;
@@ -56,6 +58,7 @@
import bisq.desktop.util.validation.CashAppValidator;
import bisq.desktop.util.validation.ChaseQuickPayValidator;
import bisq.desktop.util.validation.ClearXchangeValidator;
+import bisq.desktop.util.validation.F2FValidator;
import bisq.desktop.util.validation.IBANValidator;
import bisq.desktop.util.validation.InteracETransferValidator;
import bisq.desktop.util.validation.MoneyBeamValidator;
@@ -73,6 +76,7 @@
import bisq.core.locale.Res;
import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.ClearXchangeAccount;
+import bisq.core.payment.F2FAccount;
import bisq.core.payment.MoneyGramAccount;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.PaymentAccountFactory;
@@ -137,6 +141,7 @@ public class FiatAccountsView extends ActivatableViewAndModel paymentAccountsListView;
@@ -167,6 +172,7 @@ public FiatAccountsView(FiatAccountsViewModel model,
InteracETransferValidator interacETransferValidator,
USPostalMoneyOrderValidator usPostalMoneyOrderValidator,
WeChatPayValidator weChatPayValidator,
+ F2FValidator f2FValidator,
AccountAgeWitnessService accountAgeWitnessService,
BSFormatter formatter) {
super(model);
@@ -189,6 +195,7 @@ public FiatAccountsView(FiatAccountsViewModel model,
this.interacETransferValidator = interacETransferValidator;
this.usPostalMoneyOrderValidator = usPostalMoneyOrderValidator;
this.weChatPayValidator = weChatPayValidator;
+ this.f2FValidator = f2FValidator;
this.accountAgeWitnessService = accountAgeWitnessService;
this.formatter = formatter;
}
@@ -231,41 +238,51 @@ private void onSaveNewAccount(PaymentAccount paymentAccount) {
Coin maxTradeLimitAsCoin = paymentAccount.getPaymentMethod().getMaxTradeLimitAsCoin("USD");
Coin maxTradeLimitSecondMonth = maxTradeLimitAsCoin.divide(2L);
Coin maxTradeLimitFirstMonth = maxTradeLimitAsCoin.divide(4L);
- new Popup<>().information(Res.get("payment.limits.info",
- formatter.formatCoinWithCode(maxTradeLimitFirstMonth),
- formatter.formatCoinWithCode(maxTradeLimitSecondMonth),
- formatter.formatCoinWithCode(maxTradeLimitAsCoin)))
- .width(700)
- .closeButtonText(Res.get("shared.cancel"))
- .actionButtonText(Res.get("shared.iUnderstand"))
- .onAction(() -> {
- final String currencyName = BisqEnvironment.getBaseCurrencyNetwork().getCurrencyName();
- if (paymentAccount instanceof ClearXchangeAccount) {
- new Popup<>().information(Res.get("payment.clearXchange.info", currencyName, currencyName))
- .width(900)
- .closeButtonText(Res.get("shared.cancel"))
- .actionButtonText(Res.get("shared.iConfirm"))
- .onAction(() -> doSaveNewAccount(paymentAccount))
- .show();
- } else if (paymentAccount instanceof WesternUnionAccount) {
- new Popup<>().information(Res.get("payment.westernUnion.info"))
- .width(700)
- .closeButtonText(Res.get("shared.cancel"))
- .actionButtonText(Res.get("shared.iUnderstand"))
- .onAction(() -> 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);
- }
- })
- .show();
+ if (paymentAccount instanceof F2FAccount) {
+ new Popup<>().information(Res.get("payment.f2f.info"))
+ .width(700)
+ .closeButtonText(Res.get("payment.f2f.info.openURL"))
+ .onClose(() -> GUIUtil.openWebPage("https://docs.bisq.network/#f2f"))
+ .actionButtonText(Res.get("shared.iUnderstand"))
+ .onAction(() -> doSaveNewAccount(paymentAccount))
+ .show();
+ } else {
+ new Popup<>().information(Res.get("payment.limits.info",
+ formatter.formatCoinWithCode(maxTradeLimitFirstMonth),
+ formatter.formatCoinWithCode(maxTradeLimitSecondMonth),
+ formatter.formatCoinWithCode(maxTradeLimitAsCoin)))
+ .width(700)
+ .closeButtonText(Res.get("shared.cancel"))
+ .actionButtonText(Res.get("shared.iUnderstand"))
+ .onAction(() -> {
+ final String currencyName = BisqEnvironment.getBaseCurrencyNetwork().getCurrencyName();
+ if (paymentAccount instanceof ClearXchangeAccount) {
+ new Popup<>().information(Res.get("payment.clearXchange.info", currencyName, currencyName))
+ .width(900)
+ .closeButtonText(Res.get("shared.cancel"))
+ .actionButtonText(Res.get("shared.iConfirm"))
+ .onAction(() -> doSaveNewAccount(paymentAccount))
+ .show();
+ } else if (paymentAccount instanceof WesternUnionAccount) {
+ new Popup<>().information(Res.get("payment.westernUnion.info"))
+ .width(700)
+ .closeButtonText(Res.get("shared.cancel"))
+ .actionButtonText(Res.get("shared.iUnderstand"))
+ .onAction(() -> 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);
+ }
+ })
+ .show();
+ }
}
private void doSaveNewAccount(PaymentAccount paymentAccount) {
@@ -482,6 +499,8 @@ private PaymentMethodForm getPaymentMethodForm(PaymentMethod paymentMethod, Paym
return new WesternUnionForm(paymentAccount, accountAgeWitnessService, inputValidator, root, gridRow, formatter);
case PaymentMethod.CASH_DEPOSIT_ID:
return new CashDepositForm(paymentAccount, accountAgeWitnessService, inputValidator, root, gridRow, formatter);
+ case PaymentMethod.F2F_ID:
+ return new F2FForm(paymentAccount, accountAgeWitnessService, f2FValidator, inputValidator, root, gridRow, formatter);
default:
log.error("Not supported PaymentMethod: " + paymentMethod);
return null;
diff --git a/src/main/java/bisq/desktop/main/offer/MutableOfferDataModel.java b/src/main/java/bisq/desktop/main/offer/MutableOfferDataModel.java
index 22c7e8760e8..8ffaa704490 100644
--- a/src/main/java/bisq/desktop/main/offer/MutableOfferDataModel.java
+++ b/src/main/java/bisq/desktop/main/offer/MutableOfferDataModel.java
@@ -39,6 +39,7 @@
import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.BankAccount;
import bisq.core.payment.CountryBasedPaymentAccount;
+import bisq.core.payment.F2FAccount;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.SameBankAccount;
import bisq.core.payment.SepaAccount;
@@ -369,6 +370,13 @@ Offer createAndGetOffer() {
extraDataMap.put(OfferPayload.REFERRAL_ID, referralIdService.getOptionalReferralId().get());
}
+ if (paymentAccount instanceof F2FAccount) {
+ if (extraDataMap == null)
+ extraDataMap = new HashMap<>();
+ extraDataMap.put(OfferPayload.F2F_CITY, ((F2FAccount) paymentAccount).getCity());
+ extraDataMap.put(OfferPayload.F2F_EXTRA_INFO, ((F2FAccount) paymentAccount).getExtraInfo());
+ }
+
Coin buyerSecurityDepositAsCoin = buyerSecurityDeposit.get();
checkArgument(buyerSecurityDepositAsCoin.compareTo(Restrictions.getMaxBuyerSecurityDeposit()) <= 0,
"securityDeposit must be not exceed " +
diff --git a/src/main/java/bisq/desktop/main/offer/offerbook/OfferBookViewModel.java b/src/main/java/bisq/desktop/main/offer/offerbook/OfferBookViewModel.java
index 4aa7f1bdeb4..4cc4c349dd7 100644
--- a/src/main/java/bisq/desktop/main/offer/offerbook/OfferBookViewModel.java
+++ b/src/main/java/bisq/desktop/main/offer/offerbook/OfferBookViewModel.java
@@ -404,11 +404,15 @@ String getPaymentMethod(OfferBookListItem item) {
Offer offer = item.getOffer();
String method = Res.get(offer.getPaymentMethod().getId() + "_SHORT");
String methodCountryCode = offer.getCountryCode();
+ if (isF2F(offer)) {
+ result = method + " (" + methodCountryCode + ", " + offer.getF2FCity() + ")";
+ } else {
+ if (methodCountryCode != null)
+ result = method + " (" + methodCountryCode + ")";
+ else
+ result = method;
+ }
- if (methodCountryCode != null)
- result = method + " (" + methodCountryCode + ")";
- else
- result = method;
}
return result;
}
@@ -420,37 +424,50 @@ String getPaymentMethodToolTip(OfferBookListItem item) {
result = Res.getWithCol("shared.paymentMethod") + " " + Res.get(offer.getPaymentMethod().getId());
result += "\n" + Res.getWithCol("shared.currency") + " " + CurrencyUtil.getNameAndCode(offer.getCurrencyCode());
- String methodCountryCode = offer.getCountryCode();
- if (methodCountryCode != null) {
- String bankId = offer.getBankId();
- if (bankId != null && !bankId.equals("null")) {
- if (BankUtil.isBankIdRequired(methodCountryCode))
- result += "\n" + Res.get("offerbook.offerersBankId", bankId);
- else if (BankUtil.isBankNameRequired(methodCountryCode))
- result += "\n" + Res.get("offerbook.offerersBankName", bankId);
- }
- }
+ String countryCode = offer.getCountryCode();
+ if (isF2F(offer)) {
+ if (countryCode != null) {
+ result += "\n" + Res.get("payment.f2f.offerbook.tooltip.countryAndCity",
+ CountryUtil.getNameByCode(countryCode), offer.getF2FCity());
- if (methodCountryCode != null)
- result += "\n" + Res.get("offerbook.offerersBankSeat", CountryUtil.getNameByCode(methodCountryCode));
+ result += "\n" + Res.get("payment.f2f.offerbook.tooltip.extra", offer.getF2FExtraInfo());
+ }
+ } else {
+ if (countryCode != null) {
+ String bankId = offer.getBankId();
+ if (bankId != null && !bankId.equals("null")) {
+ if (BankUtil.isBankIdRequired(countryCode))
+ result += "\n" + Res.get("offerbook.offerersBankId", bankId);
+ else if (BankUtil.isBankNameRequired(countryCode))
+ result += "\n" + Res.get("offerbook.offerersBankName", bankId);
+ }
+ }
- List acceptedCountryCodes = offer.getAcceptedCountryCodes();
- List acceptedBanks = offer.getAcceptedBankIds();
- if (acceptedCountryCodes != null && !acceptedCountryCodes.isEmpty()) {
- if (CountryUtil.containsAllSepaEuroCountries(acceptedCountryCodes))
- result += "\n" + Res.get("offerbook.offerersAcceptedBankSeatsEuro");
- else
- result += "\n" + Res.get("offerbook.offerersAcceptedBankSeats", CountryUtil.getNamesByCodesString(acceptedCountryCodes));
- } else if (acceptedBanks != null && !acceptedBanks.isEmpty()) {
- if (offer.getPaymentMethod().equals(PaymentMethod.SAME_BANK))
- result += "\n" + Res.getWithCol("shared.bankName") + " " + acceptedBanks.get(0);
- else if (offer.getPaymentMethod().equals(PaymentMethod.SPECIFIC_BANKS))
- result += "\n" + Res.getWithCol("shared.acceptedBanks") + " " + Joiner.on(", ").join(acceptedBanks);
+ if (countryCode != null)
+ result += "\n" + Res.get("offerbook.offerersBankSeat", CountryUtil.getNameByCode(countryCode));
+
+ List acceptedCountryCodes = offer.getAcceptedCountryCodes();
+ List acceptedBanks = offer.getAcceptedBankIds();
+ if (acceptedCountryCodes != null && !acceptedCountryCodes.isEmpty()) {
+ if (CountryUtil.containsAllSepaEuroCountries(acceptedCountryCodes))
+ result += "\n" + Res.get("offerbook.offerersAcceptedBankSeatsEuro");
+ else
+ result += "\n" + Res.get("offerbook.offerersAcceptedBankSeats", CountryUtil.getNamesByCodesString(acceptedCountryCodes));
+ } else if (acceptedBanks != null && !acceptedBanks.isEmpty()) {
+ if (offer.getPaymentMethod().equals(PaymentMethod.SAME_BANK))
+ result += "\n" + Res.getWithCol("shared.bankName") + " " + acceptedBanks.get(0);
+ else if (offer.getPaymentMethod().equals(PaymentMethod.SPECIFIC_BANKS))
+ result += "\n" + Res.getWithCol("shared.acceptedBanks") + " " + Joiner.on(", ").join(acceptedBanks);
+ }
}
}
return result;
}
+ private boolean isF2F(Offer offer) {
+ return offer.getPaymentMethod().equals(PaymentMethod.F2F);
+ }
+
String getDirectionLabelTooltip(Offer offer) {
return formatter.getDirectionWithCodeDetailed(offer.getMirroredDirection(), offer.getCurrencyCode());
}
diff --git a/src/main/java/bisq/desktop/main/overlays/windows/OfferDetailsWindow.java b/src/main/java/bisq/desktop/main/overlays/windows/OfferDetailsWindow.java
index 6b890dbdaf0..b7c19b4ea69 100644
--- a/src/main/java/bisq/desktop/main/overlays/windows/OfferDetailsWindow.java
+++ b/src/main/java/bisq/desktop/main/overlays/windows/OfferDetailsWindow.java
@@ -49,6 +49,7 @@
import javafx.scene.control.Button;
import javafx.scene.control.Label;
+import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.image.ImageView;
@@ -143,18 +144,19 @@ protected void createGridPane() {
private void addContent() {
int rows = 5;
-
List acceptedBanks = offer.getAcceptedBankIds();
boolean showAcceptedBanks = acceptedBanks != null && !acceptedBanks.isEmpty();
List acceptedCountryCodes = offer.getAcceptedCountryCodes();
boolean showAcceptedCountryCodes = acceptedCountryCodes != null && !acceptedCountryCodes.isEmpty();
-
+ boolean isF2F = offer.getPaymentMethod().equals(PaymentMethod.F2F);
if (!takeOfferHandlerOptional.isPresent())
rows++;
if (showAcceptedBanks)
rows++;
if (showAcceptedCountryCodes)
rows++;
+ if (isF2F)
+ rows += 2;
addTitledGroupBg(gridPane, ++rowIndex, rows, Res.get("shared.Offer"));
@@ -214,8 +216,6 @@ private void addContent() {
}
}
final PaymentMethod paymentMethod = offer.getPaymentMethod();
- final String makerPaymentAccountId = offer.getMakerPaymentAccountId();
- final PaymentAccount paymentAccount = user.getPaymentAccount(makerPaymentAccountId);
String bankId = offer.getBankId();
if (bankId == null || bankId.equals("null"))
bankId = "";
@@ -224,8 +224,10 @@ private void addContent() {
final boolean isSpecificBanks = paymentMethod.equals(PaymentMethod.SPECIFIC_BANKS);
final boolean isNationalBanks = paymentMethod.equals(PaymentMethod.NATIONAL_BANK);
final boolean isSepa = paymentMethod.equals(PaymentMethod.SEPA);
- if (offer.isMyOffer(keyRing) && makerPaymentAccountId != null && paymentAccount != null) {
- addLabelTextField(gridPane, ++rowIndex, Res.get("offerDetailsWindow.myTradingAccount"), paymentAccount.getAccountName());
+ final String makerPaymentAccountId = offer.getMakerPaymentAccountId();
+ final PaymentAccount myPaymentAccount = user.getPaymentAccount(makerPaymentAccountId);
+ if (offer.isMyOffer(keyRing) && makerPaymentAccountId != null && myPaymentAccount != null) {
+ addLabelTextField(gridPane, ++rowIndex, Res.get("offerDetailsWindow.myTradingAccount"), myPaymentAccount.getAccountName());
} else {
final String method = Res.get(paymentMethod.getId());
String methodWithBankId = method + bankId;
@@ -282,12 +284,23 @@ else if (BankUtil.isBankNameRequired(offer.getCountryCode()))
}
}
- rows = 5;
+ if (isF2F) {
+ addLabelTextField(gridPane, ++rowIndex, Res.getWithCol("payment.f2f.city"), offer.getF2FCity());
+ TextArea textArea = addLabelTextArea(gridPane, ++rowIndex, Res.getWithCol("payment.f2f.extra"), "").second;
+ textArea.setText(offer.getF2FExtraInfo());
+ textArea.setMinHeight(33);
+ textArea.setMaxHeight(textArea.getMinHeight());
+ textArea.setEditable(false);
+ }
+
+ rows = 4;
String paymentMethodCountryCode = offer.getCountryCode();
if (paymentMethodCountryCode != null)
rows++;
if (offer.getOfferFeePaymentTxId() != null)
rows++;
+ if (!isF2F)
+ rows++;
addTitledGroupBg(gridPane, ++rowIndex, rows, Res.get("shared.details"), Layout.GROUP_DISTANCE);
addLabelTextFieldWithCopyIcon(gridPane, rowIndex, Res.getWithCol("shared.offerId"), offer.getId(),
@@ -305,7 +318,7 @@ else if (BankUtil.isBankNameRequired(offer.getCountryCode()))
formatter.formatCoinWithCode(offer.getSellerSecurityDeposit());
addLabelTextField(gridPane, ++rowIndex, Res.getWithCol("shared.securityDeposit"), value);
- if (paymentMethodCountryCode != null)
+ if (paymentMethodCountryCode != null && !isF2F)
addLabelTextField(gridPane, ++rowIndex, Res.get("offerDetailsWindow.countryBank"),
CountryUtil.getNameAndCode(paymentMethodCountryCode));
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 3bf5c82a488..4a83c23c234 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
@@ -26,6 +26,7 @@
import bisq.desktop.components.paymentmethods.ChaseQuickPayForm;
import bisq.desktop.components.paymentmethods.ClearXchangeForm;
import bisq.desktop.components.paymentmethods.CryptoCurrencyForm;
+import bisq.desktop.components.paymentmethods.F2FForm;
import bisq.desktop.components.paymentmethods.FasterPaymentsForm;
import bisq.desktop.components.paymentmethods.InteracETransferForm;
import bisq.desktop.components.paymentmethods.MoneyBeamForm;
@@ -55,6 +56,7 @@
import bisq.core.network.MessageState;
import bisq.core.payment.payload.CashDepositAccountPayload;
import bisq.core.payment.payload.CryptoCurrencyAccountPayload;
+import bisq.core.payment.payload.F2FAccountPayload;
import bisq.core.payment.payload.MoneyGramAccountPayload;
import bisq.core.payment.payload.PaymentAccountPayload;
import bisq.core.payment.payload.PaymentMethod;
@@ -75,6 +77,8 @@
import org.fxmisc.easybind.EasyBind;
import org.fxmisc.easybind.Subscription;
+import static com.google.common.base.Preconditions.checkNotNull;
+
public class BuyerStep2View extends TradeStepView {
private Button confirmButton;
@@ -257,6 +261,10 @@ protected void addContent() {
case PaymentMethod.WESTERN_UNION_ID:
gridRow = WesternUnionForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload);
break;
+ case PaymentMethod.F2F_ID:
+ checkNotNull(model.dataModel.getTrade().getOffer(), "model.dataModel.getTrade().getOffer() must not be null");
+ gridRow = F2FForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload, model.dataModel.getTrade().getOffer());
+ break;
case PaymentMethod.BLOCK_CHAINS_ID:
String labelTitle = Res.get("portfolio.pending.step2_buyer.sellersAddress",
CurrencyUtil.getNameByCode(trade.getOffer().getCurrencyCode()));
@@ -266,7 +274,8 @@ protected void addContent() {
log.error("Not supported PaymentMethod: " + paymentMethodId);
}
- if (!(paymentAccountPayload instanceof CryptoCurrencyAccountPayload))
+ if (!(paymentAccountPayload instanceof CryptoCurrencyAccountPayload) &&
+ !(paymentAccountPayload instanceof F2FAccountPayload))
FormBuilder.addLabelTextFieldWithCopyIcon(gridPane, ++gridRow,
Res.getWithCol("shared.reasonForPayment"), model.dataModel.getReference());
@@ -443,7 +452,7 @@ private void showPopup() {
message += Res.get("portfolio.pending.step2_buyer.cash",
amount) +
accountDetails +
- paymentDetailsForTradePopup + ".\n" +
+ paymentDetailsForTradePopup + ".\n\n" +
copyPaste + "\n\n" +
tradeId + paddedId +
assign +
@@ -456,7 +465,7 @@ private void showPopup() {
message += Res.get("portfolio.pending.step2_buyer.westernUnion",
amount) +
accountDetails +
- paymentDetailsForTradePopup + ".\n" +
+ paymentDetailsForTradePopup + ".\n\n" +
copyPaste + "\n\n" +
extra;
} else if (paymentAccountPayload instanceof MoneyGramAccountPayload) {
@@ -465,23 +474,29 @@ private void showPopup() {
message += Res.get("portfolio.pending.step2_buyer.moneyGram",
amount) +
accountDetails +
- paymentDetailsForTradePopup + ".\n" +
+ paymentDetailsForTradePopup + ".\n\n" +
copyPaste + "\n\n" +
extra;
} else if (paymentAccountPayload instanceof USPostalMoneyOrderAccountPayload) {
//noinspection UnusedAssignment
message += Res.get("portfolio.pending.step2_buyer.postal", amount) +
accountDetails +
- paymentDetailsForTradePopup + ".\n" +
+ paymentDetailsForTradePopup + ".\n\n" +
copyPaste + "\n\n" +
tradeId + paddedId +
assign +
refTextWarn;
+ } else if (paymentAccountPayload instanceof F2FAccountPayload) {
+ //noinspection UnusedAssignment
+ message += Res.get("portfolio.pending.step2_buyer.f2f", amount) +
+ accountDetails +
+ paymentDetailsForTradePopup + "\n\n" +
+ copyPaste;
} else {
//noinspection UnusedAssignment
message += Res.get("portfolio.pending.step2_buyer.bank", amount) +
accountDetails +
- paymentDetailsForTradePopup + ".\n" +
+ paymentDetailsForTradePopup + ".\n\n" +
copyPaste + "\n\n" +
tradeId + paddedId +
assign +
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 f89da41fbf1..1f6694d185b 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,8 +30,10 @@
import bisq.core.payment.payload.BankAccountPayload;
import bisq.core.payment.payload.CashDepositAccountPayload;
import bisq.core.payment.payload.CryptoCurrencyAccountPayload;
+import bisq.core.payment.payload.F2FAccountPayload;
import bisq.core.payment.payload.MoneyGramAccountPayload;
import bisq.core.payment.payload.PaymentAccountPayload;
+import bisq.core.payment.payload.PaymentMethod;
import bisq.core.payment.payload.SepaAccountPayload;
import bisq.core.payment.payload.SepaInstantAccountPayload;
import bisq.core.payment.payload.USPostalMoneyOrderAccountPayload;
@@ -194,7 +196,7 @@ protected void addContent() {
peersPaymentDetailsTextField.setMouseTransparent(false);
peersPaymentDetailsTextField.setTooltip(new Tooltip(peersPaymentDetails));
- if (!isBlockChain) {
+ if (!isBlockChain && !trade.getOffer().getPaymentMethod().equals(PaymentMethod.F2F)) {
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, Res.getWithCol("shared.reasonForPayment"), model.dataModel.getReference());
GridPane.setRowSpan(titledGroupBg, 4);
}
@@ -266,8 +268,10 @@ private void onPaymentReceived() {
PaymentAccountPayload paymentAccountPayload = model.dataModel.getSellersPaymentAccountPayload();
String message = Res.get("portfolio.pending.step3_seller.onPaymentReceived.part1", CurrencyUtil.getNameByCode(model.dataModel.getCurrencyCode()));
if (!(paymentAccountPayload instanceof CryptoCurrencyAccountPayload)) {
- if (!(paymentAccountPayload instanceof WesternUnionAccountPayload))
+ if (!(paymentAccountPayload instanceof WesternUnionAccountPayload) &&
+ !(paymentAccountPayload instanceof F2FAccountPayload)) {
message += Res.get("portfolio.pending.step3_seller.onPaymentReceived.fiat", trade.getShortId());
+ }
Optional optionalHolderName = getOptionalHolderName();
if (optionalHolderName.isPresent()) {
@@ -306,18 +310,22 @@ private void showPopup() {
//noinspection UnusedAssignment
message = Res.get("portfolio.pending.step3_seller.altcoin", part1, currencyName, address, tradeVolumeWithCode, currencyName);
} else {
- if (paymentAccountPayload instanceof USPostalMoneyOrderAccountPayload)
+ if (paymentAccountPayload instanceof USPostalMoneyOrderAccountPayload) {
message = Res.get("portfolio.pending.step3_seller.postal", part1, tradeVolumeWithCode, id);
- else if (!(paymentAccountPayload instanceof WesternUnionAccountPayload))
+ } else if (!(paymentAccountPayload instanceof WesternUnionAccountPayload) &&
+ !(paymentAccountPayload instanceof F2FAccountPayload)) {
message = Res.get("portfolio.pending.step3_seller.bank", currencyName, tradeVolumeWithCode, id);
+ }
String part = Res.get("portfolio.pending.step3_seller.openDispute");
if (paymentAccountPayload instanceof CashDepositAccountPayload)
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);
+ message = message + Res.get("portfolio.pending.step3_seller.westernUnion");
else if (paymentAccountPayload instanceof MoneyGramAccountPayload)
- message = message + Res.get("portfolio.pending.step3_seller.moneyGram", part);
+ message = message + Res.get("portfolio.pending.step3_seller.moneyGram");
+ else if (paymentAccountPayload instanceof F2FAccountPayload)
+ message = part1;
Optional optionalHolderName = getOptionalHolderName();
if (optionalHolderName.isPresent()) {
@@ -365,9 +373,9 @@ else if (paymentAccountPayload instanceof SepaAccountPayload)
else if (paymentAccountPayload instanceof SepaInstantAccountPayload)
return Optional.of(((SepaInstantAccountPayload) paymentAccountPayload).getHolderName());
else
- return Optional.empty();
+ return Optional.empty();
} else {
- return Optional.empty();
+ return Optional.empty();
}
}
}
diff --git a/src/main/java/bisq/desktop/util/validation/F2FValidator.java b/src/main/java/bisq/desktop/util/validation/F2FValidator.java
new file mode 100644
index 00000000000..e1ef872b894
--- /dev/null
+++ b/src/main/java/bisq/desktop/util/validation/F2FValidator.java
@@ -0,0 +1,37 @@
+/*
+ * 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.util.validation;
+
+import bisq.core.util.validation.InputValidator;
+
+public final class F2FValidator extends InputValidator {
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Public methods
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public ValidationResult validate(String input) {
+ // TODO
+ return super.validate(input);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Private methods
+ ///////////////////////////////////////////////////////////////////////////////////////////
+}