From 517ee371db0502b2418454da1fc5f4b496b611d4 Mon Sep 17 00:00:00 2001 From: Manfred Karrer Date: Thu, 14 Apr 2016 19:12:43 +0200 Subject: [PATCH] add percentage price (WIP) --- .../java/io/bitsquare/trade/offer/Offer.java | 25 +++++- .../main/java/io/bitsquare/gui/bitsquare.css | 20 +++++ .../createoffer/CreateOfferDataModel.java | 10 +++ .../offer/createoffer/CreateOfferView.java | 78 ++++++++++++++++--- .../offerbook/OfferBookViewModelTest.java | 2 + 5 files changed, 119 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/io/bitsquare/trade/offer/Offer.java b/core/src/main/java/io/bitsquare/trade/offer/Offer.java index 7c4ca84cf6..31a0eed0a6 100644 --- a/core/src/main/java/io/bitsquare/trade/offer/Offer.java +++ b/core/src/main/java/io/bitsquare/trade/offer/Offer.java @@ -106,6 +106,8 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload private final long date; private final long protocolVersion; private final long fiatPrice; + private final double percentagePrice; + private final boolean usePercentageBasedPrice; private final long amount; private final long minAmount; private final NodeAddress offererNodeAddress; @@ -138,6 +140,8 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload PubKeyRing pubKeyRing, Direction direction, long fiatPrice, + double percentagePrice, + boolean usePercentageBasedPrice, long amount, long minAmount, String currencyCode, @@ -153,6 +157,8 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload this.pubKeyRing = pubKeyRing; this.direction = direction; this.fiatPrice = fiatPrice; + this.percentagePrice = percentagePrice; + this.usePercentageBasedPrice = usePercentageBasedPrice; this.amount = amount; this.minAmount = minAmount; this.currencyCode = currencyCode; @@ -315,6 +321,14 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload return Fiat.valueOf(currencyCode, fiatPrice); } + public double getPercentagePrice() { + return percentagePrice; + } + + public boolean isUsePercentageBasedPrice() { + return usePercentageBasedPrice; + } + public Coin getAmount() { return Coin.valueOf(amount); } @@ -391,11 +405,11 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Offer)) return false; - Offer offer = (Offer) o; - if (date != offer.date) return false; if (fiatPrice != offer.fiatPrice) return false; + if (Double.compare(offer.percentagePrice, percentagePrice) != 0) return false; + if (usePercentageBasedPrice != offer.usePercentageBasedPrice) return false; if (amount != offer.amount) return false; if (minAmount != offer.minAmount) return false; if (id != null ? !id.equals(offer.id) : offer.id != null) return false; @@ -418,7 +432,6 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload if (arbitratorNodeAddresses != null ? !arbitratorNodeAddresses.equals(offer.arbitratorNodeAddresses) : offer.arbitratorNodeAddresses != null) return false; return !(offerFeePaymentTxID != null ? !offerFeePaymentTxID.equals(offer.offerFeePaymentTxID) : offer.offerFeePaymentTxID != null); - } @Override @@ -428,6 +441,9 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload result = 31 * result + (currencyCode != null ? currencyCode.hashCode() : 0); result = 31 * result + (int) (date ^ (date >>> 32)); result = 31 * result + (int) (fiatPrice ^ (fiatPrice >>> 32)); + long temp = Double.doubleToLongBits(percentagePrice); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + result = 31 * result + (usePercentageBasedPrice ? 1 : 0); result = 31 * result + (int) (amount ^ (amount >>> 32)); result = 31 * result + (int) (minAmount ^ (minAmount >>> 32)); result = 31 * result + (offererNodeAddress != null ? offererNodeAddress.hashCode() : 0); @@ -451,6 +467,8 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload "\n\tcurrencyCode='" + currencyCode + '\'' + "\n\tdate=" + date + "\n\tfiatPrice=" + fiatPrice + + "\n\tpercentagePrice=" + percentagePrice + + "\n\tusePercentageBasedPrice=" + usePercentageBasedPrice + "\n\tamount=" + amount + "\n\tminAmount=" + minAmount + "\n\toffererAddress=" + offererNodeAddress + @@ -471,5 +489,4 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload "\n\tTAC_TAKER=" + TAC_TAKER + '}'; } - } diff --git a/gui/src/main/java/io/bitsquare/gui/bitsquare.css b/gui/src/main/java/io/bitsquare/gui/bitsquare.css index 44c789f286..9aca50cd64 100644 --- a/gui/src/main/java/io/bitsquare/gui/bitsquare.css +++ b/gui/src/main/java/io/bitsquare/gui/bitsquare.css @@ -496,6 +496,26 @@ textfield */ -fx-border-insets: 0 0 0 -2; } +#toggle-price-left { + -fx-border-radius: 4 0 0 4; + -fx-padding: 4 4 4 4; + -fx-border-color: #aaa; + -fx-border-style: solid none solid solid; + -fx-border-insets: 0 -2 0 0; + -fx-background-insets: 0 -2 0 0; + -fx-background-radius: 4 0 0 4; +} + +#toggle-price-right { + -fx-border-radius: 0 4 4 0; + -fx-padding: 4 4 4 4; + -fx-border-color: #aaa; + -fx-border-style: solid solid solid none; + -fx-border-insets: 0 0 0 -2; + -fx-background-insets: 0 0 0 -2; + -fx-background-radius: 0 4 4 0; +} + #totals-separator { -fx-background: #AAAAAA; } diff --git a/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferDataModel.java b/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferDataModel.java index 20da4b83ee..ca3ac4c378 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferDataModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferDataModel.java @@ -89,6 +89,7 @@ class CreateOfferDataModel extends ActivatableDataModel { final StringProperty btcCode = new SimpleStringProperty(); final BooleanProperty isWalletFunded = new SimpleBooleanProperty(); + final BooleanProperty usePercentageBasedPrice = new SimpleBooleanProperty(); //final BooleanProperty isMainNet = new SimpleBooleanProperty(); //final BooleanProperty isFeeFromFundingTxSufficient = new SimpleBooleanProperty(); @@ -96,6 +97,7 @@ class CreateOfferDataModel extends ActivatableDataModel { final ObjectProperty amountAsCoin = new SimpleObjectProperty<>(); final ObjectProperty minAmountAsCoin = new SimpleObjectProperty<>(); final ObjectProperty priceAsFiat = new SimpleObjectProperty<>(); + final ObjectProperty priceAsPercentage = new SimpleObjectProperty<>(); final ObjectProperty volumeAsFiat = new SimpleObjectProperty<>(); final ObjectProperty totalToPayAsCoin = new SimpleObjectProperty<>(); final ObjectProperty missingCoin = new SimpleObjectProperty<>(Coin.ZERO); @@ -253,6 +255,8 @@ class CreateOfferDataModel extends ActivatableDataModel { Offer createAndGetOffer() { long fiatPrice = priceAsFiat.get() != null ? priceAsFiat.get().getValue() : 0L; + + double percentagePrice = 0; long amount = amountAsCoin.get() != null ? amountAsCoin.get().getValue() : 0L; long minAmount = minAmountAsCoin.get() != null ? minAmountAsCoin.get().getValue() : 0L; @@ -284,6 +288,8 @@ class CreateOfferDataModel extends ActivatableDataModel { keyRing.getPubKeyRing(), direction, fiatPrice, + percentagePrice, + usePercentageBasedPrice.get(), amount, minAmount, tradeCurrencyCode.get(), @@ -378,6 +384,10 @@ class CreateOfferDataModel extends ActivatableDataModel { return user.getAcceptedArbitrators().size() > 0; } + public void setUsePercentageBasedPrice(boolean usePercentageBasedPrice) { + this.usePercentageBasedPrice.set(usePercentageBasedPrice); + } + /*boolean isFeeFromFundingTxSufficient() { return !isMainNet.get() || feeFromFundingTxProperty.get().compareTo(FeePolicy.getMinRequiredFeeForFundingTx()) >= 0; }*/ diff --git a/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferView.java b/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferView.java index a8b32b6a06..e49fc624a6 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferView.java @@ -88,8 +88,8 @@ public class CreateOfferView extends ActivatableViewAndModel paymentAccountsComboBox; private ComboBox currencyComboBox; private PopOver totalToPayInfoPopover; + private Label priceAsPercentageLabel; + private ToggleButton fixedPriceButton; + private ToggleButton percentagePriceButton; private OfferView.CloseHandler closeHandler; @@ -175,6 +178,9 @@ public class CreateOfferView extends ActivatableViewAndModel model.tradeCurrencyCode.get() + "/" + model.btcCode.get(), model.btcCode, model.tradeCurrencyCode)); + priceTextField.disableProperty().bind(model.dataModel.usePercentageBasedPrice); + priceAsPercentageTextField.disableProperty().bind(model.dataModel.usePercentageBasedPrice.not()); + priceAsPercentageLabel.prefWidthProperty().bind(priceCurrencyLabel.widthProperty()); volumeCurrencyLabel.textProperty().bind(model.tradeCurrencyCode); minAmountBtcLabel.textProperty().bind(model.btcCode); priceDescriptionLabel.textProperty().bind(createStringBinding(() -> BSResources.get("createOffer.amountPriceBox.priceDescription", model.tradeCurrencyCode.get()), model.tradeCurrencyCode)); @@ -452,6 +461,8 @@ public class CreateOfferView extends ActivatableViewAndModel tuple = add2ButtonsAfterGroup(gridPane, ++gridRow, BSResources.get("createOffer.amountPriceBox.next"), BSResources.get("shared.cancel")); nextButton = tuple.first; @@ -897,7 +908,7 @@ public class CreateOfferView extends ActivatableViewAndModel priceValueCurrencyBoxTuple = FormBuilder.getValueCurrencyBox(BSResources.get("createOffer.price.prompt")); HBox priceValueCurrencyBox = priceValueCurrencyBoxTuple.first; priceTextField = priceValueCurrencyBoxTuple.second; @@ -906,6 +917,26 @@ public class CreateOfferView extends ActivatableViewAndModel { + model.dataModel.setUsePercentageBasedPrice(!newValue); + }); + + percentagePriceButton = new ToggleButton("Percentage"); + percentagePriceButton.setId("toggle-price-right"); + percentagePriceButton.setToggleGroup(toggleGroup); + percentagePriceButton.selectedProperty().addListener((ov, oldValue, newValue) -> { + model.dataModel.setUsePercentageBasedPrice(newValue); + }); + + HBox toggleButtons = new HBox(); + toggleButtons.setPadding(new Insets(18, 0, 0, 0)); + toggleButtons.getChildren().addAll(fixedPriceButton, percentagePriceButton); + // = Label resultLabel = new Label("="); resultLabel.setFont(Font.font("Helvetica-Bold", 20)); @@ -923,7 +954,7 @@ public class CreateOfferView extends ActivatableViewAndModel priceAsPercentageTuple = FormBuilder.getValueCurrencyBox(BSResources.get("createOffer.price.prompt")); + HBox priceAsPercentageValueCurrencyBox = priceAsPercentageTuple.first; + priceAsPercentageTextField = priceAsPercentageTuple.second; + priceAsPercentageLabel = priceAsPercentageTuple.third; + + Tuple2 priceAsPercentageInputBoxTuple = getTradeInputBox(priceAsPercentageValueCurrencyBox, "Distance in % from market price"); + priceAsPercentageInputBoxTuple.first.setPrefWidth(200); + VBox priceAsPercentageInputBox = priceAsPercentageInputBoxTuple.second; + + priceAsPercentageTextField.setPromptText("Enter % value"); + priceAsPercentageLabel.setText("% dist."); + priceAsPercentageLabel.setStyle("-fx-alignment: center;"); + Tuple3 amountValueCurrencyBoxTuple = getValueCurrencyBox(BSResources.get("createOffer.amount.prompt")); HBox amountValueCurrencyBox = amountValueCurrencyBoxTuple.first; minAmountTextField = amountValueCurrencyBoxTuple.second; @@ -939,11 +983,21 @@ public class CreateOfferView extends ActivatableViewAndModel amountInputBoxTuple = getTradeInputBox(amountValueCurrencyBox, BSResources.get("createOffer.amountPriceBox" + ".minAmountDescription")); - VBox box = amountInputBoxTuple.second; - GridPane.setRowIndex(box, ++gridRow); - GridPane.setColumnIndex(box, 1); - GridPane.setMargin(box, new Insets(5, 10, 5, 0)); - gridPane.getChildren().add(box); + + Label xLabel = new Label("x"); + xLabel.setFont(Font.font("Helvetica-Bold", 20)); + 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); } diff --git a/gui/src/test/java/io/bitsquare/gui/main/offer/offerbook/OfferBookViewModelTest.java b/gui/src/test/java/io/bitsquare/gui/main/offer/offerbook/OfferBookViewModelTest.java index c609f861f2..40c259c712 100644 --- a/gui/src/test/java/io/bitsquare/gui/main/offer/offerbook/OfferBookViewModelTest.java +++ b/gui/src/test/java/io/bitsquare/gui/main/offer/offerbook/OfferBookViewModelTest.java @@ -267,6 +267,8 @@ public class OfferBookViewModelTest { null, 0, 0, + false, + 0, 0, tradeCurrencyCode, null,