Merge pull request #5055 from Jakub-CZ/button-buy-bsq

Add "Buy BSQ" button next to trade fee selector
This commit is contained in:
Christoph Atteneder 2021-11-08 11:13:52 +01:00 committed by GitHub
commit 00d7913bc6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 575 additions and 395 deletions

View file

@ -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.

View file

@ -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;

View file

@ -41,11 +41,15 @@ public class HyperlinkWithIcon extends Hyperlink {
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 class HyperlinkWithIcon extends Hyperlink {
setIcon(icon);
}
public HyperlinkWithIcon(String text, AwesomeIcon awesomeIcon) {
this(text, awesomeIcon, "1.231em");
}
public HyperlinkWithIcon(String text, GlyphIcons icon) {
this(text, icon, null);
}

View file

@ -34,8 +34,6 @@ import bisq.core.util.validation.InputValidator;
import bisq.common.util.Tuple2;
import org.apache.commons.lang3.StringUtils;
import javafx.scene.control.Label;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
@ -62,8 +60,13 @@ public class AdvancedCashForm extends PaymentMethodForm {
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 @@ public class AdvancedCashForm extends PaymentMethodForm {
@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

View file

@ -41,8 +41,6 @@ import bisq.core.util.validation.InputValidator;
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.geometry.Insets;
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 class AssetsForm extends PaymentMethodForm {
@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()));
}
}

View file

@ -34,8 +34,6 @@ import bisq.core.util.validation.InputValidator;
import bisq.common.util.Tuple2;
import org.apache.commons.lang3.StringUtils;
import javafx.scene.control.Label;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
@ -100,12 +98,7 @@ public class CapitualForm extends PaymentMethodForm {
@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

View file

@ -25,7 +25,6 @@ import bisq.desktop.util.validation.JapanBankAccountNameValidator;
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 javafx.util.StringConverter;
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<String> bankComboBox, bankAccountTypeComboBox;
private InputTextField bankAccountNumberInputTextField;
protected ComboBox<String> 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 class JapanBankTransferForm extends PaymentMethodForm
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 class JapanBankTransferForm extends PaymentMethodForm
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 class JapanBankTransferForm extends PaymentMethodForm
addLimitations(false);
addAccountNameTextFieldWithAutoFillToggleButton();
} // }}}
private void addBankInput() // {{{
{
}
private void addBankInput() {
gridRow++;
Tuple4<Label, TextField, Label, ComboBox<String>> tuple4 = addTopLabelTextFieldAutocompleteComboBox(gridPane, gridRow, JapanBankData.getString("bank.code"), JapanBankData.getString("bank.name"), 10);
@ -185,14 +172,13 @@ public class JapanBankTransferForm extends PaymentMethodForm
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<String>() {
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 class JapanBankTransferForm extends PaymentMethodForm
// 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 class JapanBankTransferForm extends PaymentMethodForm
// 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<InputTextField, InputTextField> tuple2 = addInputTextFieldInputTextField(gridPane, gridRow, JapanBankData.getString("branch.code"), JapanBankData.getString("branch.name"));
@ -259,14 +238,14 @@ public class JapanBankTransferForm extends PaymentMethodForm
japanBankAccount.setBankBranchName(newValue);
updateFromInputs();
});
} // }}}
private void addBankAccountInput() // {{{
{
}
private void addBankAccountInput() {
gridRow++;
Tuple2<InputTextField, InputTextField> 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 @@ public class JapanBankTransferForm extends PaymentMethodForm
japanBankAccount.setBankAccountName(newValue);
updateFromInputs();
});
} // }}}
private void addBankAccountTypeInput() // {{{
{
}
private void addBankAccountTypeInput() {
// account currency
gridRow++;
@ -299,13 +278,13 @@ public class JapanBankTransferForm extends PaymentMethodForm
ToggleGroup toggleGroup = new ToggleGroup();
Tuple3<Label, RadioButton, RadioButton> 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 @@ public class JapanBankTransferForm extends PaymentMethodForm
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:

View file

@ -37,8 +37,6 @@ import bisq.core.util.validation.InputValidator;
import bisq.common.util.Tuple2;
import org.apache.commons.lang3.StringUtils;
import javafx.scene.control.Label;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
@ -172,11 +170,7 @@ public class MoneyGramForm extends PaymentMethodForm {
@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

View file

@ -73,6 +73,7 @@ import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;
import static bisq.desktop.util.DisplayUtils.createAccountName;
import static bisq.desktop.util.FormBuilder.*;
@Slf4j
@ -287,10 +288,8 @@ public abstract class PaymentMethodForm {
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);
}
}

