From ebd98f850f06fc8801a1ff9ec838d28bc5b7239b Mon Sep 17 00:00:00 2001 From: BtcContributor <79100296+BtcContributor@users.noreply.github.com> Date: Mon, 15 Mar 2021 15:03:38 +0100 Subject: [PATCH 1/4] Add custom withdrawal transaction fee options on Send funds and remove it from settings --- .../resources/i18n/displayStrings.properties | 9 +- .../main/funds/withdrawal/WithdrawalView.java | 77 ++++++++++++++-- .../settings/preferences/PreferencesView.java | 87 +------------------ 3 files changed, 80 insertions(+), 93 deletions(-) diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index d9b921ab97..8ca2774264 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -1029,6 +1029,11 @@ funds.withdrawal.fillDestAddress=Fill in your destination address funds.withdrawal.warn.noSourceAddressSelected=You need to select a source address in the table above. funds.withdrawal.warn.amountExceeds=You don't have sufficient funds available from the selected address.\n\ Consider to select multiple addresses in the table above or change the fee toggle to include the miner fee. +funds.withdrawal.txFee=Withdrawal transaction fee (satoshis/vbyte) +funds.withdrawal.useCustomFeeValueInfo=Insert a custom transaction fee value +funds.withdrawal.useCustomFeeValue=Use custom value +funds.withdrawal.txFeeMin=Transaction fee must be at least {0} satoshis/vbyte +funds.withdrawal.txFeeTooLarge=Your input is above any reasonable value (>5000 satoshis/vbyte). Transaction fee is usually in the range of 50-400 satoshis/vbyte. funds.reserved.noFunds=No funds are reserved in open offers funds.reserved.reserved=Reserved in local wallet for offer with ID: {0} @@ -1199,10 +1204,6 @@ setting.preferences.autoConfirmRequiredConfirmations=Required confirmations setting.preferences.autoConfirmMaxTradeSize=Max. trade amount (BTC) setting.preferences.autoConfirmServiceAddresses=Monero Explorer URLs (uses Tor, except for localhost, LAN IP addresses, and *.local hostnames) setting.preferences.deviationToLarge=Values higher than {0}% are not allowed. -setting.preferences.txFee=Withdrawal transaction fee (satoshis/vbyte) -setting.preferences.useCustomValue=Use custom value -setting.preferences.txFeeMin=Transaction fee must be at least {0} satoshis/vbyte -setting.preferences.txFeeTooLarge=Your input is above any reasonable value (>5000 satoshis/vbyte). Transaction fee is usually in the range of 50-400 satoshis/vbyte. setting.preferences.ignorePeers=Ignored peers [onion address:port] setting.preferences.ignoreDustThreshold=Min. non-dust output value setting.preferences.currenciesInList=Currencies in market price feed list diff --git a/desktop/src/main/java/bisq/desktop/main/funds/withdrawal/WithdrawalView.java b/desktop/src/main/java/bisq/desktop/main/funds/withdrawal/WithdrawalView.java index aa3e984660..19e90dc234 100644 --- a/desktop/src/main/java/bisq/desktop/main/funds/withdrawal/WithdrawalView.java +++ b/desktop/src/main/java/bisq/desktop/main/funds/withdrawal/WithdrawalView.java @@ -23,6 +23,7 @@ import bisq.desktop.components.AutoTooltipCheckBox; import bisq.desktop.components.AutoTooltipLabel; import bisq.desktop.components.ExternalHyperlink; import bisq.desktop.components.HyperlinkWithIcon; +import bisq.desktop.components.InputTextField; import bisq.desktop.components.TitledGroupBg; import bisq.desktop.main.overlays.popups.Popup; import bisq.desktop.main.overlays.windows.TxDetails; @@ -38,6 +39,7 @@ import bisq.core.btc.setup.WalletsSetup; import bisq.core.btc.wallet.BtcWalletService; import bisq.core.btc.wallet.Restrictions; import bisq.core.locale.Res; +import bisq.core.provider.fee.FeeService; import bisq.core.trade.Trade; import bisq.core.trade.TradeManager; import bisq.core.user.DontShowAgainLookup; @@ -45,7 +47,6 @@ import bisq.core.user.Preferences; import bisq.core.util.FormattingUtils; import bisq.core.util.ParsingUtils; import bisq.core.util.coin.CoinFormatter; -import bisq.core.util.coin.CoinUtil; import bisq.core.util.validation.BtcAddressValidator; import bisq.network.p2p.P2PService; @@ -79,6 +80,7 @@ import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.TextField; import javafx.scene.control.Toggle; +import javafx.scene.control.ToggleButton; import javafx.scene.control.ToggleGroup; import javafx.scene.control.Tooltip; import javafx.scene.layout.GridPane; @@ -124,7 +126,7 @@ public class WithdrawalView extends ActivatableView { private RadioButton useAllInputsRadioButton, useCustomInputsRadioButton, feeExcludedRadioButton, feeIncludedRadioButton; private Label amountLabel; - private TextField amountTextField, withdrawFromTextField, withdrawToTextField, withdrawMemoTextField; + private TextField amountTextField, withdrawFromTextField, withdrawToTextField, withdrawMemoTextField, transactionFeeInputTextField; private final BtcWalletService btcWalletService; private final TradeManager tradeManager; @@ -143,12 +145,15 @@ public class WithdrawalView extends ActivatableView { private Coin amountAsCoin = Coin.ZERO; private Coin sendersAmount = Coin.ZERO; private ChangeListener amountListener; - private ChangeListener amountFocusListener; + private ChangeListener amountFocusListener, useCustomFeeCheckboxListener, transactionFeeFocusedListener; private ChangeListener feeToggleGroupListener, inputsToggleGroupListener; + private ChangeListener transactionFeeChangeListener; private ToggleGroup feeToggleGroup, inputsToggleGroup; + private ToggleButton useCustomFee; private final BooleanProperty useAllInputs = new SimpleBooleanProperty(true); private boolean feeExcluded; private int rowIndex = 0; + private final FeeService feeService; /////////////////////////////////////////////////////////////////////////////////////////// @@ -163,7 +168,8 @@ public class WithdrawalView extends ActivatableView { @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter, Preferences preferences, BtcAddressValidator btcAddressValidator, - WalletPasswordWindow walletPasswordWindow) { + WalletPasswordWindow walletPasswordWindow, + FeeService feeService) { this.btcWalletService = btcWalletService; this.tradeManager = tradeManager; this.p2PService = p2PService; @@ -172,6 +178,7 @@ public class WithdrawalView extends ActivatableView { this.preferences = preferences; this.btcAddressValidator = btcAddressValidator; this.walletPasswordWindow = walletPasswordWindow; + this.feeService = feeService; } @Override @@ -221,6 +228,52 @@ public class WithdrawalView extends ActivatableView { withdrawMemoTextField = addTopLabelInputTextField(gridPane, ++rowIndex, Res.get("funds.withdrawal.memoLabel", Res.getBaseCurrencyCode())).second; + Tuple3 customFeeTuple = addTopLabelInputTextFieldSlideToggleButton(gridPane, ++rowIndex, + Res.get("funds.withdrawal.txFee"), Res.get("funds.withdrawal.useCustomFeeValue")); + transactionFeeInputTextField = customFeeTuple.second; + useCustomFee = customFeeTuple.third; + + useCustomFeeCheckboxListener = (observable, oldValue, newValue) -> { + transactionFeeInputTextField.setEditable(newValue); + if (!newValue) { + try { + transactionFeeInputTextField.setText(String.valueOf(feeService.getTxFeePerVbyte().value)); + } catch (Exception e) { + e.printStackTrace(); + } + } + }; + + transactionFeeFocusedListener = (o, oldValue, newValue) -> { + if (oldValue && !newValue) { + String estimatedFee = String.valueOf(feeService.getTxFeePerVbyte().value); + try { + int withdrawalTxFeePerVbyte = Integer.parseInt(transactionFeeInputTextField.getText()); + final long minFeePerVbyte = feeService.getMinFeePerVByte(); + if (withdrawalTxFeePerVbyte < minFeePerVbyte) { + new Popup().warning(Res.get("funds.withdrawal.txFeeMin", minFeePerVbyte)).show(); + transactionFeeInputTextField.setText(estimatedFee); + } else if (withdrawalTxFeePerVbyte > 5000) { + new Popup().warning(Res.get("funds.withdrawal.txFeeTooLarge")).show(); + transactionFeeInputTextField.setText(estimatedFee); + } else { + preferences.setWithdrawalTxFeeInVbytes(withdrawalTxFeePerVbyte); + } + } catch (NumberFormatException t) { + log.error(t.toString()); + t.printStackTrace(); + new Popup().warning(Res.get("validation.integerOnly")).show(); + transactionFeeInputTextField.setText(estimatedFee); + } catch (Throwable t) { + log.error(t.toString()); + t.printStackTrace(); + new Popup().warning(Res.get("validation.inputError", t.getMessage())).show(); + transactionFeeInputTextField.setText(estimatedFee); + } + } + }; + transactionFeeChangeListener = (observable, oldValue, newValue) -> transactionFeeInputTextField.setText(String.valueOf(feeService.getTxFeePerVbyte().value)); + final Button withdrawButton = addButton(gridPane, ++rowIndex, Res.get("funds.withdrawal.withdrawButton"), 15); withdrawButton.setOnAction(event -> onWithdraw()); @@ -304,6 +357,13 @@ public class WithdrawalView extends ActivatableView { if (inputsToggleGroup.getSelectedToggle() == null) inputsToggleGroup.selectToggle(useAllInputsRadioButton); + useCustomFee.setSelected(false); + transactionFeeInputTextField.setEditable(false); + transactionFeeInputTextField.setText(String.valueOf(feeService.getTxFeePerVbyte().value)); + feeService.feeUpdateCounterProperty().addListener(transactionFeeChangeListener); + useCustomFee.selectedProperty().addListener(useCustomFeeCheckboxListener); + transactionFeeInputTextField.focusedProperty().addListener(transactionFeeFocusedListener); + updateInputSelection(); GUIUtil.requestFocus(withdrawToTextField); } @@ -317,6 +377,10 @@ public class WithdrawalView extends ActivatableView { amountTextField.focusedProperty().removeListener(amountFocusListener); feeToggleGroup.selectedToggleProperty().removeListener(feeToggleGroupListener); inputsToggleGroup.selectedToggleProperty().removeListener(inputsToggleGroupListener); + transactionFeeInputTextField.focusedProperty().removeListener(transactionFeeFocusedListener); + if (transactionFeeChangeListener != null) + feeService.feeUpdateCounterProperty().removeListener(transactionFeeChangeListener); + useCustomFee.selectedProperty().removeListener(useCustomFeeCheckboxListener); } @@ -361,7 +425,7 @@ public class WithdrawalView extends ActivatableView { log.info("Fee for tx with size {}: {} " + Res.getBaseCurrencyCode() + "", txVsize, fee.toPlainString()); if (receiverAmount.isPositive()) { - double feePerVbyte = CoinUtil.getFeePerVbyte(fee, txVsize); + double feePerVbyte = Double.parseDouble(transactionFeeInputTextField.getText()); double vkb = txVsize / 1000d; String messageText = Res.get("shared.sendFundsDetailsWithFee", @@ -550,6 +614,9 @@ public class WithdrawalView extends ActivatableView { withdrawMemoTextField.setText(""); withdrawMemoTextField.setPromptText(Res.get("funds.withdrawal.memo")); + transactionFeeInputTextField.setText(""); + transactionFeeInputTextField.setPromptText(Res.get("funds.withdrawal.useCustomFeeValueInfo")); + selectedItems.clear(); tableView.getSelectionModel().clearSelection(); } diff --git a/desktop/src/main/java/bisq/desktop/main/settings/preferences/PreferencesView.java b/desktop/src/main/java/bisq/desktop/main/settings/preferences/PreferencesView.java index 5643b18c7e..246e30f654 100644 --- a/desktop/src/main/java/bisq/desktop/main/settings/preferences/PreferencesView.java +++ b/desktop/src/main/java/bisq/desktop/main/settings/preferences/PreferencesView.java @@ -47,7 +47,6 @@ import bisq.core.locale.Res; import bisq.core.locale.TradeCurrency; import bisq.core.payment.PaymentAccount; import bisq.core.payment.payload.PaymentMethod; -import bisq.core.provider.fee.FeeService; import bisq.core.user.Preferences; import bisq.core.user.User; import bisq.core.util.FormattingUtils; @@ -120,21 +119,19 @@ public class PreferencesView extends ActivatableViewAndModel preferredTradeCurrencyComboBox; private ToggleButton showOwnOffersInOfferBook, useAnimations, useDarkMode, sortMarketCurrenciesNumerically, - avoidStandbyMode, useCustomFee, autoConfirmXmrToggle, hideNonAccountPaymentMethodsToggle, denyApiTakerToggle, + avoidStandbyMode, autoConfirmXmrToggle, hideNonAccountPaymentMethodsToggle, denyApiTakerToggle, notifyOnPreReleaseToggle; private int gridRow = 0; private int displayCurrenciesGridRowIndex = 0; - private InputTextField transactionFeeInputTextField, ignoreTradersListInputTextField, ignoreDustThresholdInputTextField, + private InputTextField ignoreTradersListInputTextField, ignoreDustThresholdInputTextField, autoConfRequiredConfirmationsTf, autoConfServiceAddressTf, autoConfTradeLimitTf, /*referralIdInputTextField,*/ rpcUserTextField, blockNotifyPortTextField; private ToggleButton isDaoFullNodeToggleButton; private PasswordTextField rpcPwTextField; private TitledGroupBg daoOptionsTitledGroupBg; - private ChangeListener transactionFeeFocusedListener; private ChangeListener autoConfServiceAddressFocusOutListener, autoConfRequiredConfirmationsFocusOutListener; private final Preferences preferences; - private final FeeService feeService; //private final ReferralIdService referralIdService; private final AssetService assetService; private final FilterManager filterManager; @@ -159,8 +156,6 @@ public class PreferencesView extends ActivatableViewAndModel deviationFocusedListener, bsqAverageTrimThresholdFocusedListener; - private ChangeListener useCustomFeeCheckboxListener; - private ChangeListener transactionFeeChangeListener; private final boolean daoOptionsSet; private final boolean displayStandbyModeFeature; private ChangeListener filterChangeListener; @@ -173,7 +168,6 @@ public class PreferencesView extends ActivatableViewAndModel tuple = addTopLabelInputTextFieldSlideToggleButton(root, ++gridRow, - Res.get("setting.preferences.txFee"), Res.get("setting.preferences.useCustomValue")); - transactionFeeInputTextField = tuple.second; - useCustomFee = tuple.third; - - useCustomFeeCheckboxListener = (observable, oldValue, newValue) -> { - preferences.setUseCustomWithdrawalTxFee(newValue); - transactionFeeInputTextField.setEditable(newValue); - if (!newValue) { - transactionFeeInputTextField.setText(String.valueOf(feeService.getTxFeePerVbyte().value)); - try { - preferences.setWithdrawalTxFeeInVbytes(feeService.getTxFeePerVbyte().value); - } catch (Exception e) { - e.printStackTrace(); - } - } - - preferences.setUseCustomWithdrawalTxFee(newValue); - }; - - transactionFeeFocusedListener = (o, oldValue, newValue) -> { - if (oldValue && !newValue) { - String estimatedFee = String.valueOf(feeService.getTxFeePerVbyte().value); - try { - int withdrawalTxFeePerVbyte = Integer.parseInt(transactionFeeInputTextField.getText()); - final long minFeePerVbyte = feeService.getMinFeePerVByte(); - if (withdrawalTxFeePerVbyte < minFeePerVbyte) { - new Popup().warning(Res.get("setting.preferences.txFeeMin", minFeePerVbyte)).show(); - transactionFeeInputTextField.setText(estimatedFee); - } else if (withdrawalTxFeePerVbyte > 5000) { - new Popup().warning(Res.get("setting.preferences.txFeeTooLarge")).show(); - transactionFeeInputTextField.setText(estimatedFee); - } else { - preferences.setWithdrawalTxFeeInVbytes(withdrawalTxFeePerVbyte); - } - } catch (NumberFormatException t) { - log.error(t.toString()); - t.printStackTrace(); - new Popup().warning(Res.get("validation.integerOnly")).show(); - transactionFeeInputTextField.setText(estimatedFee); - } catch (Throwable t) { - log.error(t.toString()); - t.printStackTrace(); - new Popup().warning(Res.get("validation.inputError", t.getMessage())).show(); - transactionFeeInputTextField.setText(estimatedFee); - } - } - }; - transactionFeeChangeListener = (observable, oldValue, newValue) -> transactionFeeInputTextField.setText(String.valueOf(feeService.getTxFeePerVbyte().value)); - // deviation deviationInputTextField = addInputTextField(root, ++gridRow, Res.get("setting.preferences.deviation")); @@ -800,16 +743,6 @@ public class PreferencesView extends ActivatableViewAndModel referralIdInputTextField.setText(referralId)); referralIdInputTextField.setPromptText(Res.get("setting.preferences.refererId.prompt"));*/ @@ -873,21 +806,11 @@ public class PreferencesView extends ActivatableViewAndModel { withdrawFromTextField.getText(), withdrawToTextField.getText(), formatter.formatCoinWithCode(fee), - feePerVbyte, + Double.parseDouble(transactionFeeInputTextField.getText()), vkb, formatter.formatCoinWithCode(receiverAmount)); if (dust.isPositive()) { From bf2c3560ffbda2d2d35de161526ae63407fbb269 Mon Sep 17 00:00:00 2001 From: BtcContributor <79100296+BtcContributor@users.noreply.github.com> Date: Tue, 13 Apr 2021 12:30:49 +0200 Subject: [PATCH 3/4] Restore field used to set a manual fee for BSQ transactions --- .../bisq/desktop/main/settings/preferences/PreferencesView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desktop/src/main/java/bisq/desktop/main/settings/preferences/PreferencesView.java b/desktop/src/main/java/bisq/desktop/main/settings/preferences/PreferencesView.java index 246e30f654..70c604d211 100644 --- a/desktop/src/main/java/bisq/desktop/main/settings/preferences/PreferencesView.java +++ b/desktop/src/main/java/bisq/desktop/main/settings/preferences/PreferencesView.java @@ -123,7 +123,7 @@ public class PreferencesView extends ActivatableViewAndModel Date: Mon, 19 Apr 2021 16:58:00 +0200 Subject: [PATCH 4/4] Restore manual fees for BSQ transactions in Settings --- .../resources/i18n/displayStrings.properties | 2 + .../settings/preferences/PreferencesView.java | 85 ++++++++++++++++++- 2 files changed, 84 insertions(+), 3 deletions(-) diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index 8ca2774264..6e36cd7ce8 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -1204,6 +1204,8 @@ setting.preferences.autoConfirmRequiredConfirmations=Required confirmations setting.preferences.autoConfirmMaxTradeSize=Max. trade amount (BTC) setting.preferences.autoConfirmServiceAddresses=Monero Explorer URLs (uses Tor, except for localhost, LAN IP addresses, and *.local hostnames) setting.preferences.deviationToLarge=Values higher than {0}% are not allowed. +setting.preferences.txFee=BSQ Withdrawal transaction fee (satoshis/vbyte) +setting.preferences.useCustomValue=Use custom value setting.preferences.ignorePeers=Ignored peers [onion address:port] setting.preferences.ignoreDustThreshold=Min. non-dust output value setting.preferences.currenciesInList=Currencies in market price feed list diff --git a/desktop/src/main/java/bisq/desktop/main/settings/preferences/PreferencesView.java b/desktop/src/main/java/bisq/desktop/main/settings/preferences/PreferencesView.java index 70c604d211..bc4d42fa19 100644 --- a/desktop/src/main/java/bisq/desktop/main/settings/preferences/PreferencesView.java +++ b/desktop/src/main/java/bisq/desktop/main/settings/preferences/PreferencesView.java @@ -47,6 +47,7 @@ import bisq.core.locale.Res; import bisq.core.locale.TradeCurrency; import bisq.core.payment.PaymentAccount; import bisq.core.payment.payload.PaymentMethod; +import bisq.core.provider.fee.FeeService; import bisq.core.user.Preferences; import bisq.core.user.User; import bisq.core.util.FormattingUtils; @@ -119,7 +120,7 @@ public class PreferencesView extends ActivatableViewAndModel preferredTradeCurrencyComboBox; private ToggleButton showOwnOffersInOfferBook, useAnimations, useDarkMode, sortMarketCurrenciesNumerically, - avoidStandbyMode, autoConfirmXmrToggle, hideNonAccountPaymentMethodsToggle, denyApiTakerToggle, + avoidStandbyMode, useCustomFee, autoConfirmXmrToggle, hideNonAccountPaymentMethodsToggle, denyApiTakerToggle, notifyOnPreReleaseToggle; private int gridRow = 0; private int displayCurrenciesGridRowIndex = 0; @@ -130,8 +131,9 @@ public class PreferencesView extends ActivatableViewAndModel autoConfServiceAddressFocusOutListener, autoConfRequiredConfirmationsFocusOutListener; + private ChangeListener transactionFeeFocusedListener, autoConfServiceAddressFocusOutListener, autoConfRequiredConfirmationsFocusOutListener; private final Preferences preferences; + private final FeeService feeService; //private final ReferralIdService referralIdService; private final AssetService assetService; private final FilterManager filterManager; @@ -156,6 +158,8 @@ public class PreferencesView extends ActivatableViewAndModel deviationFocusedListener, bsqAverageTrimThresholdFocusedListener; + private ChangeListener useCustomFeeCheckboxListener; + private ChangeListener transactionFeeChangeListener; private final boolean daoOptionsSet; private final boolean displayStandbyModeFeature; private ChangeListener filterChangeListener; @@ -168,6 +172,7 @@ public class PreferencesView extends ActivatableViewAndModel tuple = addTopLabelInputTextFieldSlideToggleButton(root, ++gridRow, + Res.get("setting.preferences.txFee"), Res.get("setting.preferences.useCustomValue")); + transactionFeeInputTextField = tuple.second; + useCustomFee = tuple.third; + + useCustomFeeCheckboxListener = (observable, oldValue, newValue) -> { + preferences.setUseCustomWithdrawalTxFee(newValue); + transactionFeeInputTextField.setEditable(newValue); + if (!newValue) { + transactionFeeInputTextField.setText(String.valueOf(feeService.getTxFeePerVbyte().value)); + try { + preferences.setWithdrawalTxFeeInVbytes(feeService.getTxFeePerVbyte().value); + } catch (Exception e) { + e.printStackTrace(); + } + } + + preferences.setUseCustomWithdrawalTxFee(newValue); + }; + + transactionFeeFocusedListener = (o, oldValue, newValue) -> { + if (oldValue && !newValue) { + String estimatedFee = String.valueOf(feeService.getTxFeePerVbyte().value); + try { + int withdrawalTxFeePerVbyte = Integer.parseInt(transactionFeeInputTextField.getText()); + final long minFeePerVbyte = feeService.getMinFeePerVByte(); + if (withdrawalTxFeePerVbyte < minFeePerVbyte) { + new Popup().warning(Res.get("setting.preferences.txFeeMin", minFeePerVbyte)).show(); + transactionFeeInputTextField.setText(estimatedFee); + } else if (withdrawalTxFeePerVbyte > 5000) { + new Popup().warning(Res.get("setting.preferences.txFeeTooLarge")).show(); + transactionFeeInputTextField.setText(estimatedFee); + } else { + preferences.setWithdrawalTxFeeInVbytes(withdrawalTxFeePerVbyte); + } + } catch (NumberFormatException t) { + log.error(t.toString()); + t.printStackTrace(); + new Popup().warning(Res.get("validation.integerOnly")).show(); + transactionFeeInputTextField.setText(estimatedFee); + } catch (Throwable t) { + log.error(t.toString()); + t.printStackTrace(); + new Popup().warning(Res.get("validation.inputError", t.getMessage())).show(); + transactionFeeInputTextField.setText(estimatedFee); + } + } + }; + transactionFeeChangeListener = (observable, oldValue, newValue) -> transactionFeeInputTextField.setText(String.valueOf(feeService.getTxFeePerVbyte().value)); + // deviation deviationInputTextField = addInputTextField(root, ++gridRow, Res.get("setting.preferences.deviation")); @@ -743,6 +799,15 @@ public class PreferencesView extends ActivatableViewAndModel referralIdInputTextField.setText(referralId)); referralIdInputTextField.setPromptText(Res.get("setting.preferences.refererId.prompt"));*/ @@ -806,11 +871,21 @@ public class PreferencesView extends ActivatableViewAndModel