From e7b3629a713d2eb39382c88cbaa42216dd52bc65 Mon Sep 17 00:00:00 2001 From: Manfred Karrer Date: Fri, 10 Aug 2018 22:19:59 +0200 Subject: [PATCH 1/4] Add HalCash --- .../paymentmethods/HalCashForm.java | 112 ++++++++++++++++++ .../fiataccounts/FiatAccountsView.java | 16 +++ .../steps/buyer/BuyerStep2View.java | 30 +++++ .../steps/seller/SellerStep3View.java | 5 + .../util/validation/HalCashValidator.java | 37 ++++++ 5 files changed, 200 insertions(+) create mode 100644 src/main/java/bisq/desktop/components/paymentmethods/HalCashForm.java create mode 100644 src/main/java/bisq/desktop/util/validation/HalCashValidator.java diff --git a/src/main/java/bisq/desktop/components/paymentmethods/HalCashForm.java b/src/main/java/bisq/desktop/components/paymentmethods/HalCashForm.java new file mode 100644 index 00000000000..fa9c2eeb836 --- /dev/null +++ b/src/main/java/bisq/desktop/components/paymentmethods/HalCashForm.java @@ -0,0 +1,112 @@ +/* + * 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.util.Layout; +import bisq.desktop.util.validation.HalCashValidator; + +import bisq.core.locale.Res; +import bisq.core.locale.TradeCurrency; +import bisq.core.payment.AccountAgeWitnessService; +import bisq.core.payment.HalCashAccount; +import bisq.core.payment.PaymentAccount; +import bisq.core.payment.payload.HalCashAccountPayload; +import bisq.core.payment.payload.PaymentAccountPayload; +import bisq.core.util.BSFormatter; +import bisq.core.util.validation.InputValidator; + +import org.apache.commons.lang3.StringUtils; + +import javafx.scene.control.TextField; +import javafx.scene.layout.GridPane; + +import static bisq.desktop.util.FormBuilder.addLabelInputTextField; +import static bisq.desktop.util.FormBuilder.addLabelTextField; + +public class HalCashForm extends PaymentMethodForm { + private final HalCashAccount halCashAccount; + private final HalCashValidator halCashValidator; + private InputTextField mobileNrInputTextField; + + public static int addFormForBuyer(GridPane gridPane, int gridRow, + PaymentAccountPayload paymentAccountPayload) { + addLabelTextField(gridPane, ++gridRow, Res.get("payment.mobile"), + ((HalCashAccountPayload) paymentAccountPayload).getMobileNr()); + return gridRow; + } + + public HalCashForm(PaymentAccount paymentAccount, AccountAgeWitnessService accountAgeWitnessService, HalCashValidator halCashValidator, + InputValidator inputValidator, GridPane gridPane, int gridRow, BSFormatter formatter) { + super(paymentAccount, accountAgeWitnessService, inputValidator, gridPane, gridRow, formatter); + this.halCashAccount = (HalCashAccount) paymentAccount; + this.halCashValidator = halCashValidator; + } + + @Override + public void addFormForAddAccount() { + gridRowFrom = gridRow + 1; + + mobileNrInputTextField = addLabelInputTextField(gridPane, ++gridRow, + Res.get("payment.mobile")).second; + mobileNrInputTextField.setValidator(halCashValidator); + mobileNrInputTextField.textProperty().addListener((ov, oldValue, newValue) -> { + halCashAccount.setMobileNr(newValue); + updateFromInputs(); + }); + + TradeCurrency singleTradeCurrency = halCashAccount.getSingleTradeCurrency(); + String nameAndCode = singleTradeCurrency != null ? singleTradeCurrency.getNameAndCode() : "null"; + addLabelTextField(gridPane, ++gridRow, Res.getWithCol("shared.currency"), nameAndCode); + addLimitations(); + addAccountNameTextFieldWithAutoFillCheckBox(); + } + + @Override + protected void autoFillNameTextField() { + if (useCustomAccountNameCheckBox != null && !useCustomAccountNameCheckBox.isSelected()) { + String mobileNr = mobileNrInputTextField.getText(); + mobileNr = StringUtils.abbreviate(mobileNr, 9); + String method = Res.get(paymentAccount.getPaymentMethod().getId()); + accountNameTextField.setText(method.concat(": ").concat(mobileNr)); + } + } + + @Override + public void addFormForDisplayAccount() { + gridRowFrom = gridRow; + addLabelTextField(gridPane, gridRow, Res.get("payment.account.name"), + halCashAccount.getAccountName(), Layout.FIRST_ROW_AND_GROUP_DISTANCE); + addLabelTextField(gridPane, ++gridRow, Res.getWithCol("shared.paymentMethod"), + Res.get(halCashAccount.getPaymentMethod().getId())); + TextField field = addLabelTextField(gridPane, ++gridRow, Res.get("payment.mobile"), + halCashAccount.getMobileNr()).second; + field.setMouseTransparent(false); + TradeCurrency singleTradeCurrency = halCashAccount.getSingleTradeCurrency(); + String nameAndCode = singleTradeCurrency != null ? singleTradeCurrency.getNameAndCode() : "null"; + addLabelTextField(gridPane, ++gridRow, Res.getWithCol("shared.currency"), nameAndCode); + addLimitations(); + } + + @Override + public void updateAllInputsValid() { + allInputsValid.set(isAccountNameValid() + && halCashValidator.validate(halCashAccount.getMobileNr()).isValid + && halCashAccount.getTradeCurrencies().size() > 0); + } +} 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 81b1bf63452..23303721097 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 @@ -29,6 +29,7 @@ import bisq.desktop.components.paymentmethods.ClearXchangeForm; import bisq.desktop.components.paymentmethods.F2FForm; import bisq.desktop.components.paymentmethods.FasterPaymentsForm; +import bisq.desktop.components.paymentmethods.HalCashForm; import bisq.desktop.components.paymentmethods.InteracETransferForm; import bisq.desktop.components.paymentmethods.MoneyBeamForm; import bisq.desktop.components.paymentmethods.MoneyGramForm; @@ -59,6 +60,7 @@ import bisq.desktop.util.validation.ChaseQuickPayValidator; import bisq.desktop.util.validation.ClearXchangeValidator; import bisq.desktop.util.validation.F2FValidator; +import bisq.desktop.util.validation.HalCashValidator; import bisq.desktop.util.validation.IBANValidator; import bisq.desktop.util.validation.InteracETransferValidator; import bisq.desktop.util.validation.MoneyBeamValidator; @@ -77,6 +79,7 @@ import bisq.core.payment.AccountAgeWitnessService; import bisq.core.payment.ClearXchangeAccount; import bisq.core.payment.F2FAccount; +import bisq.core.payment.HalCashAccount; import bisq.core.payment.MoneyGramAccount; import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccountFactory; @@ -143,6 +146,7 @@ public class FiatAccountsView extends ActivatableViewAndModel 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")) + .width(700) + .closeButtonText(Res.get("shared.cancel")) + .actionButtonText(Res.get("shared.iUnderstand")) + .onAction(() -> doSaveNewAccount(paymentAccount)) + .show(); } else { new Popup<>().information(Res.get("payment.limits.info", formatter.formatCoinWithCode(maxTradeLimitFirstMonth), @@ -499,6 +513,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.HAL_CASH_ID: + return new HalCashForm(paymentAccount, accountAgeWitnessService, halCashValidator, inputValidator, root, gridRow, formatter); case PaymentMethod.F2F_ID: return new F2FForm(paymentAccount, accountAgeWitnessService, f2FValidator, inputValidator, root, gridRow, formatter); default: 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 4a83c23c234..23b0fd4abca 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 @@ -28,6 +28,7 @@ import bisq.desktop.components.paymentmethods.CryptoCurrencyForm; import bisq.desktop.components.paymentmethods.F2FForm; import bisq.desktop.components.paymentmethods.FasterPaymentsForm; +import bisq.desktop.components.paymentmethods.HalCashForm; import bisq.desktop.components.paymentmethods.InteracETransferForm; import bisq.desktop.components.paymentmethods.MoneyBeamForm; import bisq.desktop.components.paymentmethods.MoneyGramForm; @@ -57,6 +58,7 @@ import bisq.core.payment.payload.CashDepositAccountPayload; import bisq.core.payment.payload.CryptoCurrencyAccountPayload; import bisq.core.payment.payload.F2FAccountPayload; +import bisq.core.payment.payload.HalCashAccountPayload; import bisq.core.payment.payload.MoneyGramAccountPayload; import bisq.core.payment.payload.PaymentAccountPayload; import bisq.core.payment.payload.PaymentMethod; @@ -261,6 +263,9 @@ protected void addContent() { case PaymentMethod.WESTERN_UNION_ID: gridRow = WesternUnionForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload); break; + case PaymentMethod.HAL_CASH_ID: + gridRow = HalCashForm.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()); @@ -374,6 +379,25 @@ private void onPaymentStarted() { } else { showConfirmPaymentStartedPopup(); } + } else if (model.dataModel.getSellersPaymentAccountPayload() instanceof HalCashAccountPayload) { + //noinspection UnusedAssignment + //noinspection ConstantConditions + String key = "halCashCodeInfo"; + if (!DevEnv.isDevMode() && DontShowAgainLookup.showAgain(key)) { + String mobileNr = ((HalCashAccountPayload) model.dataModel.getSellersPaymentAccountPayload()).getMobileNr(); + Popup popup = new Popup<>(); + popup.headLine(Res.get("portfolio.pending.step2_buyer.halCashInfo.headline")) + .feedback(Res.get("portfolio.pending.step2_buyer.halCashInfo.msg", + model.dataModel.getTrade().getShortId(), mobileNr)) + .onAction(this::showConfirmPaymentStartedPopup) + .actionButtonText(Res.get("shared.yes")) + .closeButtonText(Res.get("shared.no")) + .onClose(popup::hide) + .dontShowAgainId(key) + .show(); + } else { + showConfirmPaymentStartedPopup(); + } } else { showConfirmPaymentStartedPopup(); } @@ -492,6 +516,12 @@ private void showPopup() { accountDetails + paymentDetailsForTradePopup + "\n\n" + copyPaste; + } else if (paymentAccountPayload instanceof HalCashAccountPayload) { + //noinspection UnusedAssignment + message += Res.get("portfolio.pending.step2_buyer.bank", amount) + + accountDetails + + paymentDetailsForTradePopup + ".\n\n" + + copyPaste; } else { //noinspection UnusedAssignment message += Res.get("portfolio.pending.step2_buyer.bank", amount) + 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 1f6694d185b..49371c6773b 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 @@ -31,6 +31,7 @@ import bisq.core.payment.payload.CashDepositAccountPayload; import bisq.core.payment.payload.CryptoCurrencyAccountPayload; import bisq.core.payment.payload.F2FAccountPayload; +import bisq.core.payment.payload.HalCashAccountPayload; import bisq.core.payment.payload.MoneyGramAccountPayload; import bisq.core.payment.payload.PaymentAccountPayload; import bisq.core.payment.payload.PaymentMethod; @@ -269,6 +270,7 @@ private void onPaymentReceived() { String message = Res.get("portfolio.pending.step3_seller.onPaymentReceived.part1", CurrencyUtil.getNameByCode(model.dataModel.getCurrencyCode())); if (!(paymentAccountPayload instanceof CryptoCurrencyAccountPayload)) { if (!(paymentAccountPayload instanceof WesternUnionAccountPayload) && + !(paymentAccountPayload instanceof HalCashAccountPayload) && !(paymentAccountPayload instanceof F2FAccountPayload)) { message += Res.get("portfolio.pending.step3_seller.onPaymentReceived.fiat", trade.getShortId()); } @@ -313,6 +315,7 @@ private void showPopup() { if (paymentAccountPayload instanceof USPostalMoneyOrderAccountPayload) { message = Res.get("portfolio.pending.step3_seller.postal", part1, tradeVolumeWithCode, id); } else if (!(paymentAccountPayload instanceof WesternUnionAccountPayload) && + !(paymentAccountPayload instanceof HalCashAccountPayload) && !(paymentAccountPayload instanceof F2FAccountPayload)) { message = Res.get("portfolio.pending.step3_seller.bank", currencyName, tradeVolumeWithCode, id); } @@ -324,6 +327,8 @@ else if (paymentAccountPayload instanceof WesternUnionAccountPayload) message = message + Res.get("portfolio.pending.step3_seller.westernUnion"); else if (paymentAccountPayload instanceof MoneyGramAccountPayload) message = message + Res.get("portfolio.pending.step3_seller.moneyGram"); + else if (paymentAccountPayload instanceof HalCashAccountPayload) + message = message + Res.get("portfolio.pending.step3_seller.halCash"); else if (paymentAccountPayload instanceof F2FAccountPayload) message = part1; diff --git a/src/main/java/bisq/desktop/util/validation/HalCashValidator.java b/src/main/java/bisq/desktop/util/validation/HalCashValidator.java new file mode 100644 index 00000000000..b90fdd20ee3 --- /dev/null +++ b/src/main/java/bisq/desktop/util/validation/HalCashValidator.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 HalCashValidator extends InputValidator { + + /////////////////////////////////////////////////////////////////////////////////////////// + // Public methods + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public ValidationResult validate(String input) { + // TODO + return super.validate(input); + } + + /////////////////////////////////////////////////////////////////////////////////////////// + // Private methods + /////////////////////////////////////////////////////////////////////////////////////////// +} From 3bce2b828be6299c15876e12eaee7dd22d4c142b Mon Sep 17 00:00:00 2001 From: Manfred Karrer Date: Sat, 11 Aug 2018 20:48:42 +0200 Subject: [PATCH 2/4] Add adjustment fro multiple ofg 10 EUR for HalCash With ATMs one can withdraw only multiples of 10 EUR. We adjust the input values the way that the EUR amount leads to multiple of 10. MinAmount and amount will be adjusted. Please note that a similar approach like implemented here for HalCash can be used for removing the decimal places from fiat amounts to improve privacy. We keep that for a follow up PR to not mix 2 different use cases. --- .../main/offer/MutableOfferDataModel.java | 17 +++++++-- .../desktop/main/offer/MutableOfferView.java | 23 ++++++------ .../main/offer/MutableOfferViewModel.java | 35 ++++++++++++++++--- .../offer/takeoffer/TakeOfferDataModel.java | 8 +++-- .../offer/takeoffer/TakeOfferViewModel.java | 6 ++++ .../portfolio/editoffer/EditOfferView.java | 2 +- 6 files changed, 70 insertions(+), 21 deletions(-) diff --git a/src/main/java/bisq/desktop/main/offer/MutableOfferDataModel.java b/src/main/java/bisq/desktop/main/offer/MutableOfferDataModel.java index 8ffaa704490..c0e87d81641 100644 --- a/src/main/java/bisq/desktop/main/offer/MutableOfferDataModel.java +++ b/src/main/java/bisq/desktop/main/offer/MutableOfferDataModel.java @@ -40,6 +40,7 @@ import bisq.core.payment.BankAccount; import bisq.core.payment.CountryBasedPaymentAccount; import bisq.core.payment.F2FAccount; +import bisq.core.payment.HalCashAccount; import bisq.core.payment.PaymentAccount; import bisq.core.payment.SameBankAccount; import bisq.core.payment.SepaAccount; @@ -307,7 +308,7 @@ void onTabSelected(boolean isSelected) { @SuppressWarnings("ConstantConditions") Offer createAndGetOffer() { - final boolean useMarketBasedPriceValue = isUseMarketBasedPriceValue(); + boolean useMarketBasedPriceValue = isUseMarketBasedPriceValue(); long priceAsLong = price.get() != null && !useMarketBasedPriceValue ? price.get().getValue() : 0L; String currencyCode = tradeCurrencyCode.get(); boolean isCryptoCurrency = CurrencyUtil.isCryptoCurrency(currencyCode); @@ -662,7 +663,13 @@ void calculateVolume() { !amount.get().isZero() && !price.get().isZero()) { try { - volume.set(price.get().getVolumeByAmount(amount.get())); + Volume volumeByAmount = price.get().getVolumeByAmount(amount.get()); + + // For HalCash we want multiple of 10 EUR + if (isHalCashAccount()) + volumeByAmount = OfferUtil.getAdjustedVolumeForHalCash(volumeByAmount); + + volume.set(volumeByAmount); } catch (Throwable t) { log.error(t.toString()); } @@ -743,7 +750,7 @@ void setBuyerSecurityDeposit(Coin buyerSecurityDeposit) { } protected boolean isUseMarketBasedPriceValue() { - return marketPriceAvailable && useMarketBasedPrice.get(); + return marketPriceAvailable && useMarketBasedPrice.get() && !isHalCashAccount(); } /////////////////////////////////////////////////////////////////////////////////////////// @@ -813,4 +820,8 @@ public boolean isCurrencyForMakerFeeBtc() { public boolean isBsqForFeeAvailable() { return OfferUtil.isBsqForFeeAvailable(bsqWalletService, amount.get(), marketPriceAvailable, marketPriceMargin); } + + public boolean isHalCashAccount() { + return paymentAccount instanceof HalCashAccount; + } } diff --git a/src/main/java/bisq/desktop/main/offer/MutableOfferView.java b/src/main/java/bisq/desktop/main/offer/MutableOfferView.java index 3f119e1c493..77081501c4c 100644 --- a/src/main/java/bisq/desktop/main/offer/MutableOfferView.java +++ b/src/main/java/bisq/desktop/main/offer/MutableOfferView.java @@ -238,7 +238,7 @@ protected void doActivate() { onPaymentAccountsComboBoxSelected(); balanceTextField.setTargetAmount(model.getDataModel().totalToPayAsCoinProperty().get()); - updateMarketPriceAvailable(); + updatePriceToggle(); } } @@ -297,7 +297,7 @@ public void initWithData(OfferPayload.Direction direction, TradeCurrency tradeCu percentagePriceDescription.setText(Res.get("shared.aboveInPercent")); } - updateMarketPriceAvailable(); + updatePriceToggle(); if (!model.getDataModel().isMakerFeeValid() && model.getDataModel().getMakerFee() != null) showInsufficientBsqFundsForBtcFeePaymentPopup(); @@ -502,6 +502,8 @@ else if (tradeCurrencies.contains(model.getTradeCurrency())) } currencyComboBox.setOnAction(currencyComboBoxSelectionHandler); + + updatePriceToggle(); } private void onCurrencyComboBoxSelected() { @@ -703,7 +705,7 @@ private void createListeners() { } }; - marketPriceAvailableListener = (observable, oldValue, newValue) -> updateMarketPriceAvailable(); + marketPriceAvailableListener = (observable, oldValue, newValue) -> updatePriceToggle(); getShowWalletFundedNotificationListener = (observable, oldValue, newValue) -> { if (newValue) { @@ -756,15 +758,16 @@ private Label createPopoverLabel(String text) { return label; } - protected void updateMarketPriceAvailable() { + protected void updatePriceToggle() { int marketPriceAvailableValue = model.marketPriceAvailableProperty.get(); if (marketPriceAvailableValue > -1) { - boolean isMarketPriceAvailable = marketPriceAvailableValue == 1; - percentagePriceBox.setVisible(isMarketPriceAvailable); - percentagePriceBox.setManaged(isMarketPriceAvailable); - priceTypeToggleButton.setVisible(isMarketPriceAvailable); - priceTypeToggleButton.setManaged(isMarketPriceAvailable); - boolean fixedPriceSelected = !model.getDataModel().getUseMarketBasedPrice().get() || !isMarketPriceAvailable; + boolean showPriceToggle = marketPriceAvailableValue == 1 && + !model.getDataModel().isHalCashAccount(); + percentagePriceBox.setVisible(showPriceToggle); + percentagePriceBox.setManaged(showPriceToggle); + priceTypeToggleButton.setVisible(showPriceToggle); + priceTypeToggleButton.setManaged(showPriceToggle); + boolean fixedPriceSelected = !model.getDataModel().getUseMarketBasedPrice().get() || !showPriceToggle; updatePriceToggleButtons(fixedPriceSelected); } } diff --git a/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java b/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java index cf4c1b172db..25ffa5cd654 100644 --- a/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java +++ b/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java @@ -45,6 +45,7 @@ import bisq.core.monetary.Volume; import bisq.core.offer.Offer; import bisq.core.offer.OfferPayload; +import bisq.core.offer.OfferUtil; import bisq.core.payment.PaymentAccount; import bisq.core.provider.price.MarketPrice; import bisq.core.provider.price.PriceFeedService; @@ -683,6 +684,9 @@ void onFocusOutAmountTextField(boolean oldValue, boolean newValue) { if (minAmount.get() != null) minAmountValidationResult.set(isBtcInputValid(minAmount.get())); } + + // We want to trigger a recalculation of the volume + UserThread.execute(() -> onFocusOutVolumeTextField(true, false)); } } @@ -723,6 +727,13 @@ void onFocusOutPriceTextField(boolean oldValue, boolean newValue) { dataModel.calculateAmount(); applyMakerFee(); } + + // We want to trigger a recalculation of the volume and minAmount + UserThread.execute(() -> { + onFocusOutVolumeTextField(true, false); + // We also need to update minAmount + onFocusOutMinAmountTextField(true, false); + }); } } @@ -743,8 +754,16 @@ void onFocusOutVolumeTextField(boolean oldValue, boolean newValue) { if (result.isValid) { setVolumeToModel(); ignoreVolumeStringListener = true; - if (dataModel.getVolume().get() != null) - volume.set(btcFormatter.formatVolume(dataModel.getVolume().get())); + + Volume volume = dataModel.getVolume().get(); + if (volume != null) { + // For HalCash we want multiple of 10 EUR + if (dataModel.isHalCashAccount()) + volume = OfferUtil.getAdjustedVolumeForHalCash(volume); + + this.volume.set(btcFormatter.formatVolume(volume)); + } + ignoreVolumeStringListener = false; dataModel.calculateAmount(); @@ -958,10 +977,16 @@ private void setAmountToModel() { } private void setMinAmountToModel() { - if (minAmount.get() != null && !minAmount.get().isEmpty()) - dataModel.setMinAmount(btcFormatter.parseToCoinWith4Decimals(minAmount.get())); - else + if (minAmount.get() != null && !minAmount.get().isEmpty()) { + Coin minAmount = btcFormatter.parseToCoinWith4Decimals(this.minAmount.get()); + + if (dataModel.isHalCashAccount() && dataModel.getPrice().get() != null) + minAmount = OfferUtil.getAdjustedMinAmountForHalCash(minAmount, dataModel.getPrice().get()); + + dataModel.setMinAmount(minAmount); + } else { dataModel.setMinAmount(null); + } } private void setPriceToModel() { diff --git a/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferDataModel.java b/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferDataModel.java index 1573015a16e..cb2f2a81028 100644 --- a/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferDataModel.java +++ b/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferDataModel.java @@ -35,6 +35,7 @@ import bisq.core.monetary.Volume; import bisq.core.offer.Offer; import bisq.core.offer.OfferPayload; +import bisq.core.offer.OfferUtil; import bisq.core.payment.AccountAgeWitnessService; import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccountUtil; @@ -490,8 +491,11 @@ void calculateVolume() { if (tradePrice != null && offer != null && amount.get() != null && !amount.get().isZero()) { - volume.set(tradePrice.getVolumeByAmount(amount.get())); - //volume.set(new ExchangeRate(tradePrice).coinToFiat(amountAsCoin.get())); + Volume volumeByAmount = tradePrice.getVolumeByAmount(amount.get()); + if (offer.getPaymentMethod().getId().equals(PaymentMethod.HAL_CASH_ID)) + volumeByAmount = OfferUtil.getAdjustedVolumeForHalCash(volumeByAmount); + + volume.set(volumeByAmount); updateBalance(); } diff --git a/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferViewModel.java b/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferViewModel.java index cadff07d8d5..9fb98dbc823 100644 --- a/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferViewModel.java +++ b/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferViewModel.java @@ -31,6 +31,7 @@ import bisq.core.locale.Res; import bisq.core.offer.Offer; import bisq.core.offer.OfferPayload; +import bisq.core.offer.OfferUtil; import bisq.core.payment.PaymentAccount; import bisq.core.payment.payload.PaymentMethod; import bisq.core.trade.Trade; @@ -280,6 +281,11 @@ void onFocusOutAmountTextField(boolean oldValue, boolean newValue, String userIn calculateVolume(); + if (dataModel.getPaymentMethod().getId().equals(PaymentMethod.HAL_CASH_ID)) { + dataModel.applyAmount(OfferUtil.getAdjustedMinAmountForHalCash(dataModel.getAmount().get(), dataModel.tradePrice)); + amount.set(btcFormatter.formatCoin(dataModel.getAmount().get())); + } + if (!dataModel.isMinAmountLessOrEqualAmount()) amountValidationResult.set(new InputValidator.ValidationResult(false, Res.get("takeOffer.validation.amountSmallerThanMinAmount"))); diff --git a/src/main/java/bisq/desktop/main/portfolio/editoffer/EditOfferView.java b/src/main/java/bisq/desktop/main/portfolio/editoffer/EditOfferView.java index 3754eeec5f8..162b6b90f67 100644 --- a/src/main/java/bisq/desktop/main/portfolio/editoffer/EditOfferView.java +++ b/src/main/java/bisq/desktop/main/portfolio/editoffer/EditOfferView.java @@ -97,7 +97,7 @@ protected void doActivate() { // Workaround to fix margin on top of amount group gridPane.setPadding(new Insets(-20, 25, -1, 25)); - updateMarketPriceAvailable(); + updatePriceToggle(); updateElementsWithDirection(); model.isNextButtonDisabled.setValue(false); From a1ab89acb3cec474d00516a9bfa8ef4bc4367e5a Mon Sep 17 00:00:00 2001 From: Manfred Karrer Date: Tue, 14 Aug 2018 19:00:43 +0200 Subject: [PATCH 3/4] Adjust amount in case of edit offer --- .../desktop/main/offer/MutableOfferViewModel.java | 12 +++++++++--- .../main/offer/takeoffer/TakeOfferViewModel.java | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java b/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java index 25ffa5cd654..40bc3f1bdb4 100644 --- a/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java +++ b/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java @@ -732,6 +732,7 @@ void onFocusOutPriceTextField(boolean oldValue, boolean newValue) { UserThread.execute(() -> { onFocusOutVolumeTextField(true, false); // We also need to update minAmount + onFocusOutAmountTextField(true, false); onFocusOutMinAmountTextField(true, false); }); } @@ -966,9 +967,14 @@ public M getDataModel() { private void setAmountToModel() { if (amount.get() != null && !amount.get().isEmpty()) { - dataModel.setAmount(btcFormatter.parseToCoinWith4Decimals(amount.get())); + Coin amount = btcFormatter.parseToCoinWith4Decimals(this.amount.get()); + + if (dataModel.isHalCashAccount() && dataModel.getPrice().get() != null) + amount = OfferUtil.getAdjustedAmountForHalCash(amount, dataModel.getPrice().get()); + + dataModel.setAmount(amount); if (syncMinAmountWithAmount || dataModel.getMinAmount().get() == null || dataModel.getMinAmount().get().equals(Coin.ZERO)) { - minAmount.set(amount.get()); + minAmount.set(this.amount.get()); setMinAmountToModel(); } } else { @@ -981,7 +987,7 @@ private void setMinAmountToModel() { Coin minAmount = btcFormatter.parseToCoinWith4Decimals(this.minAmount.get()); if (dataModel.isHalCashAccount() && dataModel.getPrice().get() != null) - minAmount = OfferUtil.getAdjustedMinAmountForHalCash(minAmount, dataModel.getPrice().get()); + minAmount = OfferUtil.getAdjustedAmountForHalCash(minAmount, dataModel.getPrice().get()); dataModel.setMinAmount(minAmount); } else { diff --git a/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferViewModel.java b/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferViewModel.java index 9fb98dbc823..c3c7b760495 100644 --- a/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferViewModel.java +++ b/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferViewModel.java @@ -282,7 +282,7 @@ void onFocusOutAmountTextField(boolean oldValue, boolean newValue, String userIn calculateVolume(); if (dataModel.getPaymentMethod().getId().equals(PaymentMethod.HAL_CASH_ID)) { - dataModel.applyAmount(OfferUtil.getAdjustedMinAmountForHalCash(dataModel.getAmount().get(), dataModel.tradePrice)); + dataModel.applyAmount(OfferUtil.getAdjustedAmountForHalCash(dataModel.getAmount().get(), dataModel.tradePrice)); amount.set(btcFormatter.formatCoin(dataModel.getAmount().get())); } From 49cad5ecfafa0c9c1b915af87b41149d04f3be38 Mon Sep 17 00:00:00 2001 From: Manfred Karrer Date: Tue, 14 Aug 2018 20:46:14 +0200 Subject: [PATCH 4/4] Add check fro trade limit and adjust if needed --- .../main/offer/MutableOfferDataModel.java | 6 +++++- .../main/offer/MutableOfferViewModel.java | 19 +++++++++++++------ .../offer/takeoffer/TakeOfferViewModel.java | 5 ++++- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/main/java/bisq/desktop/main/offer/MutableOfferDataModel.java b/src/main/java/bisq/desktop/main/offer/MutableOfferDataModel.java index c0e87d81641..f4798439a69 100644 --- a/src/main/java/bisq/desktop/main/offer/MutableOfferDataModel.java +++ b/src/main/java/bisq/desktop/main/offer/MutableOfferDataModel.java @@ -685,7 +685,11 @@ void calculateAmount() { !price.get().isZero() && allowAmountUpdate) { try { - amount.set(formatter.reduceTo4Decimals(price.get().getAmountByVolume(volume.get()))); + Coin value = formatter.reduceTo4Decimals(price.get().getAmountByVolume(volume.get())); + if (isHalCashAccount()) + value = OfferUtil.getAdjustedAmountForHalCash(value, price.get(), getMaxTradeLimit()); + + amount.set(value); calculateTotalToPay(); } catch (Throwable t) { log.error(t.toString()); diff --git a/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java b/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java index 40bc3f1bdb4..a9af33a7bb0 100644 --- a/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java +++ b/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java @@ -684,7 +684,6 @@ void onFocusOutAmountTextField(boolean oldValue, boolean newValue) { if (minAmount.get() != null) minAmountValidationResult.set(isBtcInputValid(minAmount.get())); } - // We want to trigger a recalculation of the volume UserThread.execute(() -> onFocusOutVolumeTextField(true, false)); } @@ -969,11 +968,16 @@ private void setAmountToModel() { if (amount.get() != null && !amount.get().isEmpty()) { Coin amount = btcFormatter.parseToCoinWith4Decimals(this.amount.get()); - if (dataModel.isHalCashAccount() && dataModel.getPrice().get() != null) - amount = OfferUtil.getAdjustedAmountForHalCash(amount, dataModel.getPrice().get()); + if (dataModel.isHalCashAccount() && dataModel.getPrice().get() != null) { + amount = OfferUtil.getAdjustedAmountForHalCash(amount, + dataModel.getPrice().get(), + dataModel.getMaxTradeLimit()); + } dataModel.setAmount(amount); - if (syncMinAmountWithAmount || dataModel.getMinAmount().get() == null || dataModel.getMinAmount().get().equals(Coin.ZERO)) { + if (syncMinAmountWithAmount || + dataModel.getMinAmount().get() == null || + dataModel.getMinAmount().get().equals(Coin.ZERO)) { minAmount.set(this.amount.get()); setMinAmountToModel(); } @@ -986,8 +990,11 @@ private void setMinAmountToModel() { if (minAmount.get() != null && !minAmount.get().isEmpty()) { Coin minAmount = btcFormatter.parseToCoinWith4Decimals(this.minAmount.get()); - if (dataModel.isHalCashAccount() && dataModel.getPrice().get() != null) - minAmount = OfferUtil.getAdjustedAmountForHalCash(minAmount, dataModel.getPrice().get()); + if (dataModel.isHalCashAccount() && dataModel.getPrice().get() != null) { + minAmount = OfferUtil.getAdjustedAmountForHalCash(minAmount, + dataModel.getPrice().get(), + dataModel.getMaxTradeLimit()); + } dataModel.setMinAmount(minAmount); } else { diff --git a/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferViewModel.java b/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferViewModel.java index c3c7b760495..fa247d49cfe 100644 --- a/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferViewModel.java +++ b/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferViewModel.java @@ -282,7 +282,10 @@ void onFocusOutAmountTextField(boolean oldValue, boolean newValue, String userIn calculateVolume(); if (dataModel.getPaymentMethod().getId().equals(PaymentMethod.HAL_CASH_ID)) { - dataModel.applyAmount(OfferUtil.getAdjustedAmountForHalCash(dataModel.getAmount().get(), dataModel.tradePrice)); + Coin adjustedAmountForHalCash = OfferUtil.getAdjustedAmountForHalCash(dataModel.getAmount().get(), + dataModel.tradePrice, + dataModel.getMaxTradeLimit()); + dataModel.applyAmount(adjustedAmountForHalCash); amount.set(btcFormatter.formatCoin(dataModel.getAmount().get())); }