View file

@ -20,9 +20,7 @@ package bisq.desktop.main.account.content.altcoinaccounts;
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 javafx.collections.SetChangeListener;
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<PaymentAccount> paymentAccounts = FXCollections.observableArrayList();
private final SetChangeListener<PaymentAccount> setChangeListener;
private final String accountsFileName = "AltcoinPaymentAccounts";
@ -65,14 +61,12 @@ class AltCoinAccountsDataModel extends ActivatableDataModel {
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 @@ class AltCoinAccountsDataModel extends ActivatableDataModel {
public void onSaveNewAccount(PaymentAccount paymentAccount) {
TradeCurrency singleTradeCurrency = paymentAccount.getSingleTradeCurrency();
List<TradeCurrency> 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 @@ class AltCoinAccountsDataModel extends ActivatableDataModel {
public void exportAccounts(Stage stage) {
if (user.getPaymentAccounts() != null) {
ArrayList<PaymentAccount> accounts = new ArrayList<>(user.getPaymentAccounts().stream()
ArrayList<PaymentAccount> 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);
}
}

View file

@ -21,7 +21,6 @@ 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.CurrencyUtil;
import bisq.core.locale.FiatCurrency;
import bisq.core.locale.TradeCurrency;
@ -109,22 +108,14 @@ class FiatAccountsDataModel extends ActivatableDataModel {
TradeCurrency singleTradeCurrency = paymentAccount.getSingleTradeCurrency();
List<TradeCurrency> 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 @@ class FiatAccountsDataModel extends ActivatableDataModel {
public void exportAccounts(Stage stage) {
if (user.getPaymentAccounts() != null) {
ArrayList<PaymentAccount> accounts = new ArrayList<>(user.getPaymentAccounts().stream()
ArrayList<PaymentAccount> 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);
}
}

View file

@ -520,7 +520,7 @@ public class FiatAccountsView extends PaymentAccountsView<GridPane, FiatAccounts
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:

View file

@ -176,7 +176,9 @@ public abstract class OfferView extends ActivatableView<TabPane, Void> {
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 @@ public abstract class OfferView extends ActivatableView<TabPane, Void> {
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 @@ public abstract class OfferView extends ActivatableView<TabPane, Void> {
// 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

View file

@ -781,6 +781,12 @@ public abstract class MutableOfferDataModel extends OfferDataModel implements Bs
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);

View file

@ -83,7 +83,6 @@ import javafx.scene.control.Tooltip;
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 lombok.Setter;
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<M extends MutableOfferViewModel<?>> 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<Boolean> amountFocusedListener, minAmountFocusedListener, volumeFocusedListener,
@ -270,6 +270,13 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
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 abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
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 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
}
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 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
} 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 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
tradeFeeInBtcToggle.setMouseTransparent(true);
tradeFeeInBsqToggle.setMouseTransparent(true);
buyBsqBox.setVisible(false);
buyBsqBox.setManaged(false);
setDepositTitledGroupBg.setVisible(false);
setDepositTitledGroupBg.setManaged(false);
@ -514,17 +529,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
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 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
if (DevEnv.isDaoActivated()) {
tradeFeeInBtcToggle.setVisible(newValue);
tradeFeeInBsqToggle.setVisible(newValue);
if (model.isShowBuyBsqHint()) {
buyBsqBox.setVisible(newValue);
buyBsqBox.setManaged(newValue);
}
}
};
@ -1007,15 +1016,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
///////////////////////////////////////////////////////////////////////////////////////////
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 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
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 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
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<AutoTooltipButton, HBox> 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<Button, Button> tuple = add2ButtonsAfterGroup(gridPane, ++gridRow,
Res.get("shared.nextStep"), Res.get("shared.cancel"));
@ -1152,15 +1156,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
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 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
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 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
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);
}
}

View file

@ -678,11 +678,10 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
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 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
.actionButtonTextWithGoTo("navigation.funds.depositFunds")
.onAction(() -> navigation.navigateTo(MainView.class, FundsView.class, DepositView.class))
.show();
return false;
}
}
@ -1355,4 +1353,8 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
}
}
}
public boolean isShowBuyBsqHint() {
return !dataModel.isBsqForFeeAvailable() && !dataModel.isAttemptToBuyBsq();
}
}

