diff --git a/core/src/main/java/bisq/core/locale/CurrencyUtil.java b/core/src/main/java/bisq/core/locale/CurrencyUtil.java index 2e89df8a5d1..d659c4f5ff8 100644 --- a/core/src/main/java/bisq/core/locale/CurrencyUtil.java +++ b/core/src/main/java/bisq/core/locale/CurrencyUtil.java @@ -425,6 +425,17 @@ public static List getAllCapitualCurrencies() { )); } + // https://github.com/bisq-network/growth/issues/231 + public static List getAllCelPayCurrencies() { + return new ArrayList<>(Arrays.asList( + new FiatCurrency("AUD"), + new FiatCurrency("CAD"), + new FiatCurrency("GBP"), + new FiatCurrency("HKD"), + new FiatCurrency("USD") + )); + } + // https://www.revolut.com/help/getting-started/exchanging-currencies/what-fiat-currencies-are-supported-for-holding-and-exchange public static List getAllRevolutCurrencies() { ArrayList currencies = new ArrayList<>(Arrays.asList( diff --git a/core/src/main/java/bisq/core/payment/CelPayAccount.java b/core/src/main/java/bisq/core/payment/CelPayAccount.java new file mode 100644 index 00000000000..4fbd12032cc --- /dev/null +++ b/core/src/main/java/bisq/core/payment/CelPayAccount.java @@ -0,0 +1,56 @@ +/* + * 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.PaymentAccountPayload; +import bisq.core.payment.payload.PaymentMethod; +import bisq.core.payment.payload.CelPayAccountPayload; + +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +public final class CelPayAccount extends PaymentAccount { + public CelPayAccount() { + super(PaymentMethod.CELPAY); + } + + @Override + protected PaymentAccountPayload createPayload() { + return new CelPayAccountPayload(paymentMethod.getId(), id); + } + + public void setEmail(String accountId) { + ((CelPayAccountPayload) paymentAccountPayload).setEmail(accountId); + } + + public String getEmail() { + return ((CelPayAccountPayload) paymentAccountPayload).getEmail(); + } + + public String getMessageForBuyer() { + return "payment.celpay.info.buyer"; + } + + public String getMessageForSeller() { + return "payment.celpay.info.seller"; + } + + public String getMessageForAccountCreation() { + return "payment.celpay.info.account"; + } +} diff --git a/core/src/main/java/bisq/core/payment/PaymentAccountFactory.java b/core/src/main/java/bisq/core/payment/PaymentAccountFactory.java index fc3c3f391d0..b5a69eac8e7 100644 --- a/core/src/main/java/bisq/core/payment/PaymentAccountFactory.java +++ b/core/src/main/java/bisq/core/payment/PaymentAccountFactory.java @@ -102,6 +102,8 @@ public static PaymentAccount getPaymentAccount(PaymentMethod paymentMethod) { return new InstantCryptoCurrencyAccount(); case PaymentMethod.CAPITUAL_ID: return new CapitualAccount(); + case PaymentMethod.CELPAY_ID: + return new CelPayAccount(); case PaymentMethod.SWIFT_ID: return new SwiftAccount(); diff --git a/core/src/main/java/bisq/core/payment/payload/CelPayAccountPayload.java b/core/src/main/java/bisq/core/payment/payload/CelPayAccountPayload.java new file mode 100644 index 00000000000..6a6b709cfe7 --- /dev/null +++ b/core/src/main/java/bisq/core/payment/payload/CelPayAccountPayload.java @@ -0,0 +1,89 @@ +/* + * 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 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 CelPayAccountPayload extends PaymentAccountPayload { + private String email = ""; + + public CelPayAccountPayload(String paymentMethod, String id) { + super(paymentMethod, id); + } + + private CelPayAccountPayload(String paymentMethod, + String id, + String email, + long maxTradePeriod, + Map excludeFromJsonDataMap) { + super(paymentMethod, + id, + maxTradePeriod, + excludeFromJsonDataMap); + + this.email = email; + } + + @Override + public Message toProtoMessage() { + return getPaymentAccountPayloadBuilder() + .setCelPayAccountPayload(protobuf.CelPayAccountPayload.newBuilder().setEmail(email)) + .build(); + } + + public static CelPayAccountPayload fromProto(protobuf.PaymentAccountPayload proto) { + return new CelPayAccountPayload(proto.getPaymentMethodId(), + proto.getId(), + proto.getCelPayAccountPayload().getEmail(), + proto.getMaxTradePeriod(), + new HashMap<>(proto.getExcludeFromJsonDataMap())); + } + + @Override + public String getPaymentDetails() { + return Res.get(paymentMethodId) + " - " + Res.getWithCol("payment.email") + " " + email; + } + + @Override + public String getPaymentDetailsForTradePopup() { + return getPaymentDetails(); + } + + @Override + public byte[] getAgeWitnessInputData() { + return super.getAgeWitnessInputData(email.getBytes(StandardCharsets.UTF_8)); + } +} 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 634e0c0f83d..f4ad3b8fe9d 100644 --- a/core/src/main/java/bisq/core/payment/payload/PaymentMethod.java +++ b/core/src/main/java/bisq/core/payment/payload/PaymentMethod.java @@ -107,6 +107,7 @@ public final class PaymentMethod implements PersistablePayload, Comparable. + */ + +package bisq.desktop.components.paymentmethods; + +import bisq.desktop.components.InputTextField; +import bisq.desktop.util.FormBuilder; +import bisq.desktop.util.Layout; +import bisq.desktop.util.validation.EmailValidator; + +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.CelPayAccount; +import bisq.core.payment.payload.PaymentAccountPayload; +import bisq.core.payment.payload.CelPayAccountPayload; +import bisq.core.util.coin.CoinFormatter; +import bisq.core.util.validation.InputValidator; + +import javafx.scene.control.TextField; +import javafx.scene.layout.FlowPane; +import javafx.scene.layout.GridPane; + +import static bisq.desktop.util.FormBuilder.addCompactTopLabelTextField; +import static bisq.desktop.util.FormBuilder.addCompactTopLabelTextFieldWithCopyIcon; +import static bisq.desktop.util.FormBuilder.addTopLabelTextField; + +public class CelPayForm extends PaymentMethodForm { + private final CelPayAccount account; + private InputTextField emailInputTextField; + private EmailValidator validator = new EmailValidator(); + + public static int addFormForBuyer(GridPane gridPane, int gridRow, + PaymentAccountPayload paymentAccountPayload) { + addCompactTopLabelTextFieldWithCopyIcon(gridPane, ++gridRow, Res.get("payment.email"), + ((CelPayAccountPayload) paymentAccountPayload).getEmail()); + return gridRow; + } + + public CelPayForm(PaymentAccount paymentAccount, AccountAgeWitnessService accountAgeWitnessService, + InputValidator inputValidator, GridPane gridPane, + int gridRow, CoinFormatter formatter) { + super(paymentAccount, accountAgeWitnessService, inputValidator, gridPane, gridRow, formatter); + this.account = (CelPayAccount) paymentAccount; + } + + @Override + public void addFormForAddAccount() { + gridRowFrom = gridRow + 1; + + emailInputTextField = FormBuilder.addInputTextField(gridPane, ++gridRow, Res.get("payment.email")); + emailInputTextField.setValidator(validator); + emailInputTextField.textProperty().addListener((ov, oldValue, newValue) -> { + account.setEmail(newValue.trim()); + updateFromInputs(); + }); + + addCurrenciesGrid(true); + addLimitations(false); + addAccountNameTextFieldWithAutoFillToggleButton(); + } + + private void addCurrenciesGrid(boolean isEditable) { + FlowPane flowPane = FormBuilder.addTopLabelFlowPane(gridPane, ++gridRow, + Res.get("payment.celpay.supportedCurrenciesForReceiver"), 20, 20).second; + + if (isEditable) { + flowPane.setId("flow-pane-checkboxes-bg"); + } else { + flowPane.setId("flow-pane-checkboxes-non-editable-bg"); + } + + CurrencyUtil.getAllCelPayCurrencies().forEach(currency -> + fillUpFlowPaneWithCurrencies(isEditable, flowPane, currency, account)); + } + + @Override + protected void autoFillNameTextField() { + setAccountNameWithString(emailInputTextField.getText()); + } + + @Override + public void addFormForDisplayAccount() { + gridRowFrom = gridRow; + addTopLabelTextField(gridPane, gridRow, Res.get("payment.account.name"), + account.getAccountName(), Layout.FIRST_ROW_AND_GROUP_DISTANCE); + addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("shared.paymentMethod"), + Res.get(account.getPaymentMethod().getId())); + TextField field = addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.email"), + account.getEmail()).second; + field.setMouseTransparent(false); + addLimitations(true); + addCurrenciesGrid(false); + } + + @Override + public void updateAllInputsValid() { + allInputsValid.set(isAccountNameValid() + && account.getEmail() != null + && validator.validate(account.getEmail()).isValid + && account.getTradeCurrencies().size() > 0); + } +} 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 9a6e127e919..8e614d2562a 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 @@ -26,6 +26,7 @@ import bisq.desktop.components.paymentmethods.CapitualForm; import bisq.desktop.components.paymentmethods.CashByMailForm; import bisq.desktop.components.paymentmethods.CashDepositForm; +import bisq.desktop.components.paymentmethods.CelPayForm; import bisq.desktop.components.paymentmethods.ChaseQuickPayForm; import bisq.desktop.components.paymentmethods.ClearXchangeForm; import bisq.desktop.components.paymentmethods.F2FForm; @@ -565,6 +566,8 @@ private PaymentMethodForm getPaymentMethodForm(PaymentMethod paymentMethod, Paym return new AmazonGiftCardForm(paymentAccount, accountAgeWitnessService, inputValidator, root, gridRow, formatter); case PaymentMethod.CAPITUAL_ID: return new CapitualForm(paymentAccount, accountAgeWitnessService, capitualValidator, inputValidator, root, gridRow, formatter); + case PaymentMethod.CELPAY_ID: + return new CelPayForm(paymentAccount, accountAgeWitnessService, inputValidator, root, gridRow, formatter); case PaymentMethod.SWIFT_ID: return new SwiftForm(paymentAccount, accountAgeWitnessService, inputValidator, root, gridRow, formatter); default: 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 07876d79a3f..a91ff0208f6 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 @@ -28,6 +28,7 @@ import bisq.desktop.components.paymentmethods.CapitualForm; import bisq.desktop.components.paymentmethods.CashByMailForm; import bisq.desktop.components.paymentmethods.CashDepositForm; +import bisq.desktop.components.paymentmethods.CelPayForm; import bisq.desktop.components.paymentmethods.ChaseQuickPayForm; import bisq.desktop.components.paymentmethods.ClearXchangeForm; import bisq.desktop.components.paymentmethods.F2FForm; @@ -357,6 +358,9 @@ protected void addContent() { case PaymentMethod.CAPITUAL_ID: gridRow = CapitualForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload); break; + case PaymentMethod.CELPAY_ID: + gridRow = CelPayForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload); + break; case PaymentMethod.SWIFT_ID: gridRow = SwiftForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload, trade); break; diff --git a/proto/src/main/proto/pb.proto b/proto/src/main/proto/pb.proto index 48fd69af4b3..f274d08362e 100644 --- a/proto/src/main/proto/pb.proto +++ b/proto/src/main/proto/pb.proto @@ -1000,6 +1000,7 @@ message PaymentAccountPayload { PayseraAccountPayload Paysera_account_payload = 34; PaxumAccountPayload Paxum_account_payload = 35; SwiftAccountPayload swift_account_payload = 36; + CelPayAccountPayload cel_pay_account_payload = 37; } map exclude_from_json_data = 15; } @@ -1264,6 +1265,10 @@ message CapitualAccountPayload { string account_nr = 1; } +message CelPayAccountPayload { + string email = 1; +} + message SwiftAccountPayload { string beneficiary_name = 1; string beneficiary_account_nr = 2;