diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index 04f2a585ac7..0fbc9aa99af 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -336,6 +336,7 @@ market.trades.showVolumeInUSD=Show volume in USD offerbook.createOffer=Create offer offerbook.takeOffer=Take offer +offerbook.takeOffer.createAccount=Create account and take offer offerbook.takeOfferToBuy=Take offer to buy {0} offerbook.takeOfferToSell=Take offer to sell {0} offerbook.trader=Trader @@ -388,6 +389,7 @@ offerbook.createOfferToBuy.withFiat=Create new offer to buy {0} with {1} offerbook.createOfferToSell.forFiat=Create new offer to sell {0} for {1} offerbook.createOfferToBuy.withCrypto=Create new offer to sell {0} (buy {1}) offerbook.createOfferToSell.forCrypto=Create new offer to buy {0} (sell {1}) +offerbook.createOfferDisabled.tooltip=You can only create one offer at a time offerbook.takeOfferButton.tooltip=Take offer for {0} offerbook.yesCreateOffer=Yes, create offer @@ -402,6 +404,7 @@ offerbook.warning.noTradingAccountForCurrency.headline=No payment account for se offerbook.warning.noTradingAccountForCurrency.msg=You don't have a payment account set up for the selected currency.\n\nWould you like to create an offer for another currency instead? offerbook.warning.noMatchingAccount.headline=No matching payment account. offerbook.warning.noMatchingAccount.msg=This offer uses a payment method you haven't set up yet. \n\nWould you like to set up a new payment account now? +offerbook.warning.noMatchingBsqAccount.msg=This offer uses BSQ as a payment method you haven't set up yet. \n\nWould you like to automatically create an account now? offerbook.warning.counterpartyTradeRestrictions=This offer cannot be taken due to counterparty trade restrictions @@ -440,6 +443,13 @@ offerbook.info.buyAtFixedPrice=You will buy at this fixed price. offerbook.info.sellAtFixedPrice=You will sell at this fixed price. offerbook.info.noArbitrationInUserLanguage=In case of a dispute, please note that arbitration for this offer will be handled in {0}. Language is currently set to {1}. offerbook.info.roundedFiatVolume=The amount was rounded to increase the privacy of your trade. +offerbook.info.accountCreated.headline=Congratulations +offerbook.info.accountCreated.message=You''ve just successfully created a BSQ payment account.\n\ + Your account can be found under Account > Altcoins Accounts > {0} and your BSQ wallet under DAO > BSQ Wallet.\n\n +offerbook.info.accountCreated.tradeInstant=You've chosen to take a BSQ instant offer, so a BSQ instant payment account was created for you. \ + Be aware that instant trades are meant to be completed within 1 hour, \ + so you should be online and available for the next 1 hour.\n\n +offerbook.info.accountCreated.takeOffer=You can now proceed to take this offer after closing this popup. offerbook.bsqSwap.createOffer=Create Bsq swap offer @@ -481,6 +491,11 @@ createOffer.triggerPrice.tooltip=As protection against drastic price movements y createOffer.triggerPrice.invalid.tooLow=Value must be higher than {0} createOffer.triggerPrice.invalid.tooHigh=Value must be lower than {0} +createOffer.buyBsq.popupMessage=Trading fees are paid to fund the Bisq DAO. Fees can be paid in BSQ or BTC.\n\n\ + BSQ fees directly help fund Bisq's development, so Bisq encourages traders to use BSQ by offering a 50% discount on trading fees. \ + This discount varies as the BSQ/BTC rate fluctuates. To maintain the 50% discount target, trading fees are updated every cycle as necessary.\n\n\ + For more about fees, see [HYPERLINK:https://bisq.wiki/Trading_fees]. For more about trading BSQ, see [HYPERLINK:https://bisq.wiki/Trading_BSQ]. For more about the Bisq DAO, see [HYPERLINK:https://bisq.wiki/Introduction_to_the_DAO#The_Bisq_DAO]. + # new entries createOffer.placeOfferButton=Review: Place offer to {0} bitcoin createOffer.createOfferFundWalletInfo.headline=Fund your offer @@ -860,6 +875,7 @@ portfolio.pending.step3_seller.xmrTxHash=Transaction ID portfolio.pending.step3_seller.xmrTxKey=Transaction key portfolio.pending.step3_seller.buyersAccount=Buyers account data portfolio.pending.step3_seller.confirmReceipt=Confirm payment receipt +portfolio.pending.step3_seller.showBsqWallet=Show payment in BSQ wallet portfolio.pending.step3_seller.buyerStartedPayment=The BTC buyer has started the {0} payment.\n{1} portfolio.pending.step3_seller.buyerStartedPayment.altcoin=Check for blockchain confirmations at your altcoin wallet or block explorer and confirm the payment when you have sufficient blockchain confirmations. portfolio.pending.step3_seller.buyerStartedPayment.fiat=Check at your trading account (e.g. bank account) and confirm when you have received the payment. diff --git a/desktop/src/main/java/bisq/desktop/bisq.css b/desktop/src/main/java/bisq/desktop/bisq.css index d8aac0472d6..51862da5561 100644 --- a/desktop/src/main/java/bisq/desktop/bisq.css +++ b/desktop/src/main/java/bisq/desktop/bisq.css @@ -175,6 +175,14 @@ -fx-padding: 0 10 0 10; } +.tiny-button, +.action-button.tiny-button { + -fx-font-size: 0.769em; + -fx-pref-height: 20; + -fx-padding: 3 8 3 8; + -fx-border-radius: 5; +} + .text-button { -fx-background-color: transparent; -fx-underline: true; diff --git a/desktop/src/main/java/bisq/desktop/components/HyperlinkWithIcon.java b/desktop/src/main/java/bisq/desktop/components/HyperlinkWithIcon.java index b3738ee74d0..3eebe0aab8a 100644 --- a/desktop/src/main/java/bisq/desktop/components/HyperlinkWithIcon.java +++ b/desktop/src/main/java/bisq/desktop/components/HyperlinkWithIcon.java @@ -41,11 +41,15 @@ public HyperlinkWithIcon(String text) { this(text, AwesomeIcon.INFO_SIGN); } - public HyperlinkWithIcon(String text, AwesomeIcon awesomeIcon) { + public HyperlinkWithIcon(String text, String fontSize) { + this(text, AwesomeIcon.INFO_SIGN, fontSize); + } + + public HyperlinkWithIcon(String text, AwesomeIcon awesomeIcon, String fontSize) { super(text); Label icon = new Label(); - AwesomeDude.setIcon(icon, awesomeIcon); + AwesomeDude.setIcon(icon, awesomeIcon, fontSize); icon.setMinWidth(20); icon.setOpacity(0.7); icon.getStyleClass().addAll("hyperlink", "no-underline"); @@ -55,6 +59,10 @@ public HyperlinkWithIcon(String text, AwesomeIcon awesomeIcon) { setIcon(icon); } + public HyperlinkWithIcon(String text, AwesomeIcon awesomeIcon) { + this(text, awesomeIcon, "1.231em"); + } + public HyperlinkWithIcon(String text, GlyphIcons icon) { this(text, icon, null); } diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/AdvancedCashForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/AdvancedCashForm.java index f384b5a1c63..caf34bdf327 100644 --- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/AdvancedCashForm.java +++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/AdvancedCashForm.java @@ -34,8 +34,6 @@ 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; @@ -62,8 +60,13 @@ public static int addFormForBuyer(GridPane gridPane, int gridRow, return gridRow; } - public AdvancedCashForm(PaymentAccount paymentAccount, AccountAgeWitnessService accountAgeWitnessService, AdvancedCashValidator advancedCashValidator, - InputValidator inputValidator, GridPane gridPane, int gridRow, CoinFormatter formatter) { + public AdvancedCashForm(PaymentAccount paymentAccount, + AccountAgeWitnessService accountAgeWitnessService, + AdvancedCashValidator advancedCashValidator, + InputValidator inputValidator, + GridPane gridPane, + int gridRow, + CoinFormatter formatter) { super(paymentAccount, accountAgeWitnessService, inputValidator, gridPane, gridRow, formatter); this.advancedCashAccount = (AdvancedCashAccount) paymentAccount; this.advancedCashValidator = advancedCashValidator; @@ -101,12 +104,7 @@ private void addCurrenciesGrid(boolean isEditable) { @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)); - } + setAccountNameWithString(accountNrInputTextField.getText()); } @Override diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/AssetsForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/AssetsForm.java index 2a72811dead..30f32c9ee52 100644 --- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/AssetsForm.java +++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/AssetsForm.java @@ -41,8 +41,6 @@ import bisq.common.UserThread; import bisq.common.util.Tuple3; -import org.apache.commons.lang3.StringUtils; - import javafx.scene.control.CheckBox; import javafx.scene.control.Label; import javafx.scene.control.TextField; @@ -53,6 +51,7 @@ import javafx.util.StringConverter; +import static bisq.desktop.util.DisplayUtils.createAssetsAccountName; import static bisq.desktop.util.FormBuilder.addCompactTopLabelTextField; import static bisq.desktop.util.FormBuilder.addCompactTopLabelTextFieldWithCopyIcon; import static bisq.desktop.util.FormBuilder.addLabelCheckBox; @@ -167,12 +166,7 @@ public void updateFromInputs() { @Override protected void autoFillNameTextField() { if (useCustomAccountNameToggleButton != null && !useCustomAccountNameToggleButton.isSelected()) { - String currency = paymentAccount.getSingleTradeCurrency() != null ? paymentAccount.getSingleTradeCurrency().getCode() : ""; - if (currency != null) { - String address = addressInputTextField.getText(); - address = StringUtils.abbreviate(address, 9); - accountNameTextField.setText(currency.concat(": ").concat(address)); - } + accountNameTextField.setText(createAssetsAccountName(paymentAccount, addressInputTextField.getText())); } } diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/CapitualForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/CapitualForm.java index e4fa6163a4d..4f7201cc542 100644 --- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/CapitualForm.java +++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/CapitualForm.java @@ -34,8 +34,6 @@ 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; @@ -100,12 +98,7 @@ private void addCurrenciesGrid(boolean isEditable) { @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)); - } + setAccountNameWithString(accountNrInputTextField.getText()); } @Override diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/JapanBankTransferForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/JapanBankTransferForm.java index 22eac439a5f..bfbde452b10 100644 --- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/JapanBankTransferForm.java +++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/JapanBankTransferForm.java @@ -25,7 +25,6 @@ import bisq.desktop.util.validation.JapanBankAccountNumberValidator; import bisq.desktop.util.validation.JapanBankBranchCodeValidator; import bisq.desktop.util.validation.JapanBankBranchNameValidator; -import bisq.desktop.util.validation.JapanBankTransferValidator; import bisq.desktop.util.validation.LengthValidator; import bisq.core.account.witness.AccountAgeWitnessService; @@ -57,24 +56,17 @@ import static bisq.desktop.util.FormBuilder.*; import static bisq.desktop.util.GUIUtil.getComboBoxButtonCell; -public class JapanBankTransferForm extends PaymentMethodForm -{ +public class JapanBankTransferForm extends PaymentMethodForm { private final JapanBankAccount japanBankAccount; - protected ComboBox bankComboBox, bankAccountTypeComboBox; - private InputTextField bankAccountNumberInputTextField; + protected ComboBox bankComboBox; - private JapanBankTransferValidator japanBankTransferValidator; - private JapanBankBranchNameValidator japanBankBranchNameValidator; - private JapanBankBranchCodeValidator japanBankBranchCodeValidator; - private JapanBankAccountNameValidator japanBankAccountNameValidator; - private JapanBankAccountNumberValidator japanBankAccountNumberValidator; + private final JapanBankBranchNameValidator japanBankBranchNameValidator; + private final JapanBankBranchCodeValidator japanBankBranchCodeValidator; + private final JapanBankAccountNameValidator japanBankAccountNameValidator; + private final JapanBankAccountNumberValidator japanBankAccountNumberValidator; - private LengthValidator lengthValidator; - private RegexValidator regexValidator; - - public static int addFormForBuyer(GridPane gridPane, int gridRow, // {{{ - PaymentAccountPayload paymentAccountPayload) - { + public static int addFormForBuyer(GridPane gridPane, int gridRow, + PaymentAccountPayload paymentAccountPayload) { JapanBankAccountPayload japanBankAccount = ((JapanBankAccountPayload) paymentAccountPayload); String bankText = japanBankAccount.getBankCode() + " " + japanBankAccount.getBankName(); @@ -90,30 +82,26 @@ public static int addFormForBuyer(GridPane gridPane, int gridRow, // {{{ addCompactTopLabelTextFieldWithCopyIcon(gridPane, gridRow, 1, Res.get("payment.japan.recipient"), accountNameText); return gridRow; - } // }}} + } public JapanBankTransferForm(PaymentAccount paymentAccount, - AccountAgeWitnessService accountAgeWitnessService, - JapanBankTransferValidator japanBankTransferValidator, - InputValidator inputValidator, GridPane gridPane, - int gridRow, CoinFormatter formatter) - { + AccountAgeWitnessService accountAgeWitnessService, + InputValidator inputValidator, GridPane gridPane, + int gridRow, CoinFormatter formatter) { super(paymentAccount, accountAgeWitnessService, inputValidator, gridPane, gridRow, formatter); this.japanBankAccount = (JapanBankAccount) paymentAccount; - this.japanBankTransferValidator = japanBankTransferValidator; this.japanBankBranchCodeValidator = new JapanBankBranchCodeValidator(); this.japanBankAccountNumberValidator = new JapanBankAccountNumberValidator(); - this.lengthValidator = new LengthValidator(); - this.regexValidator = new RegexValidator(); + LengthValidator lengthValidator = new LengthValidator(); + RegexValidator regexValidator = new RegexValidator(); this.japanBankBranchNameValidator = new JapanBankBranchNameValidator(lengthValidator, regexValidator); this.japanBankAccountNameValidator = new JapanBankAccountNameValidator(lengthValidator, regexValidator); } @Override - public void addFormForDisplayAccount() // {{{ - { + public void addFormForDisplayAccount() { gridRowFrom = gridRow; addTopLabelTextField(gridPane, ++gridRow, Res.get("payment.account.name"), @@ -128,37 +116,36 @@ public void addFormForDisplayAccount() // {{{ addBankAccountTypeDisplay(); addLimitations(true); - } // }}} - private void addBankDisplay() // {{{ - { + } + + private void addBankDisplay() { String bankText = japanBankAccount.getBankCode() + " " + japanBankAccount.getBankName(); TextField bankTextField = addCompactTopLabelTextField(gridPane, ++gridRow, JapanBankData.getString("bank"), bankText).second; bankTextField.setEditable(false); - } // }}} - private void addBankBranchDisplay() // {{{ - { + } + + private void addBankBranchDisplay() { String branchText = japanBankAccount.getBankBranchCode() + " " + japanBankAccount.getBankBranchName(); TextField branchTextField = addCompactTopLabelTextField(gridPane, ++gridRow, JapanBankData.getString("branch"), branchText).second; branchTextField.setEditable(false); - } // }}} - private void addBankAccountDisplay() // {{{ - { + } + + private void addBankAccountDisplay() { String accountText = japanBankAccount.getBankAccountNumber() + " " + japanBankAccount.getBankAccountName(); TextField accountTextField = addCompactTopLabelTextField(gridPane, ++gridRow, JapanBankData.getString("account"), accountText).second; accountTextField.setEditable(false); - } // }}} - private void addBankAccountTypeDisplay() // {{{ - { + } + + private void addBankAccountTypeDisplay() { TradeCurrency singleTradeCurrency = japanBankAccount.getSingleTradeCurrency(); String currency = singleTradeCurrency != null ? singleTradeCurrency.getNameAndCode() : "null"; String accountTypeText = currency + " " + japanBankAccount.getBankAccountType(); TextField accountTypeTextField = addCompactTopLabelTextField(gridPane, ++gridRow, JapanBankData.getString("account.type"), accountTypeText).second; accountTypeTextField.setEditable(false); - } // }}} + } @Override - public void addFormForAddAccount() // {{{ - { + public void addFormForAddAccount() { gridRowFrom = gridRow; addBankInput(); @@ -168,9 +155,9 @@ public void addFormForAddAccount() // {{{ addLimitations(false); addAccountNameTextFieldWithAutoFillToggleButton(); - } // }}} - private void addBankInput() // {{{ - { + } + + private void addBankInput() { gridRow++; Tuple4> tuple4 = addTopLabelTextFieldAutocompleteComboBox(gridPane, gridRow, JapanBankData.getString("bank.code"), JapanBankData.getString("bank.name"), 10); @@ -185,14 +172,13 @@ private void addBankInput() // {{{ bankComboBox = tuple4.fourth; bankComboBox.setPromptText(JapanBankData.getString("bank.select")); bankComboBox.setButtonCell(getComboBoxButtonCell(JapanBankData.getString("bank.name"), bankComboBox)); - bankComboBox.getEditor().focusedProperty().addListener(observable -> { - bankComboBox.setPromptText(""); - }); - bankComboBox.setConverter(new StringConverter() { + bankComboBox.getEditor().focusedProperty().addListener(observable -> bankComboBox.setPromptText("")); + bankComboBox.setConverter(new StringConverter<>() { @Override public String toString(String bank) { return bank != null ? bank : ""; } + public String fromString(String s) { return s != null ? s : ""; } @@ -208,8 +194,7 @@ public String fromString(String s) { // parse first 4 characters as bank code String bankCode = StringUtils.substring(bank, 0, 4); - if (bankCode != null) - { + if (bankCode != null) { // set bank code field to this value bankCodeField.setText(bankCode); // save to payload @@ -217,26 +202,20 @@ public String fromString(String s) { // parse remainder as bank name String bankNameFull = StringUtils.substringAfter(bank, JapanBankData.SPACE); - if (bankNameFull != null) - { - // parse beginning as Japanese bank name - String bankNameJa = StringUtils.substringBefore(bankNameFull, JapanBankData.SPACE); - if (bankNameJa != null) - { - // set bank name field to this value - bankComboBox.getEditor().setText(bankNameJa); - // save to payload - japanBankAccount.setBankName(bankNameJa); - } - } + // parse beginning as Japanese bank name + String bankNameJa = StringUtils.substringBefore(bankNameFull, JapanBankData.SPACE); + // set bank name field to this value + bankComboBox.getEditor().setText(bankNameJa); + // save to payload + japanBankAccount.setBankName(bankNameJa); } updateFromInputs(); }); - } // }}} - private void addBankBranchInput() // {{{ - { + } + + private void addBankBranchInput() { gridRow++; Tuple2 tuple2 = addInputTextFieldInputTextField(gridPane, gridRow, JapanBankData.getString("branch.code"), JapanBankData.getString("branch.name")); @@ -259,14 +238,14 @@ private void addBankBranchInput() // {{{ japanBankAccount.setBankBranchName(newValue); updateFromInputs(); }); - } // }}} - private void addBankAccountInput() // {{{ - { + } + + private void addBankAccountInput() { gridRow++; Tuple2 tuple2 = addInputTextFieldInputTextField(gridPane, gridRow, JapanBankData.getString("account.number"), JapanBankData.getString("account.name")); // account number - bankAccountNumberInputTextField = tuple2.first; + InputTextField bankAccountNumberInputTextField = tuple2.first; bankAccountNumberInputTextField.setValidator(japanBankAccountNumberValidator); bankAccountNumberInputTextField.setPrefWidth(200); bankAccountNumberInputTextField.setMaxWidth(200); @@ -284,9 +263,9 @@ private void addBankAccountInput() // {{{ japanBankAccount.setBankAccountName(newValue); updateFromInputs(); }); - } // }}} - private void addBankAccountTypeInput() // {{{ - { + } + + private void addBankAccountTypeInput() { // account currency gridRow++; @@ -299,13 +278,13 @@ private void addBankAccountTypeInput() // {{{ ToggleGroup toggleGroup = new ToggleGroup(); Tuple3 tuple3 = - addTopLabelRadioButtonRadioButton( - gridPane, gridRow, toggleGroup, - JapanBankData.getString("account.type.select"), - JapanBankData.getString("account.type.futsu"), - JapanBankData.getString("account.type.touza"), - 0 - ); + addTopLabelRadioButtonRadioButton( + gridPane, gridRow, toggleGroup, + JapanBankData.getString("account.type.select"), + JapanBankData.getString("account.type.futsu"), + JapanBankData.getString("account.type.touza"), + 0 + ); toggleGroup.getToggles().get(0).setSelected(true); japanBankAccount.setBankAccountType(JapanBankData.getString("account.type.futsu.ja")); @@ -314,66 +293,60 @@ private void addBankAccountTypeInput() // {{{ RadioButton touza = tuple3.third; toggleGroup.selectedToggleProperty().addListener - ( - (ov, oldValue, newValue) -> - { - if (futsu.isSelected()) - japanBankAccount.setBankAccountType(JapanBankData.getString("account.type.futsu.ja")); - if (touza.isSelected()) - japanBankAccount.setBankAccountType(JapanBankData.getString("account.type.touza.ja")); - } - ); - } // }}} + ( + (ov, oldValue, newValue) -> + { + if (futsu.isSelected()) + japanBankAccount.setBankAccountType(JapanBankData.getString("account.type.futsu.ja")); + if (touza.isSelected()) + japanBankAccount.setBankAccountType(JapanBankData.getString("account.type.touza.ja")); + } + ); + } @Override - public void updateFromInputs() // {{{ - { + public void updateFromInputs() { System.out.println("JapanBankTransferForm: updateFromInputs()"); - System.out.println("bankName: "+japanBankAccount.getBankName()); - System.out.println("bankCode: "+japanBankAccount.getBankCode()); - System.out.println("bankBranchName: "+japanBankAccount.getBankBranchName()); - System.out.println("bankBranchCode: "+japanBankAccount.getBankBranchCode()); - System.out.println("bankAccountType: "+japanBankAccount.getBankAccountType()); - System.out.println("bankAccountName: "+japanBankAccount.getBankAccountName()); - System.out.println("bankAccountNumber: "+japanBankAccount.getBankAccountNumber()); + System.out.println("bankName: " + japanBankAccount.getBankName()); + System.out.println("bankCode: " + japanBankAccount.getBankCode()); + System.out.println("bankBranchName: " + japanBankAccount.getBankBranchName()); + System.out.println("bankBranchCode: " + japanBankAccount.getBankBranchCode()); + System.out.println("bankAccountType: " + japanBankAccount.getBankAccountType()); + System.out.println("bankAccountName: " + japanBankAccount.getBankAccountName()); + System.out.println("bankAccountNumber: " + japanBankAccount.getBankAccountNumber()); super.updateFromInputs(); - } // }}} + } @Override - protected void autoFillNameTextField() // {{{ - { - if (useCustomAccountNameToggleButton != null && !useCustomAccountNameToggleButton.isSelected()) - { + protected void autoFillNameTextField() { + if (useCustomAccountNameToggleButton != null && !useCustomAccountNameToggleButton.isSelected()) { accountNameTextField.setText( Res.get(paymentAccount.getPaymentMethod().getId()) - .concat(": ") - .concat(japanBankAccount.getBankName()) - .concat(" ") - .concat(japanBankAccount.getBankBranchName()) - .concat(" ") - .concat(japanBankAccount.getBankAccountNumber()) - .concat(" ") - .concat(japanBankAccount.getBankAccountName()) + .concat(": ") + .concat(japanBankAccount.getBankName()) + .concat(" ") + .concat(japanBankAccount.getBankBranchName()) + .concat(" ") + .concat(japanBankAccount.getBankAccountNumber()) + .concat(" ") + .concat(japanBankAccount.getBankAccountName()) ); } - } // }}} + } @Override - public void updateAllInputsValid() // {{{ - { + public void updateAllInputsValid() { boolean result = - ( - isAccountNameValid() && - inputValidator.validate(japanBankAccount.getBankCode()).isValid && - inputValidator.validate(japanBankAccount.getBankName()).isValid && - japanBankBranchCodeValidator.validate(japanBankAccount.getBankBranchCode()).isValid && - japanBankBranchNameValidator.validate(japanBankAccount.getBankBranchName()).isValid && - japanBankAccountNumberValidator.validate(japanBankAccount.getBankAccountNumber()).isValid && - japanBankAccountNameValidator.validate(japanBankAccount.getBankAccountName()).isValid && - inputValidator.validate(japanBankAccount.getBankAccountType()).isValid - ); + ( + isAccountNameValid() && + inputValidator.validate(japanBankAccount.getBankCode()).isValid && + inputValidator.validate(japanBankAccount.getBankName()).isValid && + japanBankBranchCodeValidator.validate(japanBankAccount.getBankBranchCode()).isValid && + japanBankBranchNameValidator.validate(japanBankAccount.getBankBranchName()).isValid && + japanBankAccountNumberValidator.validate(japanBankAccount.getBankAccountNumber()).isValid && + japanBankAccountNameValidator.validate(japanBankAccount.getBankAccountName()).isValid && + inputValidator.validate(japanBankAccount.getBankAccountType()).isValid + ); allInputsValid.set(result); - } // }}} + } } - -// vim:ts=4:sw=4:expandtab:foldmethod=marker:nowrap: diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/MoneyGramForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/MoneyGramForm.java index 799a79a35f8..f02e59dbada 100644 --- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/MoneyGramForm.java +++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/MoneyGramForm.java @@ -37,8 +37,6 @@ 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; @@ -172,11 +170,7 @@ private MoneyGramAccount getMoneyGramPaymentAccount() { @Override protected void autoFillNameTextField() { - if (useCustomAccountNameToggleButton != null && !useCustomAccountNameToggleButton.isSelected()) { - accountNameTextField.setText(Res.get(paymentAccount.getPaymentMethod().getId()) - .concat(": ") - .concat(StringUtils.abbreviate(holderNameInputTextField.getText(), 9))); - } + setAccountNameWithString(holderNameInputTextField.getText()); } @Override diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/PaymentMethodForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/PaymentMethodForm.java index df2a8fd2d33..5909dd0f54a 100644 --- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/PaymentMethodForm.java +++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/PaymentMethodForm.java @@ -73,6 +73,7 @@ import lombok.extern.slf4j.Slf4j; +import static bisq.desktop.util.DisplayUtils.createAccountName; import static bisq.desktop.util.FormBuilder.*; @Slf4j @@ -287,10 +288,8 @@ void applyTradeCurrency(TradeCurrency tradeCurrency, FiatCurrency defaultCurrenc void setAccountNameWithString(String name) { if (useCustomAccountNameToggleButton != null && !useCustomAccountNameToggleButton.isSelected()) { - name = name.trim(); - name = StringUtils.abbreviate(name, 9); - String method = Res.get(paymentAccount.getPaymentMethod().getId()); - accountNameTextField.setText(method.concat(": ").concat(name)); + String accountName = createAccountName(paymentAccount.getPaymentMethod().getId(), name); + accountNameTextField.setText(accountName); } } diff --git a/desktop/src/main/java/bisq/desktop/main/account/content/altcoinaccounts/AltCoinAccountsDataModel.java b/desktop/src/main/java/bisq/desktop/main/account/content/altcoinaccounts/AltCoinAccountsDataModel.java index da91488357a..183d4f14195 100644 --- a/desktop/src/main/java/bisq/desktop/main/account/content/altcoinaccounts/AltCoinAccountsDataModel.java +++ b/desktop/src/main/java/bisq/desktop/main/account/content/altcoinaccounts/AltCoinAccountsDataModel.java @@ -20,9 +20,7 @@ import bisq.desktop.common.model.ActivatableDataModel; import bisq.desktop.util.GUIUtil; -import bisq.core.account.witness.AccountAgeWitnessService; import bisq.core.locale.CryptoCurrency; -import bisq.core.locale.FiatCurrency; import bisq.core.locale.TradeCurrency; import bisq.core.offer.OpenOfferManager; import bisq.core.payment.AssetAccount; @@ -44,7 +42,6 @@ import java.util.ArrayList; import java.util.Comparator; -import java.util.List; import java.util.stream.Collectors; class AltCoinAccountsDataModel extends ActivatableDataModel { @@ -53,7 +50,6 @@ class AltCoinAccountsDataModel extends ActivatableDataModel { private final Preferences preferences; private final OpenOfferManager openOfferManager; private final TradeManager tradeManager; - private final AccountAgeWitnessService accountAgeWitnessService; final ObservableList paymentAccounts = FXCollections.observableArrayList(); private final SetChangeListener setChangeListener; private final String accountsFileName = "AltcoinPaymentAccounts"; @@ -65,14 +61,12 @@ public AltCoinAccountsDataModel(User user, Preferences preferences, OpenOfferManager openOfferManager, TradeManager tradeManager, - AccountAgeWitnessService accountAgeWitnessService, PersistenceProtoResolver persistenceProtoResolver, CorruptedStorageFileHandler corruptedStorageFileHandler) { this.user = user; this.preferences = preferences; this.openOfferManager = openOfferManager; this.tradeManager = tradeManager; - this.accountAgeWitnessService = accountAgeWitnessService; this.persistenceProtoResolver = persistenceProtoResolver; this.corruptedStorageFileHandler = corruptedStorageFileHandler; setChangeListener = change -> fillAndSortPaymentAccounts(); @@ -105,25 +99,8 @@ protected void deactivate() { public void onSaveNewAccount(PaymentAccount paymentAccount) { TradeCurrency singleTradeCurrency = paymentAccount.getSingleTradeCurrency(); - List tradeCurrencies = paymentAccount.getTradeCurrencies(); - if (singleTradeCurrency != null) { - if (singleTradeCurrency instanceof FiatCurrency) - preferences.addFiatCurrency((FiatCurrency) singleTradeCurrency); - else - preferences.addCryptoCurrency((CryptoCurrency) singleTradeCurrency); - } else if (tradeCurrencies != null && !tradeCurrencies.isEmpty()) { - tradeCurrencies.forEach(tradeCurrency -> { - if (tradeCurrency instanceof FiatCurrency) - preferences.addFiatCurrency((FiatCurrency) tradeCurrency); - else - preferences.addCryptoCurrency((CryptoCurrency) tradeCurrency); - }); - } - + preferences.addCryptoCurrency((CryptoCurrency) singleTradeCurrency); user.addPaymentAccount(paymentAccount); - - if (!(paymentAccount instanceof AssetAccount)) - accountAgeWitnessService.publishMyAccountAgeWitness(paymentAccount.getPaymentAccountPayload()); } public boolean onDeleteAccount(PaymentAccount paymentAccount) { @@ -147,9 +124,9 @@ public void onSelectAccount(PaymentAccount paymentAccount) { public void exportAccounts(Stage stage) { if (user.getPaymentAccounts() != null) { - ArrayList accounts = new ArrayList<>(user.getPaymentAccounts().stream() + ArrayList accounts = user.getPaymentAccounts().stream() .filter(paymentAccount -> paymentAccount instanceof AssetAccount) - .collect(Collectors.toList())); + .collect(Collectors.toCollection(ArrayList::new)); GUIUtil.exportAccounts(accounts, accountsFileName, preferences, stage, persistenceProtoResolver, corruptedStorageFileHandler); } } diff --git a/desktop/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsDataModel.java b/desktop/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsDataModel.java index f3c30abc368..b114c4cbbcb 100644 --- a/desktop/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsDataModel.java +++ b/desktop/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsDataModel.java @@ -21,7 +21,6 @@ import bisq.desktop.util.GUIUtil; import bisq.core.account.witness.AccountAgeWitnessService; -import bisq.core.locale.CryptoCurrency; import bisq.core.locale.CurrencyUtil; import bisq.core.locale.FiatCurrency; import bisq.core.locale.TradeCurrency; @@ -109,22 +108,14 @@ public void onSaveNewAccount(PaymentAccount paymentAccount) { TradeCurrency singleTradeCurrency = paymentAccount.getSingleTradeCurrency(); List tradeCurrencies = paymentAccount.getTradeCurrencies(); if (singleTradeCurrency != null) { - if (singleTradeCurrency instanceof FiatCurrency) - preferences.addFiatCurrency((FiatCurrency) singleTradeCurrency); - else - preferences.addCryptoCurrency((CryptoCurrency) singleTradeCurrency); + preferences.addFiatCurrency((FiatCurrency) singleTradeCurrency); } else if (tradeCurrencies != null && !tradeCurrencies.isEmpty()) { if (tradeCurrencies.contains(CurrencyUtil.getDefaultTradeCurrency())) paymentAccount.setSelectedTradeCurrency(CurrencyUtil.getDefaultTradeCurrency()); else paymentAccount.setSelectedTradeCurrency(tradeCurrencies.get(0)); - tradeCurrencies.forEach(tradeCurrency -> { - if (tradeCurrency instanceof FiatCurrency) - preferences.addFiatCurrency((FiatCurrency) tradeCurrency); - else - preferences.addCryptoCurrency((CryptoCurrency) tradeCurrency); - }); + tradeCurrencies.forEach(tradeCurrency -> preferences.addFiatCurrency((FiatCurrency) tradeCurrency)); } user.addPaymentAccount(paymentAccount); @@ -154,9 +145,9 @@ public void onSelectAccount(PaymentAccount paymentAccount) { public void exportAccounts(Stage stage) { if (user.getPaymentAccounts() != null) { - ArrayList accounts = new ArrayList<>(user.getPaymentAccounts().stream() + ArrayList accounts = user.getPaymentAccounts().stream() .filter(paymentAccount -> !(paymentAccount instanceof AssetAccount)) - .collect(Collectors.toList())); + .collect(Collectors.toCollection(ArrayList::new)); GUIUtil.exportAccounts(accounts, accountsFileName, preferences, stage, persistenceProtoResolver, corruptedStorageFileHandler); } } 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 baf3dd625f5..4742864e446 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 @@ -520,7 +520,7 @@ private PaymentMethodForm getPaymentMethodForm(PaymentMethod paymentMethod, Paym case PaymentMethod.SPECIFIC_BANKS_ID: return new SpecificBankForm(paymentAccount, accountAgeWitnessService, inputValidator, root, gridRow, formatter); case PaymentMethod.JAPAN_BANK_ID: - return new JapanBankTransferForm(paymentAccount, accountAgeWitnessService, japanBankTransferValidator, inputValidator, root, gridRow, formatter); + return new JapanBankTransferForm(paymentAccount, accountAgeWitnessService, inputValidator, root, gridRow, formatter); case PaymentMethod.AUSTRALIA_PAYID_ID: return new AustraliaPayidForm(paymentAccount, accountAgeWitnessService, australiapayidValidator, inputValidator, root, gridRow, formatter); case PaymentMethod.ALI_PAY_ID: diff --git a/desktop/src/main/java/bisq/desktop/main/offer/OfferView.java b/desktop/src/main/java/bisq/desktop/main/offer/OfferView.java index 8e828c42047..cb61fe568b8 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/OfferView.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/OfferView.java @@ -176,7 +176,9 @@ protected void activate() { root.getSelectionModel().selectedItemProperty().addListener(tabChangeListener); root.getTabs().addListener(tabListChangeListener); navigation.addListener(navigationListener); - navigation.navigateTo(MainView.class, this.getClass(), OfferBookView.class); + if (offerBookView == null) { + navigation.navigateTo(MainView.class, this.getClass(), OfferBookView.class); + } } @Override @@ -202,17 +204,21 @@ private void loadView(Class viewClass) { View view; boolean isBuy = direction == OfferDirection.BUY; - if (viewClass == OfferBookView.class && offerBookView == null) { - view = viewLoader.load(viewClass); - // Offerbook must not be cached by ViewLoader as we use 2 instances for sell and buy screens. - offerBookTab = new Tab(isBuy ? Res.get("shared.buyBitcoin").toUpperCase() : Res.get("shared.sellBitcoin").toUpperCase()); - offerBookTab.setClosable(false); - offerBookTab.setContent(view.getRoot()); - tabPane.getTabs().add(offerBookTab); - offerBookView = (OfferBookView) view; - offerBookView.onTabSelected(true); - offerBookView.setOfferActionHandler(offerActionHandler); - offerBookView.setDirection(direction); + if (viewClass == OfferBookView.class) { + if (offerBookTab != null && offerBookView != null) { + tabPane.getSelectionModel().select(offerBookTab); + } else { + view = viewLoader.load(viewClass); + // Offerbook must not be cached by ViewLoader as we use 2 instances for sell and buy screens. + offerBookTab = new Tab(isBuy ? Res.get("shared.buyBitcoin").toUpperCase() : Res.get("shared.sellBitcoin").toUpperCase()); + offerBookTab.setClosable(false); + offerBookTab.setContent(view.getRoot()); + tabPane.getTabs().add(offerBookTab); + offerBookView = (OfferBookView) view; + offerBookView.onTabSelected(true); + offerBookView.setOfferActionHandler(offerActionHandler); + offerBookView.setDirection(direction); + } } else if (viewClass == CreateOfferView.class && createOfferView == null) { view = viewLoader.load(viewClass); // CreateOffer and TakeOffer must not be cached by ViewLoader as we cannot use a view multiple times @@ -247,7 +253,7 @@ private void loadView(Class viewClass) { // in different graphs takeOfferView = (TakeOfferView) view; takeOfferView.initWithData(offer); - takeOfferPane = ((TakeOfferView) view).getRoot(); + takeOfferPane = takeOfferView.getRoot(); takeOfferTab = new Tab(getTakeOfferTabName()); takeOfferTab.setClosable(true); // close handler from close on take offer action diff --git a/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/MutableOfferDataModel.java b/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/MutableOfferDataModel.java index 3321e647076..f5fdba99dc4 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/MutableOfferDataModel.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/MutableOfferDataModel.java @@ -781,6 +781,12 @@ boolean isBsqForFeeAvailable() { return offerUtil.isBsqForMakerFeeAvailable(amount.get()); } + boolean isAttemptToBuyBsq() { + // When you buy an asset you actually sell BTC. + // This is why an offer to buy BSQ is actually an offer to sell BTC for BSQ. + return !isBuyOffer() && getTradeCurrency().getCode().equals("BSQ"); + } + boolean canPlaceOffer() { return GUIUtil.isBootstrappedOrShowPopup(p2PService) && GUIUtil.canCreateOrTakeOfferOrShowPopup(user, navigation, tradeCurrency); diff --git a/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/MutableOfferView.java b/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/MutableOfferView.java index 07a86f35e44..af7581701aa 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/MutableOfferView.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/MutableOfferView.java @@ -83,7 +83,6 @@ import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.AnchorPane; -import javafx.scene.layout.ColumnConstraints; import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; @@ -122,6 +121,7 @@ import org.jetbrains.annotations.NotNull; import static bisq.core.payment.payload.PaymentMethod.HAL_CASH_ID; +import static bisq.desktop.main.offer.bisq_v1.OfferViewUtil.addPayInfoEntry; import static bisq.desktop.util.FormBuilder.*; import static javafx.beans.binding.Bindings.createStringBinding; @@ -156,7 +156,7 @@ public abstract class MutableOfferView> exten private VBox currencySelection, fixedPriceBox, percentagePriceBox, currencyTextFieldBox, triggerPriceVBox; private HBox fundingHBox, firstRowHBox, secondRowHBox, placeOfferBox, amountValueCurrencyBox, priceAsPercentageValueCurrencyBox, volumeValueCurrencyBox, priceValueCurrencyBox, - minAmountValueCurrencyBox, advancedOptionsBox, triggerPriceHBox; + minAmountValueCurrencyBox, advancedOptionsBox, triggerPriceHBox, buyBsqBox; private Subscription isWaitingForFundsSubscription, balanceSubscription; private ChangeListener amountFocusedListener, minAmountFocusedListener, volumeFocusedListener, @@ -270,6 +270,13 @@ protected void doActivate() { tradeFeeInBtcToggle.setManaged(false); tradeFeeInBsqToggle.setVisible(false); tradeFeeInBsqToggle.setManaged(false); + buyBsqBox.setVisible(false); + buyBsqBox.setManaged(false); + } + + if (!model.isShowBuyBsqHint()) { + buyBsqBox.setVisible(false); + buyBsqBox.setManaged(false); } Label popOverLabel = OfferViewUtil.createPopOverLabel(Res.get("createOffer.triggerPrice.tooltip")); @@ -336,7 +343,7 @@ public void initWithData(OfferDirection direction, TradeCurrency tradeCurrency, showInsufficientBsqFundsForBtcFeePaymentPopup(); } - // called form parent as the view does not get notified when the tab is closed + // called from parent as the view does not get notified when the tab is closed public void onClose() { // we use model.placeOfferCompleted to not react on close which was triggered by a successful placeOffer if (model.getDataModel().getBalance().get().isPositive() && !model.placeOfferCompleted.get()) { @@ -372,6 +379,16 @@ private void onPlaceOffer() { } private void showInsufficientBsqFundsForBtcFeePaymentPopup() { + String message = getMissingBsqForFeePaymentMessage(); + + if (message != null) + new Popup().warning(message) + .actionButtonTextWithGoTo("navigation.dao.wallet.receive") + .onAction(() -> navigation.navigateTo(MainView.class, DaoView.class, BsqWalletView.class, BsqReceiveView.class)) + .show(); + } + + private String getMissingBsqForFeePaymentMessage() { Coin makerFee = model.getDataModel().getMakerFee(false); String message = null; if (makerFee != null) { @@ -381,11 +398,7 @@ private void showInsufficientBsqFundsForBtcFeePaymentPopup() { } else if (model.getDataModel().getUsableBsqBalance().isZero()) message = Res.get("popup.warning.noBsqFundsForBtcFeePayment"); - if (message != null) - new Popup().warning(message) - .actionButtonTextWithGoTo("navigation.dao.wallet.receive") - .onAction(() -> navigation.navigateTo(MainView.class, DaoView.class, BsqWalletView.class, BsqReceiveView.class)) - .show(); + return message; } private void onShowPayFundsScreen() { @@ -400,6 +413,8 @@ private void onShowPayFundsScreen() { tradeFeeInBtcToggle.setMouseTransparent(true); tradeFeeInBsqToggle.setMouseTransparent(true); + buyBsqBox.setVisible(false); + buyBsqBox.setManaged(false); setDepositTitledGroupBg.setVisible(false); setDepositTitledGroupBg.setManaged(false); @@ -514,17 +529,7 @@ private void maybeShowFasterPaymentsWarning(PaymentAccount paymentAccount) { private void maybeShowAccountWarning(PaymentAccount paymentAccount, boolean isBuyer) { String msgKey = paymentAccount.getPreTradeMessage(isBuyer); - if (msgKey == null || paymentAccountWarningDisplayed.getOrDefault(msgKey, false)) { - return; - } - paymentAccountWarningDisplayed.put(msgKey, true); - UserThread.runAfter(() -> { - new Popup().information(Res.get(msgKey)) - .width(900) - .closeButtonText(Res.get("shared.iConfirm")) - .dontShowAgainId(msgKey) - .show(); - }, 500, TimeUnit.MILLISECONDS); + OfferViewUtil.showPaymentAccountWarning(msgKey, paymentAccountWarningDisplayed); } protected void onPaymentAccountsComboBoxSelected() { @@ -894,6 +899,10 @@ private void createListeners() { if (DevEnv.isDaoActivated()) { tradeFeeInBtcToggle.setVisible(newValue); tradeFeeInBsqToggle.setVisible(newValue); + if (model.isShowBuyBsqHint()) { + buyBsqBox.setVisible(newValue); + buyBsqBox.setManaged(newValue); + } } }; @@ -1007,15 +1016,7 @@ private void removeListeners() { /////////////////////////////////////////////////////////////////////////////////////////// private void addScrollPane() { - scrollPane = new ScrollPane(); - scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); - scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); - scrollPane.setFitToWidth(true); - scrollPane.setFitToHeight(true); - AnchorPane.setLeftAnchor(scrollPane, 0d); - AnchorPane.setTopAnchor(scrollPane, 0d); - AnchorPane.setRightAnchor(scrollPane, 0d); - AnchorPane.setBottomAnchor(scrollPane, 0d); + scrollPane = GUIUtil.createScrollPane(); root.getChildren().add(scrollPane); } @@ -1025,13 +1026,7 @@ private void addGridPane() { gridPane.setPadding(new Insets(30, 25, -1, 25)); gridPane.setHgap(5); gridPane.setVgap(5); - ColumnConstraints columnConstraints1 = new ColumnConstraints(); - columnConstraints1.setHalignment(HPos.RIGHT); - columnConstraints1.setHgrow(Priority.NEVER); - columnConstraints1.setMinWidth(200); - ColumnConstraints columnConstraints2 = new ColumnConstraints(); - columnConstraints2.setHgrow(Priority.ALWAYS); - gridPane.getColumnConstraints().addAll(columnConstraints1, columnConstraints2); + GUIUtil.setDefaultTwoColumnConstraintsForGridPane(gridPane); scrollPane.setContent(gridPane); } @@ -1105,12 +1100,21 @@ private void addOptionsGroup() { advancedOptionsBox.setSpacing(40); GridPane.setRowIndex(advancedOptionsBox, gridRow); + GridPane.setColumnSpan(advancedOptionsBox, GridPane.REMAINING); GridPane.setColumnIndex(advancedOptionsBox, 0); GridPane.setHalignment(advancedOptionsBox, HPos.LEFT); GridPane.setMargin(advancedOptionsBox, new Insets(Layout.COMPACT_FIRST_ROW_AND_GROUP_DISTANCE, 0, 0, 0)); gridPane.getChildren().add(advancedOptionsBox); - advancedOptionsBox.getChildren().addAll(getBuyerSecurityDepositBox(), getTradeFeeFieldsBox()); + Tuple2 buyBsqButtonBox = OfferViewUtil.createBuyBsqButtonBox( + navigation, preferences); + buyBsqBox = buyBsqButtonBox.second; + buyBsqBox.setManaged(false); + buyBsqBox.setVisible(false); + + VBox tradeFeeFieldsBox = getTradeFeeFieldsBox(); + tradeFeeFieldsBox.setMinWidth(240); + advancedOptionsBox.getChildren().addAll(getBuyerSecurityDepositBox(), tradeFeeFieldsBox, buyBsqBox); Tuple2 tuple = add2ButtonsAfterGroup(gridPane, ++gridRow, Res.get("shared.nextStep"), Res.get("shared.cancel")); @@ -1152,15 +1156,7 @@ private void showFeeOption() { boolean isPreferredFeeCurrencyBtc = model.getDataModel().isPreferredFeeCurrencyBtc(); boolean isBsqForFeeAvailable = model.getDataModel().isBsqForFeeAvailable(); if (!isPreferredFeeCurrencyBtc && !isBsqForFeeAvailable) { - Coin makerFee = model.getDataModel().getMakerFee(false); - String missingBsq = null; - if (makerFee != null) { - missingBsq = Res.get("popup.warning.insufficientBsqFundsForBtcFeePayment", - bsqFormatter.formatCoinWithCode(makerFee.subtract(model.getDataModel().getUsableBsqBalance()))); - - } else if (model.getDataModel().getUsableBsqBalance().isZero()) { - missingBsq = Res.get("popup.warning.noBsqFundsForBtcFeePayment"); - } + String missingBsq = getMissingBsqForFeePaymentMessage(); if (missingBsq != null) { new Popup().warning(missingBsq) @@ -1542,8 +1538,9 @@ private GridPane createInfoPopover() { infoGridPane.setPadding(new Insets(10, 10, 10, 10)); int i = 0; - if (model.isSellOffer()) - addPayInfoEntry(infoGridPane, i++, Res.getWithCol("shared.tradeAmount"), model.tradeAmount.get()); + if (model.isSellOffer()) { + addPayInfoEntry(infoGridPane, i++, Res.getWithCol("shared.tradeAmount"), model.getTradeAmount()); + } addPayInfoEntry(infoGridPane, i++, Res.getWithCol("shared.yourSecurityDeposit"), model.getSecurityDepositInfo()); addPayInfoEntry(infoGridPane, i++, Res.getWithCol("createOffer.fundsBox.offerFee"), model.getTradeFee()); @@ -1553,19 +1550,8 @@ private GridPane createInfoPopover() { separator.getStyleClass().add("offer-separator"); GridPane.setConstraints(separator, 1, i++); infoGridPane.getChildren().add(separator); - addPayInfoEntry(infoGridPane, i, Res.getWithCol("shared.total"), model.getTotalToPayInfo()); + addPayInfoEntry(infoGridPane, i, Res.getWithCol("shared.total"), + model.getTotalToPayInfo()); return infoGridPane; } - - private void addPayInfoEntry(GridPane infoGridPane, int row, String labelText, String value) { - Label label = new AutoTooltipLabel(labelText); - TextField textField = new TextField(value); - textField.setMinWidth(500); - textField.setEditable(false); - textField.setFocusTraversable(false); - textField.setId("payment-info"); - GridPane.setConstraints(label, 0, row, 1, 1, HPos.RIGHT, VPos.CENTER); - GridPane.setConstraints(textField, 1, row); - infoGridPane.getChildren().addAll(label, textField); - } } diff --git a/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/MutableOfferViewModel.java b/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/MutableOfferViewModel.java index 344966a0165..3ab607ca958 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/MutableOfferViewModel.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/MutableOfferViewModel.java @@ -678,11 +678,10 @@ void onShowPayFundsScreen(Runnable actionHandler) { updateSpinnerInfo(); } - boolean fundFromSavingsWallet() { + void fundFromSavingsWallet() { dataModel.fundFromSavingsWallet(); if (dataModel.getIsBtcWalletFunded().get()) { updateButtonDisableState(); - return true; } else { new Popup().warning(Res.get("shared.notEnoughFunds", btcFormatter.formatCoinWithCode(dataModel.totalToPayAsCoinProperty().get()), @@ -690,7 +689,6 @@ boolean fundFromSavingsWallet() { .actionButtonTextWithGoTo("navigation.funds.depositFunds") .onAction(() -> navigation.navigateTo(MainView.class, FundsView.class, DepositView.class)) .show(); - return false; } } @@ -1355,4 +1353,8 @@ private void updateMarketPriceToManual() { } } } + + public boolean isShowBuyBsqHint() { + return !dataModel.isBsqForFeeAvailable() && !dataModel.isAttemptToBuyBsq(); + } } diff --git a/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/OfferViewUtil.java b/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/OfferViewUtil.java index f5aff0937d7..712a8fdd20b 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/OfferViewUtil.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/OfferViewUtil.java @@ -17,12 +17,37 @@ package bisq.desktop.main.offer.bisq_v1; +import bisq.desktop.Navigation; +import bisq.desktop.components.AutoTooltipButton; +import bisq.desktop.components.AutoTooltipLabel; +import bisq.desktop.components.HyperlinkWithIcon; +import bisq.desktop.main.MainView; +import bisq.desktop.main.offer.SellOfferView; +import bisq.desktop.main.offer.offerbook.OfferBookView; +import bisq.desktop.main.overlays.popups.Popup; + +import bisq.core.locale.Res; +import bisq.core.user.Preferences; + +import bisq.common.UserThread; +import bisq.common.util.Tuple2; + import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.HBox; +import javafx.geometry.HPos; import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.geometry.VPos; + +import java.util.HashMap; +import java.util.concurrent.TimeUnit; // Shared utils for Views public class OfferViewUtil { + public static Label createPopOverLabel(String text) { final Label label = new Label(text); label.setPrefWidth(300); @@ -31,4 +56,64 @@ public static Label createPopOverLabel(String text) { label.setPadding(new Insets(10)); return label; } + + public static void showPaymentAccountWarning(String msgKey, + HashMap paymentAccountWarningDisplayed) { + if (msgKey == null || paymentAccountWarningDisplayed.getOrDefault(msgKey, false)) { + return; + } + paymentAccountWarningDisplayed.put(msgKey, true); + UserThread.runAfter(() -> { + new Popup().information(Res.get(msgKey)) + .width(900) + .closeButtonText(Res.get("shared.iConfirm")) + .dontShowAgainId(msgKey) + .show(); + }, 500, TimeUnit.MILLISECONDS); + } + + public static void addPayInfoEntry(GridPane infoGridPane, int row, String labelText, String value) { + Label label = new AutoTooltipLabel(labelText); + TextField textField = new TextField(value); + textField.setMinWidth(500); + textField.setEditable(false); + textField.setFocusTraversable(false); + textField.setId("payment-info"); + GridPane.setConstraints(label, 0, row, 1, 1, HPos.RIGHT, VPos.CENTER); + GridPane.setConstraints(textField, 1, row); + infoGridPane.getChildren().addAll(label, textField); + } + + public static Tuple2 createBuyBsqButtonBox(Navigation navigation, + Preferences preferences) { + String buyBsqText = Res.get("shared.buyCurrency", "BSQ"); + var buyBsqButton = new AutoTooltipButton(buyBsqText); + buyBsqButton.getStyleClass().add("action-button"); + buyBsqButton.getStyleClass().add("tiny-button"); + buyBsqButton.setMinWidth(60); + buyBsqButton.setOnAction(e -> openBuyBsqOfferBook(navigation, preferences) + ); + + var info = new AutoTooltipLabel("BSQ is colored BTC that helps fund Bisq developers."); + var learnMore = new HyperlinkWithIcon("Learn More"); + learnMore.setOnAction(e -> new Popup().headLine(buyBsqText) + .information(Res.get("createOffer.buyBsq.popupMessage")) + .actionButtonText(buyBsqText) + .buttonAlignment(HPos.CENTER) + .onAction(() -> openBuyBsqOfferBook(navigation, preferences)).show()); + learnMore.setMinWidth(100); + + HBox buyBsqBox = new HBox(buyBsqButton, info, learnMore); + buyBsqBox.setAlignment(Pos.BOTTOM_LEFT); + buyBsqBox.setSpacing(10); + buyBsqBox.setPadding(new Insets(0, 0, 4, -20)); + + return new Tuple2<>(buyBsqButton, buyBsqBox); + } + + private static void openBuyBsqOfferBook(Navigation navigation, Preferences preferences) { + preferences.setSellScreenCurrencyCode("BSQ"); + navigation.navigateTo( + MainView.class, SellOfferView.class, OfferBookView.class); + } } diff --git a/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/takeoffer/TakeOfferDataModel.java b/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/takeoffer/TakeOfferDataModel.java index c5914b0869b..26171216a1b 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/takeoffer/TakeOfferDataModel.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/takeoffer/TakeOfferDataModel.java @@ -712,4 +712,10 @@ boolean isTakerFeeValid() { public boolean isBsqForFeeAvailable() { return offerUtil.isBsqForTakerFeeAvailable(amount.get()); } + + public boolean isAttemptToBuyBsq() { + // When you buy an asset you actually sell BTC. + // This is why an offer to buy BSQ is actually an offer to sell BTC for BSQ. + return !isBuyOffer() && getOffer().getCurrencyCode().equals("BSQ"); + } } diff --git a/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/takeoffer/TakeOfferView.java b/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/takeoffer/TakeOfferView.java index 3eb24820233..21a08d06e35 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/takeoffer/TakeOfferView.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/takeoffer/TakeOfferView.java @@ -90,7 +90,6 @@ import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.AnchorPane; -import javafx.scene.layout.ColumnConstraints; import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; @@ -118,6 +117,7 @@ import org.jetbrains.annotations.NotNull; +import static bisq.desktop.main.offer.bisq_v1.OfferViewUtil.addPayInfoEntry; import static bisq.desktop.util.FormBuilder.*; import static javafx.beans.binding.Bindings.createStringBinding; @@ -135,7 +135,7 @@ public class TakeOfferView extends ActivatableViewAndModel paymentAccountsComboBox; private Label amountDescriptionLabel, paymentMethodLabel, @@ -247,6 +247,10 @@ protected void initialize() { if (DevEnv.isDaoActivated()) { tradeFeeInBtcToggle.setVisible(newValue); tradeFeeInBsqToggle.setVisible(newValue); + if (model.isShowBuyBsqHint()) { + buyBsqBox.setVisible(newValue); + buyBsqBox.setManaged(newValue); + } } }; @@ -330,6 +334,13 @@ protected void activate() { tradeFeeInBtcToggle.setManaged(false); tradeFeeInBsqToggle.setVisible(false); tradeFeeInBsqToggle.setManaged(false); + buyBsqBox.setVisible(false); + buyBsqBox.setManaged(false); + } + + if (!model.isShowBuyBsqHint()) { + buyBsqBox.setVisible(false); + buyBsqBox.setManaged(false); } } @@ -470,6 +481,8 @@ private void onShowPayFundsScreen() { tradeFeeInBtcToggle.setMouseTransparent(true); tradeFeeInBsqToggle.setMouseTransparent(true); + buyBsqBox.setVisible(false); + buyBsqBox.setManaged(false); int delay = 500; int diff = 100; @@ -672,7 +685,7 @@ private void addSubscriptions() { offerDetailsWindow.hide(); UserThread.runAfter(() -> new Popup().warning(newValue + "\n\n" + - Res.get("takeOffer.alreadyPaidInFunds")) + Res.get("takeOffer.alreadyPaidInFunds")) .actionButtonTextWithGoTo("navigation.funds.availableForWithdrawal") .onAction(() -> { errorPopupDisplayed.set(true); @@ -787,15 +800,7 @@ private void removeListeners() { /////////////////////////////////////////////////////////////////////////////////////////// private void addScrollPane() { - scrollPane = new ScrollPane(); - scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); - scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); - scrollPane.setFitToWidth(true); - scrollPane.setFitToHeight(true); - AnchorPane.setLeftAnchor(scrollPane, 0d); - AnchorPane.setTopAnchor(scrollPane, 0d); - AnchorPane.setRightAnchor(scrollPane, 0d); - AnchorPane.setBottomAnchor(scrollPane, 0d); + scrollPane = GUIUtil.createScrollPane(); root.getChildren().add(scrollPane); } @@ -805,13 +810,7 @@ private void addGridPane() { gridPane.setPadding(new Insets(15, 15, -1, 15)); gridPane.setHgap(5); gridPane.setVgap(5); - ColumnConstraints columnConstraints1 = new ColumnConstraints(); - columnConstraints1.setHalignment(HPos.RIGHT); - columnConstraints1.setHgrow(Priority.NEVER); - columnConstraints1.setMinWidth(200); - ColumnConstraints columnConstraints2 = new ColumnConstraints(); - columnConstraints2.setHgrow(Priority.ALWAYS); - gridPane.getColumnConstraints().addAll(columnConstraints1, columnConstraints2); + GUIUtil.setDefaultTwoColumnConstraintsForGridPane(gridPane); scrollPane.setContent(gridPane); } @@ -879,12 +878,21 @@ private void addOptionsGroup() { advancedOptionsBox.setSpacing(40); GridPane.setRowIndex(advancedOptionsBox, gridRow); + GridPane.setColumnSpan(advancedOptionsBox, GridPane.REMAINING); GridPane.setColumnIndex(advancedOptionsBox, 0); GridPane.setHalignment(advancedOptionsBox, HPos.LEFT); GridPane.setMargin(advancedOptionsBox, new Insets(Layout.COMPACT_FIRST_ROW_AND_GROUP_DISTANCE, 0, 0, 0)); gridPane.getChildren().add(advancedOptionsBox); - advancedOptionsBox.getChildren().addAll(getTradeFeeFieldsBox()); + Tuple2 buyBsqButtonBox = OfferViewUtil.createBuyBsqButtonBox( + navigation, model.dataModel.preferences); + buyBsqBox = buyBsqButtonBox.second; + buyBsqBox.setManaged(false); + buyBsqBox.setVisible(false); + + VBox tradeFeeFieldsBox = getTradeFeeFieldsBox(); + tradeFeeFieldsBox.setMinWidth(240); + advancedOptionsBox.getChildren().addAll(tradeFeeFieldsBox, buyBsqBox); } private void addButtons() { @@ -1279,17 +1287,7 @@ private void maybeShowFasterPaymentsWarning(PaymentAccount paymentAccount) { private void maybeShowAccountWarning(PaymentAccount paymentAccount, boolean isBuyer) { String msgKey = paymentAccount.getPreTradeMessage(!isBuyer); - if (msgKey == null || paymentAccountWarningDisplayed.getOrDefault(msgKey, false)) { - return; - } - paymentAccountWarningDisplayed.put(msgKey, true); - UserThread.runAfter(() -> { - new Popup().information(Res.get(msgKey)) - .width(900) - .closeButtonText(Res.get("shared.iConfirm")) - .dontShowAgainId(msgKey) - .show(); - }, 500, TimeUnit.MILLISECONDS); + OfferViewUtil.showPaymentAccountWarning(msgKey, paymentAccountWarningDisplayed); } private void maybeShowCashByMailWarning(PaymentAccount paymentAccount, Offer offer) { @@ -1329,8 +1327,9 @@ private GridPane createInfoPopover() { infoGridPane.setPadding(new Insets(10, 10, 10, 10)); int i = 0; - if (model.isSeller()) + if (model.isSeller()) { addPayInfoEntry(infoGridPane, i++, Res.get("takeOffer.fundsBox.tradeAmount"), model.getTradeAmount()); + } addPayInfoEntry(infoGridPane, i++, Res.getWithCol("shared.yourSecurityDeposit"), model.getSecurityDepositInfo()); addPayInfoEntry(infoGridPane, i++, Res.get("takeOffer.fundsBox.offerFee"), model.getTradeFee()); @@ -1345,17 +1344,5 @@ private GridPane createInfoPopover() { return infoGridPane; } - - private void addPayInfoEntry(GridPane infoGridPane, int row, String labelText, String value) { - Label label = new AutoTooltipLabel(labelText); - TextField textField = new TextField(value); - textField.setMinWidth(500); - textField.setEditable(false); - textField.setFocusTraversable(false); - textField.setId("payment-info"); - GridPane.setConstraints(label, 0, row, 1, 1, HPos.RIGHT, VPos.CENTER); - GridPane.setConstraints(textField, 1, row); - infoGridPane.getChildren().addAll(label, textField); - } } diff --git a/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/takeoffer/TakeOfferViewModel.java b/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/takeoffer/TakeOfferViewModel.java index 1376b9baec0..5d8c180d351 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/takeoffer/TakeOfferViewModel.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/bisq_v1/takeoffer/TakeOfferViewModel.java @@ -800,4 +800,8 @@ String getPercentagePriceDescription() { Res.get("shared.aboveInPercent"); } } + + public boolean isShowBuyBsqHint() { + return !dataModel.isBsqForFeeAvailable() && !dataModel.isAttemptToBuyBsq(); + } } diff --git a/desktop/src/main/java/bisq/desktop/main/offer/offerbook/OfferBookView.java b/desktop/src/main/java/bisq/desktop/main/offer/offerbook/OfferBookView.java index 5c60d5f9b7d..4f571c2bc13 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/offerbook/OfferBookView.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/offerbook/OfferBookView.java @@ -33,6 +33,7 @@ import bisq.desktop.components.TitledGroupBg; import bisq.desktop.main.MainView; import bisq.desktop.main.account.AccountView; +import bisq.desktop.main.account.content.altcoinaccounts.AltCoinAccountsView; import bisq.desktop.main.account.content.fiataccounts.FiatAccountsView; import bisq.desktop.main.funds.FundsView; import bisq.desktop.main.funds.withdrawal.WithdrawalView; @@ -91,6 +92,7 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import javafx.scene.text.TextAlignment; @@ -135,17 +137,22 @@ public class OfferBookView extends ActivatableViewAndModel paymentMethodComboBox; private AutoTooltipButton createOfferButton; private AutoTooltipSlideToggleButton matchingOffersToggle; - private AutoTooltipTableColumn amountColumn, volumeColumn, marketColumn, - priceColumn, paymentMethodColumn, depositColumn, signingStateColumn, avatarColumn; + private AutoTooltipTableColumn amountColumn; + private AutoTooltipTableColumn volumeColumn; + private AutoTooltipTableColumn marketColumn; + private AutoTooltipTableColumn priceColumn; + private AutoTooltipTableColumn depositColumn; + private AutoTooltipTableColumn signingStateColumn; + private AutoTooltipTableColumn avatarColumn; private TableView tableView; - private OfferView.OfferActionHandler offerActionHandler; private int gridRow = 0; private Label nrOfOffersLabel; private ListChangeListener offerListListener; private ChangeListener priceFeedUpdateCounterListener; private Subscription currencySelectionSubscriber; private static final int SHOW_ALL = 0; + private Label disabledCreateOfferButtonTooltip; /////////////////////////////////////////////////////////////////////////////////////////// // Constructor, lifecycle @@ -200,13 +207,23 @@ public void initialize() { matchingOffersToggle.setText(Res.get("offerbook.matchingOffers")); HBox.setMargin(matchingOffersToggle, new Insets(7, 0, -9, -15)); - createOfferButton = new AutoTooltipButton(); createOfferButton.setMinHeight(40); createOfferButton.setGraphicTextGap(10); + disabledCreateOfferButtonTooltip = new Label(""); + disabledCreateOfferButtonTooltip.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE); + disabledCreateOfferButtonTooltip.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE); + disabledCreateOfferButtonTooltip.prefWidthProperty().bind(createOfferButton.widthProperty()); + disabledCreateOfferButtonTooltip.prefHeightProperty().bind(createOfferButton.heightProperty()); + disabledCreateOfferButtonTooltip.setTooltip(new Tooltip(Res.get("offerbook.createOfferDisabled.tooltip"))); + disabledCreateOfferButtonTooltip.setManaged(false); + disabledCreateOfferButtonTooltip.setVisible(false); + + var createOfferButtonStack = new StackPane(createOfferButton, disabledCreateOfferButtonTooltip); + offerToolsBox.getChildren().addAll(currencyBoxTuple.first, paymentBoxTuple.first, - matchingOffersToggle, getSpacer(), createOfferButton); + matchingOffersToggle, getSpacer(), createOfferButtonStack); GridPane.setHgrow(offerToolsBox, Priority.ALWAYS); GridPane.setRowIndex(offerToolsBox, gridRow); @@ -231,7 +248,7 @@ public void initialize() { tableView.getColumns().add(amountColumn); volumeColumn = getVolumeColumn(); tableView.getColumns().add(volumeColumn); - paymentMethodColumn = getPaymentMethodColumn(); + AutoTooltipTableColumn paymentMethodColumn = getPaymentMethodColumn(); tableView.getColumns().add(paymentMethodColumn); depositColumn = getDepositColumn(); tableView.getColumns().add(depositColumn); @@ -538,6 +555,16 @@ private PaymentMethod specialShowAllItem() { public void enableCreateOfferButton() { createOfferButton.setDisable(false); + disabledCreateOfferButtonTooltip.setManaged(false); + disabledCreateOfferButtonTooltip.setVisible(false); + } + + private void disableCreateOfferButton() { + createOfferButton.setDisable(true); + disabledCreateOfferButtonTooltip.setManaged(true); + disabledCreateOfferButtonTooltip.setVisible(true); + + model.onCreateOffer(); } public void setDirection(OfferDirection direction) { @@ -581,11 +608,16 @@ private void setDirectionTitles() { } public void setOfferActionHandler(OfferView.OfferActionHandler offerActionHandler) { - this.offerActionHandler = offerActionHandler; + model.setOfferActionHandler(offerActionHandler); } public void onTabSelected(boolean isSelected) { model.onTabSelected(isSelected); + + if (isSelected) { + updateCurrencyComboBoxFromModel(); + root.requestFocus(); + } } /////////////////////////////////////////////////////////////////////////////////////////// @@ -594,16 +626,11 @@ public void onTabSelected(boolean isSelected) { private void onCreateOffer() { if (model.canCreateOrTakeOffer()) { - PaymentMethod selectedPaymentMethod = model.selectedPaymentMethod; - TradeCurrency selectedTradeCurrency = model.getSelectedTradeCurrency(); if (!model.hasPaymentAccountForCurrency()) { new Popup().headLine(Res.get("offerbook.warning.noTradingAccountForCurrency.headline")) .instruction(Res.get("offerbook.warning.noTradingAccountForCurrency.msg")) .actionButtonText(Res.get("offerbook.yesCreateOffer")) - .onAction(() -> { - createOfferButton.setDisable(true); - offerActionHandler.onCreateOffer(selectedTradeCurrency, selectedPaymentMethod); - }) + .onAction(this::disableCreateOfferButton) .secondaryActionButtonText(Res.get("offerbook.setupNewAccount")) .onSecondaryAction(() -> { navigation.setReturnPath(navigation.getCurrentPath()); @@ -614,24 +641,18 @@ private void onCreateOffer() { return; } - createOfferButton.setDisable(true); - offerActionHandler.onCreateOffer(selectedTradeCurrency, selectedPaymentMethod); + disableCreateOfferButton(); } } private void onShowInfo(Offer offer, OfferFilterService.Result result) { switch (result) { - case VALID: - break; case API_DISABLED: DevEnv.logErrorAndThrowIfDevMode("We are in desktop and in the taker position " + "viewing offers, so it cannot be that we got that result as we are not an API user."); break; case HAS_NO_PAYMENT_ACCOUNT_VALID_FOR_OFFER: - openPopupForMissingAccountSetup(Res.get("offerbook.warning.noMatchingAccount.headline"), - Res.get("offerbook.warning.noMatchingAccount.msg"), - FiatAccountsView.class, - "navigation.account"); + openPopupForMissingAccountSetup(offer); break; case HAS_NOT_SAME_PROTOCOL_VERSION: new Popup().warning(Res.get("offerbook.warning.wrongTradeProtocol")).show(); @@ -675,6 +696,7 @@ private void onShowInfo(Offer offer, OfferFilterService.Result result) { case HIDE_BSQ_SWAPS_DUE_DAO_DEACTIVATED: new Popup().warning(Res.get("offerbook.warning.hideBsqSwapsDueDaoDeactivated")).show(); break; + case VALID: default: break; } @@ -686,10 +708,10 @@ private void onTakeOffer(Offer offer) { offer.getPaymentMethod().getId().equals(PaymentMethod.CASH_DEPOSIT.getId())) { new Popup().confirmation(Res.get("popup.info.cashDepositInfo", offer.getBankId())) .actionButtonText(Res.get("popup.info.cashDepositInfo.confirm")) - .onAction(() -> offerActionHandler.onTakeOffer(offer)) + .onAction(() -> model.onTakeOffer(offer)) .show(); } else { - offerActionHandler.onTakeOffer(offer); + model.onTakeOffer(offer); } } } @@ -728,14 +750,37 @@ private void doRemoveOffer(Offer offer) { }); } - private void openPopupForMissingAccountSetup(String headLine, String message, Class target, String targetAsString) { - new Popup().headLine(headLine) - .instruction(message) - .actionButtonTextWithGoTo(targetAsString) - .onAction(() -> { - navigation.setReturnPath(navigation.getCurrentPath()); - navigation.navigateTo(MainView.class, AccountView.class, target); - }).show(); + private void openPopupForMissingAccountSetup(Offer offer) { + String headline = Res.get("offerbook.warning.noMatchingAccount.headline"); + + if (offer.getCurrencyCode().equals("BSQ")) { + new Popup().headLine(headline) + .instruction(Res.get("offerbook.warning.noMatchingBsqAccount.msg")) + .actionButtonText(Res.get("offerbook.takeOffer.createAccount")) + .onAction(() -> { + var bsqAccount = model.createBsqAccount(offer); + var message = Res.get("offerbook.info.accountCreated.message", bsqAccount.getAccountName()); + if (model.isInstantPaymentMethod(offer)) { + message += Res.get("offerbook.info.accountCreated.tradeInstant"); + } + message += Res.get("offerbook.info.accountCreated.takeOffer"); + new Popup().headLine(Res.get("offerbook.info.accountCreated.headline")) + .information(message) + .onClose(() -> model.onTakeOffer(offer)) + .show(); + }).show(); + } else { + + var accountViewClass = CurrencyUtil.isFiatCurrency(offer.getCurrencyCode()) ? FiatAccountsView.class : AltCoinAccountsView.class; + + new Popup().headLine(headline) + .instruction(Res.get("offerbook.warning.noMatchingAccount.msg")) + .actionButtonTextWithGoTo("navigation.account") + .onAction(() -> { + navigation.setReturnPath(navigation.getCurrentPath()); + navigation.navigateTo(MainView.class, AccountView.class, accountViewClass); + }).show(); + } } /////////////////////////////////////////////////////////////////////////////////////////// @@ -1068,13 +1113,11 @@ public void updateItem(final OfferBookListItem item, boolean empty) { tableRow.setOnMousePressed(null); } else { button.setDefaultButton(false); - if (!myOffer) { - tableRow.setOnMousePressed(e -> { - // ugly hack to get the icon clickable when deactivated - if (!(e.getTarget() instanceof ImageView || e.getTarget() instanceof Canvas)) - onShowInfo(offer, canTakeOfferResult); - }); - } + tableRow.setOnMousePressed(e -> { + // ugly hack to get the icon clickable when deactivated + if (!(e.getTarget() instanceof ImageView || e.getTarget() instanceof Canvas)) + onShowInfo(offer, canTakeOfferResult); + }); } } 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 1e9a4d226b4..fa747c27d11 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 @@ -20,13 +20,16 @@ import bisq.desktop.Navigation; import bisq.desktop.common.model.ActivatableViewModel; import bisq.desktop.main.MainView; +import bisq.desktop.main.offer.OfferView; import bisq.desktop.main.settings.SettingsView; import bisq.desktop.main.settings.preferences.PreferencesView; import bisq.desktop.util.DisplayUtils; import bisq.desktop.util.GUIUtil; import bisq.core.account.witness.AccountAgeWitnessService; +import bisq.core.api.CoreApi; import bisq.core.btc.setup.WalletsSetup; +import bisq.core.btc.wallet.BsqWalletService; import bisq.core.locale.BankUtil; import bisq.core.locale.CountryUtil; import bisq.core.locale.CryptoCurrency; @@ -111,6 +114,8 @@ class OfferBookViewModel extends ActivatableViewModel { private final BsqFormatter bsqFormatter; private final FilteredList filteredItems; + private final BsqWalletService bsqWalletService; + private final CoreApi coreApi; private final SortedList sortedItems; private final ListChangeListener tradeCurrencyListChangeListener; private final ListChangeListener filterItemsListener; @@ -121,6 +126,8 @@ class OfferBookViewModel extends ActivatableViewModel { final StringProperty tradeCurrencyCode = new SimpleStringProperty(); + private OfferView.OfferActionHandler offerActionHandler; + // If id is empty string we ignore filter (display all methods) PaymentMethod selectedPaymentMethod = getShowAllEntryForPaymentMethod(); @@ -154,7 +161,9 @@ public OfferBookViewModel(User user, PriceUtil priceUtil, OfferFilterService offerFilterService, @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter, - BsqFormatter bsqFormatter) { + BsqFormatter bsqFormatter, + BsqWalletService bsqWalletService, + CoreApi coreApi) { super(); this.openOfferManager = openOfferManager; @@ -173,6 +182,8 @@ public OfferBookViewModel(User user, this.bsqFormatter = bsqFormatter; this.filteredItems = new FilteredList<>(offerBook.getOfferBookListItems()); + this.bsqWalletService = bsqWalletService; + this.coreApi = coreApi; this.sortedItems = new SortedList<>(filteredItems); tradeCurrencyListChangeListener = c -> fillAllTradeCurrencies(); @@ -207,7 +218,7 @@ public OfferBookViewModel(User user, .filter(o -> o.getOffer().isUseMarketBasedPrice()) .max(Comparator.comparing(o -> new DecimalFormat("#0.00").format(o.getOffer().getMarketPriceMargin() * 100).length())); - highestMarketPriceMarginOffer.ifPresent(offerBookListItem -> maxPlacesForMarketPriceMargin.set(formatMarketPriceMargin(offerBookListItem.getOffer(), false).length())); + highestMarketPriceMarginOffer.ifPresent(offerBookListItem -> maxPlacesForMarketPriceMargin.set(formatMarketPriceMargin(offerBookListItem.getOffer()).length())); }; } @@ -215,16 +226,7 @@ public OfferBookViewModel(User user, protected void activate() { filteredItems.addListener(filterItemsListener); - String code = direction == OfferDirection.BUY ? preferences.getBuyScreenCurrencyCode() : preferences.getSellScreenCurrencyCode(); - if (code != null && !code.isEmpty() && !isShowAllEntry(code) && - CurrencyUtil.getTradeCurrency(code).isPresent()) { - showAllTradeCurrenciesProperty.set(false); - selectedTradeCurrency = CurrencyUtil.getTradeCurrency(code).get(); - } else { - showAllTradeCurrenciesProperty.set(true); - selectedTradeCurrency = GlobalSettings.getDefaultTradeCurrency(); - } - tradeCurrencyCode.set(selectedTradeCurrency.getCode()); + updateSelectedTradeCurrency(); if (user != null) { disableMatchToggle.set(user.getPaymentAccounts() == null || user.getPaymentAccounts().isEmpty()); @@ -258,6 +260,11 @@ void initWithDirection(OfferDirection direction) { void onTabSelected(boolean isSelected) { this.isTabSelected = isSelected; setMarketPriceFeedCurrency(); + + if (isTabSelected) { + updateSelectedTradeCurrency(); + filterOffers(); + } } /////////////////////////////////////////////////////////////////////////////////////////// @@ -413,16 +420,12 @@ public Optional getMarketBasedPrice(Offer offer) { return priceUtil.getMarketBasedPrice(offer, direction); } - String formatMarketPriceMargin(Offer offer, boolean decimalAligned) { + String formatMarketPriceMargin(Offer offer) { String postFix = ""; if (offer.isUseMarketBasedPrice()) { postFix = " (" + FormattingUtils.formatPercentagePrice(offer.getMarketPriceMargin()) + ")"; } - if (decimalAligned) { - postFix = FormattingUtils.fillUpPlacesWithEmptyStrings(postFix, maxPlacesForMarketPriceMargin.get()); - } - return postFix; } @@ -670,4 +673,43 @@ private TradeCurrency getEditEntryForCurrency() { PaymentMethod getShowAllEntryForPaymentMethod() { return PaymentMethod.getDummyPaymentMethod(GUIUtil.SHOW_ALL_FLAG); } + + public boolean isInstantPaymentMethod(Offer offer) { + return offer.getPaymentMethod().equals(PaymentMethod.BLOCK_CHAINS_INSTANT); + } + + public PaymentAccount createBsqAccount(Offer offer) { + var unusedBsqAddressAsString = bsqWalletService.getUnusedBsqAddressAsString(); + + return coreApi.createCryptoCurrencyPaymentAccount(DisplayUtils.createAssetsAccountName("BSQ", unusedBsqAddressAsString), + "BSQ", + unusedBsqAddressAsString, + isInstantPaymentMethod(offer), + false); + } + + public void setOfferActionHandler(OfferView.OfferActionHandler offerActionHandler) { + this.offerActionHandler = offerActionHandler; + } + + public void onCreateOffer() { + offerActionHandler.onCreateOffer(getSelectedTradeCurrency(), selectedPaymentMethod); + } + + public void onTakeOffer(Offer offer) { + offerActionHandler.onTakeOffer(offer); + } + + private void updateSelectedTradeCurrency() { + String code = direction == OfferDirection.BUY ? preferences.getBuyScreenCurrencyCode() : preferences.getSellScreenCurrencyCode(); + if (code != null && !code.isEmpty() && !isShowAllEntry(code) && + CurrencyUtil.getTradeCurrency(code).isPresent()) { + showAllTradeCurrenciesProperty.set(false); + selectedTradeCurrency = CurrencyUtil.getTradeCurrency(code).get(); + } else { + showAllTradeCurrenciesProperty.set(true); + selectedTradeCurrency = GlobalSettings.getDefaultTradeCurrency(); + } + tradeCurrencyCode.set(selectedTradeCurrency.getCode()); + } } 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 cb6715a5738..2d9c46e5b55 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 @@ -17,10 +17,15 @@ package bisq.desktop.main.portfolio.pendingtrades.steps.seller; +import bisq.desktop.components.AutoTooltipButton; import bisq.desktop.components.BusyAnimation; import bisq.desktop.components.InfoTextField; import bisq.desktop.components.TextFieldWithCopyIcon; import bisq.desktop.components.indicator.TxConfidenceIndicator; +import bisq.desktop.main.MainView; +import bisq.desktop.main.dao.DaoView; +import bisq.desktop.main.dao.wallet.BsqWalletView; +import bisq.desktop.main.dao.wallet.tx.BsqTxView; import bisq.desktop.main.overlays.popups.Popup; import bisq.desktop.main.portfolio.pendingtrades.PendingTradesViewModel; import bisq.desktop.main.portfolio.pendingtrades.steps.TradeStepView; @@ -82,6 +87,7 @@ public class SellerStep3View extends TradeStepView { private Button confirmButton; + private AutoTooltipButton showBsqWallet; private Label statusLabel; private BusyAnimation busyAnimation; private Subscription tradeStatePropertySubscription; @@ -296,11 +302,21 @@ protected void addContent() { Tuple4 tuple = addButtonBusyAnimationLabelAfterGroup(gridPane, ++gridRow, Res.get("portfolio.pending.step3_seller.confirmReceipt")); + HBox hBox = tuple.fourth; GridPane.setColumnSpan(tuple.fourth, 2); confirmButton = tuple.first; confirmButton.setOnAction(e -> onPaymentReceived()); busyAnimation = tuple.second; statusLabel = tuple.third; + + if (trade.getOffer().getCurrencyCode().equals("BSQ")) { + showBsqWallet = new AutoTooltipButton(Res.get("portfolio.pending.step3_seller.showBsqWallet")); + hBox.getChildren().add(1, showBsqWallet); + showBsqWallet.setOnAction(e -> { + model.getNavigation().navigateTo(MainView.class, DaoView.class, BsqWalletView.class, + BsqTxView.class); + }); + } } diff --git a/desktop/src/main/java/bisq/desktop/util/DisplayUtils.java b/desktop/src/main/java/bisq/desktop/util/DisplayUtils.java index e3ebb02d566..fb9674f9dd0 100644 --- a/desktop/src/main/java/bisq/desktop/util/DisplayUtils.java +++ b/desktop/src/main/java/bisq/desktop/util/DisplayUtils.java @@ -6,8 +6,9 @@ import bisq.core.monetary.Price; import bisq.core.monetary.Volume; import bisq.core.offer.Offer; -import bisq.core.offer.OfferDirection; import bisq.core.util.FormattingUtils; +import bisq.core.offer.OfferDirection; +import bisq.core.payment.PaymentAccount; import bisq.core.util.ParsingUtils; import bisq.core.util.VolumeUtil; import bisq.core.util.coin.CoinFormatter; @@ -251,4 +252,21 @@ public static boolean hasBtcValidDecimals(String input, CoinFormatter coinFormat public static Coin reduceTo4Decimals(Coin coin, CoinFormatter coinFormatter) { return ParsingUtils.parseToCoin(coinFormatter.formatCoin(coin), coinFormatter); } + + public static String createAccountName(String paymentMethodId, String name) { + name = name.trim(); + name = StringUtils.abbreviate(name, 9); + String method = Res.get(paymentMethodId); + return method.concat(": ").concat(name); + } + + public static String createAssetsAccountName(PaymentAccount paymentAccount, String address) { + String currency = paymentAccount.getSingleTradeCurrency() != null ? paymentAccount.getSingleTradeCurrency().getCode() : ""; + return createAssetsAccountName(currency, address); + } + + public static String createAssetsAccountName(String currency, String address) { + address = StringUtils.abbreviate(address, 9); + return currency.concat(": ").concat(address); + } } diff --git a/desktop/src/main/java/bisq/desktop/util/GUIUtil.java b/desktop/src/main/java/bisq/desktop/util/GUIUtil.java index 3698a13ab6b..efbb53ba4f3 100644 --- a/desktop/src/main/java/bisq/desktop/util/GUIUtil.java +++ b/desktop/src/main/java/bisq/desktop/util/GUIUtil.java @@ -108,13 +108,17 @@ import javafx.scene.control.ListCell; import javafx.scene.control.ListView; import javafx.scene.control.ScrollBar; +import javafx.scene.control.ScrollPane; import javafx.scene.control.TableView; import javafx.scene.control.TextArea; import javafx.scene.control.Tooltip; import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.ColumnConstraints; import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.geometry.HPos; import javafx.geometry.Orientation; import javafx.collections.FXCollections; @@ -1218,4 +1222,28 @@ public static String getProofResultAsString(@Nullable AssetTxProofResult result) return result.name(); } } + + public static ScrollPane createScrollPane() { + ScrollPane scrollPane = new ScrollPane(); + scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + scrollPane.setFitToWidth(true); + scrollPane.setFitToHeight(true); + AnchorPane.setLeftAnchor(scrollPane, 0d); + AnchorPane.setTopAnchor(scrollPane, 0d); + AnchorPane.setRightAnchor(scrollPane, 0d); + AnchorPane.setBottomAnchor(scrollPane, 0d); + return scrollPane; + } + + public static void setDefaultTwoColumnConstraintsForGridPane(GridPane gridPane) { + ColumnConstraints columnConstraints1 = new ColumnConstraints(); + columnConstraints1.setHalignment(HPos.RIGHT); + columnConstraints1.setHgrow(Priority.NEVER); + columnConstraints1.setMinWidth(200); + ColumnConstraints columnConstraints2 = new ColumnConstraints(); + columnConstraints2.setHgrow(Priority.ALWAYS); + gridPane.getColumnConstraints().addAll(columnConstraints1, columnConstraints2); + } + } diff --git a/desktop/src/test/java/bisq/desktop/main/offer/offerbook/OfferBookViewModelTest.java b/desktop/src/test/java/bisq/desktop/main/offer/offerbook/OfferBookViewModelTest.java index d8fd3ca11af..5e5e25cb8fa 100644 --- a/desktop/src/test/java/bisq/desktop/main/offer/offerbook/OfferBookViewModelTest.java +++ b/desktop/src/test/java/bisq/desktop/main/offer/offerbook/OfferBookViewModelTest.java @@ -239,7 +239,7 @@ public void testMaxCharactersForAmountWithNoOffers() { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); final OfferBookViewModel model = new OfferBookViewModel(null, null, offerBook, empty, null, null, null, - null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter()); + null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter(), null, null); assertEquals(0, model.maxPlacesForAmount.intValue()); } @@ -253,7 +253,7 @@ public void testMaxCharactersForAmount() { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); final OfferBookViewModel model = new OfferBookViewModel(null, openOfferManager, offerBook, empty, null, null, null, - null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter()); + null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter(), null, null); model.activate(); assertEquals(6, model.maxPlacesForAmount.intValue()); @@ -271,7 +271,7 @@ public void testMaxCharactersForAmountRange() { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); final OfferBookViewModel model = new OfferBookViewModel(null, openOfferManager, offerBook, empty, null, null, null, - null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter()); + null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter(), null, null); model.activate(); assertEquals(15, model.maxPlacesForAmount.intValue()); @@ -290,7 +290,7 @@ public void testMaxCharactersForVolumeWithNoOffers() { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); final OfferBookViewModel model = new OfferBookViewModel(null, null, offerBook, empty, null, null, null, - null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter()); + null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter(), null, null); assertEquals(0, model.maxPlacesForVolume.intValue()); } @@ -304,7 +304,7 @@ public void testMaxCharactersForVolume() { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); final OfferBookViewModel model = new OfferBookViewModel(null, openOfferManager, offerBook, empty, null, null, null, - null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter()); + null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter(), null, null); model.activate(); assertEquals(5, model.maxPlacesForVolume.intValue()); @@ -322,7 +322,7 @@ public void testMaxCharactersForVolumeRange() { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); final OfferBookViewModel model = new OfferBookViewModel(null, openOfferManager, offerBook, empty, null, null, null, - null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter()); + null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter(), null, null); model.activate(); assertEquals(9, model.maxPlacesForVolume.intValue()); @@ -341,7 +341,7 @@ public void testMaxCharactersForPriceWithNoOffers() { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); final OfferBookViewModel model = new OfferBookViewModel(null, null, offerBook, empty, null, null, null, - null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter()); + null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter(), null, null); assertEquals(0, model.maxPlacesForPrice.intValue()); } @@ -355,7 +355,7 @@ public void testMaxCharactersForPrice() { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); final OfferBookViewModel model = new OfferBookViewModel(null, openOfferManager, offerBook, empty, null, null, null, - null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter()); + null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter(), null, null); model.activate(); assertEquals(7, model.maxPlacesForPrice.intValue()); @@ -373,7 +373,7 @@ public void testMaxCharactersForPriceDistanceWithNoOffers() { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); final OfferBookViewModel model = new OfferBookViewModel(null, null, offerBook, empty, null, null, null, - null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter()); + null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter(), null, null); assertEquals(0, model.maxPlacesForMarketPriceMargin.intValue()); } @@ -408,7 +408,7 @@ public void testMaxCharactersForPriceDistance() { offerBookListItems.addAll(item1, item2); final OfferBookViewModel model = new OfferBookViewModel(null, openOfferManager, offerBook, empty, null, null, priceFeedService, - null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter()); + null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter(), null, null); model.activate(); assertEquals(8, model.maxPlacesForMarketPriceMargin.intValue()); //" (1.97%)" @@ -429,7 +429,7 @@ public void testGetPrice() { when(priceFeedService.getMarketPrice(anyString())).thenReturn(new MarketPrice("USD", 12684.0450, Instant.now().getEpochSecond(), true)); final OfferBookViewModel model = new OfferBookViewModel(null, openOfferManager, offerBook, empty, null, null, null, - null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter()); + null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter(), null, null); final OfferBookListItem item = make(btcBuyItem.but( with(useMarketBasedPrice, true),