Use percentage based price as default, swap input text controls when toggle between fixed price and percentage based price. Hide percentage based inputs if no market price is available.

This commit is contained in:
Manfred Karrer 2017-02-20 11:02:54 -05:00
parent 3777a65b2f
commit 78a8e1ba39
4 changed files with 135 additions and 61 deletions

View File

@ -129,7 +129,7 @@ public final class Preferences implements Persistable {
private boolean useStickyMarketPrice = false;
private boolean sortMarketCurrenciesNumerically = true;
private boolean usePercentageBasedPrice = false;
private boolean usePercentageBasedPrice = true;
private Map<String, String> peerTagMap = new HashMap<>();
private String bitcoinNodes = "";

View File

@ -612,10 +612,8 @@ class CreateOfferDataModel extends ActivatableDataModel {
void updateTradeFee() {
createOfferFeeAsCoin = Utilities.getFeePerBtc(feeService.getCreateOfferFeeInBtcPerBtc(), amount.get());
// We don't want too fractional btc values so we use only a divide by 10 instead of 100
createOfferFeeAsCoin = createOfferFeeAsCoin.divide(10).multiply(Math.round(marketPriceMargin * 1_000));
createOfferFeeAsCoin = Utilities.maxCoin(createOfferFeeAsCoin, feeService.getMinCreateOfferFeeInBtc());
}
}

View File

@ -129,6 +129,12 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
private List<Node> editOfferElements = new ArrayList<>();
private boolean isActivated;
private Label xLabel;
private VBox fixedPriceBox;
private VBox percentagePriceBox;
private HBox secondRowHBox;
private HBox firstRowHBox;
private HBox toggleButtonsHBox;
private ChangeListener<Number> marketPriceAvailableListener;
///////////////////////////////////////////////////////////////////////////////////////////
@ -190,9 +196,6 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
if (waitingForFundsBusyAnimation != null)
waitingForFundsBusyAnimation.play();
useMarketBasedPriceButton.setSelected(model.dataModel.useMarketBasedPrice.get());
fixedPriceButton.setSelected(!model.dataModel.useMarketBasedPrice.get());
directionLabel.setText(model.getDirectionLabel());
amountDescriptionLabel.setText(model.getAmountDescription());
addressTextField.setAddress(model.getAddressAsString());
@ -437,10 +440,7 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
private void addBindings() {
amountBtcLabel.textProperty().bind(model.btcCode);
priceCurrencyLabel.textProperty().bind(createStringBinding(() -> formatter.getCounterCurrency(model.tradeCurrencyCode.get()), model.btcCode, model.tradeCurrencyCode));
fixedPriceTextField.disableProperty().bind(model.dataModel.useMarketBasedPrice);
priceCurrencyLabel.disableProperty().bind(model.dataModel.useMarketBasedPrice);
marketBasedPriceTextField.disableProperty().bind(model.dataModel.useMarketBasedPrice.not());
marketBasedPriceLabel.disableProperty().bind(model.dataModel.useMarketBasedPrice.not());
marketBasedPriceLabel.prefWidthProperty().bind(priceCurrencyLabel.widthProperty());
volumeCurrencyLabel.textProperty().bind(model.tradeCurrencyCode);
minAmountBtcLabel.textProperty().bind(model.btcCode);
@ -645,10 +645,24 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
}
}
};
marketPriceAvailableListener = (observable, oldValue, newValue) -> {
if (newValue.intValue() > -1) {
boolean isMarketPriceAvailable = newValue.intValue() == 1;
percentagePriceBox.setVisible(isMarketPriceAvailable);
percentagePriceBox.setManaged(isMarketPriceAvailable);
toggleButtonsHBox.setVisible(isMarketPriceAvailable);
toggleButtonsHBox.setManaged(isMarketPriceAvailable);
boolean fixedPriceSelected = !model.dataModel.useMarketBasedPrice.get() || !isMarketPriceAvailable;
updateToggleButtons(fixedPriceSelected);
}
};
}
private void addListeners() {
model.tradeCurrencyCode.addListener(tradeCurrencyCodeListener);
model.marketPriceAvailableProperty.addListener(marketPriceAvailableListener);
// focus out
amountTextField.focusedProperty().addListener(amountFocusedListener);
@ -670,6 +684,7 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
private void removeListeners() {
model.tradeCurrencyCode.removeListener(tradeCurrencyCodeListener);
model.marketPriceAvailableProperty.removeListener(marketPriceAvailableListener);
// focus out
amountTextField.focusedProperty().removeListener(amountFocusedListener);
@ -944,17 +959,16 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
xLabel.setMinWidth(14);
xLabel.setMaxWidth(14);
// price as fiat
Tuple3<HBox, InputTextField, Label> priceValueCurrencyBoxTuple = FormBuilder.getValueCurrencyBox(BSResources.get("createOffer.price.prompt"));
HBox priceValueCurrencyBox = priceValueCurrencyBoxTuple.first;
fixedPriceTextField = priceValueCurrencyBoxTuple.second;
editOfferElements.add(fixedPriceTextField);
priceCurrencyLabel = priceValueCurrencyBoxTuple.third;
editOfferElements.add(priceCurrencyLabel);
Tuple2<Label, VBox> priceInputBoxTuple = getTradeInputBox(priceValueCurrencyBox, "");
priceDescriptionLabel = priceInputBoxTuple.first;
editOfferElements.add(priceDescriptionLabel);
VBox priceBox = priceInputBoxTuple.second;
// price as percent
Tuple3<HBox, InputTextField, Label> priceAsPercentageTuple = FormBuilder.getValueCurrencyBox(BSResources.get("createOffer.price.prompt"));
HBox priceAsPercentageValueCurrencyBox = priceAsPercentageTuple.first;
marketBasedPriceTextField = priceAsPercentageTuple.second;
editOfferElements.add(marketBasedPriceTextField);
marketBasedPriceLabel = priceAsPercentageTuple.third;
editOfferElements.add(marketBasedPriceLabel);
Tuple2<Label, VBox> priceAsPercentageInputBoxTuple = getTradeInputBox(priceAsPercentageValueCurrencyBox, "Distance in % from market price");
priceAsPercentageInputBoxTuple.first.setPrefWidth(200);
percentagePriceBox = priceAsPercentageInputBoxTuple.second;
// Fixed/Percentage toggle
ToggleGroup toggleGroup = new ToggleGroup();
@ -963,8 +977,7 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
fixedPriceButton.setId("toggle-price-left");
fixedPriceButton.setToggleGroup(toggleGroup);
fixedPriceButton.selectedProperty().addListener((ov, oldValue, newValue) -> {
model.dataModel.setUseMarketBasedPrice(!newValue);
useMarketBasedPriceButton.setSelected(!newValue);
updateToggleButtons(newValue);
});
useMarketBasedPriceButton = new ToggleButton("Percentage");
@ -972,13 +985,12 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
useMarketBasedPriceButton.setId("toggle-price-right");
useMarketBasedPriceButton.setToggleGroup(toggleGroup);
useMarketBasedPriceButton.selectedProperty().addListener((ov, oldValue, newValue) -> {
model.dataModel.setUseMarketBasedPrice(newValue);
fixedPriceButton.setSelected(!newValue);
updateToggleButtons(!newValue);
});
HBox toggleButtons = new HBox();
toggleButtons.setPadding(new Insets(18, 0, 0, 0));
toggleButtons.getChildren().addAll(fixedPriceButton, useMarketBasedPriceButton);
toggleButtonsHBox = new HBox();
toggleButtonsHBox.setPadding(new Insets(18, 0, 0, 0));
toggleButtonsHBox.getChildren().addAll(fixedPriceButton, useMarketBasedPriceButton);
// =
Label resultLabel = new Label("=");
@ -997,28 +1009,69 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
editOfferElements.add(volumeDescriptionLabel);
VBox volumeBox = volumeInputBoxTuple.second;
HBox hBox = new HBox();
hBox.setSpacing(5);
hBox.setAlignment(Pos.CENTER_LEFT);
hBox.getChildren().addAll(amountBox, xLabel, priceBox, toggleButtons, resultLabel, volumeBox);
GridPane.setRowIndex(hBox, gridRow);
GridPane.setColumnIndex(hBox, 1);
GridPane.setMargin(hBox, new Insets(Layout.FIRST_ROW_AND_GROUP_DISTANCE, 10, 0, 0));
GridPane.setColumnSpan(hBox, 2);
gridPane.getChildren().add(hBox);
firstRowHBox = new HBox();
firstRowHBox.setSpacing(5);
firstRowHBox.setAlignment(Pos.CENTER_LEFT);
firstRowHBox.getChildren().addAll(amountBox, xLabel, percentagePriceBox, toggleButtonsHBox, resultLabel, volumeBox);
GridPane.setRowIndex(firstRowHBox, gridRow);
GridPane.setColumnIndex(firstRowHBox, 1);
GridPane.setMargin(firstRowHBox, new Insets(Layout.FIRST_ROW_AND_GROUP_DISTANCE, 10, 0, 0));
GridPane.setColumnSpan(firstRowHBox, 2);
gridPane.getChildren().add(firstRowHBox);
}
private void updateToggleButtons(boolean fixedPriceSelected) {
int marketPriceAvailable = model.marketPriceAvailableProperty.get();
fixedPriceSelected |= marketPriceAvailable == 0;
if (marketPriceAvailable == 1) {
model.dataModel.setUseMarketBasedPrice(!fixedPriceSelected);
if (!fixedPriceButton.isSelected() && fixedPriceSelected)
fixedPriceButton.setSelected(fixedPriceSelected);
if (useMarketBasedPriceButton.isSelected() && !fixedPriceSelected)
useMarketBasedPriceButton.setSelected(!fixedPriceSelected);
}
fixedPriceButton.setMouseTransparent(fixedPriceSelected);
useMarketBasedPriceButton.setMouseTransparent(!fixedPriceSelected);
fixedPriceButton.setStyle(fixedPriceSelected ? "-fx-background-color: -bs-blue-transparent" : "-fx-background-color: -bs-very-light-grey");
useMarketBasedPriceButton.setStyle(!fixedPriceSelected ? "-fx-background-color: -bs-blue-transparent" : "-fx-background-color: -bs-very-light-grey");
if (fixedPriceSelected) {
if (firstRowHBox.getChildren().contains(percentagePriceBox))
firstRowHBox.getChildren().remove(percentagePriceBox);
if (secondRowHBox.getChildren().contains(fixedPriceBox))
secondRowHBox.getChildren().remove(fixedPriceBox);
if (!firstRowHBox.getChildren().contains(fixedPriceBox))
firstRowHBox.getChildren().add(2, fixedPriceBox);
if (!secondRowHBox.getChildren().contains(percentagePriceBox))
secondRowHBox.getChildren().add(percentagePriceBox);
} else {
if (firstRowHBox.getChildren().contains(fixedPriceBox))
firstRowHBox.getChildren().remove(fixedPriceBox);
if (secondRowHBox.getChildren().contains(percentagePriceBox))
secondRowHBox.getChildren().remove(percentagePriceBox);
if (!firstRowHBox.getChildren().contains(percentagePriceBox))
firstRowHBox.getChildren().add(2, percentagePriceBox);
if (!secondRowHBox.getChildren().contains(fixedPriceBox))
secondRowHBox.getChildren().add(fixedPriceBox);
}
}
private void addSecondRow() {
Tuple3<HBox, InputTextField, Label> priceAsPercentageTuple = FormBuilder.getValueCurrencyBox(BSResources.get("createOffer.price.prompt"));
HBox priceAsPercentageValueCurrencyBox = priceAsPercentageTuple.first;
marketBasedPriceTextField = priceAsPercentageTuple.second;
editOfferElements.add(marketBasedPriceTextField);
marketBasedPriceLabel = priceAsPercentageTuple.third;
editOfferElements.add(marketBasedPriceLabel);
Tuple2<Label, VBox> priceAsPercentageInputBoxTuple = getTradeInputBox(priceAsPercentageValueCurrencyBox, "Distance in % from market price");
priceAsPercentageInputBoxTuple.first.setPrefWidth(200);
VBox priceAsPercentageInputBox = priceAsPercentageInputBoxTuple.second;
// price as fiat
Tuple3<HBox, InputTextField, Label> priceValueCurrencyBoxTuple = FormBuilder.getValueCurrencyBox(BSResources.get("createOffer.price.prompt"));
HBox priceValueCurrencyBox = priceValueCurrencyBoxTuple.first;
fixedPriceTextField = priceValueCurrencyBoxTuple.second;
editOfferElements.add(fixedPriceTextField);
priceCurrencyLabel = priceValueCurrencyBoxTuple.third;
editOfferElements.add(priceCurrencyLabel);
Tuple2<Label, VBox> priceInputBoxTuple = getTradeInputBox(priceValueCurrencyBox, "");
priceDescriptionLabel = priceInputBoxTuple.first;
editOfferElements.add(priceDescriptionLabel);
fixedPriceBox = priceInputBoxTuple.second;
marketBasedPriceTextField.setPromptText("Enter % value");
marketBasedPriceLabel.setText("%");
@ -1039,15 +1092,15 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
xLabel.setPadding(new Insets(14, 3, 0, 3));
xLabel.setVisible(false); // we just use it to get the same layout as the upper row
HBox hBox = new HBox();
hBox.setSpacing(5);
hBox.setAlignment(Pos.CENTER_LEFT);
hBox.getChildren().addAll(amountInputBoxTuple.second, xLabel, priceAsPercentageInputBox);
GridPane.setRowIndex(hBox, ++gridRow);
GridPane.setColumnIndex(hBox, 1);
GridPane.setMargin(hBox, new Insets(5, 10, 5, 0));
GridPane.setColumnSpan(hBox, 2);
gridPane.getChildren().add(hBox);
secondRowHBox = new HBox();
secondRowHBox.setSpacing(5);
secondRowHBox.setAlignment(Pos.CENTER_LEFT);
secondRowHBox.getChildren().addAll(amountInputBoxTuple.second, xLabel, fixedPriceBox);
GridPane.setRowIndex(secondRowHBox, ++gridRow);
GridPane.setColumnIndex(secondRowHBox, 1);
GridPane.setMargin(secondRowHBox, new Insets(5, 10, 5, 0));
GridPane.setColumnSpan(secondRowHBox, 2);
gridPane.getChildren().add(secondRowHBox);
}

View File

@ -126,6 +126,9 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
private boolean inputIsMarketBasedPrice;
private ChangeListener<Boolean> useMarketBasedPriceListener;
private boolean ignorePriceStringListener, ignoreVolumeStringListener, ignoreAmountStringListener;
private MarketPrice marketPrice;
final IntegerProperty marketPriceAvailableProperty = new SimpleIntegerProperty(-1);
private ChangeListener<Number> currenciesUpdateListener;
///////////////////////////////////////////////////////////////////////////////////////////
@ -161,7 +164,10 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
UserThread.runAfter(() -> {
amount.set("1");
minAmount.set(amount.get());
price.set("1000");
UserThread.runAfter(() -> {
price.set("1000");
onFocusOutPriceAsPercentageTextField(true, false, "");
}, 1);
setAmountToModel();
setMinAmountToModel();
@ -247,6 +253,10 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
updateButtonDisableState();
};
priceStringListener = (ov, oldValue, newValue) -> {
final String currencyCode = dataModel.tradeCurrencyCode.get();
marketPrice = priceFeedService.getMarketPrice(currencyCode);
marketPriceAvailableProperty.set(marketPrice == null ? 0 : 1);
if (!ignorePriceStringListener) {
if (isPriceInputValid(newValue).isValid) {
setPriceToModel();
@ -254,8 +264,6 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
dataModel.calculateTotalToPay();
if (!inputIsMarketBasedPrice) {
final String currencyCode = dataModel.tradeCurrencyCode.get();
MarketPrice marketPrice = priceFeedService.getMarketPrice(currencyCode);
if (marketPrice != null) {
double marketPriceAsDouble = marketPrice.getPrice(getPriceFeedType());
try {
@ -280,8 +288,8 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
}
}
}
updateButtonDisableState();
}
updateButtonDisableState();
};
marketPriceMarginStringListener = (ov, oldValue, newValue) -> {
if (inputIsMarketBasedPrice) {
@ -298,7 +306,7 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
percentage = MathUtils.roundDouble(percentage, 4);
dataModel.setMarketPriceMargin(percentage);
dataModel.updateTradeFee();
double marketPriceAsDouble = marketPrice.getPrice(getPriceFeedType());
double factor;
if (CurrencyUtil.isCryptoCurrency(currencyCode))
@ -379,6 +387,13 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
/* feeFromFundingTxListener = (ov, oldValue, newValue) -> {
updateButtonDisableState();
};*/
currenciesUpdateListener = (observable, oldValue, newValue) -> {
final String currencyCode = dataModel.tradeCurrencyCode.get();
marketPrice = priceFeedService.getMarketPrice(currencyCode);
marketPriceAvailableProperty.set(marketPrice == null ? 0 : 1);
updateButtonDisableState();
};
}
private void addListeners() {
@ -399,6 +414,8 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
// dataModel.feeFromFundingTxProperty.addListener(feeFromFundingTxListener);
dataModel.isWalletFunded.addListener(isWalletFundedListener);
priceFeedService.currenciesUpdateFlagProperty().addListener(currenciesUpdateListener);
}
private void removeListeners() {
@ -420,6 +437,8 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
if (offer != null && errorMessageListener != null)
offer.errorMessageProperty().removeListener(errorMessageListener);
priceFeedService.currenciesUpdateFlagProperty().removeListener(currenciesUpdateListener);
}
@ -497,6 +516,10 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
public void onCurrencySelected(TradeCurrency tradeCurrency) {
dataModel.onCurrencySelected(tradeCurrency);
marketPrice = priceFeedService.getMarketPrice(dataModel.tradeCurrencyCode.get());
marketPriceAvailableProperty.set(marketPrice == null ? 0 : 1);
updateButtonDisableState();
}
void onShowPayFundsScreen() {