View file

@ -17,12 +17,37 @@
package bisq.desktop.main.offer.bisq_v1;
import javafx.scene.control.Label;
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 class OfferViewUtil {
label.setPadding(new Insets(10));
return label;
}
public static void showPaymentAccountWarning(String msgKey,
HashMap<String, Boolean> 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<AutoTooltipButton, HBox> 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);
}
}

View file

@ -712,4 +712,10 @@ class TakeOfferDataModel extends OfferDataModel {
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");
}
}

View file

@ -90,7 +90,6 @@ import javafx.scene.control.Tooltip;
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 java.util.concurrent.TimeUnit;
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<AnchorPane, TakeOffer
private VBox priceAsPercentageInputBox, amountRangeBox;
private HBox fundingHBox, amountValueCurrencyBox, priceValueCurrencyBox, volumeValueCurrencyBox,
priceAsPercentageValueCurrencyBox, minAmountValueCurrencyBox, advancedOptionsBox,
takeOfferBox, buttonBox, firstRowHBox;
takeOfferBox, buttonBox, firstRowHBox, buyBsqBox;
private ComboBox<PaymentAccount> paymentAccountsComboBox;
private Label amountDescriptionLabel,
paymentMethodLabel,
@ -247,6 +247,10 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
if (DevEnv.isDaoActivated()) {
tradeFeeInBtcToggle.setVisible(newValue);
tradeFeeInBsqToggle.setVisible(newValue);
if (model.isShowBuyBsqHint()) {
buyBsqBox.setVisible(newValue);
buyBsqBox.setManaged(newValue);
}
}
};
@ -330,6 +334,13 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
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 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
tradeFeeInBtcToggle.setMouseTransparent(true);
tradeFeeInBsqToggle.setMouseTransparent(true);
buyBsqBox.setVisible(false);
buyBsqBox.setManaged(false);
int delay = 500;
int diff = 100;
@ -672,7 +685,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
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 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
///////////////////////////////////////////////////////////////////////////////////////////
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 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
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 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
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<AutoTooltipButton, HBox> 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 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
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 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
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 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
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);
}
}

View file

@ -800,4 +800,8 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
Res.get("shared.aboveInPercent");
}
}
public boolean isShowBuyBsqHint() {
return !dataModel.isBsqForFeeAvailable() && !dataModel.isAttemptToBuyBsq();
}
}

View file

