diff --git a/core/src/main/java/bisq/core/offer/Offer.java b/core/src/main/java/bisq/core/offer/Offer.java index 963009a0d2b..05305dadf0d 100644 --- a/core/src/main/java/bisq/core/offer/Offer.java +++ b/core/src/main/java/bisq/core/offer/Offer.java @@ -365,9 +365,11 @@ public String getF2FCity() { return ""; } - public String getF2FExtraInfo() { + public String getExtraInfo() { if (getExtraDataMap() != null && getExtraDataMap().containsKey(OfferPayload.F2F_EXTRA_INFO)) return getExtraDataMap().get(OfferPayload.F2F_EXTRA_INFO); + else if (getExtraDataMap() != null && getExtraDataMap().containsKey(OfferPayload.CASH_BY_MAIL_EXTRA_INFO)) + return getExtraDataMap().get(OfferPayload.CASH_BY_MAIL_EXTRA_INFO); else return ""; } diff --git a/core/src/main/java/bisq/core/offer/OfferPayload.java b/core/src/main/java/bisq/core/offer/OfferPayload.java index 88b1690c5f1..e8be50708ed 100644 --- a/core/src/main/java/bisq/core/offer/OfferPayload.java +++ b/core/src/main/java/bisq/core/offer/OfferPayload.java @@ -80,6 +80,7 @@ public static protobuf.OfferPayload.Direction toProtoMessage(Direction direction // Only used in payment method F2F public static final String F2F_CITY = "f2fCity"; public static final String F2F_EXTRA_INFO = "f2fExtraInfo"; + public static final String CASH_BY_MAIL_EXTRA_INFO = "cashByMailExtraInfo"; // Comma separated list of ordinal of a bisq.common.app.Capability. E.g. ordinal of // Capability.SIGNED_ACCOUNT_AGE_WITNESS is 11 and Capability.MEDIATION is 12 so if we want to signal that maker diff --git a/core/src/main/java/bisq/core/offer/OfferUtil.java b/core/src/main/java/bisq/core/offer/OfferUtil.java index 8cc861f0240..8ea47fd2be0 100644 --- a/core/src/main/java/bisq/core/offer/OfferUtil.java +++ b/core/src/main/java/bisq/core/offer/OfferUtil.java @@ -25,6 +25,7 @@ import bisq.core.locale.Res; import bisq.core.monetary.Price; import bisq.core.monetary.Volume; +import bisq.core.payment.CashByMailAccount; import bisq.core.payment.F2FAccount; import bisq.core.payment.PaymentAccount; import bisq.core.provider.fee.FeeService; @@ -329,6 +330,10 @@ public Map getExtraDataMap(PaymentAccount paymentAccount, extraDataMap.put(F2F_EXTRA_INFO, ((F2FAccount) paymentAccount).getExtraInfo()); } + if (paymentAccount instanceof CashByMailAccount) { + extraDataMap.put(CASH_BY_MAIL_EXTRA_INFO, ((CashByMailAccount) paymentAccount).getExtraInfo()); + } + extraDataMap.put(CAPABILITIES, Capabilities.app.toStringList()); if (currencyCode.equals("XMR") && direction == Direction.SELL) { diff --git a/core/src/main/java/bisq/core/payment/CashByMailAccount.java b/core/src/main/java/bisq/core/payment/CashByMailAccount.java new file mode 100644 index 00000000000..d7d1b85ecce --- /dev/null +++ b/core/src/main/java/bisq/core/payment/CashByMailAccount.java @@ -0,0 +1,58 @@ +/* + * 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.core.payment; + +import bisq.core.payment.payload.CashByMailAccountPayload; +import bisq.core.payment.payload.PaymentAccountPayload; +import bisq.core.payment.payload.PaymentMethod; + +public final class CashByMailAccount extends PaymentAccount { + + public CashByMailAccount() { + super(PaymentMethod.CASH_BY_MAIL); + } + + @Override + protected PaymentAccountPayload createPayload() { + return new CashByMailAccountPayload(paymentMethod.getId(), id); + } + + public void setPostalAddress(String postalAddress) { + ((CashByMailAccountPayload) paymentAccountPayload).setPostalAddress(postalAddress); + } + + public String getPostalAddress() { + return ((CashByMailAccountPayload) paymentAccountPayload).getPostalAddress(); + } + + public void setContact(String contact) { + ((CashByMailAccountPayload) paymentAccountPayload).setContact(contact); + } + + public String getContact() { + return ((CashByMailAccountPayload) paymentAccountPayload).getContact(); + } + + public void setExtraInfo(String extraInfo) { + ((CashByMailAccountPayload) paymentAccountPayload).setExtraInfo(extraInfo); + } + + public String getExtraInfo() { + return ((CashByMailAccountPayload) paymentAccountPayload).getExtraInfo(); + } +} diff --git a/core/src/main/java/bisq/core/payment/PaymentAccountFactory.java b/core/src/main/java/bisq/core/payment/PaymentAccountFactory.java index 14a8017e3ff..faed57acd34 100644 --- a/core/src/main/java/bisq/core/payment/PaymentAccountFactory.java +++ b/core/src/main/java/bisq/core/payment/PaymentAccountFactory.java @@ -74,6 +74,8 @@ public static PaymentAccount getPaymentAccount(PaymentMethod paymentMethod) { return new HalCashAccount(); case PaymentMethod.F2F_ID: return new F2FAccount(); + case PaymentMethod.CASH_BY_MAIL_ID: + return new CashByMailAccount(); case PaymentMethod.PROMPT_PAY_ID: return new PromptPayAccount(); case PaymentMethod.ADVANCED_CASH_ID: diff --git a/core/src/main/java/bisq/core/payment/payload/CashByMailAccountPayload.java b/core/src/main/java/bisq/core/payment/payload/CashByMailAccountPayload.java new file mode 100644 index 00000000000..f1b906f90de --- /dev/null +++ b/core/src/main/java/bisq/core/payment/payload/CashByMailAccountPayload.java @@ -0,0 +1,124 @@ +/* + * 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.core.payment.payload; + +import bisq.core.locale.Res; + +import com.google.protobuf.Message; + +import org.apache.commons.lang3.ArrayUtils; + +import java.nio.charset.StandardCharsets; + +import java.util.HashMap; +import java.util.Map; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import lombok.extern.slf4j.Slf4j; + +@EqualsAndHashCode(callSuper = true) +@ToString +@Setter +@Getter +@Slf4j +public final class CashByMailAccountPayload extends PaymentAccountPayload implements PayloadWithHolderName { + private String postalAddress = ""; + private String contact = ""; + private String extraInfo = ""; + + public CashByMailAccountPayload(String paymentMethod, String id) { + super(paymentMethod, id); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // PROTO BUFFER + /////////////////////////////////////////////////////////////////////////////////////////// + + private CashByMailAccountPayload(String paymentMethod, String id, + String postalAddress, + String contact, + String extraInfo, + long maxTradePeriod, + Map excludeFromJsonDataMap) { + super(paymentMethod, + id, + maxTradePeriod, + excludeFromJsonDataMap); + this.postalAddress = postalAddress; + this.contact = contact; + this.extraInfo = extraInfo; + } + + @Override + public Message toProtoMessage() { + return getPaymentAccountPayloadBuilder() + .setCashByMailAccountPayload(protobuf.CashByMailAccountPayload.newBuilder() + .setPostalAddress(postalAddress) + .setContact(contact) + .setExtraInfo(extraInfo)) + .build(); + } + + public static CashByMailAccountPayload fromProto(protobuf.PaymentAccountPayload proto) { + return new CashByMailAccountPayload(proto.getPaymentMethodId(), + proto.getId(), + proto.getCashByMailAccountPayload().getPostalAddress(), + proto.getCashByMailAccountPayload().getContact(), + proto.getCashByMailAccountPayload().getExtraInfo(), + proto.getMaxTradePeriod(), + new HashMap<>(proto.getExcludeFromJsonDataMap())); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // API + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public String getPaymentDetails() { + return Res.get(paymentMethodId) + " - " + Res.getWithCol("payment.account.owner") + " " + contact + ", " + + Res.getWithCol("payment.postal.address") + " " + postalAddress + ", " + + Res.getWithCol("payment.shared.extraInfo") + " " + extraInfo; + } + + @Override + public String getPaymentDetailsForTradePopup() { + return Res.getWithCol("payment.account.owner") + " " + contact + "\n" + + Res.getWithCol("payment.postal.address") + " " + postalAddress; + } + + @Override + public byte[] getAgeWitnessInputData() { + // We use here the contact because the address alone seems to be too weak + return super.getAgeWitnessInputData(ArrayUtils.addAll(contact.getBytes(StandardCharsets.UTF_8), + postalAddress.getBytes(StandardCharsets.UTF_8))); + } + + @Override + public String getOwnerId() { + return contact; + } + @Override + public String getHolderName() { + return contact; + } +} diff --git a/core/src/main/java/bisq/core/payment/payload/F2FAccountPayload.java b/core/src/main/java/bisq/core/payment/payload/F2FAccountPayload.java index 0f725668d85..ec3246dd50e 100644 --- a/core/src/main/java/bisq/core/payment/payload/F2FAccountPayload.java +++ b/core/src/main/java/bisq/core/payment/payload/F2FAccountPayload.java @@ -107,7 +107,7 @@ public static PaymentAccountPayload fromProto(protobuf.PaymentAccountPayload pro public String getPaymentDetails() { return Res.get(paymentMethodId) + " - " + Res.getWithCol("payment.f2f.contact") + " " + contact + ", " + Res.getWithCol("payment.f2f.city") + " " + city + - ", " + Res.getWithCol("payment.f2f.extra") + " " + extraInfo; + ", " + Res.getWithCol("payment.shared.extraInfo") + " " + extraInfo; } diff --git a/core/src/main/java/bisq/core/payment/payload/PaymentMethod.java b/core/src/main/java/bisq/core/payment/payload/PaymentMethod.java index 879a2ace13b..5498b7da177 100644 --- a/core/src/main/java/bisq/core/payment/payload/PaymentMethod.java +++ b/core/src/main/java/bisq/core/payment/payload/PaymentMethod.java @@ -95,6 +95,7 @@ public final class PaymentMethod implements PersistablePayload, Comparable. + */ + +package bisq.desktop.components.paymentmethods; + +import bisq.desktop.components.InputTextField; +import bisq.desktop.util.Layout; + +import bisq.core.account.witness.AccountAgeWitnessService; +import bisq.core.locale.CurrencyUtil; +import bisq.core.locale.Res; +import bisq.core.payment.PaymentAccount; +import bisq.core.payment.CashByMailAccount; +import bisq.core.payment.payload.PaymentAccountPayload; +import bisq.core.payment.payload.CashByMailAccountPayload; +import bisq.core.util.coin.CoinFormatter; +import bisq.core.util.validation.InputValidator; + +import com.jfoenix.controls.JFXTextArea; + +import javafx.scene.control.TextArea; +import javafx.scene.layout.FlowPane; +import javafx.scene.layout.GridPane; + +import static bisq.desktop.util.FormBuilder.*; + +public class CashByMailForm extends PaymentMethodForm { + private final CashByMailAccount cashByMailAccount; + private TextArea postalAddressTextArea; + private InputTextField contactField; + + public static int addFormForBuyer(GridPane gridPane, int gridRow, + PaymentAccountPayload paymentAccountPayload) { + CashByMailAccountPayload cbm = (CashByMailAccountPayload) paymentAccountPayload; + addTopLabelTextFieldWithCopyIcon(gridPane, gridRow, 1, + Res.get("payment.account.owner"), + cbm.getHolderName(), + Layout.COMPACT_FIRST_ROW_AND_GROUP_DISTANCE); + + TextArea textAddress = addCompactTopLabelTextArea(gridPane, ++gridRow, Res.get("payment.postal.address"), "").second; + textAddress.setMinHeight(70); + textAddress.setEditable(false); + textAddress.setText(cbm.getPostalAddress()); + + TextArea textExtraInfo = addCompactTopLabelTextArea(gridPane, gridRow, 1, Res.get("payment.shared.extraInfo"), "").second; + textExtraInfo.setMinHeight(70); + textExtraInfo.setEditable(false); + textExtraInfo.setText(cbm.getExtraInfo()); + return gridRow; + } + + public CashByMailForm(PaymentAccount paymentAccount, + AccountAgeWitnessService accountAgeWitnessService, + InputValidator inputValidator, GridPane gridPane, int gridRow, CoinFormatter formatter) { + super(paymentAccount, accountAgeWitnessService, inputValidator, gridPane, gridRow, formatter); + this.cashByMailAccount = (CashByMailAccount) paymentAccount; + } + + private void addCurrenciesGrid(boolean isEditable) { + FlowPane flowPane = addTopLabelFlowPane(gridPane, ++gridRow, + Res.get("payment.supportedCurrenciesForReceiver"), 20, 20).second; + + if (isEditable) { + flowPane.setId("flow-pane-checkboxes-bg"); + } else { + flowPane.setId("flow-pane-checkboxes-non-editable-bg"); + } + + CurrencyUtil.getMainFiatCurrencies().forEach(currency -> + fillUpFlowPaneWithCurrencies(isEditable, flowPane, currency, paymentAccount)); + } + + @Override + public void addFormForAddAccount() { + gridRowFrom = gridRow + 1; + + contactField = addInputTextField(gridPane, ++gridRow, + Res.get("payment.cashByMail.contact")); + contactField.setPromptText(Res.get("payment.cashByMail.contact.prompt")); + contactField.setValidator(inputValidator); + contactField.textProperty().addListener((ov, oldValue, newValue) -> { + cashByMailAccount.setContact(newValue); + updateFromInputs(); + }); + + postalAddressTextArea = addTopLabelTextArea(gridPane, ++gridRow, + Res.get("payment.postal.address"), "").second; + postalAddressTextArea.setMinHeight(70); + postalAddressTextArea.textProperty().addListener((ov, oldValue, newValue) -> { + cashByMailAccount.setPostalAddress(newValue); + updateFromInputs(); + }); + + TextArea extraTextArea = addTopLabelTextArea(gridPane, ++gridRow, + Res.get("payment.shared.optionalExtra"), Res.get("payment.shared.extraInfo.prompt")).second; + extraTextArea.setMinHeight(70); + ((JFXTextArea) extraTextArea).setLabelFloat(false); + extraTextArea.textProperty().addListener((ov, oldValue, newValue) -> { + cashByMailAccount.setExtraInfo(newValue); + updateFromInputs(); + }); + + addCurrenciesGrid(true); + + addLimitations(false); + addAccountNameTextFieldWithAutoFillToggleButton(); + } + + @Override + protected void autoFillNameTextField() { + setAccountNameWithString(contactField.getText()); + } + + @Override + public void addFormForDisplayAccount() { + gridRowFrom = gridRow; + addTopLabelTextField(gridPane, gridRow, Res.get("payment.account.name"), + cashByMailAccount.getAccountName(), Layout.FIRST_ROW_AND_GROUP_DISTANCE); + addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("shared.paymentMethod"), + Res.get(cashByMailAccount.getPaymentMethod().getId())); + addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.f2f.contact"), + cashByMailAccount.getContact()); + TextArea textArea = addCompactTopLabelTextArea(gridPane, ++gridRow, Res.get("payment.postal.address"), "").second; + textArea.setText(cashByMailAccount.getPostalAddress()); + textArea.setMinHeight(70); + textArea.setEditable(false); + + TextArea textAreaExtra = addCompactTopLabelTextArea(gridPane, ++gridRow, Res.get("payment.shared.extraInfo"), "").second; + textAreaExtra.setText(cashByMailAccount.getExtraInfo()); + textAreaExtra.setMinHeight(70); + textAreaExtra.setEditable(false); + + addCurrenciesGrid(false); + + addLimitations(true); + } + + @Override + public void updateAllInputsValid() { + allInputsValid.set(isAccountNameValid() + && !postalAddressTextArea.getText().isEmpty() + && inputValidator.validate(cashByMailAccount.getContact()).isValid + && paymentAccount.getTradeCurrencies().size() > 0); + } +} diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/F2FForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/F2FForm.java index 431662a5808..cc338ad6733 100644 --- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/F2FForm.java +++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/F2FForm.java @@ -64,11 +64,11 @@ public static int addFormForBuyer(GridPane gridPane, int gridRow, offer.getF2FCity(), top); addCompactTopLabelTextFieldWithCopyIcon(gridPane, ++gridRow, Res.get("payment.f2f.contact"), f2fAccountPayload.getContact()); - TextArea textArea = addTopLabelTextArea(gridPane, gridRow, 1, Res.get("payment.f2f.extra"), "").second; + TextArea textArea = addTopLabelTextArea(gridPane, gridRow, 1, Res.get("payment.shared.extraInfo"), "").second; textArea.setMinHeight(70); textArea.setEditable(false); textArea.setId("text-area-disabled"); - textArea.setText(offer.getF2FExtraInfo()); + textArea.setText(offer.getExtraInfo()); return gridRow; } @@ -109,7 +109,7 @@ public void addFormForAddAccount() { }); TextArea extraTextArea = addTopLabelTextArea(gridPane, ++gridRow, - Res.get("payment.f2f.optionalExtra"), Res.get("payment.f2f.extra.prompt")).second; + Res.get("payment.shared.optionalExtra"), Res.get("payment.shared.extraInfo.prompt")).second; extraTextArea.setMinHeight(70); ((JFXTextArea) extraTextArea).setLabelFloat(false); //extraTextArea.setValidator(f2fValidator); @@ -163,7 +163,7 @@ public void addFormForDisplayAccount() { f2fAccount.getContact()); addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.f2f.city", f2fAccount.getCity()), f2fAccount.getCity()); - TextArea textArea = addCompactTopLabelTextArea(gridPane, ++gridRow, Res.get("payment.f2f.extra"), "").second; + TextArea textArea = addCompactTopLabelTextArea(gridPane, ++gridRow, Res.get("payment.shared.extraInfo"), "").second; textArea.setText(f2fAccount.getExtraInfo()); textArea.setMinHeight(70); textArea.setEditable(false); diff --git a/desktop/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsView.java b/desktop/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsView.java index a9421c728ba..75e4d59d6e4 100644 --- a/desktop/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsView.java +++ b/desktop/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsView.java @@ -23,6 +23,7 @@ import bisq.desktop.components.paymentmethods.AliPayForm; import bisq.desktop.components.paymentmethods.AmazonGiftCardForm; import bisq.desktop.components.paymentmethods.AustraliaPayidForm; +import bisq.desktop.components.paymentmethods.CashByMailForm; import bisq.desktop.components.paymentmethods.CashDepositForm; import bisq.desktop.components.paymentmethods.ChaseQuickPayForm; import bisq.desktop.components.paymentmethods.ClearXchangeForm; @@ -75,12 +76,14 @@ import bisq.desktop.util.validation.USPostalMoneyOrderValidator; import bisq.desktop.util.validation.UpholdValidator; import bisq.desktop.util.validation.WeChatPayValidator; +import bisq.desktop.util.validation.LengthValidator; import bisq.core.account.witness.AccountAgeWitnessService; import bisq.core.locale.Res; import bisq.core.offer.OfferRestrictions; import bisq.core.payment.AmazonGiftCardAccount; import bisq.core.payment.AustraliaPayid; +import bisq.core.payment.CashByMailAccount; import bisq.core.payment.CashDepositAccount; import bisq.core.payment.ClearXchangeAccount; import bisq.core.payment.F2FAccount; @@ -94,7 +97,6 @@ import bisq.core.payment.payload.PaymentMethod; import bisq.core.util.FormattingUtils; import bisq.core.util.coin.CoinFormatter; -import bisq.core.util.validation.InputValidator; import bisq.common.config.Config; import bisq.common.util.Tuple2; @@ -133,7 +135,7 @@ public class FiatAccountsView extends PaymentAccountsView doSaveNewAccount(paymentAccount)) .show(); + } else if (paymentAccount instanceof CashByMailAccount) { + // CashByMail has no chargeback risk so we don't show the text from payment.limits.info. + new Popup().information(Res.get("payment.cashByMail.info")) + .width(700) + .closeButtonText(Res.get("shared.cancel")) + .actionButtonText(Res.get("shared.iUnderstand")) + .onAction(() -> doSaveNewAccount(paymentAccount)) + .show(); } else if (paymentAccount instanceof HalCashAccount) { // HalCash has no chargeback risk so we don't show the text from payment.limits.info. new Popup().information(Res.get("payment.halCash.info")) @@ -504,6 +516,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.CASH_BY_MAIL_ID: + return new CashByMailForm(paymentAccount, accountAgeWitnessService, inputValidator, root, gridRow, formatter); case PaymentMethod.HAL_CASH_ID: return new HalCashForm(paymentAccount, accountAgeWitnessService, halCashValidator, inputValidator, root, gridRow, formatter); case PaymentMethod.F2F_ID: diff --git a/desktop/src/main/java/bisq/desktop/main/offer/offerbook/OfferBookViewModel.java b/desktop/src/main/java/bisq/desktop/main/offer/offerbook/OfferBookViewModel.java index 6e0ddd0fa3d..ce1dfa13c9f 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/offerbook/OfferBookViewModel.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/offerbook/OfferBookViewModel.java @@ -484,7 +484,7 @@ String getPaymentMethodToolTip(OfferBookListItem item) { result += "\n" + Res.get("payment.f2f.offerbook.tooltip.countryAndCity", CountryUtil.getNameByCode(countryCode), offer.getF2FCity()); - result += "\n" + Res.get("payment.f2f.offerbook.tooltip.extra", offer.getF2FExtraInfo()); + result += "\n" + Res.get("payment.f2f.offerbook.tooltip.extra", offer.getExtraInfo()); } } else { if (countryCode != null) { diff --git a/desktop/src/main/java/bisq/desktop/main/overlays/windows/OfferDetailsWindow.java b/desktop/src/main/java/bisq/desktop/main/overlays/windows/OfferDetailsWindow.java index 95d46979a59..5b845c9244c 100644 --- a/desktop/src/main/java/bisq/desktop/main/overlays/windows/OfferDetailsWindow.java +++ b/desktop/src/main/java/bisq/desktop/main/overlays/windows/OfferDetailsWindow.java @@ -163,14 +163,17 @@ private void addContent() { List acceptedCountryCodes = offer.getAcceptedCountryCodes(); boolean showAcceptedCountryCodes = acceptedCountryCodes != null && !acceptedCountryCodes.isEmpty(); boolean isF2F = offer.getPaymentMethod().equals(PaymentMethod.F2F); + boolean showExtraInfo = offer.getPaymentMethod().equals(PaymentMethod.F2F) || offer.getPaymentMethod().equals(PaymentMethod.CASH_BY_MAIL); if (!takeOfferHandlerOptional.isPresent()) rows++; if (showAcceptedBanks) rows++; if (showAcceptedCountryCodes) rows++; + if (showExtraInfo) + rows++; if (isF2F) - rows += 2; + rows++; boolean showXmrAutoConf = offer.isXmr() && offer.getDirection() == OfferPayload.Direction.SELL; if (showXmrAutoConf) { @@ -313,8 +316,10 @@ else if (BankUtil.isBankNameRequired(countryCode)) if (isF2F) { addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("payment.f2f.city"), offer.getF2FCity()); - TextArea textArea = addConfirmationLabelTextArea(gridPane, ++rowIndex, Res.get("payment.f2f.extra"), "", 0).second; - textArea.setText(offer.getF2FExtraInfo()); + } + if (showExtraInfo) { + TextArea textArea = addConfirmationLabelTextArea(gridPane, ++rowIndex, Res.get("payment.shared.extraInfo"), "", 0).second; + textArea.setText(offer.getExtraInfo()); textArea.setMinHeight(33); textArea.setMaxHeight(textArea.getMinHeight()); textArea.setEditable(false); diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java index 9e6d56d9fd6..787d36bac99 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java @@ -24,6 +24,7 @@ import bisq.desktop.components.paymentmethods.AliPayForm; import bisq.desktop.components.paymentmethods.AmazonGiftCardForm; import bisq.desktop.components.paymentmethods.AssetsForm; +import bisq.desktop.components.paymentmethods.CashByMailForm; import bisq.desktop.components.paymentmethods.CashDepositForm; import bisq.desktop.components.paymentmethods.ChaseQuickPayForm; import bisq.desktop.components.paymentmethods.ClearXchangeForm; @@ -64,6 +65,7 @@ import bisq.core.payment.PaymentAccountUtil; import bisq.core.payment.payload.AmazonGiftCardAccountPayload; import bisq.core.payment.payload.AssetsAccountPayload; +import bisq.core.payment.payload.CashByMailAccountPayload; import bisq.core.payment.payload.CashDepositAccountPayload; import bisq.core.payment.payload.F2FAccountPayload; import bisq.core.payment.payload.FasterPaymentsAccountPayload; @@ -279,6 +281,9 @@ protected void addContent() { case PaymentMethod.CASH_DEPOSIT_ID: gridRow = CashDepositForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload); break; + case PaymentMethod.CASH_BY_MAIL_ID: + gridRow = CashByMailForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload); + break; case PaymentMethod.MONEY_GRAM_ID: gridRow = MoneyGramForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload); break; @@ -567,6 +572,9 @@ private void showPopup() { } else if (paymentAccountPayload instanceof AmazonGiftCardAccountPayload) { message += Res.get("portfolio.pending.step2_buyer.amazonGiftCard", amount) + refTextWarn; + } else if (paymentAccountPayload instanceof CashByMailAccountPayload || + paymentAccountPayload instanceof HalCashAccountPayload) { + message += Res.get("portfolio.pending.step2_buyer.pay", amount); } else { message += Res.get("portfolio.pending.step2_buyer.pay", amount) + refTextWarn + "\n\n" + diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java index e8c3db02293..faf42804e29 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java @@ -20,7 +20,6 @@ import bisq.desktop.components.BusyAnimation; import bisq.desktop.components.InfoTextField; import bisq.desktop.components.TextFieldWithCopyIcon; -import bisq.desktop.components.TitledGroupBg; import bisq.desktop.components.indicator.TxConfidenceIndicator; import bisq.desktop.main.overlays.popups.Popup; import bisq.desktop.main.portfolio.pendingtrades.PendingTradesViewModel; @@ -35,6 +34,7 @@ import bisq.core.payment.payload.AmazonGiftCardAccountPayload; import bisq.core.payment.payload.AssetsAccountPayload; import bisq.core.payment.payload.BankAccountPayload; +import bisq.core.payment.payload.CashByMailAccountPayload; import bisq.core.payment.payload.CashDepositAccountPayload; import bisq.core.payment.payload.F2FAccountPayload; import bisq.core.payment.payload.HalCashAccountPayload; @@ -194,7 +194,7 @@ protected void addContent() { addTradeInfoBlock(); - TitledGroupBg titledGroupBg = addTitledGroupBg(gridPane, ++gridRow, 3, + addTitledGroupBg(gridPane, ++gridRow, 3, Res.get("portfolio.pending.step3_seller.confirmPaymentReceipt"), Layout.COMPACT_GROUP_DISTANCE); TextFieldWithCopyIcon field = addTopLabelTextFieldWithCopyIcon(gridPane, gridRow, @@ -206,7 +206,6 @@ protected void addContent() { String peersPaymentDetails = ""; String myTitle = ""; String peersTitle = ""; - boolean isBlockChain = false; String currencyName = getCurrencyName(trade); Contract contract = trade.getContract(); if (contract != null) { @@ -225,7 +224,6 @@ protected void addContent() { peersPaymentDetails = ((AssetsAccountPayload) peersPaymentAccountPayload).getAddress(); myTitle = Res.get("portfolio.pending.step3_seller.yourAddress", currencyName); peersTitle = Res.get("portfolio.pending.step3_seller.buyersAddress", currencyName); - isBlockChain = true; } else { if (myPaymentDetails.isEmpty()) { // Not expected @@ -400,6 +398,8 @@ private void showPopup() { } else { if (paymentAccountPayload instanceof USPostalMoneyOrderAccountPayload) { message = Res.get("portfolio.pending.step3_seller.postal", part1, tradeVolumeWithCode); + } else if (paymentAccountPayload instanceof CashByMailAccountPayload) { + message = Res.get("portfolio.pending.step3_seller.cashByMail", part1, tradeVolumeWithCode); } else if (!(paymentAccountPayload instanceof WesternUnionAccountPayload) && !(paymentAccountPayload instanceof HalCashAccountPayload) && !(paymentAccountPayload instanceof F2FAccountPayload) && diff --git a/desktop/src/main/java/bisq/desktop/util/validation/EmailValidator.java b/desktop/src/main/java/bisq/desktop/util/validation/EmailValidator.java index 01b3062c596..4b732e075c1 100644 --- a/desktop/src/main/java/bisq/desktop/util/validation/EmailValidator.java +++ b/desktop/src/main/java/bisq/desktop/util/validation/EmailValidator.java @@ -45,7 +45,7 @@ public final class EmailValidator extends InputValidator { @Override public ValidationResult validate(String input) { - if (input == null || input.length() < 6) // shortest address is l@d.cc + if (input == null || input.length() < 6 || input.length() > 100) // shortest address is l@d.cc, max length 100 return invalidAddress; String[] subStrings; String local, domain; diff --git a/proto/src/main/proto/pb.proto b/proto/src/main/proto/pb.proto index 55ea8dd5dbe..493371075dc 100644 --- a/proto/src/main/proto/pb.proto +++ b/proto/src/main/proto/pb.proto @@ -960,6 +960,7 @@ message PaymentAccountPayload { TransferwiseAccountPayload Transferwise_account_payload = 29; AustraliaPayidPayload australia_payid_payload = 30; AmazonGiftCardAccountPayload amazon_gift_card_account_payload = 31; + CashByMailAccountPayload cash_by_mail_account_payload = 32; } map exclude_from_json_data = 15; } @@ -1161,6 +1162,12 @@ message F2FAccountPayload { string extra_info = 3; } +message CashByMailAccountPayload { + string postal_address = 1; + string contact = 2; + string extra_info = 3; +} + message PromptPayAccountPayload { string prompt_pay_id = 1; }