diff --git a/core/src/main/java/bisq/core/locale/CurrencyUtil.java b/core/src/main/java/bisq/core/locale/CurrencyUtil.java index d38729f8f0..988db39c91 100644 --- a/core/src/main/java/bisq/core/locale/CurrencyUtil.java +++ b/core/src/main/java/bisq/core/locale/CurrencyUtil.java @@ -348,6 +348,17 @@ public class CurrencyUtil { return currencies; } + public static List getAllCapitualCurrencies() { + List currencies = new ArrayList<>(Arrays.asList( + new FiatCurrency("EUR"), + new FiatCurrency("BRL"), + new FiatCurrency("GBP"), + new FiatCurrency("USD") + )); + currencies.sort(Comparator.comparing(TradeCurrency::getCode)); + return currencies; + } + // 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/CapitualAccount.java b/core/src/main/java/bisq/core/payment/CapitualAccount.java new file mode 100644 index 0000000000..46ba14a43f --- /dev/null +++ b/core/src/main/java/bisq/core/payment/CapitualAccount.java @@ -0,0 +1,46 @@ +/* + * 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.locale.CurrencyUtil; +import bisq.core.payment.payload.CapitualAccountPayload; +import bisq.core.payment.payload.PaymentAccountPayload; +import bisq.core.payment.payload.PaymentMethod; + +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +public final class CapitualAccount extends PaymentAccount { + public CapitualAccount() { + super(PaymentMethod.CAPITUAL); + tradeCurrencies.addAll(CurrencyUtil.getAllCapitualCurrencies()); + } + + @Override + protected PaymentAccountPayload createPayload() { + return new CapitualAccountPayload(paymentMethod.getId(), id); + } + + public void setAccountNr(String accountNr) { + ((CapitualAccountPayload) paymentAccountPayload).setAccountNr(accountNr); + } + + public String getAccountNr() { + return ((CapitualAccountPayload) paymentAccountPayload).getAccountNr(); + } +} diff --git a/core/src/main/java/bisq/core/payment/PaymentAccountFactory.java b/core/src/main/java/bisq/core/payment/PaymentAccountFactory.java index faed57acd3..0cceb0cb86 100644 --- a/core/src/main/java/bisq/core/payment/PaymentAccountFactory.java +++ b/core/src/main/java/bisq/core/payment/PaymentAccountFactory.java @@ -86,6 +86,8 @@ public class PaymentAccountFactory { return new AmazonGiftCardAccount(); case PaymentMethod.BLOCK_CHAINS_INSTANT_ID: return new InstantCryptoCurrencyAccount(); + case PaymentMethod.CAPITUAL_ID: + return new CapitualAccount(); // Cannot be deleted as it would break old trade history entries case PaymentMethod.OK_PAY_ID: diff --git a/core/src/main/java/bisq/core/payment/payload/CapitualAccountPayload.java b/core/src/main/java/bisq/core/payment/payload/CapitualAccountPayload.java new file mode 100644 index 0000000000..e8db6f0b50 --- /dev/null +++ b/core/src/main/java/bisq/core/payment/payload/CapitualAccountPayload.java @@ -0,0 +1,99 @@ +/* + * 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 CapitualAccountPayload extends PaymentAccountPayload { + private String accountNr = ""; + + public CapitualAccountPayload(String paymentMethod, String id) { + super(paymentMethod, id); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // PROTO BUFFER + /////////////////////////////////////////////////////////////////////////////////////////// + + private CapitualAccountPayload(String paymentMethod, + String id, + String accountNr, + long maxTradePeriod, + Map excludeFromJsonDataMap) { + super(paymentMethod, + id, + maxTradePeriod, + excludeFromJsonDataMap); + + this.accountNr = accountNr; + } + + @Override + public Message toProtoMessage() { + return getPaymentAccountPayloadBuilder() + .setCapitualAccountPayload(protobuf.CapitualAccountPayload.newBuilder() + .setAccountNr(accountNr)) + .build(); + } + + public static CapitualAccountPayload fromProto(protobuf.PaymentAccountPayload proto) { + return new CapitualAccountPayload(proto.getPaymentMethodId(), + proto.getId(), + proto.getCapitualAccountPayload().getAccountNr(), + proto.getMaxTradePeriod(), + new HashMap<>(proto.getExcludeFromJsonDataMap())); + } + + /////////////////////////////////////////////////////////////////////////////////////////// + // API + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public String getPaymentDetails() { + return Res.get(paymentMethodId) + " - " + Res.getWithCol("payment.capitual.cap") + " " + accountNr; + } + + @Override + public String getPaymentDetailsForTradePopup() { + return getPaymentDetails(); + } + + @Override + public byte[] getAgeWitnessInputData() { + return super.getAgeWitnessInputData(accountNr.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 3d2c3004f2..0a6072e69d 100644 --- a/core/src/main/java/bisq/core/payment/payload/PaymentMethod.java +++ b/core/src/main/java/bisq/core/payment/payload/PaymentMethod.java @@ -99,6 +99,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.CapitualValidator; + +import bisq.core.account.witness.AccountAgeWitnessService; +import bisq.core.locale.CurrencyUtil; +import bisq.core.locale.Res; +import bisq.core.payment.CapitualAccount; +import bisq.core.payment.PaymentAccount; +import bisq.core.payment.payload.CapitualAccountPayload; +import bisq.core.payment.payload.PaymentAccountPayload; +import bisq.core.util.coin.CoinFormatter; +import bisq.core.util.validation.InputValidator; + +import bisq.common.util.Tuple2; + +import org.apache.commons.lang3.StringUtils; + +import javafx.scene.control.Label; +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.addTopLabelFlowPane; + +public class CapitualForm extends PaymentMethodForm { + private final CapitualAccount capitualAccount; + private final CapitualValidator capitualValidator; + private InputTextField accountNrInputTextField; + + public static int addFormForBuyer(GridPane gridPane, int gridRow, + PaymentAccountPayload paymentAccountPayload) { + addCompactTopLabelTextFieldWithCopyIcon(gridPane, ++gridRow, Res.get("payment.capitual.cap"), + ((CapitualAccountPayload) paymentAccountPayload).getAccountNr()); + return gridRow; + } + + public CapitualForm(PaymentAccount paymentAccount, AccountAgeWitnessService accountAgeWitnessService, CapitualValidator capitualValidator, + InputValidator inputValidator, GridPane gridPane, int gridRow, CoinFormatter formatter) { + super(paymentAccount, accountAgeWitnessService, inputValidator, gridPane, gridRow, formatter); + this.capitualAccount = (CapitualAccount) paymentAccount; + this.capitualValidator = capitualValidator; + } + + @Override + public void addFormForAddAccount() { + gridRowFrom = gridRow + 1; + + accountNrInputTextField = FormBuilder.addInputTextField(gridPane, ++gridRow, Res.get("payment.capitual.cap")); + accountNrInputTextField.setValidator(capitualValidator); + accountNrInputTextField.textProperty().addListener((ov, oldValue, newValue) -> { + capitualAccount.setAccountNr(newValue); + updateFromInputs(); + }); + + addCurrenciesGrid(true); + addLimitations(false); + addAccountNameTextFieldWithAutoFillToggleButton(); + } + + private void addCurrenciesGrid(boolean isEditable) { + final Tuple2 labelFlowPaneTuple2 = addTopLabelFlowPane(gridPane, ++gridRow, Res.get("payment.supportedCurrencies"), 0); + + FlowPane flowPane = labelFlowPaneTuple2.second; + + if (isEditable) + flowPane.setId("flow-pane-checkboxes-bg"); + else + flowPane.setId("flow-pane-checkboxes-non-editable-bg"); + + CurrencyUtil.getAllCapitualCurrencies().stream().forEach(e -> + fillUpFlowPaneWithCurrencies(isEditable, flowPane, e, capitualAccount)); + } + + @Override + protected void autoFillNameTextField() { + if (useCustomAccountNameToggleButton != null && !useCustomAccountNameToggleButton.isSelected()) { + String accountNr = accountNrInputTextField.getText(); + accountNr = StringUtils.abbreviate(accountNr, 9); + String method = Res.get(paymentAccount.getPaymentMethod().getId()); + accountNameTextField.setText(method.concat(": ").concat(accountNr)); + } + } + + @Override + public void addFormForDisplayAccount() { + gridRowFrom = gridRow; + addCompactTopLabelTextField(gridPane, gridRow, Res.get("payment.account.name"), + capitualAccount.getAccountName(), Layout.FIRST_ROW_AND_GROUP_DISTANCE); + addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("shared.paymentMethod"), + Res.get(capitualAccount.getPaymentMethod().getId())); + addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.capitual.cap"), + capitualAccount.getAccountNr()); + addLimitations(true); + addCurrenciesGrid(false); + } + + @Override + public void updateAllInputsValid() { + allInputsValid.set(isAccountNameValid() + && capitualValidator.validate(capitualAccount.getAccountNr()).isValid + && capitualAccount.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 728c87156e..663abcb7d2 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.AdvancedCashForm; import bisq.desktop.components.paymentmethods.AliPayForm; import bisq.desktop.components.paymentmethods.AmazonGiftCardForm; import bisq.desktop.components.paymentmethods.AustraliaPayidForm; +import bisq.desktop.components.paymentmethods.CapitualForm; import bisq.desktop.components.paymentmethods.CashByMailForm; import bisq.desktop.components.paymentmethods.CashDepositForm; import bisq.desktop.components.paymentmethods.ChaseQuickPayForm; @@ -59,6 +60,7 @@ import bisq.desktop.util.validation.AdvancedCashValidator; import bisq.desktop.util.validation.AliPayValidator; import bisq.desktop.util.validation.AustraliaPayidValidator; import bisq.desktop.util.validation.BICValidator; +import bisq.desktop.util.validation.CapitualValidator; import bisq.desktop.util.validation.ChaseQuickPayValidator; import bisq.desktop.util.validation.ClearXchangeValidator; import bisq.desktop.util.validation.F2FValidator; @@ -83,6 +85,7 @@ import bisq.core.locale.Res; import bisq.core.offer.OfferRestrictions; import bisq.core.payment.AmazonGiftCardAccount; import bisq.core.payment.AustraliaPayid; +import bisq.core.payment.CapitualAccount; import bisq.core.payment.CashByMailAccount; import bisq.core.payment.CashDepositAccount; import bisq.core.payment.ClearXchangeAccount; @@ -135,6 +138,7 @@ public class FiatAccountsView extends PaymentAccountsView doSaveNewAccount(paymentAccount)) .show(); - } else { + } else if (paymentAccount instanceof CapitualAccount) { + new Popup().information(Res.get("payment.capitual.info", currencyName, currencyName)) + .width(900) + .closeButtonText(Res.get("shared.cancel")) + .actionButtonText(Res.get("shared.iUnderstand")) + .onAction(() -> doSaveNewAccount(paymentAccount)) + .show(); + } + else { doSaveNewAccount(paymentAccount); } }) @@ -530,6 +544,8 @@ public class FiatAccountsView extends PaymentAccountsView exclude_from_json_data = 15; } @@ -1217,6 +1218,10 @@ message TransferwiseAccountPayload { string email = 1; } +message CapitualAccountPayload { + string account_nr = 1; +} + /////////////////////////////////////////////////////////////////////////////////////////// // PersistableEnvelope ///////////////////////////////////////////////////////////////////////////////////////////