@ -33,6 +33,7 @@ import bisq.desktop.components.PeerInfoIconTrading;
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.GridPane;
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<GridPane, OfferBookVi
private AutocompleteComboBox<PaymentMethod> paymentMethodComboBox;
private AutoTooltipButton createOfferButton;
private AutoTooltipSlideToggleButton matchingOffersToggle;
private AutoTooltipTableColumn<OfferBookListItem, OfferBookListItem> amountColumn, volumeColumn, marketColumn,
priceColumn, paymentMethodColumn, depositColumn, signingStateColumn, avatarColumn;
private AutoTooltipTableColumn<OfferBookListItem, OfferBookListItem> amountColumn;
private AutoTooltipTableColumn<OfferBookListItem, OfferBookListItem> volumeColumn;
private AutoTooltipTableColumn<OfferBookListItem, OfferBookListItem> marketColumn;
private AutoTooltipTableColumn<OfferBookListItem, OfferBookListItem> priceColumn;
private AutoTooltipTableColumn<OfferBookListItem, OfferBookListItem> depositColumn;
private AutoTooltipTableColumn<OfferBookListItem, OfferBookListItem> signingStateColumn;
private AutoTooltipTableColumn<OfferBookListItem, OfferBookListItem> avatarColumn;
private TableView<OfferBookListItem> tableView;
private OfferView.OfferActionHandler offerActionHandler;
private int gridRow = 0;
private Label nrOfOffersLabel;
private ListChangeListener<OfferBookListItem> offerListListener;
private ChangeListener<Number> priceFeedUpdateCounterListener;
private Subscription currencySelectionSubscriber;
private static final int SHOW_ALL = 0;
private Label disabledCreateOfferButtonTooltip;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, lifecycle
@ -200,13 +207,23 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
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 class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
tableView.getColumns().add(amountColumn);
volumeColumn = getVolumeColumn();
tableView.getColumns().add(volumeColumn);
paymentMethodColumn = getPaymentMethodColumn();
AutoTooltipTableColumn<OfferBookListItem, OfferBookListItem> paymentMethodColumn = getPaymentMethodColumn();
tableView.getColumns().add(paymentMethodColumn);
depositColumn = getDepositColumn();
tableView.getColumns().add(depositColumn);
@ -538,6 +555,16 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
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 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
}
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 class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
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 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
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 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
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 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
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 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
});
}
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 class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
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);
});
}
}

View file

@ -20,13 +20,16 @@ package bisq.desktop.main.offer.offerbook;
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<OfferBookListItem> filteredItems;
private final BsqWalletService bsqWalletService;
private final CoreApi coreApi;
private final SortedList<OfferBookListItem> sortedItems;
private final ListChangeListener<TradeCurrency> tradeCurrencyListChangeListener;
private final ListChangeListener<OfferBookListItem> 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 @@ class OfferBookViewModel extends ActivatableViewModel {
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 @@ class OfferBookViewModel extends ActivatableViewModel {
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 @@ class OfferBookViewModel extends ActivatableViewModel {
.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 @@ class OfferBookViewModel extends ActivatableViewModel {
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 @@ class OfferBookViewModel extends ActivatableViewModel {
void onTabSelected(boolean isSelected) {
this.isTabSelected = isSelected;
setMarketPriceFeedCurrency();
if (isTabSelected) {
updateSelectedTradeCurrency();
filterOffers();
}
}
///////////////////////////////////////////////////////////////////////////////////////////
@ -413,16 +420,12 @@ class OfferBookViewModel extends ActivatableViewModel {
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 @@ class OfferBookViewModel extends ActivatableViewModel {
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());
}
}

View file

@ -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 @@ import static com.google.common.base.Preconditions.checkNotNull;
public class SellerStep3View extends TradeStepView {
private Button confirmButton;
private AutoTooltipButton showBsqWallet;
private Label statusLabel;
private BusyAnimation busyAnimation;
private Subscription tradeStatePropertySubscription;
@ -296,11 +302,21 @@ public class SellerStep3View extends TradeStepView {
Tuple4<Button, BusyAnimation, Label, HBox> 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);
});
}
}

View file

@ -6,8 +6,9 @@ import bisq.core.locale.Res;
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 class DisplayUtils {
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);
}
}

View file

@ -108,13 +108,17 @@ import javafx.scene.control.Label;
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 class GUIUtil {
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);
}
}

View file

@ -239,7 +239,7 @@ public class OfferBookViewModelTest {
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 class OfferBookViewModelTest {
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 class OfferBookViewModelTest {
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 class OfferBookViewModelTest {
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 class OfferBookViewModelTest {
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 class OfferBookViewModelTest {
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 class OfferBookViewModelTest {
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 class OfferBookViewModelTest {
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 class OfferBookViewModelTest {
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 class OfferBookViewModelTest {
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 class OfferBookViewModelTest {
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),