From aa496c6920f94cefb6361c0bc22bdf22792ecb69 Mon Sep 17 00:00:00 2001 From: axpoems <145597137+axpoems@users.noreply.github.com> Date: Sat, 2 Nov 2024 16:58:24 +0100 Subject: [PATCH 01/33] refactor: rename trade wizard direction and market package --- .../content/bisq_easy/trade_wizard/TradeWizardController.java | 2 +- .../TradeWizardDirectionAndMarketController.java | 2 +- .../TradeWizardDirectionAndMarketModel.java | 2 +- .../TradeWizardDirectionAndMarketView.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/{directionAndMarket => direction_and_market}/TradeWizardDirectionAndMarketController.java (99%) rename apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/{directionAndMarket => direction_and_market}/TradeWizardDirectionAndMarketModel.java (99%) rename apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/{directionAndMarket => direction_and_market}/TradeWizardDirectionAndMarketView.java (99%) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardController.java index f6592e6b1e..dc0bdb6287 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardController.java @@ -27,7 +27,7 @@ import bisq.desktop.common.view.Navigation; import bisq.desktop.common.view.NavigationController; import bisq.desktop.main.content.bisq_easy.trade_wizard.amount.TradeWizardAmountController; -import bisq.desktop.main.content.bisq_easy.trade_wizard.directionAndMarket.TradeWizardDirectionAndMarketController; +import bisq.desktop.main.content.bisq_easy.trade_wizard.direction_and_market.TradeWizardDirectionAndMarketController; import bisq.desktop.main.content.bisq_easy.trade_wizard.payment_methods.TradeWizardPaymentMethodsController; import bisq.desktop.main.content.bisq_easy.trade_wizard.price.TradeWizardPriceController; import bisq.desktop.main.content.bisq_easy.trade_wizard.review.TradeWizardReviewController; diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/directionAndMarket/TradeWizardDirectionAndMarketController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/direction_and_market/TradeWizardDirectionAndMarketController.java similarity index 99% rename from apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/directionAndMarket/TradeWizardDirectionAndMarketController.java rename to apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/direction_and_market/TradeWizardDirectionAndMarketController.java index 215d62d802..75a11ed9ef 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/directionAndMarket/TradeWizardDirectionAndMarketController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/direction_and_market/TradeWizardDirectionAndMarketController.java @@ -15,7 +15,7 @@ * along with Bisq. If not, see . */ -package bisq.desktop.main.content.bisq_easy.trade_wizard.directionAndMarket; +package bisq.desktop.main.content.bisq_easy.trade_wizard.direction_and_market; import bisq.bisq_easy.BisqEasyTradeAmountLimits; import bisq.bisq_easy.NavigationTarget; diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/directionAndMarket/TradeWizardDirectionAndMarketModel.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/direction_and_market/TradeWizardDirectionAndMarketModel.java similarity index 99% rename from apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/directionAndMarket/TradeWizardDirectionAndMarketModel.java rename to apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/direction_and_market/TradeWizardDirectionAndMarketModel.java index ba36528585..869af92407 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/directionAndMarket/TradeWizardDirectionAndMarketModel.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/direction_and_market/TradeWizardDirectionAndMarketModel.java @@ -15,7 +15,7 @@ * along with Bisq. If not, see . */ -package bisq.desktop.main.content.bisq_easy.trade_wizard.directionAndMarket; +package bisq.desktop.main.content.bisq_easy.trade_wizard.direction_and_market; import bisq.common.currency.Market; import bisq.desktop.common.view.Model; diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/directionAndMarket/TradeWizardDirectionAndMarketView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/direction_and_market/TradeWizardDirectionAndMarketView.java similarity index 99% rename from apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/directionAndMarket/TradeWizardDirectionAndMarketView.java rename to apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/direction_and_market/TradeWizardDirectionAndMarketView.java index 0eec84d2a7..77a15dc53e 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/directionAndMarket/TradeWizardDirectionAndMarketView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/direction_and_market/TradeWizardDirectionAndMarketView.java @@ -15,7 +15,7 @@ * along with Bisq. If not, see . */ -package bisq.desktop.main.content.bisq_easy.trade_wizard.directionAndMarket; +package bisq.desktop.main.content.bisq_easy.trade_wizard.direction_and_market; import bisq.common.currency.FiatCurrency; import bisq.common.currency.Market; From c899d6ac63c173e8d10c00dabca06d92f8040650 Mon Sep 17 00:00:00 2001 From: axpoems <145597137+axpoems@users.noreply.github.com> Date: Sun, 3 Nov 2024 08:48:36 +0100 Subject: [PATCH 02/33] Add new page to trade wizard consolidating amount and price --- .../trade_wizard/TradeWizardController.java | 8 ++- .../trade_wizard/TradeWizardView.java | 12 +++-- .../TradeWizardAmountAndPriceController.java | 51 +++++++++++++++++++ .../TradeWizardAmountAndPriceModel.java | 31 +++++++++++ .../TradeWizardAmountAndPriceView.java | 46 +++++++++++++++++ .../java/bisq/bisq_easy/NavigationTarget.java | 1 + i18n/src/main/resources/bisq_easy.properties | 1 + 7 files changed, 145 insertions(+), 5 deletions(-) create mode 100644 apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceController.java create mode 100644 apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceModel.java create mode 100644 apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardController.java index dc0bdb6287..4e82bcc575 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardController.java @@ -27,6 +27,7 @@ import bisq.desktop.common.view.Navigation; import bisq.desktop.common.view.NavigationController; import bisq.desktop.main.content.bisq_easy.trade_wizard.amount.TradeWizardAmountController; +import bisq.desktop.main.content.bisq_easy.trade_wizard.amount_and_price.TradeWizardAmountAndPriceController; import bisq.desktop.main.content.bisq_easy.trade_wizard.direction_and_market.TradeWizardDirectionAndMarketController; import bisq.desktop.main.content.bisq_easy.trade_wizard.payment_methods.TradeWizardPaymentMethodsController; import bisq.desktop.main.content.bisq_easy.trade_wizard.price.TradeWizardPriceController; @@ -68,6 +69,7 @@ public InitData(boolean isCreateOfferMode) { @Getter private final TradeWizardView view; private final TradeWizardDirectionAndMarketController tradeWizardDirectionAndMarketController; + private final TradeWizardAmountAndPriceController tradeWizardAmountAndPriceController; private final TradeWizardPriceController tradeWizardPriceController; private final TradeWizardAmountController tradeWizardAmountController; private final TradeWizardPaymentMethodsController tradeWizardPaymentMethodsController; @@ -92,6 +94,7 @@ public TradeWizardController(ServiceProvider serviceProvider) { this::onNext, this::setMainButtonsVisibleState, this::closeAndNavigateTo); + tradeWizardAmountAndPriceController = new TradeWizardAmountAndPriceController(serviceProvider, view.getRoot()); tradeWizardPriceController = new TradeWizardPriceController(serviceProvider, view.getRoot()); tradeWizardAmountController = new TradeWizardAmountController(serviceProvider, view.getRoot()); tradeWizardPaymentMethodsController = new TradeWizardPaymentMethodsController(serviceProvider, view.getRoot(), this::onNext); @@ -131,6 +134,7 @@ public void onActivate() { model.getChildTargets().clear(); model.getChildTargets().addAll(List.of( NavigationTarget.TRADE_WIZARD_DIRECTION_AND_MARKET, + NavigationTarget.TRADE_WIZARD_AMOUNT_AND_PRICE, NavigationTarget.TRADE_WIZARD_AMOUNT, NavigationTarget.TRADE_WIZARD_PAYMENT_METHODS, NavigationTarget.TRADE_WIZARD_TAKE_OFFER_OFFER, @@ -138,7 +142,7 @@ public void onActivate() { )); if (model.getPriceProgressItemVisible().get()) { - model.getChildTargets().add(2, NavigationTarget.TRADE_WIZARD_PRICE); + model.getChildTargets().add(3, NavigationTarget.TRADE_WIZARD_PRICE); } else { model.getChildTargets().remove(NavigationTarget.TRADE_WIZARD_PRICE); } @@ -233,6 +237,7 @@ protected void onNavigationTargetApplied(NavigationTarget navigationTarget, Opti protected Optional createController(NavigationTarget navigationTarget) { return switch (navigationTarget) { case TRADE_WIZARD_DIRECTION_AND_MARKET -> Optional.of(tradeWizardDirectionAndMarketController); + case TRADE_WIZARD_AMOUNT_AND_PRICE -> Optional.of(tradeWizardAmountAndPriceController); case TRADE_WIZARD_PRICE -> Optional.of(tradeWizardPriceController); case TRADE_WIZARD_PAYMENT_METHODS -> Optional.of(tradeWizardPaymentMethodsController); case TRADE_WIZARD_AMOUNT -> Optional.of(tradeWizardAmountController); @@ -328,6 +333,7 @@ private void reset() { resetSelectedChildTarget(); tradeWizardDirectionAndMarketController.reset(); + tradeWizardAmountAndPriceController.reset(); tradeWizardPriceController.reset(); tradeWizardAmountController.reset(); tradeWizardPaymentMethodsController.reset(); diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardView.java index 00787d09b7..ff41e70988 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardView.java @@ -146,13 +146,13 @@ protected void onViewAttached() { priceProgressItemVisiblePin = EasyBind.subscribe(model.getPriceProgressItemVisible(), isVisible -> { if (isVisible) { if (!progressItemsBox.getChildren().contains(priceProgressItemLine)) { - progressItemsBox.getChildren().add(5, priceProgressItemLine); + progressItemsBox.getChildren().add(7, priceProgressItemLine); } if (!progressItemsBox.getChildren().contains(priceProgressItemLabel)) { - progressItemsBox.getChildren().add(5, priceProgressItemLabel); + progressItemsBox.getChildren().add(7, priceProgressItemLabel); } if (!progressLabelList.contains(priceProgressItemLabel)) { - progressLabelList.add(2, priceProgressItemLabel); + progressLabelList.add(3, priceProgressItemLabel); } } else { progressItemsBox.getChildren().remove(priceProgressItemLine); @@ -207,6 +207,7 @@ private Triple> getProgressItems() { Label directionAndMarket = createAndGetProgressLabel(Res.get("bisqEasy.tradeWizard.progress.directionAndMarket")); priceProgressItemLabel = createAndGetProgressLabel(Res.get("bisqEasy.tradeWizard.progress.price")); priceProgressItemLine = getHLine(); + Label amountAtPrice = createAndGetProgressLabel(Res.get("bisqEasy.tradeWizard.progress.amountAndPrice")); Label amount = createAndGetProgressLabel(Res.get("bisqEasy.tradeWizard.progress.amount")); Label paymentMethods = createAndGetProgressLabel(Res.get("bisqEasy.tradeWizard.progress.paymentMethods")); takeOfferProgressItem = createAndGetProgressLabel(Res.get("bisqEasy.tradeWizard.progress.takeOffer")); @@ -225,6 +226,8 @@ private Triple> getProgressItems() { hBox.getChildren().addAll(Spacer.fillHBox(), directionAndMarket, getHLine(), + amountAtPrice, + getHLine(), amount, getHLine(), paymentMethods, @@ -235,7 +238,8 @@ private Triple> getProgressItems() { Spacer.fillHBox(), closeButton); - return new Triple<>(hBox, closeButton, new ArrayList<>(List.of(directionAndMarket, amount, paymentMethods, takeOfferProgressItem, review))); + return new Triple<>(hBox, closeButton, new ArrayList<>(List.of(directionAndMarket, amountAtPrice, amount, + paymentMethods, takeOfferProgressItem, review))); } private Region getHLine() { diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceController.java new file mode 100644 index 0000000000..64fd82a0d6 --- /dev/null +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceController.java @@ -0,0 +1,51 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.desktop.main.content.bisq_easy.trade_wizard.amount_and_price; + +import bisq.desktop.ServiceProvider; +import bisq.desktop.common.view.Controller; +import javafx.scene.layout.Region; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class TradeWizardAmountAndPriceController implements Controller { + + private final TradeWizardAmountAndPriceModel model; + @Getter + private final TradeWizardAmountAndPriceView view; + private final Region owner; + + public TradeWizardAmountAndPriceController(ServiceProvider serviceProvider, Region owner) { + this.owner = owner; + model = new TradeWizardAmountAndPriceModel(); + view = new TradeWizardAmountAndPriceView(model, this); + } + + @Override + public void onActivate() { + } + + @Override + public void onDeactivate() { + } + + public void reset() { + model.reset(); + } +} diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceModel.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceModel.java new file mode 100644 index 0000000000..7f46fc1bc7 --- /dev/null +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceModel.java @@ -0,0 +1,31 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.desktop.main.content.bisq_easy.trade_wizard.amount_and_price; + +import bisq.desktop.common.view.Model; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Getter +public class TradeWizardAmountAndPriceModel implements Model { + + public void reset() { + + } +} diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java new file mode 100644 index 0000000000..692a400aff --- /dev/null +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java @@ -0,0 +1,46 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.desktop.main.content.bisq_easy.trade_wizard.amount_and_price; + +import bisq.desktop.common.view.View; +import javafx.scene.control.Label; +import javafx.scene.layout.StackPane; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class TradeWizardAmountAndPriceView extends View { + + + public TradeWizardAmountAndPriceView(TradeWizardAmountAndPriceModel model, + TradeWizardAmountAndPriceController controller) { + super(new StackPane(), model, controller); + + Label label = new Label("Testing"); + root.getChildren().add(label); + } + + @Override + protected void onViewAttached() { + + } + + @Override + protected void onViewDetached() { + + } +} diff --git a/bisq-easy/src/main/java/bisq/bisq_easy/NavigationTarget.java b/bisq-easy/src/main/java/bisq/bisq_easy/NavigationTarget.java index 16fba9ee1c..9d095d47af 100644 --- a/bisq-easy/src/main/java/bisq/bisq_easy/NavigationTarget.java +++ b/bisq-easy/src/main/java/bisq/bisq_easy/NavigationTarget.java @@ -52,6 +52,7 @@ public enum NavigationTarget { TRADE_WIZARD(OVERLAY, false), TRADE_WIZARD_DIRECTION_AND_MARKET(TRADE_WIZARD, false), + TRADE_WIZARD_AMOUNT_AND_PRICE(TRADE_WIZARD, false), TRADE_WIZARD_PRICE(TRADE_WIZARD, false), TRADE_WIZARD_AMOUNT(TRADE_WIZARD, false), TRADE_WIZARD_PAYMENT_METHODS(TRADE_WIZARD, false), diff --git a/i18n/src/main/resources/bisq_easy.properties b/i18n/src/main/resources/bisq_easy.properties index 78e7e19cb7..53f498d987 100644 --- a/i18n/src/main/resources/bisq_easy.properties +++ b/i18n/src/main/resources/bisq_easy.properties @@ -52,6 +52,7 @@ bisqEasy.onboarding.right.button=Open offerbook ################################################################################ bisqEasy.tradeWizard.progress.directionAndMarket=Offer type +bisqEasy.tradeWizard.progress.amountAndPrice=Amount @ price bisqEasy.tradeWizard.progress.price=Price bisqEasy.tradeWizard.progress.amount=Amount bisqEasy.tradeWizard.progress.paymentMethods=Payment methods From 67866b4753310b5f41eb05d06662ef4f14cdee67 Mon Sep 17 00:00:00 2001 From: axpoems <145597137+axpoems@users.noreply.github.com> Date: Sun, 3 Nov 2024 09:17:04 +0100 Subject: [PATCH 03/33] Use amount component inside amountAndPrice --- .../trade_wizard/TradeWizardController.java | 12 +++++-- .../TradeWizardAmountAndPriceController.java | 35 ++++++++++++++++++- .../TradeWizardAmountAndPriceView.java | 9 +++-- 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardController.java index 4e82bcc575..e8673f3cae 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardController.java @@ -120,6 +120,7 @@ public TradeWizardController(ServiceProvider serviceProvider) { public void initWithData(InitData initData) { boolean isCreateOfferMode = initData.isCreateOfferMode(); model.setCreateOfferMode(isCreateOfferMode); + tradeWizardAmountAndPriceController.setIsCreateOfferMode(isCreateOfferMode); tradeWizardAmountController.setIsCreateOfferMode(isCreateOfferMode); model.getPriceProgressItemVisible().set(isCreateOfferMode); } @@ -141,6 +142,8 @@ public void onActivate() { NavigationTarget.TRADE_WIZARD_REVIEW_OFFER )); + // TODO: for take offer wizard we only want to add amount component + if (model.getPriceProgressItemVisible().get()) { model.getChildTargets().add(3, NavigationTarget.TRADE_WIZARD_PRICE); } else { @@ -149,6 +152,7 @@ public void onActivate() { directionPin = EasyBind.subscribe(tradeWizardDirectionAndMarketController.getDirection(), direction -> { tradeWizardSelectOfferController.setDirection(direction); + tradeWizardAmountAndPriceController.setDirection(direction); tradeWizardAmountController.setDirection(direction); tradeWizardPaymentMethodsController.setDirection(direction); tradeWizardPriceController.setDirection(direction); @@ -156,6 +160,7 @@ public void onActivate() { marketPin = EasyBind.subscribe(tradeWizardDirectionAndMarketController.getMarket(), market -> { tradeWizardSelectOfferController.setMarket(market); tradeWizardPaymentMethodsController.setMarket(market); + tradeWizardAmountAndPriceController.setMarket(market); tradeWizardPriceController.setMarket(market); tradeWizardAmountController.setMarket(market); updateNextButtonDisabledState(); @@ -164,6 +169,7 @@ public void onActivate() { tradeWizardSelectOfferController::setQuoteSideAmountSpec); priceSpecPin = EasyBind.subscribe(tradeWizardPriceController.getPriceSpec(), priceSpec -> { + tradeWizardAmountAndPriceController.updateQuoteSideAmountSpecWithPriceSpec(priceSpec); tradeWizardAmountController.updateQuoteSideAmountSpecWithPriceSpec(priceSpec); tradeWizardSelectOfferController.setPriceSpec(priceSpec); }); @@ -205,7 +211,7 @@ protected void onStartProcessNavigationTarget(NavigationTarget navigationTarget, tradeWizardDirectionAndMarketController.getMarket().get(), tradeWizardPaymentMethodsController.getBitcoinPaymentMethods(), tradeWizardPaymentMethodsController.getFiatPaymentMethods(), - tradeWizardAmountController.getQuoteSideAmountSpec().get(), + tradeWizardAmountAndPriceController.getQuoteSideAmountSpec().get(), tradeWizardPriceController.getPriceSpec().get() ); model.getNextButtonText().set(Res.get("bisqEasy.tradeWizard.review.nextButton.createOffer")); @@ -303,7 +309,9 @@ void onBack() { } private boolean validate(boolean calledFromNext) { - if (model.getSelectedChildTarget().get() == NavigationTarget.TRADE_WIZARD_PRICE) { + if (model.getSelectedChildTarget().get() == NavigationTarget.TRADE_WIZARD_AMOUNT_AND_PRICE) { + return tradeWizardAmountAndPriceController.validate(); + } else if (model.getSelectedChildTarget().get() == NavigationTarget.TRADE_WIZARD_PRICE) { return tradeWizardPriceController.validate(); } else if (model.getSelectedChildTarget().get() == NavigationTarget.TRADE_WIZARD_AMOUNT) { return tradeWizardAmountController.validate(); diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceController.java index 64fd82a0d6..7fcd6b2398 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceController.java @@ -17,8 +17,14 @@ package bisq.desktop.main.content.bisq_easy.trade_wizard.amount_and_price; +import bisq.common.currency.Market; import bisq.desktop.ServiceProvider; import bisq.desktop.common.view.Controller; +import bisq.desktop.main.content.bisq_easy.trade_wizard.amount.TradeWizardAmountController; +import bisq.offer.Direction; +import bisq.offer.amount.spec.QuoteSideAmountSpec; +import bisq.offer.price.spec.PriceSpec; +import javafx.beans.property.ReadOnlyObjectProperty; import javafx.scene.layout.Region; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -30,11 +36,14 @@ public class TradeWizardAmountAndPriceController implements Controller { @Getter private final TradeWizardAmountAndPriceView view; private final Region owner; + private final TradeWizardAmountController tradeWizardAmountController; public TradeWizardAmountAndPriceController(ServiceProvider serviceProvider, Region owner) { this.owner = owner; + tradeWizardAmountController = new TradeWizardAmountController(serviceProvider, owner); + model = new TradeWizardAmountAndPriceModel(); - view = new TradeWizardAmountAndPriceView(model, this); + view = new TradeWizardAmountAndPriceView(model, this, tradeWizardAmountController.getView().getRoot()); } @Override @@ -48,4 +57,28 @@ public void onDeactivate() { public void reset() { model.reset(); } + + public void setIsCreateOfferMode(boolean isCreateOfferMode) { + tradeWizardAmountController.setIsCreateOfferMode(isCreateOfferMode); + } + + public void setDirection(Direction direction) { + tradeWizardAmountController.setDirection(direction); + } + + public void setMarket(Market market) { + tradeWizardAmountController.setMarket(market); + } + + public void updateQuoteSideAmountSpecWithPriceSpec(PriceSpec priceSpec) { + tradeWizardAmountController.updateQuoteSideAmountSpecWithPriceSpec(priceSpec); + } + + public ReadOnlyObjectProperty getQuoteSideAmountSpec() { + return tradeWizardAmountController.getQuoteSideAmountSpec(); + } + + public boolean validate() { + return tradeWizardAmountController.validate(); + } } diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java index 692a400aff..fba4084c58 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java @@ -19,6 +19,8 @@ import bisq.desktop.common.view.View; import javafx.scene.control.Label; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Pane; import javafx.scene.layout.StackPane; import lombok.extern.slf4j.Slf4j; @@ -27,11 +29,12 @@ public class TradeWizardAmountAndPriceView extends View Date: Sun, 3 Nov 2024 10:04:06 +0100 Subject: [PATCH 04/33] Add new amount model selection --- .../amount/TradeWizardAmountView.java | 22 +++++++++++++++++-- .../price/TradeWizardPriceView.java | 12 +++++----- .../src/main/resources/css/bisq_easy.css | 12 ++++++---- i18n/src/main/resources/bisq_easy.properties | 4 ++++ 4 files changed, 38 insertions(+), 12 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java index c64f435ae8..371627e1c0 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java @@ -45,7 +45,7 @@ public class TradeWizardAmountView extends View { - private static final String SELECTED_PRICE_MODEL_STYLE_CLASS = "selected-price-model"; + private static final String SELECTED_PRICE_MODEL_STYLE_CLASS = "selected-model"; private final MaterialTextField percentageInput; private final VBox fieldsBox, learnWhyOverlay, content; @@ -70,20 +70,20 @@ public TradeWizardPriceView(TradeWizardPriceModel model, TradeWizardPriceControl // Pricing model selection percentagePrice = new Button(Res.get("bisqEasy.price.percentage.title")); - percentagePrice.getStyleClass().add("price-item"); + percentagePrice.getStyleClass().add("model-selection-item"); fixedPrice = new Button(Res.get("bisqEasy.price.tradePrice.title")); - fixedPrice.getStyleClass().add("price-item"); + fixedPrice.getStyleClass().add("model-selection-item"); Label separator = new Label("|"); HBox percentagePriceBox = new HBox(percentagePrice); - percentagePriceBox.getStyleClass().add("price-item-box"); + percentagePriceBox.getStyleClass().add("model-selection-item-box"); percentagePriceBox.setAlignment(Pos.CENTER_RIGHT); HBox fixedPriceBox = new HBox(fixedPrice); - fixedPriceBox.getStyleClass().add("price-item-box"); + fixedPriceBox.getStyleClass().add("model-selection-item-box"); fixedPriceBox.setAlignment(Pos.CENTER_LEFT); HBox pricingModels = new HBox(30, percentagePriceBox, separator, fixedPriceBox); - pricingModels.getStyleClass().addAll("pricing-models", "bisq-text-3"); + pricingModels.getStyleClass().addAll("selection-models", "bisq-text-3"); // Input box percentageInput = new MaterialTextField(Res.get("bisqEasy.price.percentage.inputBoxText")); diff --git a/apps/desktop/desktop/src/main/resources/css/bisq_easy.css b/apps/desktop/desktop/src/main/resources/css/bisq_easy.css index d66f34cc63..3e0d613e41 100644 --- a/apps/desktop/desktop/src/main/resources/css/bisq_easy.css +++ b/apps/desktop/desktop/src/main/resources/css/bisq_easy.css @@ -720,25 +720,29 @@ -fx-alignment: center; } -.bisq-easy-trade-wizard-price-step .pricing-models { +.bisq-easy-trade-wizard-price-step .selection-models, +.bisq-easy-trade-wizard-amount-step .selection-models { -fx-alignment: center; -fx-padding: 10 0 10 0; } -.bisq-easy-trade-wizard-price-step .pricing-models .price-item-box { +.bisq-easy-trade-wizard-price-step .selection-models .model-selection-item-box, +.bisq-easy-trade-wizard-amount-step .selection-models .model-selection-item-box { -fx-max-width: 300; -fx-min-width: 300; -fx-pref-width: 300; } -.bisq-easy-trade-wizard-price-step .pricing-models .price-item-box .price-item { +.bisq-easy-trade-wizard-price-step .selection-models .model-selection-item-box .model-selection-item, +.bisq-easy-trade-wizard-amount-step .selection-models .model-selection-item-box .model-selection-item { -fx-padding: 5; -fx-background-color: transparent; -fx-fill: -fx-mid-text-color; -fx-text-fill: -fx-mid-text-color; } -.bisq-easy-trade-wizard-price-step .selected-price-model { +.bisq-easy-trade-wizard-price-step .selected-model, +.bisq-easy-trade-wizard-amount-step .selected-model { -fx-fill: -bisq2-green !important; -fx-text-fill: -bisq2-green !important; } diff --git a/i18n/src/main/resources/bisq_easy.properties b/i18n/src/main/resources/bisq_easy.properties index 53f498d987..5f5e04921d 100644 --- a/i18n/src/main/resources/bisq_easy.properties +++ b/i18n/src/main/resources/bisq_easy.properties @@ -134,8 +134,12 @@ bisqEasy.tradeWizard.amount.headline.seller=How much do you want to receive? bisqEasy.tradeWizard.amount.description.minAmount=Set the minimum value for the amount range bisqEasy.tradeWizard.amount.description.maxAmount=Set the maximum value for the amount range bisqEasy.tradeWizard.amount.description.fixAmount=Set the amount you want to trade +bisqEasy.tradeWizard.amount.amountModel.fixedAmount=Fixed amount +bisqEasy.tradeWizard.amount.amountModel.rangeAmount=Range amount + bisqEasy.tradeWizard.amount.addMinAmountOption=Add min/max range for amount bisqEasy.tradeWizard.amount.removeMinAmountOption=Use fix value amount + bisqEasy.component.amount.minRangeValue=Min {0} bisqEasy.component.amount.maxRangeValue=Max {0} bisqEasy.component.amount.baseSide.tooltip.btcAmount.marketPrice=This is the Bitcoin amount with current market price. From 640f61763fb52dbd39c9b6bdef5e3c700aa532c1 Mon Sep 17 00:00:00 2001 From: axpoems <145597137+axpoems@users.noreply.github.com> Date: Sun, 3 Nov 2024 12:10:07 +0100 Subject: [PATCH 05/33] Refactor: rename IsMinAmountEnabled to isRangeAmountEnabled --- .../amount/TradeWizardAmountController.java | 24 +++++++++---------- .../amount/TradeWizardAmountModel.java | 11 ++++++--- .../amount/TradeWizardAmountView.java | 4 ++-- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java index f39dd43857..cdadd55d96 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java @@ -117,7 +117,7 @@ public void setIsCreateOfferMode(boolean isCreateOfferMode) { model.setCreateOfferMode(isCreateOfferMode); model.getShowRangeAmounts().set(isCreateOfferMode); if (!isCreateOfferMode) { - model.getIsMinAmountEnabled().set(false); + model.getIsRangeAmountEnabled().set(false); } } @@ -202,7 +202,7 @@ public ReadOnlyObjectProperty getQuoteSideAmountSpec() { } public ReadOnlyBooleanProperty getIsMinAmountEnabled() { - return model.getIsMinAmountEnabled(); + return model.getIsRangeAmountEnabled(); } @Override @@ -217,11 +217,11 @@ public void onActivate() { Res.get("bisqEasy.tradeWizard.amount.headline.seller")); Boolean cookieValue = settingsService.getCookie().asBoolean(CookieKey.CREATE_BISQ_EASY_OFFER_IS_MIN_AMOUNT_ENABLED).orElse(false); - model.getIsMinAmountEnabled().set(cookieValue && model.getShowRangeAmounts().get()); + model.getIsRangeAmountEnabled().set(cookieValue && model.getShowRangeAmounts().get()); minAmountCompBaseSideAmountPin = EasyBind.subscribe(minAmountComponent.getBaseSideAmount(), value -> { - if (model.getIsMinAmountEnabled().get()) { + if (model.getIsRangeAmountEnabled().get()) { if (value != null && maxOrFixAmountComponent.getBaseSideAmount().get() != null && value.getValue() > maxOrFixAmountComponent.getBaseSideAmount().get().getValue()) { maxOrFixAmountComponent.setBaseSideAmount(value); @@ -231,7 +231,7 @@ public void onActivate() { maxOrFixAmountCompBaseSideAmountPin = EasyBind.subscribe(maxOrFixAmountComponent.getBaseSideAmount(), value -> { if (value != null && - model.getIsMinAmountEnabled().get() && + model.getIsRangeAmountEnabled().get() && minAmountComponent.getBaseSideAmount().get() != null && value.getValue() < minAmountComponent.getBaseSideAmount().get().getValue()) { minAmountComponent.setBaseSideAmount(value); @@ -241,7 +241,7 @@ public void onActivate() { minAmountCompQuoteSideAmountPin = EasyBind.subscribe(minAmountComponent.getQuoteSideAmount(), value -> { if (value != null) { - if (model.getIsMinAmountEnabled().get() && + if (model.getIsRangeAmountEnabled().get() && maxOrFixAmountComponent.getQuoteSideAmount().get() != null && value.getValue() > maxOrFixAmountComponent.getQuoteSideAmount().get().getValue()) { maxOrFixAmountComponent.setQuoteSideAmount(value); @@ -253,7 +253,7 @@ public void onActivate() { maxAmountCompQuoteSideAmountPin = EasyBind.subscribe(maxOrFixAmountComponent.getQuoteSideAmount(), value -> { if (value != null) { - if (model.getIsMinAmountEnabled().get() && + if (model.getIsRangeAmountEnabled().get() && minAmountComponent.getQuoteSideAmount().get() != null && value.getValue() < minAmountComponent.getQuoteSideAmount().get().getValue()) { minAmountComponent.setQuoteSideAmount(value); @@ -263,7 +263,7 @@ public void onActivate() { } }); - isMinAmountEnabledPin = EasyBind.subscribe(model.getIsMinAmountEnabled(), isMinAmountEnabled -> { + isMinAmountEnabledPin = EasyBind.subscribe(model.getIsRangeAmountEnabled(), isMinAmountEnabled -> { model.getToggleButtonText().set(isMinAmountEnabled ? Res.get("bisqEasy.tradeWizard.amount.removeMinAmountOption") : Res.get("bisqEasy.tradeWizard.amount.addMinAmountOption")); @@ -342,8 +342,8 @@ void onOpenWiki(String url) { } void onToggleMinAmountVisibility() { - boolean value = !model.getIsMinAmountEnabled().get(); - model.getIsMinAmountEnabled().set(value); + boolean value = !model.getIsRangeAmountEnabled().get(); + model.getIsRangeAmountEnabled().set(value); quoteSideAmountsChanged(!value); settingsService.setCookie(CookieKey.CREATE_BISQ_EASY_OFFER_IS_MIN_AMOUNT_ENABLED, value); } @@ -354,7 +354,7 @@ private void applyAmountSpec() { return; } - if (model.getIsMinAmountEnabled().get()) { + if (model.getIsRangeAmountEnabled().get()) { Long minAmount = getAmountValue(minAmountComponent.getQuoteSideAmount()); checkNotNull(minAmount); if (maxOrFixAmount.compareTo(minAmount) < 0) { @@ -527,7 +527,7 @@ private void quoteSideAmountsChanged(boolean maxAmountChanged) { // Buyer String formattedAmountWithoutReputationNeeded = formatAmountWithCode(amountWithoutReputationNeeded); String formattedMaxOrFixedAmount = formatAmountWithCode(maxOrFixedQuoteSideAmount); - if (model.getIsMinAmountEnabled().get()) { + if (model.getIsRangeAmountEnabled().get()) { // Amount range String formattedMinAmount = formatAmountWithCode(minQuoteSideAmount); boolean noReputationNeededForMinAmount = minQuoteSideAmount.isLessThanOrEqual(amountWithoutReputationNeeded); diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountModel.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountModel.java index e3fb78f4ba..28ce6168e6 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountModel.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountModel.java @@ -26,7 +26,12 @@ import bisq.desktop.common.view.Model; import bisq.offer.Direction; import bisq.offer.amount.spec.QuoteSideAmountSpec; -import javafx.beans.property.*; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; import lombok.Getter; import lombok.Setter; @@ -64,7 +69,7 @@ public class TradeWizardAmountModel implements Model { @Setter private long myReputationScore; private final BooleanProperty showRangeAmounts = new SimpleBooleanProperty(); - private final BooleanProperty isMinAmountEnabled = new SimpleBooleanProperty(); + private final BooleanProperty isRangeAmountEnabled = new SimpleBooleanProperty(); private final BooleanProperty isAmountLimitInfoOverlayVisible = new SimpleBooleanProperty(); private final BooleanProperty isWarningIconVisible = new SimpleBooleanProperty(); private final BooleanProperty isLearnMoreVisible = new SimpleBooleanProperty(); @@ -89,7 +94,7 @@ public void reset() { isCreateOfferMode = false; baseSideAmount = Optional.empty(); showRangeAmounts.set(false); - isMinAmountEnabled.set(false); + isRangeAmountEnabled.set(false); isAmountLimitInfoOverlayVisible.set(false); isWarningIconVisible.set(false); isLearnMoreVisible.set(false); diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java index 371627e1c0..e99d2841b7 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java @@ -144,8 +144,8 @@ protected void onViewAttached() { warningIcon.visibleProperty().bind(model.getIsWarningIconVisible()); amountLimitInfoAmount.visibleProperty().bind(model.getAmountLimitInfoAmount().isEmpty().not()); amountLimitInfoAmount.managedProperty().bind(model.getAmountLimitInfoAmount().isEmpty().not()); - minAmountRoot.visibleProperty().bind(model.getIsMinAmountEnabled()); - minAmountRoot.managedProperty().bind(model.getIsMinAmountEnabled()); + minAmountRoot.visibleProperty().bind(model.getIsRangeAmountEnabled()); + minAmountRoot.managedProperty().bind(model.getIsRangeAmountEnabled()); toggleButton.visibleProperty().bind(model.getShowRangeAmounts()); toggleButton.managedProperty().bind(model.getShowRangeAmounts()); From a76fc47ae33bd3bfa14aac0bd1c18faf74b6ee1d Mon Sep 17 00:00:00 2001 From: axpoems <145597137+axpoems@users.noreply.github.com> Date: Sun, 3 Nov 2024 12:33:26 +0100 Subject: [PATCH 06/33] Add logic to new amount model selection buttons --- .../amount/TradeWizardAmountController.java | 31 +++++++++++++------ .../amount/TradeWizardAmountView.java | 27 ++++++++++++++-- 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java index cdadd55d96..0ef868f25e 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java @@ -41,7 +41,11 @@ import bisq.offer.Direction; import bisq.offer.Offer; import bisq.offer.amount.OfferAmountUtil; -import bisq.offer.amount.spec.*; +import bisq.offer.amount.spec.AmountSpecUtil; +import bisq.offer.amount.spec.FixedAmountSpec; +import bisq.offer.amount.spec.QuoteSideAmountSpec; +import bisq.offer.amount.spec.QuoteSideFixedAmountSpec; +import bisq.offer.amount.spec.QuoteSideRangeAmountSpec; import bisq.offer.bisq_easy.BisqEasyOffer; import bisq.offer.payment_method.BitcoinPaymentMethodSpec; import bisq.offer.payment_method.FiatPaymentMethodSpec; @@ -56,7 +60,6 @@ import bisq.user.profile.UserProfile; import bisq.user.profile.UserProfileService; import bisq.user.reputation.ReputationService; -import javafx.beans.property.ReadOnlyBooleanProperty; import javafx.beans.property.ReadOnlyObjectProperty; import javafx.scene.layout.Region; import lombok.Getter; @@ -90,7 +93,7 @@ public class TradeWizardAmountController implements Controller { private final ReputationService reputationService; private final UserIdentityService userIdentityService; private final BisqEasyService bisqEasyService; - private Subscription isMinAmountEnabledPin, maxOrFixAmountCompBaseSideAmountPin, minAmountCompBaseSideAmountPin, + private Subscription isRangeAmountEnabledPin, maxOrFixAmountCompBaseSideAmountPin, minAmountCompBaseSideAmountPin, maxAmountCompQuoteSideAmountPin, minAmountCompQuoteSideAmountPin, priceTooltipPin; public TradeWizardAmountController(ServiceProvider serviceProvider, Region owner) { @@ -201,10 +204,6 @@ public ReadOnlyObjectProperty getQuoteSideAmountSpec() { return model.getQuoteSideAmountSpec(); } - public ReadOnlyBooleanProperty getIsMinAmountEnabled() { - return model.getIsRangeAmountEnabled(); - } - @Override public void onActivate() { applyQuoteSideMinMaxRange(); @@ -263,7 +262,7 @@ public void onActivate() { } }); - isMinAmountEnabledPin = EasyBind.subscribe(model.getIsRangeAmountEnabled(), isMinAmountEnabled -> { + isRangeAmountEnabledPin = EasyBind.subscribe(model.getIsRangeAmountEnabled(), isMinAmountEnabled -> { model.getToggleButtonText().set(isMinAmountEnabled ? Res.get("bisqEasy.tradeWizard.amount.removeMinAmountOption") : Res.get("bisqEasy.tradeWizard.amount.addMinAmountOption")); @@ -309,7 +308,7 @@ public void onActivate() { @Override public void onDeactivate() { - isMinAmountEnabledPin.unsubscribe(); + isRangeAmountEnabledPin.unsubscribe(); maxOrFixAmountCompBaseSideAmountPin.unsubscribe(); maxAmountCompQuoteSideAmountPin.unsubscribe(); minAmountCompBaseSideAmountPin.unsubscribe(); @@ -348,6 +347,20 @@ void onToggleMinAmountVisibility() { settingsService.setCookie(CookieKey.CREATE_BISQ_EASY_OFFER_IS_MIN_AMOUNT_ENABLED, value); } + void useFixedAmount() { + updateIsRangeAmountEnabled(false); + } + + void useRangeAmount() { + updateIsRangeAmountEnabled(true); + } + + private void updateIsRangeAmountEnabled(boolean useRangeAmount) { + model.getIsRangeAmountEnabled().set(useRangeAmount); + quoteSideAmountsChanged(!useRangeAmount); + settingsService.setCookie(CookieKey.CREATE_BISQ_EASY_OFFER_IS_MIN_AMOUNT_ENABLED, useRangeAmount); + } + private void applyAmountSpec() { Long maxOrFixAmount = getAmountValue(maxOrFixAmountComponent.getQuoteSideAmount()); if (maxOrFixAmount == null) { diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java index e99d2841b7..7252ae1ab8 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java @@ -42,13 +42,15 @@ @Slf4j public class TradeWizardAmountView extends View { + private static final String SELECTED_PRICE_MODEL_STYLE_CLASS = "selected-model"; + private final Label headlineLabel, amountLimitInfo, amountLimitInfoLeadLine, amountLimitInfoOverlayInfo, linkToWikiText, warningIcon; private final Hyperlink amountLimitInfoAmount, learnMoreHyperLink, linkToWiki; private final VBox minAmountRoot, content, amountLimitInfoOverlay; private final Button toggleButton, closeOverlayButton, fixedAmount, rangeAmount; - private final HBox amountLimitInfoHBox; + private final HBox amountLimitInfoHBox, amountModelsBox; private final HBox amountLimitInfoWithWarnIcon; - private Subscription isAmountLimitInfoVisiblePin, amountLimitInfoLeadLinePin; + private Subscription isAmountLimitInfoVisiblePin, amountLimitInfoLeadLinePin, isRangeAmountEnabledPin; public TradeWizardAmountView(TradeWizardAmountModel model, TradeWizardAmountController controller, @@ -104,7 +106,7 @@ public TradeWizardAmountView(TradeWizardAmountModel model, rangeAmountBox.getStyleClass().add("model-selection-item-box"); rangeAmountBox.setAlignment(Pos.CENTER_LEFT); - HBox amountModelsBox = new HBox(30, fixedAmountBox, separator, rangeAmountBox); + amountModelsBox = new HBox(30, fixedAmountBox, separator, rangeAmountBox); amountModelsBox.getStyleClass().addAll("selection-models", "bisq-text-3"); toggleButton = new Button(Res.get("bisqEasy.tradeWizard.amount.addMinAmountOption")); @@ -148,6 +150,8 @@ protected void onViewAttached() { minAmountRoot.managedProperty().bind(model.getIsRangeAmountEnabled()); toggleButton.visibleProperty().bind(model.getShowRangeAmounts()); toggleButton.managedProperty().bind(model.getShowRangeAmounts()); + amountModelsBox.visibleProperty().bind(model.getShowRangeAmounts()); + amountModelsBox.managedProperty().bind(model.getShowRangeAmounts()); amountLimitInfoLeadLinePin = EasyBind.subscribe(model.getAmountLimitInfoLeadLine(), value -> { boolean isEmpty = StringUtils.isEmpty(value); @@ -173,11 +177,23 @@ protected void onViewAttached() { } }); + isRangeAmountEnabledPin = EasyBind.subscribe(model.getIsRangeAmountEnabled(), isRangeAmountEnabled -> { + fixedAmount.getStyleClass().remove(SELECTED_PRICE_MODEL_STYLE_CLASS); + rangeAmount.getStyleClass().remove(SELECTED_PRICE_MODEL_STYLE_CLASS); + if (isRangeAmountEnabled) { + rangeAmount.getStyleClass().add(SELECTED_PRICE_MODEL_STYLE_CLASS); + } else { + fixedAmount.getStyleClass().add(SELECTED_PRICE_MODEL_STYLE_CLASS); + } + }); + amountLimitInfoAmount.setOnAction(e -> controller.onSetReputationBasedAmount()); learnMoreHyperLink.setOnAction(e -> controller.onShowAmountLimitInfoOverlay()); linkToWiki.setOnAction(e -> controller.onOpenWiki(linkToWiki.getText())); closeOverlayButton.setOnAction(e -> controller.onCloseAmountLimitInfoOverlay()); toggleButton.setOnAction(e -> controller.onToggleMinAmountVisibility()); + fixedAmount.setOnAction(e -> controller.useFixedAmount()); + rangeAmount.setOnAction(e -> controller.useRangeAmount()); } @Override @@ -196,15 +212,20 @@ protected void onViewDetached() { minAmountRoot.managedProperty().unbind(); amountLimitInfoAmount.visibleProperty().unbind(); amountLimitInfoAmount.managedProperty().unbind(); + amountModelsBox.visibleProperty().unbind(); + amountModelsBox.managedProperty().unbind(); amountLimitInfoLeadLinePin.unsubscribe(); isAmountLimitInfoVisiblePin.unsubscribe(); + isRangeAmountEnabledPin.unsubscribe(); amountLimitInfoAmount.setOnAction(null); learnMoreHyperLink.setOnAction(null); linkToWiki.setOnAction(null); closeOverlayButton.setOnAction(null); toggleButton.setOnAction(null); + fixedAmount.setOnAction(null); + rangeAmount.setOnAction(null); } private static VBox getAmountLimitInfoOverlay(Label amountLimitInfoOverlayInfo, From 352a815e823a42b1bb2efd4d6b2a44f4777d9d91 Mon Sep 17 00:00:00 2001 From: axpoems <145597137+axpoems@users.noreply.github.com> Date: Sun, 3 Nov 2024 12:36:43 +0100 Subject: [PATCH 07/33] Remove old toggle to switch between amount model --- .../amount/TradeWizardAmountController.java | 4 ---- .../amount/TradeWizardAmountModel.java | 2 -- .../trade_wizard/amount/TradeWizardAmountView.java | 14 ++------------ i18n/src/main/resources/bisq_easy.properties | 3 --- 4 files changed, 2 insertions(+), 21 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java index 0ef868f25e..a830af9f31 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java @@ -263,10 +263,6 @@ public void onActivate() { }); isRangeAmountEnabledPin = EasyBind.subscribe(model.getIsRangeAmountEnabled(), isMinAmountEnabled -> { - model.getToggleButtonText().set(isMinAmountEnabled ? - Res.get("bisqEasy.tradeWizard.amount.removeMinAmountOption") : - Res.get("bisqEasy.tradeWizard.amount.addMinAmountOption")); - maxOrFixAmountComponent.setDescription(isMinAmountEnabled ? Res.get("bisqEasy.tradeWizard.amount.description.maxAmount") : Res.get("bisqEasy.tradeWizard.amount.description.fixAmount")); diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountModel.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountModel.java index 28ce6168e6..94e8bd8d75 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountModel.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountModel.java @@ -73,7 +73,6 @@ public class TradeWizardAmountModel implements Model { private final BooleanProperty isAmountLimitInfoOverlayVisible = new SimpleBooleanProperty(); private final BooleanProperty isWarningIconVisible = new SimpleBooleanProperty(); private final BooleanProperty isLearnMoreVisible = new SimpleBooleanProperty(); - private final StringProperty toggleButtonText = new SimpleStringProperty(); private final StringProperty priceTooltip = new SimpleStringProperty(); private final ObjectProperty quoteSideAmountSpec = new SimpleObjectProperty<>(); private final ObjectProperty priceQuote = new SimpleObjectProperty<>(); @@ -98,7 +97,6 @@ public void reset() { isAmountLimitInfoOverlayVisible.set(false); isWarningIconVisible.set(false); isLearnMoreVisible.set(false); - toggleButtonText.set(null); priceTooltip.set(null); quoteSideAmountSpec.set(null); priceQuote.set(null); diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java index 7252ae1ab8..6d49e3cc1f 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java @@ -47,7 +47,7 @@ public class TradeWizardAmountView extends View controller.onShowAmountLimitInfoOverlay()); linkToWiki.setOnAction(e -> controller.onOpenWiki(linkToWiki.getText())); closeOverlayButton.setOnAction(e -> controller.onCloseAmountLimitInfoOverlay()); - toggleButton.setOnAction(e -> controller.onToggleMinAmountVisibility()); fixedAmount.setOnAction(e -> controller.useFixedAmount()); rangeAmount.setOnAction(e -> controller.useRangeAmount()); } @Override protected void onViewDetached() { - toggleButton.textProperty().unbind(); amountLimitInfo.textProperty().unbind(); amountLimitInfoLeadLine.textProperty().unbind(); amountLimitInfoAmount.textProperty().unbind(); @@ -223,7 +214,6 @@ protected void onViewDetached() { learnMoreHyperLink.setOnAction(null); linkToWiki.setOnAction(null); closeOverlayButton.setOnAction(null); - toggleButton.setOnAction(null); fixedAmount.setOnAction(null); rangeAmount.setOnAction(null); } diff --git a/i18n/src/main/resources/bisq_easy.properties b/i18n/src/main/resources/bisq_easy.properties index 5f5e04921d..84a2287713 100644 --- a/i18n/src/main/resources/bisq_easy.properties +++ b/i18n/src/main/resources/bisq_easy.properties @@ -137,9 +137,6 @@ bisqEasy.tradeWizard.amount.description.fixAmount=Set the amount you want to tra bisqEasy.tradeWizard.amount.amountModel.fixedAmount=Fixed amount bisqEasy.tradeWizard.amount.amountModel.rangeAmount=Range amount -bisqEasy.tradeWizard.amount.addMinAmountOption=Add min/max range for amount -bisqEasy.tradeWizard.amount.removeMinAmountOption=Use fix value amount - bisqEasy.component.amount.minRangeValue=Min {0} bisqEasy.component.amount.maxRangeValue=Max {0} bisqEasy.component.amount.baseSide.tooltip.btcAmount.marketPrice=This is the Bitcoin amount with current market price. From d78b85f3300e5d88851a3bbb5ec17f4f7a547499 Mon Sep 17 00:00:00 2001 From: axpoems <145597137+axpoems@users.noreply.github.com> Date: Sun, 3 Nov 2024 12:45:52 +0100 Subject: [PATCH 08/33] Remove old description texts --- .../amount/TradeWizardAmountController.java | 17 +---------------- i18n/src/main/resources/bisq_easy.properties | 3 --- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java index a830af9f31..744d0beb46 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java @@ -108,7 +108,6 @@ public TradeWizardAmountController(ServiceProvider serviceProvider, Region owner model = new TradeWizardAmountModel(); minAmountComponent = new AmountComponent(serviceProvider, true); - minAmountComponent.setDescription(Res.get("bisqEasy.tradeWizard.amount.description.minAmount")); maxOrFixAmountComponent = new AmountComponent(serviceProvider, true); view = new TradeWizardAmountView(model, this, @@ -262,14 +261,7 @@ public void onActivate() { } }); - isRangeAmountEnabledPin = EasyBind.subscribe(model.getIsRangeAmountEnabled(), isMinAmountEnabled -> { - maxOrFixAmountComponent.setDescription(isMinAmountEnabled ? - Res.get("bisqEasy.tradeWizard.amount.description.maxAmount") : - Res.get("bisqEasy.tradeWizard.amount.description.fixAmount")); - - applyAmountSpec(); - }); - + isRangeAmountEnabledPin = EasyBind.subscribe(model.getIsRangeAmountEnabled(), isMinAmountEnabled -> applyAmountSpec()); applyAmountSpec(); if (model.isCreateOfferMode()) { @@ -336,13 +328,6 @@ void onOpenWiki(String url) { Browser.open(url); } - void onToggleMinAmountVisibility() { - boolean value = !model.getIsRangeAmountEnabled().get(); - model.getIsRangeAmountEnabled().set(value); - quoteSideAmountsChanged(!value); - settingsService.setCookie(CookieKey.CREATE_BISQ_EASY_OFFER_IS_MIN_AMOUNT_ENABLED, value); - } - void useFixedAmount() { updateIsRangeAmountEnabled(false); } diff --git a/i18n/src/main/resources/bisq_easy.properties b/i18n/src/main/resources/bisq_easy.properties index 84a2287713..8ce0b8b2da 100644 --- a/i18n/src/main/resources/bisq_easy.properties +++ b/i18n/src/main/resources/bisq_easy.properties @@ -131,9 +131,6 @@ bisqEasy.price.warn.invalidPrice.exception=The price you entered is invalid.\n\n bisqEasy.tradeWizard.amount.headline.buyer=How much do you want to spend? bisqEasy.tradeWizard.amount.headline.seller=How much do you want to receive? -bisqEasy.tradeWizard.amount.description.minAmount=Set the minimum value for the amount range -bisqEasy.tradeWizard.amount.description.maxAmount=Set the maximum value for the amount range -bisqEasy.tradeWizard.amount.description.fixAmount=Set the amount you want to trade bisqEasy.tradeWizard.amount.amountModel.fixedAmount=Fixed amount bisqEasy.tradeWizard.amount.amountModel.rangeAmount=Range amount From 08947f0d384978ef8735709611cfaa254ddf50dd Mon Sep 17 00:00:00 2001 From: axpoems <145597137+axpoems@users.noreply.github.com> Date: Mon, 4 Nov 2024 10:50:43 +0100 Subject: [PATCH 09/33] Improve AmountComponent --- .../bisq_easy/components/AmountComponent.java | 19 +++++++---------- .../components/SmallAmountInput.java | 17 +++++++-------- .../amount/TakeOfferAmountController.java | 2 ++ .../amount/TradeWizardAmountView.java | 9 ++++---- .../src/main/resources/css/bisq_easy.css | 21 +++++++++++++++++++ i18n/src/main/resources/bisq_easy.properties | 2 +- 6 files changed, 44 insertions(+), 26 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/AmountComponent.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/AmountComponent.java index eab8746950..f74399672b 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/AmountComponent.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/AmountComponent.java @@ -283,6 +283,7 @@ public void onActivate() { model.getMaxRangeBaseSideValue().set(null); model.getMinRangeQuoteSideValue().set(null); model.getMaxRangeQuoteSideValue().set(null); + model.getDescription().set(Res.get("bisqEasy.tradeWizard.amount.description", model.getMarket().getQuoteCurrencyCode())); applyInitialRangeValues(); model.getBaseSideAmount().addListener(baseSideAmountFromModelListener); @@ -585,18 +586,14 @@ private View(Model model, root.setAlignment(Pos.TOP_CENTER); description = new Label(); - description.setTextAlignment(TextAlignment.CENTER); - description.setAlignment(Pos.CENTER); description.getStyleClass().addAll("bisq-text-3", "wrap-text"); + description.setMouseTransparent(true); - VBox.setMargin(quoteAmountRoot, new Insets(-15, 0, 0, 0)); - VBox.setMargin(baseAmountRoot, new Insets(-17, 0, 0, 0)); - VBox vbox = new VBox(0, quoteAmountRoot, baseAmountRoot); + VBox vbox = new VBox(0, description, quoteAmountRoot, baseAmountRoot); vbox.getStyleClass().add("bisq-dual-amount-bg"); - vbox.setAlignment(Pos.CENTER); vbox.setMinWidth(AMOUNT_BOX_WIDTH); vbox.setMaxWidth(AMOUNT_BOX_WIDTH); - vbox.setPadding(new Insets(25, 20, 10, 20)); + vbox.setPadding(new Insets(10, 20, 10, 20)); Region line = new Region(); line.setLayoutY(121); @@ -612,7 +609,7 @@ private View(Model model, selectionLine.setLayoutY(119); selectionLine.setMouseTransparent(true); - Pane amountPane = new Pane(vbox, line, selectionLine); + Pane amountPane = new Pane(vbox/*, line, selectionLine*/); amountPane.setMaxWidth(AMOUNT_BOX_WIDTH); slider.setMin(model.getSliderMin()); @@ -627,8 +624,8 @@ private View(Model model, VBox sliderBox = new VBox(2, slider, new HBox(minRangeValue, Spacer.fillHBox(), maxRangeValue)); sliderBox.setMaxWidth(AMOUNT_BOX_WIDTH); - VBox.setMargin(amountPane, new Insets(0, 0, 20, 0)); - root.getChildren().addAll(description, amountPane, sliderBox); +// VBox.setMargin(amountPane, new Insets(0, 0, 20, 0)); + root.getChildren().addAll(amountPane, sliderBox); } @Override @@ -644,7 +641,7 @@ protected void onViewAttached() { sliderTrackStylePin = EasyBind.subscribe(model.getSliderTrackStyle(), slider::setStyle); slider.valueProperty().bindBidirectional(model.getSliderValue()); model.getSliderFocus().bind(slider.focusedProperty()); - description.textProperty().bind(model.description); + description.textProperty().bind(model.getDescription()); minRangeValue.textProperty().bind(model.getMinRangeValueAsString()); maxRangeValue.textProperty().bind(model.getMaxRangeValueAsString()); // Needed to trigger focusOut event on amount components diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/SmallAmountInput.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/SmallAmountInput.java index 40a17bc88c..374f08f3f3 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/SmallAmountInput.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/SmallAmountInput.java @@ -28,6 +28,8 @@ import javafx.scene.control.Label; import javafx.scene.control.TextField; import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; import lombok.extern.slf4j.Slf4j; @Slf4j @@ -52,7 +54,6 @@ public void setUseLowPrecision(boolean useLowPrecision) { } private static class SmallAmountInputView extends View { - private BisqTooltip tooltip; protected SmallAmountInputView(Model model, Controller controller) { @@ -66,16 +67,15 @@ private Button createIconButton() { iconButton.setOpacity(ICON_OPACITY); tooltip = new BisqTooltip(BisqTooltip.Style.DARK); iconButton.setTooltip(tooltip); + HBox.setMargin(iconButton, new Insets(0, 0, 8, 0)); return iconButton; } @Override protected void initView() { root.setAlignment(Pos.CENTER); - root.setSpacing(3); + root.getStyleClass().add("small-amount-input"); Button iconButton = createIconButton(); - HBox.setMargin(textInput, new Insets(0, 0, 0, -35)); - HBox.setMargin(iconButton, new Insets(-8, 0, 0, 1)); root.getChildren().add(iconButton); } @@ -83,17 +83,17 @@ protected void initView() { protected TextField createTextInput() { var textInput = new TextField(); textInput.setId(QUOTE_AMOUNT_ID); - textInput.setAlignment(Pos.CENTER_RIGHT); - textInput.setPadding(new Insets(0, 0, 0, 0)); + textInput.getStyleClass().add("text-input"); + textInput.setPadding(new Insets(0, 8, 3, 0)); return textInput; } @Override protected Label createCodeLabel() { var codeLabel = new Label(); - codeLabel.setAlignment(Pos.CENTER_LEFT); codeLabel.setId(QUOTE_AMOUNT_ID); - codeLabel.setPadding(new Insets(0, 0, 0, 0)); + codeLabel.getStyleClass().add("currency-code"); + codeLabel.setMinWidth(Label.USE_PREF_SIZE); return codeLabel; } @@ -111,7 +111,6 @@ protected void onViewDetached() { } private static class SmallAmountInputModel extends Model { - private final StringProperty tooltip = new SimpleStringProperty(Res.get(DEFAULT_TOOLTIP)); protected SmallAmountInputModel(boolean isBaseCurrency) { diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/take_offer/amount/TakeOfferAmountController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/take_offer/amount/TakeOfferAmountController.java index b76b123176..2dd8fb7e06 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/take_offer/amount/TakeOfferAmountController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/take_offer/amount/TakeOfferAmountController.java @@ -94,6 +94,7 @@ public void init(BisqEasyOffer bisqEasyOffer, Optional optionalReputat applyQuoteSideMinMaxRange(quoteSideMinAmount, maxAmount); long sellersScore = reputationService.getReputationScore(userIdentityService.getSelectedUserIdentity().getUserProfile()).getTotalScore(); + // TODO: Move this outside of the component amountComponent.setDescription(Res.get("bisqEasy.takeOffer.amount.description.limitedByTakersReputation", sellersScore, formattedMinAmount, @@ -102,6 +103,7 @@ public void init(BisqEasyOffer bisqEasyOffer, Optional optionalReputat // Range amounts buyer case maxAmount = offersQuoteSideMaxOrFixedAmount; applyQuoteSideMinMaxRange(quoteSideMinAmount, maxAmount); + // TODO: Move this outside of the component amountComponent.setDescription(Res.get("bisqEasy.takeOffer.amount.description", formattedMinAmount, AmountFormatter.formatAmountWithCode(maxAmount))); diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java index 6d49e3cc1f..0bfb01719d 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java @@ -58,10 +58,6 @@ public TradeWizardAmountView(TradeWizardAmountModel model, AmountComponent maxOrFixAmountComponent) { super(new StackPane(), model, controller); - root.setAlignment(Pos.CENTER); - content = new VBox(10); - content.setAlignment(Pos.TOP_CENTER); - headlineLabel = new Label(); headlineLabel.getStyleClass().add("bisq-text-headline-2"); @@ -110,7 +106,9 @@ public TradeWizardAmountView(TradeWizardAmountModel model, amountModelsBox.getStyleClass().addAll("selection-models", "bisq-text-3"); VBox.setMargin(headlineLabel, new Insets(-10, 0, 0, 0)); - VBox.setMargin(amountLimitInfoWithWarnIcon, new Insets(15, 0, 15, 0)); +// VBox.setMargin(amountLimitInfoWithWarnIcon, new Insets(15, 0, 15, 0)); + content = new VBox(20); + content.setAlignment(Pos.TOP_CENTER); content.getChildren().addAll(Spacer.fillVBox(), headlineLabel, amountModelsBox, amountBox, amountLimitInfoWithWarnIcon, Spacer.fillVBox()); content.getStyleClass().add("bisq-easy-trade-wizard-amount-step"); @@ -122,6 +120,7 @@ public TradeWizardAmountView(TradeWizardAmountModel model, StackPane.setMargin(amountLimitInfoOverlay, new Insets(-TradeWizardView.TOP_PANE_HEIGHT, 0, 0, 0)); root.getChildren().addAll(content, amountLimitInfoOverlay); + root.setAlignment(Pos.CENTER); } @Override diff --git a/apps/desktop/desktop/src/main/resources/css/bisq_easy.css b/apps/desktop/desktop/src/main/resources/css/bisq_easy.css index 3e0d613e41..8dfdfba5ee 100644 --- a/apps/desktop/desktop/src/main/resources/css/bisq_easy.css +++ b/apps/desktop/desktop/src/main/resources/css/bisq_easy.css @@ -716,6 +716,27 @@ * * ******************************************************************************/ +.small-amount-input { + -fx-padding: -7 55 0 0; +} + +.small-amount-input .text-input, +.small-amount-input .currency-code { + -fx-fill: -fx-mid-text-color !important; + -fx-text-fill: -fx-mid-text-color !important; + -fx-font-family: "IBM Plex Sans Light" !important; +} + +.small-amount-input .text-input { + -fx-font-size: 1.45em !important; + -fx-alignment: baseline-right; +} + +.small-amount-input .currency-code { + -fx-font-size: 1.15em !important; + -fx-alignment: baseline-left; +} + .bisq-easy-trade-wizard-price-step .price-content { -fx-alignment: center; } diff --git a/i18n/src/main/resources/bisq_easy.properties b/i18n/src/main/resources/bisq_easy.properties index 8ce0b8b2da..48e8c9faf5 100644 --- a/i18n/src/main/resources/bisq_easy.properties +++ b/i18n/src/main/resources/bisq_easy.properties @@ -133,7 +133,7 @@ bisqEasy.tradeWizard.amount.headline.buyer=How much do you want to spend? bisqEasy.tradeWizard.amount.headline.seller=How much do you want to receive? bisqEasy.tradeWizard.amount.amountModel.fixedAmount=Fixed amount bisqEasy.tradeWizard.amount.amountModel.rangeAmount=Range amount - +bisqEasy.tradeWizard.amount.description={0} amount to trade bisqEasy.component.amount.minRangeValue=Min {0} bisqEasy.component.amount.maxRangeValue=Max {0} bisqEasy.component.amount.baseSide.tooltip.btcAmount.marketPrice=This is the Bitcoin amount with current market price. From 1fb01da98d1236e19ebfcd0d4f56879a23048cc3 Mon Sep 17 00:00:00 2001 From: axpoems <145597137+axpoems@users.noreply.github.com> Date: Mon, 4 Nov 2024 11:47:39 +0100 Subject: [PATCH 10/33] More improvements in amount component --- .../bisq_easy/components/AmountComponent.java | 39 ++++++++++++------- .../bisq_easy/components/BigAmountInput.java | 9 +++-- .../components/SmallAmountInput.java | 6 +-- .../src/main/resources/css/bisq_easy.css | 12 +++++- .../desktop/src/main/resources/css/text.css | 2 +- 5 files changed, 44 insertions(+), 24 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/AmountComponent.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/AmountComponent.java index f74399672b..73e44cbb31 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/AmountComponent.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/AmountComponent.java @@ -32,7 +32,16 @@ import bisq.i18n.Res; import bisq.offer.Direction; import bisq.presentation.formatters.AmountFormatter; -import javafx.beans.property.*; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.DoubleProperty; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.ReadOnlyBooleanProperty; +import javafx.beans.property.ReadOnlyObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleDoubleProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; import javafx.beans.value.ChangeListener; import javafx.geometry.Insets; import javafx.geometry.Pos; @@ -43,7 +52,6 @@ import javafx.scene.layout.Pane; import javafx.scene.layout.Region; import javafx.scene.layout.VBox; -import javafx.scene.text.TextAlignment; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; @@ -565,6 +573,8 @@ void reset() { @Slf4j public static class View extends bisq.desktop.common.view.View { public final static int AMOUNT_BOX_WIDTH = 330; + public final static int AMOUNT_BOX_HEIGHT = 130; + private final Slider slider = new Slider(); private final Label minRangeValue, maxRangeValue, description; private final Region selectionLine; @@ -583,22 +593,23 @@ private View(Model model, Pane quoteAmountRoot = quoteAmount.getRoot(); this.quoteAmount = quoteAmount; - root.setAlignment(Pos.TOP_CENTER); - description = new Label(); - description.getStyleClass().addAll("bisq-text-3", "wrap-text"); + description.getStyleClass().add("description"); description.setMouseTransparent(true); - VBox vbox = new VBox(0, description, quoteAmountRoot, baseAmountRoot); - vbox.getStyleClass().add("bisq-dual-amount-bg"); - vbox.setMinWidth(AMOUNT_BOX_WIDTH); - vbox.setMaxWidth(AMOUNT_BOX_WIDTH); - vbox.setPadding(new Insets(10, 20, 10, 20)); + VBox amountVBox = new VBox(0, description, Spacer.fillVBox(), quoteAmountRoot, + Spacer.fillVBox(), baseAmountRoot); + amountVBox.getStyleClass().add("bisq-dual-amount-bg"); + amountVBox.setMinWidth(AMOUNT_BOX_WIDTH); + amountVBox.setMaxWidth(AMOUNT_BOX_WIDTH); + amountVBox.setMinHeight(AMOUNT_BOX_HEIGHT); + amountVBox.setMaxHeight(AMOUNT_BOX_HEIGHT); + amountVBox.setPadding(new Insets(5, 20, 10, 20)); Region line = new Region(); - line.setLayoutY(121); line.setPrefHeight(1); line.setPrefWidth(AMOUNT_BOX_WIDTH); + line.setLayoutY(AMOUNT_BOX_HEIGHT); line.setStyle("-fx-background-color: -bisq-mid-grey-20"); line.setMouseTransparent(true); @@ -606,10 +617,10 @@ private View(Model model, selectionLine.getStyleClass().add("material-text-field-selection-line"); selectionLine.setPrefHeight(3); selectionLine.setPrefWidth(0); - selectionLine.setLayoutY(119); + selectionLine.setLayoutY(AMOUNT_BOX_HEIGHT - 2); selectionLine.setMouseTransparent(true); - Pane amountPane = new Pane(vbox/*, line, selectionLine*/); + Pane amountPane = new Pane(amountVBox, line, selectionLine); amountPane.setMaxWidth(AMOUNT_BOX_WIDTH); slider.setMin(model.getSliderMin()); @@ -626,6 +637,8 @@ private View(Model model, // VBox.setMargin(amountPane, new Insets(0, 0, 20, 0)); root.getChildren().addAll(amountPane, sliderBox); + root.getStyleClass().add("amount-component"); + root.setAlignment(Pos.TOP_CENTER); } @Override diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/BigAmountInput.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/BigAmountInput.java index b3b326f903..fe3382a928 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/BigAmountInput.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/BigAmountInput.java @@ -26,11 +26,10 @@ @Slf4j public class BigAmountInput extends AmountInput { - private static final double TEXT_INPUT_PREF_WIDTH = 250; private static final String BIG_TEXT_INPUT_ID = "base-amount-text-field"; private static final String SMALL_TEXT_INPUT_ID = "base-amount-text-field-small"; - private static final int TEXT_LENGTH_THRESHOLD = 6; + private static final int TEXT_LENGTH_THRESHOLD = 9; public BigAmountInput(boolean isBaseCurrency) { super(isBaseCurrency); @@ -48,6 +47,7 @@ public void initView() { HBox.setMargin(textInput, new Insets(0, 0, 0, -30)); root.setAlignment(Pos.BASELINE_CENTER); root.setSpacing(10); + root.getStyleClass().add("big-amount-input"); } @Override @@ -56,6 +56,7 @@ protected TextField createTextInput() { textInput.setPrefWidth(TEXT_INPUT_PREF_WIDTH); textInput.setId(BIG_TEXT_INPUT_ID); textInput.setAlignment(Pos.BASELINE_RIGHT); + textInput.getStyleClass().add("text-input"); textInput.setPadding(new Insets(0, 0, 5, 0)); return textInput; } @@ -63,8 +64,8 @@ protected TextField createTextInput() { @Override protected Label createCodeLabel() { var codeLabel = new Label(); - codeLabel.setPadding(new Insets(0, 0, 0, 0)); - codeLabel.getStyleClass().add("bisq-text-9"); + codeLabel.setPadding(new Insets(0, -20, 0, 0)); + codeLabel.getStyleClass().add("currency-code"); codeLabel.setAlignment(Pos.BASELINE_LEFT); return codeLabel; } diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/SmallAmountInput.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/SmallAmountInput.java index 374f08f3f3..3cc4f53811 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/SmallAmountInput.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/SmallAmountInput.java @@ -28,8 +28,6 @@ import javafx.scene.control.Label; import javafx.scene.control.TextField; import javafx.scene.layout.HBox; -import javafx.scene.layout.Priority; -import javafx.scene.layout.Region; import lombok.extern.slf4j.Slf4j; @Slf4j @@ -67,7 +65,7 @@ private Button createIconButton() { iconButton.setOpacity(ICON_OPACITY); tooltip = new BisqTooltip(BisqTooltip.Style.DARK); iconButton.setTooltip(tooltip); - HBox.setMargin(iconButton, new Insets(0, 0, 8, 0)); + HBox.setMargin(iconButton, new Insets(0, 0, 5, 0)); return iconButton; } @@ -84,7 +82,7 @@ protected TextField createTextInput() { var textInput = new TextField(); textInput.setId(QUOTE_AMOUNT_ID); textInput.getStyleClass().add("text-input"); - textInput.setPadding(new Insets(0, 8, 3, 0)); + textInput.setPadding(new Insets(0, 7, 3, 0)); return textInput; } diff --git a/apps/desktop/desktop/src/main/resources/css/bisq_easy.css b/apps/desktop/desktop/src/main/resources/css/bisq_easy.css index 8dfdfba5ee..1800756d96 100644 --- a/apps/desktop/desktop/src/main/resources/css/bisq_easy.css +++ b/apps/desktop/desktop/src/main/resources/css/bisq_easy.css @@ -716,6 +716,14 @@ * * ******************************************************************************/ +.amount-component .description { + -fx-fill: -fx-mid-text-color; + -fx-text-fill: -fx-mid-text-color; + -fx-font-size: 1em; + -fx-font-family: "IBM Plex Sans Light"; + -fx-wrap-text: true; +} + .small-amount-input { -fx-padding: -7 55 0 0; } @@ -728,12 +736,12 @@ } .small-amount-input .text-input { - -fx-font-size: 1.45em !important; + -fx-font-size: 1.25em !important; -fx-alignment: baseline-right; } .small-amount-input .currency-code { - -fx-font-size: 1.15em !important; + -fx-font-size: 0.95em !important; -fx-alignment: baseline-left; } diff --git a/apps/desktop/desktop/src/main/resources/css/text.css b/apps/desktop/desktop/src/main/resources/css/text.css index 032829dc09..1a3c3ccf2e 100644 --- a/apps/desktop/desktop/src/main/resources/css/text.css +++ b/apps/desktop/desktop/src/main/resources/css/text.css @@ -422,7 +422,7 @@ -fx-border-style: none; -fx-text-fill: -fx-light-text-color; -fx-highlight-fill: -bisq2-green; - -fx-font-size: 5.2em; + -fx-font-size: 3.75em; -fx-font-family: "IBM Plex Sans Thin"; } From 1605975d2b7d2cff307921f5ec4600287f87909e Mon Sep 17 00:00:00 2001 From: axpoems <145597137+axpoems@users.noreply.github.com> Date: Tue, 5 Nov 2024 09:21:44 +0100 Subject: [PATCH 11/33] Refactor: split amount component into controller/model/view files --- .../bisq_easy/components/AmountComponent.java | 704 ------------------ .../AmountSelectionController.java | 427 +++++++++++ .../AmountSelectionModel.java | 90 +++ .../amount_selection/AmountSelectionView.java | 170 +++++ .../amount/TakeOfferAmountController.java | 44 +- .../amount/TradeWizardAmountController.java | 122 +-- .../amount/TradeWizardAmountView.java | 10 +- 7 files changed, 775 insertions(+), 792 deletions(-) delete mode 100644 apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/AmountComponent.java create mode 100644 apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionController.java create mode 100644 apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionModel.java create mode 100644 apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/AmountComponent.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/AmountComponent.java deleted file mode 100644 index 73e44cbb31..0000000000 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/AmountComponent.java +++ /dev/null @@ -1,704 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.desktop.main.content.bisq_easy.components; - -import bisq.bisq_easy.BisqEasyTradeAmountLimits; -import bisq.common.currency.FiatCurrencyRepository; -import bisq.common.currency.Market; -import bisq.common.currency.MarketRepository; -import bisq.common.monetary.Fiat; -import bisq.common.monetary.Monetary; -import bisq.common.monetary.PriceQuote; -import bisq.desktop.ServiceProvider; -import bisq.desktop.common.Transitions; -import bisq.desktop.common.threading.UIScheduler; -import bisq.desktop.common.threading.UIThread; -import bisq.desktop.components.containers.Spacer; -import bisq.i18n.Res; -import bisq.offer.Direction; -import bisq.presentation.formatters.AmountFormatter; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.DoubleProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.ReadOnlyBooleanProperty; -import javafx.beans.property.ReadOnlyObjectProperty; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleDoubleProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.property.StringProperty; -import javafx.beans.value.ChangeListener; -import javafx.geometry.Insets; -import javafx.geometry.Pos; -import javafx.scene.Parent; -import javafx.scene.control.Label; -import javafx.scene.control.Slider; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Pane; -import javafx.scene.layout.Region; -import javafx.scene.layout.VBox; -import lombok.Getter; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; -import org.fxmisc.easybind.EasyBind; -import org.fxmisc.easybind.Subscription; - -import java.util.Optional; - -import static com.google.common.base.Preconditions.checkArgument; - -@Slf4j -public class AmountComponent { - private final Controller controller; - - public AmountComponent(ServiceProvider serviceProvider, - boolean useQuoteCurrencyForMinMaxRange) { - controller = new Controller(serviceProvider, useQuoteCurrencyForMinMaxRange); - } - - public View getView() { - return controller.getView(); - } - - public ReadOnlyObjectProperty getBaseSideAmount() { - return controller.getBaseSideAmount(); - } - - public ReadOnlyObjectProperty getQuoteSideAmount() { - return controller.getQuoteSideAmount(); - } - - public void setBaseSideAmount(Monetary value) { - controller.setBaseSideAmount(value); - } - - public void setQuoteSideAmount(Monetary value) { - controller.setQuoteSideAmount(value); - } - - public void setDirection(Direction direction) { - controller.setDirection(direction); - } - - public void setMarket(Market market) { - controller.setMarket(market); - } - - public void setMinMaxRange(Monetary minRangeValue, Monetary maxRangeValue) { - controller.setMinMaxRange(minRangeValue, maxRangeValue); - } - - public void setLeftMarkerQuoteSideValue(Monetary quoteSideAmount) { - controller.setLeftMarkerQuoteSideValue(quoteSideAmount); - } - - public void setRightMarkerQuoteSideValue(Monetary quoteSideAmount) { - controller.setRightMarkerQuoteSideValue(quoteSideAmount); - } - - public Monetary getRightMarkerQuoteSideValue() { - return controller.model.getRightMarkerQuoteSideValue(); - } - - public void applyReputationBasedQuoteSideAmount() { - controller.applyReputationBasedQuoteSideAmount(); - } - - public void setTooltip(String tooltip) { - controller.setTooltip(tooltip); - } - - public void setQuote(PriceQuote priceQuote) { - if (priceQuote != null) { - controller.setQuote(priceQuote); - } - } - - public ReadOnlyObjectProperty getQuote() { - return controller.price.getQuote(); - } - - public void reset() { - controller.reset(); - } - - public void setDescription(String description) { - controller.setDescription(description); - } - - private static class Controller implements bisq.desktop.common.view.Controller { - private static final String SLIDER_TRACK_DEFAULT_COLOR = "-bisq-dark-grey-50"; - private static final String SLIDER_TRACK_MARKER_COLOR = "-bisq2-green"; - - private final Model model; - @Getter - private final View view; - private final BigAmountInput quoteSideAmountInput; - private final SmallAmountInput baseSideAmountInput; - private final ChangeListener baseSideAmountFromModelListener, quoteSideAmountFromModelListener; - private final ChangeListener quoteListener; - private final PriceInput price; - private final ChangeListener sliderListener; - private Subscription baseAmountFromModelPin, baseAmountFromCompPin, - quoteAmountFromCompPin, priceFromCompPin, minRangeCustomValuePin, maxRangeCustomValuePin, - baseSideAmountValidPin, quoteSideAmountValidPin; - - private Controller(ServiceProvider serviceProvider, - boolean useQuoteCurrencyForMinMaxRange) { - quoteSideAmountInput = new BigAmountInput(false); - baseSideAmountInput = new SmallAmountInput(true); - baseSideAmountInput.setUseLowPrecision(false); - price = new PriceInput(serviceProvider.getBondedRolesService().getMarketPriceService()); - - model = new Model(useQuoteCurrencyForMinMaxRange); - view = new View(model, this, - baseSideAmountInput, - quoteSideAmountInput); - - // We delay with runLater to avoid that we get triggered at market change from the component's data changes and - // apply the conversion before the other component has processed the market change event. - // The order of the event notification is not deterministic. - baseSideAmountFromModelListener = (observable, oldValue, newValue) -> UIThread.runOnNextRenderFrame(this::setQuoteFromBase); - quoteSideAmountFromModelListener = (observable, oldValue, newValue) -> UIThread.runOnNextRenderFrame(this::setBaseFromQuote); - quoteListener = (observable, oldValue, newValue) -> { - model.getMinRangeBaseSideValue().set(null); - model.getMaxRangeBaseSideValue().set(null); - model.getMinRangeQuoteSideValue().set(null); - model.getMaxRangeQuoteSideValue().set(null); - applyInitialRangeValues(); - UIThread.runOnNextRenderFrame(this::applyQuote); - }; - sliderListener = (observable, oldValue, newValue) -> { - if (model.getMinRangeQuoteSideValue().get() != null && model.getMinRangeBaseSideValue().get() != null) { - double sliderValue = newValue.doubleValue(); - long min = model.useQuoteCurrencyForMinMaxRange ? - model.getMinRangeQuoteSideValue().get().getValue() : - model.getMinRangeBaseSideValue().get().getValue(); - long max = model.useQuoteCurrencyForMinMaxRange ? - model.getMaxRangeQuoteSideValue().get().getValue() : - model.getMaxRangeBaseSideValue().get().getValue(); - long value = Math.round(sliderValue * (max - min)) + min; - if (model.useQuoteCurrencyForMinMaxRange) { - quoteSideAmountInput.setAmount(Monetary.from(value, model.getMarket().getQuoteCurrencyCode())); - } else { - baseSideAmountInput.setAmount(Monetary.from(value, model.getMarket().getBaseCurrencyCode())); - } - } - }; - } - - private void setBaseSideAmount(Monetary value) { - model.getBaseSideAmount().set(value); - } - - private void setQuoteSideAmount(Monetary value) { - model.getQuoteSideAmount().set(value); - } - - private ReadOnlyObjectProperty getBaseSideAmount() { - return model.getBaseSideAmount(); - } - - private ReadOnlyObjectProperty getQuoteSideAmount() { - return model.getQuoteSideAmount(); - } - - private void setDirection(Direction direction) { - if (direction == null) { - return; - } - model.setDirection(direction); - model.getSpendOrReceiveString().set(direction == Direction.BUY ? Res.get("offer.buying") : Res.get("offer.selling")); - } - - private void setTooltip(String tooltip) { - baseSideAmountInput.setTooltip(tooltip); - } - - private void setMarket(Market market) { - if (market == null) { - return; - } - model.setMarket(market); - baseSideAmountInput.setSelectedMarket(market); - quoteSideAmountInput.setSelectedMarket(market); - price.setMarket(market); - } - - public void setDescription(String description) { - model.getDescription().set(description); - } - - public void setMinMaxRange(Monetary minRangeValue, Monetary maxRangeValue) { - boolean minRangeValueIsFiat = FiatCurrencyRepository.getCurrencyByCodeMap().containsKey(minRangeValue.getCode()); - boolean maxRangeValueIsFiat = FiatCurrencyRepository.getCurrencyByCodeMap().containsKey(maxRangeValue.getCode()); - if (model.useQuoteCurrencyForMinMaxRange) { - checkArgument(minRangeValueIsFiat && maxRangeValueIsFiat, - "The provided minRangeValue and maxRangeValue must be fiat currencies as useQuoteCurrencyForMinMaxRange is set to true."); - } else { - checkArgument(!minRangeValueIsFiat && !maxRangeValueIsFiat, - "The provided minRangeValue and maxRangeValue must not be fiat currencies as useQuoteCurrencyForMinMaxRange is set to false."); - } - - model.getMinRangeMonetary().set(minRangeValue); - model.getMaxRangeMonetary().set(maxRangeValue); - applyInitialRangeValues(); - } - - public void setLeftMarkerQuoteSideValue(Monetary quoteSideAmount) { - model.setLeftMarkerQuoteSideValue(quoteSideAmount); - applySliderTrackStyle(); - } - - public void setRightMarkerQuoteSideValue(Monetary quoteSideAmount) { - model.setRightMarkerQuoteSideValue(quoteSideAmount); - applySliderTrackStyle(); - } - - public void applyReputationBasedQuoteSideAmount() { - quoteSideAmountInput.setAmount(model.getRightMarkerQuoteSideValue()); - } - - public void setQuote(PriceQuote priceQuote) { - price.setQuote(priceQuote); - } - - private void reset() { - baseSideAmountInput.reset(); - quoteSideAmountInput.reset(); - price.reset(); - model.reset(); - } - - @Override - public void onActivate() { - model.getMinRangeBaseSideValue().set(null); - model.getMaxRangeBaseSideValue().set(null); - model.getMinRangeQuoteSideValue().set(null); - model.getMaxRangeQuoteSideValue().set(null); - model.getDescription().set(Res.get("bisqEasy.tradeWizard.amount.description", model.getMarket().getQuoteCurrencyCode())); - applyInitialRangeValues(); - - model.getBaseSideAmount().addListener(baseSideAmountFromModelListener); - model.getQuoteSideAmount().addListener(quoteSideAmountFromModelListener); - price.getQuote().addListener(quoteListener); - - baseSideAmountInput.setAmount(null); - if (model.getQuoteSideAmount().get() == null) { - PriceQuote priceQuote = price.getQuote().get(); - if (priceQuote != null) { - Monetary minRangeQuoteSideValue = model.getMinRangeQuoteSideValue().get(); - Monetary maxRangeQuoteSideValue = model.getMaxRangeQuoteSideValue().get(); - long midValue = minRangeQuoteSideValue.getValue() + (maxRangeQuoteSideValue.getValue() - minRangeQuoteSideValue.getValue()) / 2; - Monetary exactAmount = Fiat.fromValue(midValue, priceQuote.getQuoteSideMonetary().getCode()); - quoteSideAmountInput.setAmount(exactAmount.round(0)); - } else { - log.warn("price.quoteProperty().get() is null. We use a fiat value of 100 as default value."); - Fiat defaultQuoteSideAmount = Fiat.fromFaceValue(100, model.getMarket().getQuoteCurrencyCode()); - quoteSideAmountInput.setAmount(defaultQuoteSideAmount); - } - } else { - quoteSideAmountInput.setAmount(model.getQuoteSideAmount().get()); - } - setBaseFromQuote(); - - baseAmountFromModelPin = EasyBind.subscribe(model.getBaseSideAmount(), amount -> { - // Only apply value from component to slider if we have no focus on slider (not used) - if (amount != null) { - if (!model.getSliderFocus().get()) { - long min = model.getMinRangeBaseSideValue().get().getValue(); - long max = model.getMaxRangeBaseSideValue().get().getValue(); - double sliderValue = (amount.getValue() - min) / ((double) max - min); - model.getSliderValue().set(sliderValue); - } - } - }); - - baseAmountFromCompPin = EasyBind.subscribe(baseSideAmountInput.amountProperty(), - amount -> { - Monetary minRangeValue = model.getMinRangeBaseSideValue().get(); - Monetary maxRangeValue = model.getMaxRangeBaseSideValue().get(); - if (amount != null && amount.getValue() > maxRangeValue.getValue()) { - model.getBaseSideAmount().set(maxRangeValue); - setQuoteFromBase(); - baseSideAmountInput.setAmount(maxRangeValue); - } else if (amount != null && amount.getValue() < minRangeValue.getValue()) { - model.getBaseSideAmount().set(minRangeValue); - setQuoteFromBase(); - baseSideAmountInput.setAmount(minRangeValue); - } else { - model.getBaseSideAmount().set(amount); - } - }); - - quoteAmountFromCompPin = EasyBind.subscribe(quoteSideAmountInput.amountProperty(), - amount -> { - Monetary minRangeValue = model.getMinRangeQuoteSideValue().get(); - Monetary maxRangeValue = model.getMaxRangeQuoteSideValue().get(); - if (maxRangeValue != null && amount != null && amount.getValue() > maxRangeValue.getValue()) { - model.getQuoteSideAmount().set(maxRangeValue); - setBaseFromQuote(); - quoteSideAmountInput.setAmount(maxRangeValue); - } else if (minRangeValue != null && amount != null && amount.getValue() < minRangeValue.getValue()) { - model.getQuoteSideAmount().set(minRangeValue); - setBaseFromQuote(); - quoteSideAmountInput.setAmount(minRangeValue); - } else { - model.getQuoteSideAmount().set(amount); - } - }); - priceFromCompPin = EasyBind.subscribe(price.getQuote(), - quote -> applyInitialRangeValues()); - - minRangeCustomValuePin = EasyBind.subscribe(model.getMinRangeMonetary(), - value -> applyInitialRangeValues()); - maxRangeCustomValuePin = EasyBind.subscribe(model.getMaxRangeMonetary(), - value -> applyInitialRangeValues()); - - baseSideAmountValidPin = subscribeToAmountValidity(baseSideAmountInput, this::setBaseFromQuote); - quoteSideAmountValidPin = subscribeToAmountValidity(quoteSideAmountInput, this::setQuoteFromBase); - model.getSliderValue().addListener(sliderListener); - } - - private Subscription subscribeToAmountValidity(AmountInput amountInput, Runnable autocorrect) { - return EasyBind.subscribe(amountInput.isAmountValidProperty(), isAmountValid -> { - if (!amountInput.isAmountValidProperty().get()) { - autocorrect.run(); - amountInput.isAmountValidProperty().set(true); - } - }); - } - - private void applyInitialRangeValues() { - PriceQuote priceQuote = price.getQuote().get(); - if (priceQuote == null) { - return; - } - - Monetary minRangeMonetary = model.getMinRangeMonetary().get(); - Monetary maxRangeMonetary = model.getMaxRangeMonetary().get(); - boolean isMinRangeMonetaryFiat = FiatCurrencyRepository.getCurrencyByCodeMap().containsKey(minRangeMonetary.getCode()); - boolean isMaxRangeMonetaryFiat = FiatCurrencyRepository.getCurrencyByCodeMap().containsKey(maxRangeMonetary.getCode()); - - Monetary minRangeMonetaryAsCoin = !isMinRangeMonetaryFiat ? - minRangeMonetary : - priceQuote.toBaseSideMonetary(minRangeMonetary); - model.getMinRangeBaseSideValue().set(minRangeMonetaryAsCoin); - if (!model.useQuoteCurrencyForMinMaxRange) { - model.getMinRangeValueAsString().set(Res.get("bisqEasy.component.amount.minRangeValue", - AmountFormatter.formatAmountWithCode(minRangeMonetaryAsCoin))); - } - - Monetary maxRangeMonetaryAsCoin = !isMaxRangeMonetaryFiat ? - maxRangeMonetary : - priceQuote.toBaseSideMonetary(maxRangeMonetary); - model.getMaxRangeBaseSideValue().set(maxRangeMonetaryAsCoin); - if (!model.useQuoteCurrencyForMinMaxRange) { - model.getMaxRangeValueAsString().set(Res.get("bisqEasy.component.amount.maxRangeValue", - AmountFormatter.formatAmountWithCode(maxRangeMonetaryAsCoin))); - } - - Monetary minRangeMonetaryAsFiat = isMinRangeMonetaryFiat ? - minRangeMonetary : - priceQuote.toQuoteSideMonetary(minRangeMonetary).round(0); - model.getMinRangeQuoteSideValue().set(minRangeMonetaryAsFiat); - if (model.useQuoteCurrencyForMinMaxRange) { - model.getMinRangeValueAsString().set(Res.get("bisqEasy.component.amount.minRangeValue", - AmountFormatter.formatAmountWithCode(minRangeMonetaryAsFiat))); - } - - Monetary maxRangeMonetaryAsFiat = isMaxRangeMonetaryFiat ? - maxRangeMonetary : - priceQuote.toQuoteSideMonetary(maxRangeMonetary).round(0); - model.getMaxRangeQuoteSideValue().set(maxRangeMonetaryAsFiat); - if (model.useQuoteCurrencyForMinMaxRange) { - model.getMaxRangeValueAsString().set(Res.get("bisqEasy.component.amount.maxRangeValue", - AmountFormatter.formatAmountWithCode(maxRangeMonetaryAsFiat))); - } - - applySliderTrackStyle(); - } - - private void applySliderTrackStyle() { - Monetary minRangeMonetary = model.getMinRangeQuoteSideValue().get(); - Monetary maxRangeMonetary = model.getMaxRangeQuoteSideValue().get(); - if (minRangeMonetary == null || maxRangeMonetary == null) { - return; - } - long minRangeMonetaryValue = minRangeMonetary.getValue(); - long maxRangeMonetaryValue = maxRangeMonetary.getValue(); - double range = maxRangeMonetaryValue - minRangeMonetaryValue; - - // If left value is not set we use minRange - // If left value is set but right value not set we don't show any marker - Monetary markerQuoteSideValue = model.getLeftMarkerQuoteSideValue(); - long leftMarkerQuoteSideValue = Optional.ofNullable(markerQuoteSideValue).orElse(minRangeMonetary).getValue(); - double left = leftMarkerQuoteSideValue - minRangeMonetaryValue; - double leftPercentage = range != 0 ? 100 * left / range : 0; - - long rightMarkerQuoteSideValue = Optional.ofNullable(model.getRightMarkerQuoteSideValue()).orElse(minRangeMonetary).getValue(); - double right = rightMarkerQuoteSideValue - minRangeMonetaryValue; - double rightPercentage = range != 0 ? 100 * right / range : 0; - - // E.g.: -bisq-dark-grey-50 0%, -bisq-dark-grey-50 30.0%, -bisq2-green 30.0%, -bisq2-green 60.0%, -bisq-dark-grey-50 60.0%, -bisq-dark-grey-50 100%) - String segments = String.format( - SLIDER_TRACK_DEFAULT_COLOR + " 0%%, " + - SLIDER_TRACK_DEFAULT_COLOR + " %1$.1f%%, " + - - SLIDER_TRACK_MARKER_COLOR + " %1$.1f%%, " + - SLIDER_TRACK_MARKER_COLOR + " %2$.1f%%, " + - - SLIDER_TRACK_DEFAULT_COLOR + " %2$.1f%%, " + - SLIDER_TRACK_DEFAULT_COLOR + " 100%%)", - leftPercentage, rightPercentage); - String style = "-track-color: linear-gradient(to right, " + segments + ";"; - model.getSliderTrackStyle().set(style); - } - - @Override - public void onDeactivate() { - model.getBaseSideAmount().removeListener(baseSideAmountFromModelListener); - model.getQuoteSideAmount().removeListener(quoteSideAmountFromModelListener); - price.getQuote().removeListener(quoteListener); - model.getSliderValue().removeListener(sliderListener); - baseAmountFromModelPin.unsubscribe(); - baseAmountFromCompPin.unsubscribe(); - quoteAmountFromCompPin.unsubscribe(); - priceFromCompPin.unsubscribe(); - minRangeCustomValuePin.unsubscribe(); - maxRangeCustomValuePin.unsubscribe(); - baseSideAmountValidPin.unsubscribe(); - quoteSideAmountValidPin.unsubscribe(); - model.setLeftMarkerQuoteSideValue(null); - model.setRightMarkerQuoteSideValue(null); - } - - private void setQuoteFromBase() { - PriceQuote priceQuote = price.getQuote().get(); - if (priceQuote == null) return; - Monetary baseSideAmount = model.getBaseSideAmount().get(); - if (baseSideAmount == null) return; - quoteSideAmountInput.setAmount(priceQuote.toQuoteSideMonetary(baseSideAmount).round(0)); - } - - private void setBaseFromQuote() { - PriceQuote priceQuote = price.getQuote().get(); - if (priceQuote == null) return; - Monetary quoteSideAmount = model.getQuoteSideAmount().get(); - if (quoteSideAmount == null) return; - baseSideAmountInput.setAmount(priceQuote.toBaseSideMonetary(quoteSideAmount)); - } - - private void applyQuote() { - if (model.getBaseSideAmount() == null) { - setBaseFromQuote(); - } else { - setQuoteFromBase(); - } - } - } - - - @Getter - private static class Model implements bisq.desktop.common.view.Model { - private final boolean useQuoteCurrencyForMinMaxRange; - private final double sliderMin = 0; - private final double sliderMax = 1; - - private final ObjectProperty baseSideAmount = new SimpleObjectProperty<>(); - private final ObjectProperty quoteSideAmount = new SimpleObjectProperty<>(); - private final StringProperty spendOrReceiveString = new SimpleStringProperty(); - - private final DoubleProperty sliderValue = new SimpleDoubleProperty(); - private final BooleanProperty sliderFocus = new SimpleBooleanProperty(); - - @Setter - private ObjectProperty minRangeMonetary = new SimpleObjectProperty<>(BisqEasyTradeAmountLimits.DEFAULT_MIN_BTC_TRADE_AMOUNT); - @Setter - private ObjectProperty maxRangeMonetary = new SimpleObjectProperty<>(BisqEasyTradeAmountLimits.DEFAULT_MAX_BTC_TRADE_AMOUNT); - @Setter - private ObjectProperty minRangeBaseSideValue = new SimpleObjectProperty<>(); - @Setter - private ObjectProperty maxRangeBaseSideValue = new SimpleObjectProperty<>(); - @Setter - private ObjectProperty minRangeQuoteSideValue = new SimpleObjectProperty<>(); - @Setter - private ObjectProperty maxRangeQuoteSideValue = new SimpleObjectProperty<>(); - @Setter - private Monetary leftMarkerQuoteSideValue; - @Setter - private Monetary rightMarkerQuoteSideValue; - private final StringProperty sliderTrackStyle = new SimpleStringProperty(); - @Setter - private Market market = MarketRepository.getDefault(); - @Setter - private Direction direction = Direction.BUY; - private final StringProperty description = new SimpleStringProperty(); - private final StringProperty minRangeValueAsString = new SimpleStringProperty(); - private final StringProperty maxRangeValueAsString = new SimpleStringProperty(); - - Model(boolean useQuoteCurrencyForMinMaxRange) { - this.useQuoteCurrencyForMinMaxRange = useQuoteCurrencyForMinMaxRange; - } - - void reset() { - baseSideAmount.set(null); - quoteSideAmount.set(null); - spendOrReceiveString.set(null); - sliderValue.set(0L); - sliderFocus.set(false); - market = MarketRepository.getDefault(); - direction = Direction.BUY; - leftMarkerQuoteSideValue = null; - rightMarkerQuoteSideValue = null; - } - } - - - @Slf4j - public static class View extends bisq.desktop.common.view.View { - public final static int AMOUNT_BOX_WIDTH = 330; - public final static int AMOUNT_BOX_HEIGHT = 130; - - private final Slider slider = new Slider(); - private final Label minRangeValue, maxRangeValue, description; - private final Region selectionLine; - private final SmallAmountInput baseAmount; - private final BigAmountInput quoteAmount; - private Subscription baseAmountFocusPin, quoteAmountFocusPin, sliderTrackStylePin; - - private View(Model model, - AmountComponent.Controller controller, - SmallAmountInput baseAmount, - BigAmountInput quoteAmount) { - super(new VBox(10), model, controller); - - Pane baseAmountRoot = baseAmount.getRoot(); - this.baseAmount = baseAmount; - Pane quoteAmountRoot = quoteAmount.getRoot(); - this.quoteAmount = quoteAmount; - - description = new Label(); - description.getStyleClass().add("description"); - description.setMouseTransparent(true); - - VBox amountVBox = new VBox(0, description, Spacer.fillVBox(), quoteAmountRoot, - Spacer.fillVBox(), baseAmountRoot); - amountVBox.getStyleClass().add("bisq-dual-amount-bg"); - amountVBox.setMinWidth(AMOUNT_BOX_WIDTH); - amountVBox.setMaxWidth(AMOUNT_BOX_WIDTH); - amountVBox.setMinHeight(AMOUNT_BOX_HEIGHT); - amountVBox.setMaxHeight(AMOUNT_BOX_HEIGHT); - amountVBox.setPadding(new Insets(5, 20, 10, 20)); - - Region line = new Region(); - line.setPrefHeight(1); - line.setPrefWidth(AMOUNT_BOX_WIDTH); - line.setLayoutY(AMOUNT_BOX_HEIGHT); - line.setStyle("-fx-background-color: -bisq-mid-grey-20"); - line.setMouseTransparent(true); - - selectionLine = new Region(); - selectionLine.getStyleClass().add("material-text-field-selection-line"); - selectionLine.setPrefHeight(3); - selectionLine.setPrefWidth(0); - selectionLine.setLayoutY(AMOUNT_BOX_HEIGHT - 2); - selectionLine.setMouseTransparent(true); - - Pane amountPane = new Pane(amountVBox, line, selectionLine); - amountPane.setMaxWidth(AMOUNT_BOX_WIDTH); - - slider.setMin(model.getSliderMin()); - slider.setMax(model.getSliderMax()); - - minRangeValue = new Label(); - minRangeValue.getStyleClass().add("bisq-small-light-label-dimmed"); - - maxRangeValue = new Label(); - maxRangeValue.getStyleClass().add("bisq-small-light-label-dimmed"); - - VBox sliderBox = new VBox(2, slider, new HBox(minRangeValue, Spacer.fillHBox(), maxRangeValue)); - sliderBox.setMaxWidth(AMOUNT_BOX_WIDTH); - -// VBox.setMargin(amountPane, new Insets(0, 0, 20, 0)); - root.getChildren().addAll(amountPane, sliderBox); - root.getStyleClass().add("amount-component"); - root.setAlignment(Pos.TOP_CENTER); - } - - @Override - protected void onViewAttached() { - UIScheduler.run(() -> { - quoteAmount.requestFocus(); - baseAmountFocusPin = EasyBind.subscribe(baseAmount.focusedProperty(), - focus -> onInputTextFieldFocus(quoteAmount.focusedProperty(), focus)); - quoteAmountFocusPin = EasyBind.subscribe(quoteAmount.focusedProperty(), - focus -> onInputTextFieldFocus(baseAmount.focusedProperty(), focus)); - }).after(700); - - sliderTrackStylePin = EasyBind.subscribe(model.getSliderTrackStyle(), slider::setStyle); - slider.valueProperty().bindBidirectional(model.getSliderValue()); - model.getSliderFocus().bind(slider.focusedProperty()); - description.textProperty().bind(model.getDescription()); - minRangeValue.textProperty().bind(model.getMinRangeValueAsString()); - maxRangeValue.textProperty().bind(model.getMaxRangeValueAsString()); - // Needed to trigger focusOut event on amount components - // We handle all parents mouse events. - Parent node = root; - while (node.getParent() != null) { - node.setOnMousePressed(e -> root.requestFocus()); - node = node.getParent(); - } - } - - @Override - protected void onViewDetached() { - if (baseAmountFocusPin != null) { - baseAmountFocusPin.unsubscribe(); - } - if (quoteAmountFocusPin != null) { - quoteAmountFocusPin.unsubscribe(); - } - sliderTrackStylePin.unsubscribe(); - slider.valueProperty().unbindBidirectional(model.getSliderValue()); - model.getSliderFocus().unbind(); - description.textProperty().unbind(); - minRangeValue.textProperty().unbind(); - maxRangeValue.textProperty().unbind(); - baseAmount.isAmountValidProperty().set(true); - quoteAmount.isAmountValidProperty().set(true); - Parent node = root; - while (node.getParent() != null) { - node.setOnMousePressed(null); - node = node.getParent(); - } - } - - private void onInputTextFieldFocus(ReadOnlyBooleanProperty other, boolean focus) { - if (focus) { - selectionLine.setPrefWidth(0); - selectionLine.setOpacity(1); - Transitions.animateWidth(selectionLine, AMOUNT_BOX_WIDTH); - } else if (!other.get()) { - // If switching between the 2 fields we want to avoid to get the fadeout called that's why - // we do the check with !other.get() - Transitions.fadeOut(selectionLine, 200); - } - } - } -} \ No newline at end of file diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionController.java new file mode 100644 index 0000000000..0db84528a6 --- /dev/null +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionController.java @@ -0,0 +1,427 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.desktop.main.content.bisq_easy.components.amount_selection; + +import bisq.common.currency.FiatCurrencyRepository; +import bisq.common.currency.Market; +import bisq.common.monetary.Fiat; +import bisq.common.monetary.Monetary; +import bisq.common.monetary.PriceQuote; +import bisq.desktop.ServiceProvider; +import bisq.desktop.common.threading.UIThread; +import bisq.desktop.common.view.Controller; +import bisq.desktop.main.content.bisq_easy.components.AmountInput; +import bisq.desktop.main.content.bisq_easy.components.BigAmountInput; +import bisq.desktop.main.content.bisq_easy.components.PriceInput; +import bisq.desktop.main.content.bisq_easy.components.SmallAmountInput; +import bisq.i18n.Res; +import bisq.offer.Direction; +import bisq.presentation.formatters.AmountFormatter; +import javafx.beans.property.ReadOnlyObjectProperty; +import javafx.beans.value.ChangeListener; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.fxmisc.easybind.EasyBind; +import org.fxmisc.easybind.Subscription; + +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; + +@Slf4j +public class AmountSelectionController implements Controller { + private static final String SLIDER_TRACK_DEFAULT_COLOR = "-bisq-dark-grey-50"; + private static final String SLIDER_TRACK_MARKER_COLOR = "-bisq2-green"; + + final AmountSelectionModel model; + @Getter + private final AmountSelectionView view; + private final BigAmountInput quoteSideAmountInput; + private final SmallAmountInput baseSideAmountInput; + private final ChangeListener baseSideAmountFromModelListener, quoteSideAmountFromModelListener; + private final ChangeListener quoteListener; + final PriceInput price; + private final ChangeListener sliderListener; + private Subscription baseAmountFromModelPin, baseAmountFromCompPin, + quoteAmountFromCompPin, priceFromCompPin, minRangeCustomValuePin, maxRangeCustomValuePin, + baseSideAmountValidPin, quoteSideAmountValidPin; + + public AmountSelectionController(ServiceProvider serviceProvider, + boolean useQuoteCurrencyForMinMaxRange) { + quoteSideAmountInput = new BigAmountInput(false); + baseSideAmountInput = new SmallAmountInput(true); + baseSideAmountInput.setUseLowPrecision(false); + price = new PriceInput(serviceProvider.getBondedRolesService().getMarketPriceService()); + + model = new AmountSelectionModel(useQuoteCurrencyForMinMaxRange); + view = new AmountSelectionView(model, this, + baseSideAmountInput, + quoteSideAmountInput); + + // We delay with runLater to avoid that we get triggered at market change from the component's data changes and + // apply the conversion before the other component has processed the market change event. + // The order of the event notification is not deterministic. + baseSideAmountFromModelListener = (observable, oldValue, newValue) -> UIThread.runOnNextRenderFrame(this::setQuoteFromBase); + quoteSideAmountFromModelListener = (observable, oldValue, newValue) -> UIThread.runOnNextRenderFrame(this::setBaseFromQuote); + quoteListener = (observable, oldValue, newValue) -> { + model.getMinRangeBaseSideValue().set(null); + model.getMaxRangeBaseSideValue().set(null); + model.getMinRangeQuoteSideValue().set(null); + model.getMaxRangeQuoteSideValue().set(null); + applyInitialRangeValues(); + UIThread.runOnNextRenderFrame(this::applyQuote); + }; + sliderListener = (observable, oldValue, newValue) -> { + if (model.getMinRangeQuoteSideValue().get() != null && model.getMinRangeBaseSideValue().get() != null) { + double sliderValue = newValue.doubleValue(); + long min = model.isUseQuoteCurrencyForMinMaxRange() ? + model.getMinRangeQuoteSideValue().get().getValue() : + model.getMinRangeBaseSideValue().get().getValue(); + long max = model.isUseQuoteCurrencyForMinMaxRange() ? + model.getMaxRangeQuoteSideValue().get().getValue() : + model.getMaxRangeBaseSideValue().get().getValue(); + long value = Math.round(sliderValue * (max - min)) + min; + if (model.isUseQuoteCurrencyForMinMaxRange()) { + quoteSideAmountInput.setAmount(Monetary.from(value, model.getMarket().getQuoteCurrencyCode())); + } else { + baseSideAmountInput.setAmount(Monetary.from(value, model.getMarket().getBaseCurrencyCode())); + } + } + }; + } + + void setBaseSideAmount(Monetary value) { + model.getBaseSideAmount().set(value); + } + + void setQuoteSideAmount(Monetary value) { + model.getQuoteSideAmount().set(value); + } + + public ReadOnlyObjectProperty getBaseSideAmount() { + return model.getBaseSideAmount(); + } + + public ReadOnlyObjectProperty getQuoteSideAmount() { + return model.getQuoteSideAmount(); + } + + public void setDirection(Direction direction) { + if (direction == null) { + return; + } + model.setDirection(direction); + model.getSpendOrReceiveString().set(direction == Direction.BUY ? Res.get("offer.buying") : Res.get("offer.selling")); + } + + void setTooltip(String tooltip) { + baseSideAmountInput.setTooltip(tooltip); + } + + public void setMarket(Market market) { + if (market == null) { + return; + } + model.setMarket(market); + baseSideAmountInput.setSelectedMarket(market); + quoteSideAmountInput.setSelectedMarket(market); + price.setMarket(market); + } + + public void setDescription(String description) { + model.getDescription().set(description); + } + + public void setMinMaxRange(Monetary minRangeValue, Monetary maxRangeValue) { + boolean minRangeValueIsFiat = FiatCurrencyRepository.getCurrencyByCodeMap().containsKey(minRangeValue.getCode()); + boolean maxRangeValueIsFiat = FiatCurrencyRepository.getCurrencyByCodeMap().containsKey(maxRangeValue.getCode()); + if (model.isUseQuoteCurrencyForMinMaxRange()) { + checkArgument(minRangeValueIsFiat && maxRangeValueIsFiat, + "The provided minRangeValue and maxRangeValue must be fiat currencies as useQuoteCurrencyForMinMaxRange is set to true."); + } else { + checkArgument(!minRangeValueIsFiat && !maxRangeValueIsFiat, + "The provided minRangeValue and maxRangeValue must not be fiat currencies as useQuoteCurrencyForMinMaxRange is set to false."); + } + + model.getMinRangeMonetary().set(minRangeValue); + model.getMaxRangeMonetary().set(maxRangeValue); + applyInitialRangeValues(); + } + + public void setLeftMarkerQuoteSideValue(Monetary quoteSideAmount) { + model.setLeftMarkerQuoteSideValue(quoteSideAmount); + applySliderTrackStyle(); + } + + public void setRightMarkerQuoteSideValue(Monetary quoteSideAmount) { + model.setRightMarkerQuoteSideValue(quoteSideAmount); + applySliderTrackStyle(); + } + + public void applyReputationBasedQuoteSideAmount() { + quoteSideAmountInput.setAmount(model.getRightMarkerQuoteSideValue()); + } + + public void setQuote(PriceQuote priceQuote) { + if (priceQuote != null) { + price.setQuote(priceQuote); + } + } + + public ReadOnlyObjectProperty getQuote() { + return price.getQuote(); + } + + public Monetary getRightMarkerQuoteSideValue() { + return model.getRightMarkerQuoteSideValue(); + } + + public void reset() { + baseSideAmountInput.reset(); + quoteSideAmountInput.reset(); + price.reset(); + model.reset(); + } + + @Override + public void onActivate() { + model.getMinRangeBaseSideValue().set(null); + model.getMaxRangeBaseSideValue().set(null); + model.getMinRangeQuoteSideValue().set(null); + model.getMaxRangeQuoteSideValue().set(null); + model.getDescription().set(Res.get("bisqEasy.tradeWizard.amount.description", model.getMarket().getQuoteCurrencyCode())); + applyInitialRangeValues(); + + model.getBaseSideAmount().addListener(baseSideAmountFromModelListener); + model.getQuoteSideAmount().addListener(quoteSideAmountFromModelListener); + price.getQuote().addListener(quoteListener); + + baseSideAmountInput.setAmount(null); + if (model.getQuoteSideAmount().get() == null) { + PriceQuote priceQuote = price.getQuote().get(); + if (priceQuote != null) { + Monetary minRangeQuoteSideValue = model.getMinRangeQuoteSideValue().get(); + Monetary maxRangeQuoteSideValue = model.getMaxRangeQuoteSideValue().get(); + long midValue = minRangeQuoteSideValue.getValue() + (maxRangeQuoteSideValue.getValue() - minRangeQuoteSideValue.getValue()) / 2; + Monetary exactAmount = Fiat.fromValue(midValue, priceQuote.getQuoteSideMonetary().getCode()); + quoteSideAmountInput.setAmount(exactAmount.round(0)); + } else { + log.warn("price.quoteProperty().get() is null. We use a fiat value of 100 as default value."); + Fiat defaultQuoteSideAmount = Fiat.fromFaceValue(100, model.getMarket().getQuoteCurrencyCode()); + quoteSideAmountInput.setAmount(defaultQuoteSideAmount); + } + } else { + quoteSideAmountInput.setAmount(model.getQuoteSideAmount().get()); + } + setBaseFromQuote(); + + baseAmountFromModelPin = EasyBind.subscribe(model.getBaseSideAmount(), amount -> { + // Only apply value from component to slider if we have no focus on slider (not used) + if (amount != null) { + if (!model.getSliderFocus().get()) { + long min = model.getMinRangeBaseSideValue().get().getValue(); + long max = model.getMaxRangeBaseSideValue().get().getValue(); + double sliderValue = (amount.getValue() - min) / ((double) max - min); + model.getSliderValue().set(sliderValue); + } + } + }); + + baseAmountFromCompPin = EasyBind.subscribe(baseSideAmountInput.amountProperty(), + amount -> { + Monetary minRangeValue = model.getMinRangeBaseSideValue().get(); + Monetary maxRangeValue = model.getMaxRangeBaseSideValue().get(); + if (amount != null && amount.getValue() > maxRangeValue.getValue()) { + model.getBaseSideAmount().set(maxRangeValue); + setQuoteFromBase(); + baseSideAmountInput.setAmount(maxRangeValue); + } else if (amount != null && amount.getValue() < minRangeValue.getValue()) { + model.getBaseSideAmount().set(minRangeValue); + setQuoteFromBase(); + baseSideAmountInput.setAmount(minRangeValue); + } else { + model.getBaseSideAmount().set(amount); + } + }); + + quoteAmountFromCompPin = EasyBind.subscribe(quoteSideAmountInput.amountProperty(), + amount -> { + Monetary minRangeValue = model.getMinRangeQuoteSideValue().get(); + Monetary maxRangeValue = model.getMaxRangeQuoteSideValue().get(); + if (maxRangeValue != null && amount != null && amount.getValue() > maxRangeValue.getValue()) { + model.getQuoteSideAmount().set(maxRangeValue); + setBaseFromQuote(); + quoteSideAmountInput.setAmount(maxRangeValue); + } else if (minRangeValue != null && amount != null && amount.getValue() < minRangeValue.getValue()) { + model.getQuoteSideAmount().set(minRangeValue); + setBaseFromQuote(); + quoteSideAmountInput.setAmount(minRangeValue); + } else { + model.getQuoteSideAmount().set(amount); + } + }); + priceFromCompPin = EasyBind.subscribe(price.getQuote(), + quote -> applyInitialRangeValues()); + + minRangeCustomValuePin = EasyBind.subscribe(model.getMinRangeMonetary(), + value -> applyInitialRangeValues()); + maxRangeCustomValuePin = EasyBind.subscribe(model.getMaxRangeMonetary(), + value -> applyInitialRangeValues()); + + baseSideAmountValidPin = subscribeToAmountValidity(baseSideAmountInput, this::setBaseFromQuote); + quoteSideAmountValidPin = subscribeToAmountValidity(quoteSideAmountInput, this::setQuoteFromBase); + model.getSliderValue().addListener(sliderListener); + } + + private Subscription subscribeToAmountValidity(AmountInput amountInput, Runnable autocorrect) { + return EasyBind.subscribe(amountInput.isAmountValidProperty(), isAmountValid -> { + if (!amountInput.isAmountValidProperty().get()) { + autocorrect.run(); + amountInput.isAmountValidProperty().set(true); + } + }); + } + + private void applyInitialRangeValues() { + PriceQuote priceQuote = price.getQuote().get(); + if (priceQuote == null) { + return; + } + + Monetary minRangeMonetary = model.getMinRangeMonetary().get(); + Monetary maxRangeMonetary = model.getMaxRangeMonetary().get(); + boolean isMinRangeMonetaryFiat = FiatCurrencyRepository.getCurrencyByCodeMap().containsKey(minRangeMonetary.getCode()); + boolean isMaxRangeMonetaryFiat = FiatCurrencyRepository.getCurrencyByCodeMap().containsKey(maxRangeMonetary.getCode()); + + Monetary minRangeMonetaryAsCoin = !isMinRangeMonetaryFiat ? + minRangeMonetary : + priceQuote.toBaseSideMonetary(minRangeMonetary); + model.getMinRangeBaseSideValue().set(minRangeMonetaryAsCoin); + if (!model.isUseQuoteCurrencyForMinMaxRange()) { + model.getMinRangeValueAsString().set(Res.get("bisqEasy.component.amount.minRangeValue", + AmountFormatter.formatAmountWithCode(minRangeMonetaryAsCoin))); + } + + Monetary maxRangeMonetaryAsCoin = !isMaxRangeMonetaryFiat ? + maxRangeMonetary : + priceQuote.toBaseSideMonetary(maxRangeMonetary); + model.getMaxRangeBaseSideValue().set(maxRangeMonetaryAsCoin); + if (!model.isUseQuoteCurrencyForMinMaxRange()) { + model.getMaxRangeValueAsString().set(Res.get("bisqEasy.component.amount.maxRangeValue", + AmountFormatter.formatAmountWithCode(maxRangeMonetaryAsCoin))); + } + + Monetary minRangeMonetaryAsFiat = isMinRangeMonetaryFiat ? + minRangeMonetary : + priceQuote.toQuoteSideMonetary(minRangeMonetary).round(0); + model.getMinRangeQuoteSideValue().set(minRangeMonetaryAsFiat); + if (model.isUseQuoteCurrencyForMinMaxRange()) { + model.getMinRangeValueAsString().set(Res.get("bisqEasy.component.amount.minRangeValue", + AmountFormatter.formatAmountWithCode(minRangeMonetaryAsFiat))); + } + + Monetary maxRangeMonetaryAsFiat = isMaxRangeMonetaryFiat ? + maxRangeMonetary : + priceQuote.toQuoteSideMonetary(maxRangeMonetary).round(0); + model.getMaxRangeQuoteSideValue().set(maxRangeMonetaryAsFiat); + if (model.isUseQuoteCurrencyForMinMaxRange()) { + model.getMaxRangeValueAsString().set(Res.get("bisqEasy.component.amount.maxRangeValue", + AmountFormatter.formatAmountWithCode(maxRangeMonetaryAsFiat))); + } + + applySliderTrackStyle(); + } + + private void applySliderTrackStyle() { + Monetary minRangeMonetary = model.getMinRangeQuoteSideValue().get(); + Monetary maxRangeMonetary = model.getMaxRangeQuoteSideValue().get(); + if (minRangeMonetary == null || maxRangeMonetary == null) { + return; + } + long minRangeMonetaryValue = minRangeMonetary.getValue(); + long maxRangeMonetaryValue = maxRangeMonetary.getValue(); + double range = maxRangeMonetaryValue - minRangeMonetaryValue; + + // If left value is not set we use minRange + // If left value is set but right value not set we don't show any marker + Monetary markerQuoteSideValue = model.getLeftMarkerQuoteSideValue(); + long leftMarkerQuoteSideValue = Optional.ofNullable(markerQuoteSideValue).orElse(minRangeMonetary).getValue(); + double left = leftMarkerQuoteSideValue - minRangeMonetaryValue; + double leftPercentage = range != 0 ? 100 * left / range : 0; + + long rightMarkerQuoteSideValue = Optional.ofNullable(model.getRightMarkerQuoteSideValue()).orElse(minRangeMonetary).getValue(); + double right = rightMarkerQuoteSideValue - minRangeMonetaryValue; + double rightPercentage = range != 0 ? 100 * right / range : 0; + + // E.g.: -bisq-dark-grey-50 0%, -bisq-dark-grey-50 30.0%, -bisq2-green 30.0%, -bisq2-green 60.0%, -bisq-dark-grey-50 60.0%, -bisq-dark-grey-50 100%) + String segments = String.format( + SLIDER_TRACK_DEFAULT_COLOR + " 0%%, " + + SLIDER_TRACK_DEFAULT_COLOR + " %1$.1f%%, " + + + SLIDER_TRACK_MARKER_COLOR + " %1$.1f%%, " + + SLIDER_TRACK_MARKER_COLOR + " %2$.1f%%, " + + + SLIDER_TRACK_DEFAULT_COLOR + " %2$.1f%%, " + + SLIDER_TRACK_DEFAULT_COLOR + " 100%%)", + leftPercentage, rightPercentage); + String style = "-track-color: linear-gradient(to right, " + segments + ";"; + model.getSliderTrackStyle().set(style); + } + + @Override + public void onDeactivate() { + model.getBaseSideAmount().removeListener(baseSideAmountFromModelListener); + model.getQuoteSideAmount().removeListener(quoteSideAmountFromModelListener); + price.getQuote().removeListener(quoteListener); + model.getSliderValue().removeListener(sliderListener); + baseAmountFromModelPin.unsubscribe(); + baseAmountFromCompPin.unsubscribe(); + quoteAmountFromCompPin.unsubscribe(); + priceFromCompPin.unsubscribe(); + minRangeCustomValuePin.unsubscribe(); + maxRangeCustomValuePin.unsubscribe(); + baseSideAmountValidPin.unsubscribe(); + quoteSideAmountValidPin.unsubscribe(); + model.setLeftMarkerQuoteSideValue(null); + model.setRightMarkerQuoteSideValue(null); + } + + private void setQuoteFromBase() { + PriceQuote priceQuote = price.getQuote().get(); + if (priceQuote == null) return; + Monetary baseSideAmount = model.getBaseSideAmount().get(); + if (baseSideAmount == null) return; + quoteSideAmountInput.setAmount(priceQuote.toQuoteSideMonetary(baseSideAmount).round(0)); + } + + private void setBaseFromQuote() { + PriceQuote priceQuote = price.getQuote().get(); + if (priceQuote == null) return; + Monetary quoteSideAmount = model.getQuoteSideAmount().get(); + if (quoteSideAmount == null) return; + baseSideAmountInput.setAmount(priceQuote.toBaseSideMonetary(quoteSideAmount)); + } + + private void applyQuote() { + if (model.getBaseSideAmount() == null) { + setBaseFromQuote(); + } else { + setQuoteFromBase(); + } + } +} diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionModel.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionModel.java new file mode 100644 index 0000000000..3c05879370 --- /dev/null +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionModel.java @@ -0,0 +1,90 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.desktop.main.content.bisq_easy.components.amount_selection; + +import bisq.bisq_easy.BisqEasyTradeAmountLimits; +import bisq.common.currency.Market; +import bisq.common.currency.MarketRepository; +import bisq.common.monetary.Monetary; +import bisq.desktop.common.view.Model; +import bisq.offer.Direction; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.DoubleProperty; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleDoubleProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import lombok.Getter; +import lombok.Setter; + +@Getter +public class AmountSelectionModel implements Model { + private final boolean useQuoteCurrencyForMinMaxRange; + private final double sliderMin = 0; + private final double sliderMax = 1; + + private final ObjectProperty baseSideAmount = new SimpleObjectProperty<>(); + private final ObjectProperty quoteSideAmount = new SimpleObjectProperty<>(); + private final StringProperty spendOrReceiveString = new SimpleStringProperty(); + + private final DoubleProperty sliderValue = new SimpleDoubleProperty(); + private final BooleanProperty sliderFocus = new SimpleBooleanProperty(); + + @Setter + private ObjectProperty minRangeMonetary = new SimpleObjectProperty<>(BisqEasyTradeAmountLimits.DEFAULT_MIN_BTC_TRADE_AMOUNT); + @Setter + private ObjectProperty maxRangeMonetary = new SimpleObjectProperty<>(BisqEasyTradeAmountLimits.DEFAULT_MAX_BTC_TRADE_AMOUNT); + @Setter + private ObjectProperty minRangeBaseSideValue = new SimpleObjectProperty<>(); + @Setter + private ObjectProperty maxRangeBaseSideValue = new SimpleObjectProperty<>(); + @Setter + private ObjectProperty minRangeQuoteSideValue = new SimpleObjectProperty<>(); + @Setter + private ObjectProperty maxRangeQuoteSideValue = new SimpleObjectProperty<>(); + @Setter + private Monetary leftMarkerQuoteSideValue; + @Setter + private Monetary rightMarkerQuoteSideValue; + private final StringProperty sliderTrackStyle = new SimpleStringProperty(); + @Setter + private Market market = MarketRepository.getDefault(); + @Setter + private Direction direction = Direction.BUY; + private final StringProperty description = new SimpleStringProperty(); + private final StringProperty minRangeValueAsString = new SimpleStringProperty(); + private final StringProperty maxRangeValueAsString = new SimpleStringProperty(); + + public AmountSelectionModel(boolean useQuoteCurrencyForMinMaxRange) { + this.useQuoteCurrencyForMinMaxRange = useQuoteCurrencyForMinMaxRange; + } + + void reset() { + baseSideAmount.set(null); + quoteSideAmount.set(null); + spendOrReceiveString.set(null); + sliderValue.set(0L); + sliderFocus.set(false); + market = MarketRepository.getDefault(); + direction = Direction.BUY; + leftMarkerQuoteSideValue = null; + rightMarkerQuoteSideValue = null; + } +} diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java new file mode 100644 index 0000000000..87f875625d --- /dev/null +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java @@ -0,0 +1,170 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.desktop.main.content.bisq_easy.components.amount_selection; + +import bisq.desktop.common.Transitions; +import bisq.desktop.common.threading.UIScheduler; +import bisq.desktop.common.view.View; +import bisq.desktop.components.containers.Spacer; +import bisq.desktop.main.content.bisq_easy.components.BigAmountInput; +import bisq.desktop.main.content.bisq_easy.components.SmallAmountInput; +import javafx.beans.property.ReadOnlyBooleanProperty; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Parent; +import javafx.scene.control.Label; +import javafx.scene.control.Slider; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Pane; +import javafx.scene.layout.Region; +import javafx.scene.layout.VBox; +import lombok.extern.slf4j.Slf4j; +import org.fxmisc.easybind.EasyBind; +import org.fxmisc.easybind.Subscription; + +@Slf4j +public class AmountSelectionView extends View { + public final static int AMOUNT_BOX_WIDTH = 330; + public final static int AMOUNT_BOX_HEIGHT = 130; + + private final Slider slider = new Slider(); + private final Label minRangeValue, maxRangeValue, description; + private final Region selectionLine; + private final SmallAmountInput baseAmount; + private final BigAmountInput quoteAmount; + private Subscription baseAmountFocusPin, quoteAmountFocusPin, sliderTrackStylePin; + + AmountSelectionView(AmountSelectionModel model, + AmountSelectionController controller, + SmallAmountInput baseAmount, + BigAmountInput quoteAmount) { + super(new VBox(10), model, controller); + + Pane baseAmountRoot = baseAmount.getRoot(); + this.baseAmount = baseAmount; + Pane quoteAmountRoot = quoteAmount.getRoot(); + this.quoteAmount = quoteAmount; + + description = new Label(); + description.getStyleClass().add("description"); + description.setMouseTransparent(true); + + VBox amountVBox = new VBox(0, description, Spacer.fillVBox(), quoteAmountRoot, + Spacer.fillVBox(), baseAmountRoot); + amountVBox.getStyleClass().add("bisq-dual-amount-bg"); + amountVBox.setMinWidth(AMOUNT_BOX_WIDTH); + amountVBox.setMaxWidth(AMOUNT_BOX_WIDTH); + amountVBox.setMinHeight(AMOUNT_BOX_HEIGHT); + amountVBox.setMaxHeight(AMOUNT_BOX_HEIGHT); + amountVBox.setPadding(new Insets(5, 20, 10, 20)); + + Region line = new Region(); + line.setPrefHeight(1); + line.setPrefWidth(AMOUNT_BOX_WIDTH); + line.setLayoutY(AMOUNT_BOX_HEIGHT); + line.setStyle("-fx-background-color: -bisq-mid-grey-20"); + line.setMouseTransparent(true); + + selectionLine = new Region(); + selectionLine.getStyleClass().add("material-text-field-selection-line"); + selectionLine.setPrefHeight(3); + selectionLine.setPrefWidth(0); + selectionLine.setLayoutY(AMOUNT_BOX_HEIGHT - 2); + selectionLine.setMouseTransparent(true); + + Pane amountPane = new Pane(amountVBox, line, selectionLine); + amountPane.setMaxWidth(AMOUNT_BOX_WIDTH); + + slider.setMin(model.getSliderMin()); + slider.setMax(model.getSliderMax()); + + minRangeValue = new Label(); + minRangeValue.getStyleClass().add("bisq-small-light-label-dimmed"); + + maxRangeValue = new Label(); + maxRangeValue.getStyleClass().add("bisq-small-light-label-dimmed"); + + VBox sliderBox = new VBox(2, slider, new HBox(minRangeValue, Spacer.fillHBox(), maxRangeValue)); + sliderBox.setMaxWidth(AMOUNT_BOX_WIDTH); + +// VBox.setMargin(amountPane, new Insets(0, 0, 20, 0)); + root.getChildren().addAll(amountPane, sliderBox); + root.getStyleClass().add("amount-component"); + root.setAlignment(Pos.TOP_CENTER); + } + + @Override + protected void onViewAttached() { + UIScheduler.run(() -> { + quoteAmount.requestFocus(); + baseAmountFocusPin = EasyBind.subscribe(baseAmount.focusedProperty(), + focus -> onInputTextFieldFocus(quoteAmount.focusedProperty(), focus)); + quoteAmountFocusPin = EasyBind.subscribe(quoteAmount.focusedProperty(), + focus -> onInputTextFieldFocus(baseAmount.focusedProperty(), focus)); + }).after(700); + + sliderTrackStylePin = EasyBind.subscribe(model.getSliderTrackStyle(), slider::setStyle); + slider.valueProperty().bindBidirectional(model.getSliderValue()); + model.getSliderFocus().bind(slider.focusedProperty()); + description.textProperty().bind(model.getDescription()); + minRangeValue.textProperty().bind(model.getMinRangeValueAsString()); + maxRangeValue.textProperty().bind(model.getMaxRangeValueAsString()); + // Needed to trigger focusOut event on amount components + // We handle all parents mouse events. + Parent node = root; + while (node.getParent() != null) { + node.setOnMousePressed(e -> root.requestFocus()); + node = node.getParent(); + } + } + + @Override + protected void onViewDetached() { + if (baseAmountFocusPin != null) { + baseAmountFocusPin.unsubscribe(); + } + if (quoteAmountFocusPin != null) { + quoteAmountFocusPin.unsubscribe(); + } + sliderTrackStylePin.unsubscribe(); + slider.valueProperty().unbindBidirectional(model.getSliderValue()); + model.getSliderFocus().unbind(); + description.textProperty().unbind(); + minRangeValue.textProperty().unbind(); + maxRangeValue.textProperty().unbind(); + baseAmount.isAmountValidProperty().set(true); + quoteAmount.isAmountValidProperty().set(true); + Parent node = root; + while (node.getParent() != null) { + node.setOnMousePressed(null); + node = node.getParent(); + } + } + + private void onInputTextFieldFocus(ReadOnlyBooleanProperty other, boolean focus) { + if (focus) { + selectionLine.setPrefWidth(0); + selectionLine.setOpacity(1); + Transitions.animateWidth(selectionLine, AMOUNT_BOX_WIDTH); + } else if (!other.get()) { + // If switching between the 2 fields we want to avoid to get the fadeout called that's why + // we do the check with !other.get() + Transitions.fadeOut(selectionLine, 200); + } + } +} diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/take_offer/amount/TakeOfferAmountController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/take_offer/amount/TakeOfferAmountController.java index 2dd8fb7e06..ee103144e8 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/take_offer/amount/TakeOfferAmountController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/take_offer/amount/TakeOfferAmountController.java @@ -25,7 +25,7 @@ import bisq.desktop.common.Browser; import bisq.desktop.common.utils.KeyHandlerUtil; import bisq.desktop.common.view.Controller; -import bisq.desktop.main.content.bisq_easy.components.AmountComponent; +import bisq.desktop.main.content.bisq_easy.components.amount_selection.AmountSelectionController; import bisq.i18n.Res; import bisq.offer.Direction; import bisq.offer.amount.OfferAmountUtil; @@ -51,7 +51,7 @@ public class TakeOfferAmountController implements Controller { private final TakeOfferAmountModel model; @Getter private final TakeOfferAmountView view; - private final AmountComponent amountComponent; + private final AmountSelectionController amountSelectionController; private final MarketPriceService marketPriceService; private final UserIdentityService userIdentityService; private final ReputationService reputationService; @@ -62,8 +62,8 @@ public TakeOfferAmountController(ServiceProvider serviceProvider) { marketPriceService = serviceProvider.getBondedRolesService().getMarketPriceService(); userIdentityService = serviceProvider.getUserService().getUserIdentityService(); reputationService = serviceProvider.getUserService().getReputationService(); - amountComponent = new AmountComponent(serviceProvider, true); - view = new TakeOfferAmountView(model, this, amountComponent.getView().getRoot()); + amountSelectionController = new AmountSelectionController(serviceProvider, true); + view = new TakeOfferAmountView(model, this, amountSelectionController.getView().getRoot()); } public void init(BisqEasyOffer bisqEasyOffer, Optional optionalReputationBasedQuoteSideAmount) { @@ -71,12 +71,12 @@ public void init(BisqEasyOffer bisqEasyOffer, Optional optionalReputat Direction takersDirection = bisqEasyOffer.getTakersDirection(); model.setHeadline(takersDirection.isBuy() ? Res.get("bisqEasy.takeOffer.amount.headline.buyer") : Res.get("bisqEasy.takeOffer.amount.headline.seller")); - amountComponent.setDirection(takersDirection); + amountSelectionController.setDirection(takersDirection); Market market = bisqEasyOffer.getMarket(); - amountComponent.setMarket(market); + amountSelectionController.setMarket(market); PriceUtil.findQuote(marketPriceService, bisqEasyOffer.getPriceSpec(), bisqEasyOffer.getMarket()) - .ifPresent(amountComponent::setQuote); + .ifPresent(amountSelectionController::setQuote); Optional OptionalQuoteSideMinAmount = OfferAmountUtil.findQuoteSideMinAmount(marketPriceService, bisqEasyOffer); if (OptionalQuoteSideMinAmount.isPresent()) { @@ -90,12 +90,12 @@ public void init(BisqEasyOffer bisqEasyOffer, Optional optionalReputat maxAmount = reputationBasedQuoteSideAmount.isGreaterThan(offersQuoteSideMaxOrFixedAmount) ? offersQuoteSideMaxOrFixedAmount : reputationBasedQuoteSideAmount; - amountComponent.setRightMarkerQuoteSideValue(maxAmount); + amountSelectionController.setRightMarkerQuoteSideValue(maxAmount); applyQuoteSideMinMaxRange(quoteSideMinAmount, maxAmount); long sellersScore = reputationService.getReputationScore(userIdentityService.getSelectedUserIdentity().getUserProfile()).getTotalScore(); // TODO: Move this outside of the component - amountComponent.setDescription(Res.get("bisqEasy.takeOffer.amount.description.limitedByTakersReputation", + amountSelectionController.setDescription(Res.get("bisqEasy.takeOffer.amount.description.limitedByTakersReputation", sellersScore, formattedMinAmount, AmountFormatter.formatAmountWithCode(maxAmount))); @@ -104,7 +104,7 @@ public void init(BisqEasyOffer bisqEasyOffer, Optional optionalReputat maxAmount = offersQuoteSideMaxOrFixedAmount; applyQuoteSideMinMaxRange(quoteSideMinAmount, maxAmount); // TODO: Move this outside of the component - amountComponent.setDescription(Res.get("bisqEasy.takeOffer.amount.description", + amountSelectionController.setDescription(Res.get("bisqEasy.takeOffer.amount.description", formattedMinAmount, AmountFormatter.formatAmountWithCode(maxAmount))); } @@ -113,7 +113,7 @@ public void init(BisqEasyOffer bisqEasyOffer, Optional optionalReputat : Res.get("bisqEasy.component.amount.baseSide.tooltip.seller.btcAmount"); Optional priceQuoteOptional = PriceUtil.findQuote(marketPriceService, model.getBisqEasyOffer()) .map(priceQuote -> "\n" + Res.get("bisqEasy.component.amount.baseSide.tooltip.taker.offerPrice", PriceFormatter.formatWithCode(priceQuote))); - priceQuoteOptional.ifPresent(priceQuote -> amountComponent.setTooltip(String.format("%s%s", btcAmount, priceQuote))); + priceQuoteOptional.ifPresent(priceQuote -> amountSelectionController.setTooltip(String.format("%s%s", btcAmount, priceQuote))); } } @@ -127,9 +127,9 @@ public ReadOnlyObjectProperty getTakersBaseSideAmount() { @Override public void onActivate() { - baseSideAmountPin = EasyBind.subscribe(amountComponent.getBaseSideAmount(), + baseSideAmountPin = EasyBind.subscribe(amountSelectionController.getBaseSideAmount(), amount -> model.getTakersBaseSideAmount().set(amount)); - quoteSideAmountPin = EasyBind.subscribe(amountComponent.getQuoteSideAmount(), + quoteSideAmountPin = EasyBind.subscribe(amountSelectionController.getQuoteSideAmount(), amount -> { model.getTakersQuoteSideAmount().set(amount); if (amount != null) { @@ -149,7 +149,7 @@ public void onDeactivate() { } void onSetReputationBasedAmount() { - amountComponent.setQuoteSideAmount(amountComponent.getRightMarkerQuoteSideValue().round(0)); + amountSelectionController.setQuoteSideAmount(amountSelectionController.getRightMarkerQuoteSideValue().round(0)); } void onShowAmountLimitInfoOverlay() { @@ -171,7 +171,7 @@ void onOpenWiki(String url) { } private void applyQuoteSideMinMaxRange(Monetary minRangeValue, Monetary maxRangeValue) { - amountComponent.setMinMaxRange(minRangeValue, maxRangeValue); + amountSelectionController.setMinMaxRange(minRangeValue, maxRangeValue); BisqEasyOffer bisqEasyOffer = model.getBisqEasyOffer(); Market market = bisqEasyOffer.getMarket(); @@ -193,8 +193,8 @@ private void applyQuoteSideMinMaxRange(Monetary minRangeValue, Monetary maxRange if (reputationBasedQuoteSideAmount.isLessThan(maxRangeValue)) { model.getIsAmountLimitInfoVisible().set(true); - amountComponent.setRightMarkerQuoteSideValue(reputationBasedQuoteSideAmount); - amountComponent.setQuoteSideAmount(reputationBasedQuoteSideAmount); + amountSelectionController.setRightMarkerQuoteSideValue(reputationBasedQuoteSideAmount); + amountSelectionController.setQuoteSideAmount(reputationBasedQuoteSideAmount); String formattedAmount = AmountFormatter.formatAmountWithCode(reputationBasedQuoteSideAmount); if (sellersReputationScore <= MIN_REPUTAION_SCORE) { @@ -230,13 +230,13 @@ private void applyQuoteSideMinMaxRange(Monetary minRangeValue, Monetary maxRange model.setLinkToWikiText(Res.get("bisqEasy.tradeWizard.amount.seller.limitInfo.overlay.linkToWikiText")); String myProfileId = userIdentityService.getSelectedUserIdentity().getUserProfile().getId(); long myReputationScore = reputationService.getReputationScore(myProfileId).getTotalScore(); - Monetary quoteSideAmount = amountComponent.getQuoteSideAmount().get(); + Monetary quoteSideAmount = amountSelectionController.getQuoteSideAmount().get(); BisqEasyTradeAmountLimits.getReputationBasedQuoteSideAmount(marketPriceService, market, myReputationScore) .ifPresent(myReputationBasedQuoteSideAmount -> { myReputationBasedQuoteSideAmount = myReputationBasedQuoteSideAmount.round(0); model.getIsAmountHyperLinkDisabled().set(myReputationBasedQuoteSideAmount.isGreaterThan(maxRangeValue)); - amountComponent.setRightMarkerQuoteSideValue(myReputationBasedQuoteSideAmount); + amountSelectionController.setRightMarkerQuoteSideValue(myReputationBasedQuoteSideAmount); String formattedAmount = AmountFormatter.formatAmountWithCode(myReputationBasedQuoteSideAmount); model.getIsAmountLimitInfoVisible().set(true); model.getAmountLimitInfoAmount().set(Res.get("bisqEasy.tradeWizard.amount.seller.limitInfoAmount", formattedAmount)); @@ -275,13 +275,13 @@ private void applyQuoteSideMinMaxRange(Monetary minRangeValue, Monetary maxRange } private void applyReputationBasedQuoteSideAmount() { - amountComponent.setQuoteSideAmount(amountComponent.getRightMarkerQuoteSideValue().round(0)); + amountSelectionController.setQuoteSideAmount(amountSelectionController.getRightMarkerQuoteSideValue().round(0)); } private void maxOrFixedQuoteSideAmountChanged(Monetary value) { - if (amountComponent.getRightMarkerQuoteSideValue() == null) { + if (amountSelectionController.getRightMarkerQuoteSideValue() == null) { return; } - model.getIsWarningIconVisible().set(value.round(0).getValue() > amountComponent.getRightMarkerQuoteSideValue().round(0).getValue()); + model.getIsWarningIconVisible().set(value.round(0).getValue() > amountSelectionController.getRightMarkerQuoteSideValue().round(0).getValue()); } } diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java index 744d0beb46..5fb554afde 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java @@ -36,7 +36,7 @@ import bisq.desktop.common.utils.KeyHandlerUtil; import bisq.desktop.common.view.Controller; import bisq.desktop.components.overlay.Popup; -import bisq.desktop.main.content.bisq_easy.components.AmountComponent; +import bisq.desktop.main.content.bisq_easy.components.amount_selection.AmountSelectionController; import bisq.i18n.Res; import bisq.offer.Direction; import bisq.offer.Offer; @@ -84,7 +84,7 @@ public class TradeWizardAmountController implements Controller { private final TradeWizardAmountModel model; @Getter private final TradeWizardAmountView view; - private final AmountComponent minAmountComponent, maxOrFixAmountComponent; + private final AmountSelectionController minAmountSelectionController, maxOrFixAmountSelectionController; private final SettingsService settingsService; private final MarketPriceService marketPriceService; private final BisqEasyOfferbookChannelService bisqEasyOfferbookChannelService; @@ -107,12 +107,12 @@ public TradeWizardAmountController(ServiceProvider serviceProvider, Region owner this.owner = owner; model = new TradeWizardAmountModel(); - minAmountComponent = new AmountComponent(serviceProvider, true); - maxOrFixAmountComponent = new AmountComponent(serviceProvider, true); + minAmountSelectionController = new AmountSelectionController(serviceProvider, true); + maxOrFixAmountSelectionController = new AmountSelectionController(serviceProvider, true); view = new TradeWizardAmountView(model, this, - minAmountComponent, - maxOrFixAmountComponent); + minAmountSelectionController, + maxOrFixAmountSelectionController); } public void setIsCreateOfferMode(boolean isCreateOfferMode) { @@ -128,16 +128,16 @@ public void setDirection(Direction direction) { return; } model.setDirection(direction); - minAmountComponent.setDirection(direction); - maxOrFixAmountComponent.setDirection(direction); + minAmountSelectionController.setDirection(direction); + maxOrFixAmountSelectionController.setDirection(direction); } public void setMarket(Market market) { if (market == null) { return; } - minAmountComponent.setMarket(market); - maxOrFixAmountComponent.setMarket(market); + minAmountSelectionController.setMarket(market); + maxOrFixAmountSelectionController.setMarket(market); model.setMarket(market); applyQuoteSideMinMaxRange(); } @@ -186,16 +186,16 @@ public void updateQuoteSideAmountSpecWithPriceSpec(PriceSpec priceSpec) { return; } model.getPriceQuote().set(priceQuote.get()); - minAmountComponent.setQuote(priceQuote.get()); - maxOrFixAmountComponent.setQuote(priceQuote.get()); + minAmountSelectionController.setQuote(priceQuote.get()); + maxOrFixAmountSelectionController.setQuote(priceQuote.get()); OfferAmountUtil.updateQuoteSideAmountSpecWithPriceSpec(marketPriceService, amountSpec, priceSpec, market) .ifPresent(quoteSideAmountSpec -> model.getQuoteSideAmountSpec().set(quoteSideAmountSpec)); } public void reset() { - minAmountComponent.reset(); - maxOrFixAmountComponent.reset(); + minAmountSelectionController.reset(); + maxOrFixAmountSelectionController.reset(); model.reset(); } @@ -207,8 +207,8 @@ public ReadOnlyObjectProperty getQuoteSideAmountSpec() { public void onActivate() { applyQuoteSideMinMaxRange(); - if (model.getPriceQuote().get() == null && minAmountComponent.getQuote().get() != null) { - model.getPriceQuote().set(minAmountComponent.getQuote().get()); + if (model.getPriceQuote().get() == null && minAmountSelectionController.getQuote().get() != null) { + model.getPriceQuote().set(minAmountSelectionController.getQuote().get()); } model.setHeadline(model.getDirection().isBuy() ? Res.get("bisqEasy.tradeWizard.amount.headline.buyer") : @@ -217,44 +217,44 @@ public void onActivate() { Boolean cookieValue = settingsService.getCookie().asBoolean(CookieKey.CREATE_BISQ_EASY_OFFER_IS_MIN_AMOUNT_ENABLED).orElse(false); model.getIsRangeAmountEnabled().set(cookieValue && model.getShowRangeAmounts().get()); - minAmountCompBaseSideAmountPin = EasyBind.subscribe(minAmountComponent.getBaseSideAmount(), + minAmountCompBaseSideAmountPin = EasyBind.subscribe(minAmountSelectionController.getBaseSideAmount(), value -> { if (model.getIsRangeAmountEnabled().get()) { - if (value != null && maxOrFixAmountComponent.getBaseSideAmount().get() != null && - value.getValue() > maxOrFixAmountComponent.getBaseSideAmount().get().getValue()) { - maxOrFixAmountComponent.setBaseSideAmount(value); + if (value != null && maxOrFixAmountSelectionController.getBaseSideAmount().get() != null && + value.getValue() > maxOrFixAmountSelectionController.getBaseSideAmount().get().getValue()) { + maxOrFixAmountSelectionController.setBaseSideAmount(value); } } }); - maxOrFixAmountCompBaseSideAmountPin = EasyBind.subscribe(maxOrFixAmountComponent.getBaseSideAmount(), + maxOrFixAmountCompBaseSideAmountPin = EasyBind.subscribe(maxOrFixAmountSelectionController.getBaseSideAmount(), value -> { if (value != null && model.getIsRangeAmountEnabled().get() && - minAmountComponent.getBaseSideAmount().get() != null && - value.getValue() < minAmountComponent.getBaseSideAmount().get().getValue()) { - minAmountComponent.setBaseSideAmount(value); + minAmountSelectionController.getBaseSideAmount().get() != null && + value.getValue() < minAmountSelectionController.getBaseSideAmount().get().getValue()) { + minAmountSelectionController.setBaseSideAmount(value); } }); - minAmountCompQuoteSideAmountPin = EasyBind.subscribe(minAmountComponent.getQuoteSideAmount(), + minAmountCompQuoteSideAmountPin = EasyBind.subscribe(minAmountSelectionController.getQuoteSideAmount(), value -> { if (value != null) { if (model.getIsRangeAmountEnabled().get() && - maxOrFixAmountComponent.getQuoteSideAmount().get() != null && - value.getValue() > maxOrFixAmountComponent.getQuoteSideAmount().get().getValue()) { - maxOrFixAmountComponent.setQuoteSideAmount(value); + maxOrFixAmountSelectionController.getQuoteSideAmount().get() != null && + value.getValue() > maxOrFixAmountSelectionController.getQuoteSideAmount().get().getValue()) { + maxOrFixAmountSelectionController.setQuoteSideAmount(value); } applyAmountSpec(); quoteSideAmountsChanged(false); } }); - maxAmountCompQuoteSideAmountPin = EasyBind.subscribe(maxOrFixAmountComponent.getQuoteSideAmount(), + maxAmountCompQuoteSideAmountPin = EasyBind.subscribe(maxOrFixAmountSelectionController.getQuoteSideAmount(), value -> { if (value != null) { if (model.getIsRangeAmountEnabled().get() && - minAmountComponent.getQuoteSideAmount().get() != null && - value.getValue() < minAmountComponent.getQuoteSideAmount().get().getValue()) { - minAmountComponent.setQuoteSideAmount(value); + minAmountSelectionController.getQuoteSideAmount().get() != null && + value.getValue() < minAmountSelectionController.getQuoteSideAmount().get().getValue()) { + minAmountSelectionController.setQuoteSideAmount(value); } applyAmountSpec(); quoteSideAmountsChanged(true); @@ -288,8 +288,8 @@ public void onActivate() { priceTooltipPin = EasyBind.subscribe(model.getPriceTooltip(), priceTooltip -> { if (priceTooltip != null) { - minAmountComponent.setTooltip(priceTooltip); - maxOrFixAmountComponent.setTooltip(priceTooltip); + minAmountSelectionController.setTooltip(priceTooltip); + maxOrFixAmountSelectionController.setTooltip(priceTooltip); } }); } @@ -343,17 +343,17 @@ private void updateIsRangeAmountEnabled(boolean useRangeAmount) { } private void applyAmountSpec() { - Long maxOrFixAmount = getAmountValue(maxOrFixAmountComponent.getQuoteSideAmount()); + Long maxOrFixAmount = getAmountValue(maxOrFixAmountSelectionController.getQuoteSideAmount()); if (maxOrFixAmount == null) { return; } if (model.getIsRangeAmountEnabled().get()) { - Long minAmount = getAmountValue(minAmountComponent.getQuoteSideAmount()); + Long minAmount = getAmountValue(minAmountSelectionController.getQuoteSideAmount()); checkNotNull(minAmount); if (maxOrFixAmount.compareTo(minAmount) < 0) { - minAmountComponent.setQuoteSideAmount(maxOrFixAmountComponent.getQuoteSideAmount().get()); - minAmount = getAmountValue(minAmountComponent.getQuoteSideAmount()); + minAmountSelectionController.setQuoteSideAmount(maxOrFixAmountSelectionController.getQuoteSideAmount().get()); + minAmount = getAmountValue(minAmountSelectionController.getQuoteSideAmount()); } applyRangeOrFixedAmountSpec(minAmount, maxOrFixAmount); } else { @@ -410,12 +410,12 @@ private Optional findBestOfferQuote() { ? priceQuoteStream.min(Comparator.comparing(PriceQuote::getValue)) : priceQuoteStream.max(Comparator.comparing(PriceQuote::getValue)); if (bestOffersPrice.isPresent()) { - maxOrFixAmountComponent.setQuote(bestOffersPrice.get()); + maxOrFixAmountSelectionController.setQuote(bestOffersPrice.get()); } else { - getMarketPriceQuote().ifPresent(maxOrFixAmountComponent::setQuote); + getMarketPriceQuote().ifPresent(maxOrFixAmountSelectionController::setQuote); } AmountSpecUtil.findQuoteSideFixedAmountFromSpec(model.getQuoteSideAmountSpec().get(), model.getMarket().getQuoteCurrencyCode()) - .ifPresent(amount -> UIThread.runOnNextRenderFrame(() -> maxOrFixAmountComponent.setQuoteSideAmount(amount))); + .ifPresent(amount -> UIThread.runOnNextRenderFrame(() -> maxOrFixAmountSelectionController.setQuoteSideAmount(amount))); return bestOffersPrice; } @@ -488,12 +488,12 @@ private Optional getMarketPriceQuote() { } private void quoteSideAmountsChanged(boolean maxAmountChanged) { - Monetary minQuoteSideAmount = minAmountComponent.getQuoteSideAmount().get(); - Monetary maxOrFixedQuoteSideAmount = maxOrFixAmountComponent.getQuoteSideAmount().get(); + Monetary minQuoteSideAmount = minAmountSelectionController.getQuoteSideAmount().get(); + Monetary maxOrFixedQuoteSideAmount = maxOrFixAmountSelectionController.getQuoteSideAmount().get(); model.getIsAmountHyperLinkDisabled().set(false); - boolean insecureValue = maxOrFixAmountComponent.getRightMarkerQuoteSideValue() != null && - maxOrFixedQuoteSideAmount.isGreaterThan(maxOrFixAmountComponent.getRightMarkerQuoteSideValue().round(0)); + boolean insecureValue = maxOrFixAmountSelectionController.getRightMarkerQuoteSideValue() != null && + maxOrFixedQuoteSideAmount.isGreaterThan(maxOrFixAmountSelectionController.getRightMarkerQuoteSideValue().round(0)); model.getIsWarningIconVisible().set(insecureValue); long highestScore = reputationService.getScoreByUserProfileId().entrySet().stream() @@ -662,21 +662,21 @@ private void applyQuoteSideMinMaxRange() { boolean isCreateOfferMode = model.isCreateOfferMode(); if (isCreateOfferMode) { model.getIsLearnMoreVisible().set(true); - minAmountComponent.setMinMaxRange(minRangeValue, maxRangeValue); - maxOrFixAmountComponent.setMinMaxRange(minRangeValue, maxRangeValue); + minAmountSelectionController.setMinMaxRange(minRangeValue, maxRangeValue); + maxOrFixAmountSelectionController.setMinMaxRange(minRangeValue, maxRangeValue); } else { // Wizard applyMarkerRange(); model.getIsLearnMoreVisible().set(model.getDirection().isSell()); if (model.getDirection().isBuy()) { - maxOrFixAmountComponent.setMinMaxRange(minRangeValue, maxRangeValue); + maxOrFixAmountSelectionController.setMinMaxRange(minRangeValue, maxRangeValue); } else { - maxOrFixAmountComponent.setMinMaxRange(minRangeValue, model.getReputationBasedMaxAmount().round(0)); + maxOrFixAmountSelectionController.setMinMaxRange(minRangeValue, model.getReputationBasedMaxAmount().round(0)); } - if (maxOrFixAmountComponent.getQuoteSideAmount().get() == null) { - maxOrFixAmountComponent.setQuoteSideAmount(defaultFiatAmount); + if (maxOrFixAmountSelectionController.getQuoteSideAmount().get() == null) { + maxOrFixAmountSelectionController.setQuoteSideAmount(defaultFiatAmount); } } @@ -694,11 +694,11 @@ private void applyQuoteSideMinMaxRange() { Monetary highestPossibleUsdAmount = BisqEasyTradeAmountLimits.getUsdAmountFromReputationScore(highestScore); if (isCreateOfferMode) { - minAmountComponent.setRightMarkerQuoteSideValue(highestPossibleUsdAmount); - maxOrFixAmountComponent.setRightMarkerQuoteSideValue(highestPossibleUsdAmount); + minAmountSelectionController.setRightMarkerQuoteSideValue(highestPossibleUsdAmount); + maxOrFixAmountSelectionController.setRightMarkerQuoteSideValue(highestPossibleUsdAmount); } - if (maxOrFixAmountComponent.getQuoteSideAmount().get() == null) { - maxOrFixAmountComponent.setQuoteSideAmount(defaultFiatAmount); + if (maxOrFixAmountSelectionController.getQuoteSideAmount().get() == null) { + maxOrFixAmountSelectionController.setQuoteSideAmount(defaultFiatAmount); } } else { // Seller case @@ -709,8 +709,8 @@ private void applyQuoteSideMinMaxRange() { Monetary reputationBasedQuoteSideAmount = model.getReputationBasedMaxAmount(); long myReputationScore = model.getMyReputationScore(); model.getAmountLimitInfo().set(Res.get("bisqEasy.tradeWizard.amount.seller.limitInfo", myReputationScore)); - minAmountComponent.setRightMarkerQuoteSideValue(reputationBasedQuoteSideAmount); - maxOrFixAmountComponent.setRightMarkerQuoteSideValue(reputationBasedQuoteSideAmount); + minAmountSelectionController.setRightMarkerQuoteSideValue(reputationBasedQuoteSideAmount); + maxOrFixAmountSelectionController.setRightMarkerQuoteSideValue(reputationBasedQuoteSideAmount); String formattedAmount = formatAmountWithCode(reputationBasedQuoteSideAmount); model.getAmountLimitInfoAmount().set(Res.get("bisqEasy.tradeWizard.amount.seller.limitInfoAmount", formattedAmount)); @@ -723,7 +723,7 @@ private void applyQuoteSideMinMaxRange() { model.setAmountLimitInfoLink(Res.get("bisqEasy.tradeWizard.amount.seller.limitInfo.link")); Monetary reputationBasedQuoteSideAmount = model.getReputationBasedMaxAmount(); - maxOrFixAmountComponent.setQuoteSideAmount(reputationBasedQuoteSideAmount); + maxOrFixAmountSelectionController.setQuoteSideAmount(reputationBasedQuoteSideAmount); long myReputationScore = model.getMyReputationScore(); model.getAmountLimitInfo().set(Res.get("bisqEasy.tradeWizard.amount.seller.limitInfo", myReputationScore)); String formattedAmount = formatAmountWithCode(reputationBasedQuoteSideAmount); @@ -738,13 +738,13 @@ private void applyQuoteSideMinMaxRange() { private void applyMarkerRange() { Pair, Optional> availableOfferAmountRange = getLowestAndHighestAmountInAvailableOffers(); - maxOrFixAmountComponent.setLeftMarkerQuoteSideValue(availableOfferAmountRange.getFirst().orElse(null)); - maxOrFixAmountComponent.setRightMarkerQuoteSideValue(availableOfferAmountRange.getSecond().orElse(null)); + maxOrFixAmountSelectionController.setLeftMarkerQuoteSideValue(availableOfferAmountRange.getFirst().orElse(null)); + maxOrFixAmountSelectionController.setRightMarkerQuoteSideValue(availableOfferAmountRange.getSecond().orElse(null)); } private void applyReputationBasedQuoteSideAmount() { if (model.isCreateOfferMode()) { - maxOrFixAmountComponent.setQuoteSideAmount(maxOrFixAmountComponent.getRightMarkerQuoteSideValue().round(0)); + maxOrFixAmountSelectionController.setQuoteSideAmount(maxOrFixAmountSelectionController.getRightMarkerQuoteSideValue().round(0)); } } diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java index 0bfb01719d..4c2a8ec26b 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java @@ -24,7 +24,7 @@ import bisq.desktop.common.view.View; import bisq.desktop.components.containers.Spacer; import bisq.desktop.components.controls.BisqTooltip; -import bisq.desktop.main.content.bisq_easy.components.AmountComponent; +import bisq.desktop.main.content.bisq_easy.components.amount_selection.AmountSelectionController; import bisq.desktop.main.content.bisq_easy.trade_wizard.TradeWizardView; import bisq.i18n.Res; import de.jensd.fx.fontawesome.AwesomeIcon; @@ -54,15 +54,15 @@ public class TradeWizardAmountView extends View Date: Tue, 5 Nov 2024 11:35:01 +0100 Subject: [PATCH 12/33] Improve amount component for the case of using range --- .../AmountSelectionController.java | 21 ++++++--- .../AmountSelectionModel.java | 1 + .../amount_selection/AmountSelectionView.java | 17 ++++--- .../amount_input}/AmountInput.java | 46 +++++++++++++++---- .../amount_input}/BigAmountInput.java | 2 +- .../amount_input}/SmallAmountInput.java | 12 ++++- .../amount/TradeWizardAmountController.java | 7 ++- .../amount/TradeWizardAmountView.java | 2 +- 8 files changed, 83 insertions(+), 25 deletions(-) rename apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/{ => amount_selection/amount_input}/AmountInput.java (82%) rename apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/{ => amount_selection/amount_input}/BigAmountInput.java (97%) rename apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/{ => amount_selection/amount_input}/SmallAmountInput.java (90%) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionController.java index 0db84528a6..a190a3df25 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionController.java @@ -25,10 +25,10 @@ import bisq.desktop.ServiceProvider; import bisq.desktop.common.threading.UIThread; import bisq.desktop.common.view.Controller; -import bisq.desktop.main.content.bisq_easy.components.AmountInput; -import bisq.desktop.main.content.bisq_easy.components.BigAmountInput; +import bisq.desktop.main.content.bisq_easy.components.amount_selection.amount_input.AmountInput; +import bisq.desktop.main.content.bisq_easy.components.amount_selection.amount_input.BigAmountInput; import bisq.desktop.main.content.bisq_easy.components.PriceInput; -import bisq.desktop.main.content.bisq_easy.components.SmallAmountInput; +import bisq.desktop.main.content.bisq_easy.components.amount_selection.amount_input.SmallAmountInput; import bisq.i18n.Res; import bisq.offer.Direction; import bisq.presentation.formatters.AmountFormatter; @@ -105,11 +105,11 @@ public AmountSelectionController(ServiceProvider serviceProvider, }; } - void setBaseSideAmount(Monetary value) { + public void setBaseSideAmount(Monetary value) { model.getBaseSideAmount().set(value); } - void setQuoteSideAmount(Monetary value) { + public void setQuoteSideAmount(Monetary value) { model.getQuoteSideAmount().set(value); } @@ -129,7 +129,7 @@ public void setDirection(Direction direction) { model.getSpendOrReceiveString().set(direction == Direction.BUY ? Res.get("offer.buying") : Res.get("offer.selling")); } - void setTooltip(String tooltip) { + public void setTooltip(String tooltip) { baseSideAmountInput.setTooltip(tooltip); } @@ -191,6 +191,15 @@ public Monetary getRightMarkerQuoteSideValue() { return model.getRightMarkerQuoteSideValue(); } + public void useCompactFormat(boolean useCompactFormat) { + model.getUseCompactFormat().set(useCompactFormat); + } + + public void showHyphenInsteadOfCurrencyCode(boolean showHyphenInsteadOfCurrencyCode) { + quoteSideAmountInput.setShowHyphenInsteadOfCurrencyCode(showHyphenInsteadOfCurrencyCode); + baseSideAmountInput.setShowHyphenInsteadOfCurrencyCode(showHyphenInsteadOfCurrencyCode); + } + public void reset() { baseSideAmountInput.reset(); quoteSideAmountInput.reset(); diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionModel.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionModel.java index 3c05879370..494e79f0d1 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionModel.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionModel.java @@ -71,6 +71,7 @@ public class AmountSelectionModel implements Model { private final StringProperty description = new SimpleStringProperty(); private final StringProperty minRangeValueAsString = new SimpleStringProperty(); private final StringProperty maxRangeValueAsString = new SimpleStringProperty(); + private final BooleanProperty useCompactFormat = new SimpleBooleanProperty(); public AmountSelectionModel(boolean useQuoteCurrencyForMinMaxRange) { this.useQuoteCurrencyForMinMaxRange = useQuoteCurrencyForMinMaxRange; diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java index 87f875625d..799379831d 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java @@ -21,8 +21,8 @@ import bisq.desktop.common.threading.UIScheduler; import bisq.desktop.common.view.View; import bisq.desktop.components.containers.Spacer; -import bisq.desktop.main.content.bisq_easy.components.BigAmountInput; -import bisq.desktop.main.content.bisq_easy.components.SmallAmountInput; +import bisq.desktop.main.content.bisq_easy.components.amount_selection.amount_input.BigAmountInput; +import bisq.desktop.main.content.bisq_easy.components.amount_selection.amount_input.SmallAmountInput; import javafx.beans.property.ReadOnlyBooleanProperty; import javafx.geometry.Insets; import javafx.geometry.Pos; @@ -47,12 +47,12 @@ public class AmountSelectionView extends View { + + }); + // Needed to trigger focusOut event on amount components // We handle all parents mouse events. Parent node = root; diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/AmountInput.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/AmountInput.java similarity index 82% rename from apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/AmountInput.java rename to apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/AmountInput.java index bba97d8900..afc2ae1918 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/AmountInput.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/AmountInput.java @@ -15,7 +15,7 @@ * along with Bisq. If not, see . */ -package bisq.desktop.main.content.bisq_easy.components; +package bisq.desktop.main.content.bisq_easy.components.amount_selection.amount_input; import bisq.common.currency.Market; import bisq.common.monetary.Monetary; @@ -24,7 +24,14 @@ import bisq.desktop.components.controls.validator.NumberValidator; import bisq.presentation.formatters.AmountFormatter; import bisq.presentation.parser.AmountParser; -import javafx.beans.property.*; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.ReadOnlyBooleanProperty; +import javafx.beans.property.ReadOnlyObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.scene.control.Label; @@ -37,7 +44,6 @@ @Slf4j public abstract class AmountInput { - protected final Controller controller; public AmountInput(boolean isBaseCurrency) { @@ -78,6 +84,10 @@ public void requestFocus() { textInput.selectRange(textInput.getLength(), textInput.getLength()); } + public void setShowHyphenInsteadOfCurrencyCode(boolean showHyphenInsteadOfCurrencyCode) { + controller.model.showHyphenInsteadOfCurrencyCode.set(showHyphenInsteadOfCurrencyCode); + } + protected static class Controller implements bisq.desktop.common.view.Controller { @Setter protected Model model; @@ -169,6 +179,7 @@ protected static class Model implements bisq.desktop.common.view.Model { protected boolean hasFocus; @Setter protected boolean useLowPrecision = true; + protected final BooleanProperty showHyphenInsteadOfCurrencyCode = new SimpleBooleanProperty(false); private final BooleanProperty isAmountValid = new SimpleBooleanProperty(true); protected Model(boolean isBaseCurrency) { @@ -180,6 +191,8 @@ void reset() { code.set(null); selectedMarket = null; hasFocus = false; + showHyphenInsteadOfCurrencyCode.set(false); + isAmountValid.set(false); } } @@ -187,13 +200,15 @@ protected static class View extends bisq.desktop.common.view.View focusListener; protected final ChangeListener amountListener; protected final TextField textInput; - protected final Label codeLabel; + protected final Label hyphenLabel, codeLabel; protected View(Model model, Controller controller) { super(new HBox(), model, controller); + textInput = createTextInput(); + hyphenLabel = createHyphenLabel(); codeLabel = createCodeLabel(); - root.getChildren().addAll(textInput, codeLabel); + root.getChildren().addAll(textInput, hyphenLabel, codeLabel); focusListener = this::onFocusChanged; amountListener = this::onAmountChanged; initView(); @@ -203,6 +218,10 @@ protected TextField createTextInput() { return new TextField(); } + protected Label createHyphenLabel() { + return new Label("-"); + } + protected Label createCodeLabel() { return new Label(); } @@ -235,9 +254,15 @@ protected void adjustTextFieldStyle() { @Override protected void onViewAttached() { - textInput.focusedProperty().addListener(focusListener); + hyphenLabel.visibleProperty().bind(model.showHyphenInsteadOfCurrencyCode); + hyphenLabel.managedProperty().bind(model.showHyphenInsteadOfCurrencyCode); codeLabel.textProperty().bind(model.code); + codeLabel.visibleProperty().bind(model.showHyphenInsteadOfCurrencyCode.not()); + codeLabel.managedProperty().bind(model.showHyphenInsteadOfCurrencyCode.not()); + + textInput.focusedProperty().addListener(focusListener); model.amount.addListener(amountListener); + applyAmount(model.amount.get()); textInput.requestFocus(); textInput.selectRange(textInput.getLength(), textInput.getLength()); @@ -245,9 +270,14 @@ protected void onViewAttached() { @Override protected void onViewDetached() { - textInput.focusedProperty().removeListener(focusListener); + hyphenLabel.visibleProperty().unbind(); + hyphenLabel.managedProperty().unbind(); codeLabel.textProperty().unbind(); + codeLabel.visibleProperty().unbind(); + codeLabel.managedProperty().unbind(); + + textInput.focusedProperty().removeListener(focusListener); model.amount.removeListener(amountListener); } } -} \ No newline at end of file +} diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/BigAmountInput.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/BigAmountInput.java similarity index 97% rename from apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/BigAmountInput.java rename to apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/BigAmountInput.java index fe3382a928..c2c7cf2e31 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/BigAmountInput.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/BigAmountInput.java @@ -15,7 +15,7 @@ * along with Bisq. If not, see . */ -package bisq.desktop.main.content.bisq_easy.components; +package bisq.desktop.main.content.bisq_easy.components.amount_selection.amount_input; import javafx.geometry.Insets; import javafx.geometry.Pos; diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/SmallAmountInput.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/SmallAmountInput.java similarity index 90% rename from apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/SmallAmountInput.java rename to apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/SmallAmountInput.java index 3cc4f53811..0f417e9b56 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/SmallAmountInput.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/SmallAmountInput.java @@ -15,7 +15,7 @@ * along with Bisq. If not, see . */ -package bisq.desktop.main.content.bisq_easy.components; +package bisq.desktop.main.content.bisq_easy.components.amount_selection.amount_input; import bisq.desktop.components.controls.BisqIconButton; import bisq.desktop.components.controls.BisqTooltip; @@ -39,6 +39,7 @@ public class SmallAmountInput extends AmountInput { public SmallAmountInput(boolean isBaseCurrency) { super(isBaseCurrency); + this.controller.setModel(new SmallAmountInputModel(isBaseCurrency)); this.controller.setView(new SmallAmountInputView(controller.model, controller)); } @@ -53,6 +54,7 @@ public void setUseLowPrecision(boolean useLowPrecision) { private static class SmallAmountInputView extends View { private BisqTooltip tooltip; + private Button iconButton; protected SmallAmountInputView(Model model, Controller controller) { super(model, controller); @@ -73,7 +75,7 @@ private Button createIconButton() { protected void initView() { root.setAlignment(Pos.CENTER); root.getStyleClass().add("small-amount-input"); - Button iconButton = createIconButton(); + iconButton = createIconButton(); root.getChildren().add(iconButton); } @@ -98,13 +100,19 @@ protected Label createCodeLabel() { @Override protected void onViewAttached() { super.onViewAttached(); + tooltip.textProperty().bind(((SmallAmountInputModel) model).tooltipProperty()); + iconButton.visibleProperty().bind(model.showHyphenInsteadOfCurrencyCode); + iconButton.managedProperty().bind(model.showHyphenInsteadOfCurrencyCode); } @Override protected void onViewDetached() { super.onViewDetached(); + tooltip.textProperty().unbind(); + iconButton.visibleProperty().unbind(); + iconButton.managedProperty().unbind(); } } diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java index 5fb554afde..9d1405e013 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java @@ -108,6 +108,7 @@ public TradeWizardAmountController(ServiceProvider serviceProvider, Region owner model = new TradeWizardAmountModel(); minAmountSelectionController = new AmountSelectionController(serviceProvider, true); + minAmountSelectionController.showHyphenInsteadOfCurrencyCode(true); maxOrFixAmountSelectionController = new AmountSelectionController(serviceProvider, true); view = new TradeWizardAmountView(model, this, @@ -261,7 +262,11 @@ public void onActivate() { } }); - isRangeAmountEnabledPin = EasyBind.subscribe(model.getIsRangeAmountEnabled(), isMinAmountEnabled -> applyAmountSpec()); + isRangeAmountEnabledPin = EasyBind.subscribe(model.getIsRangeAmountEnabled(), isRangeAmountEnabled -> { + applyAmountSpec(); + minAmountSelectionController.useCompactFormat(isRangeAmountEnabled); + maxOrFixAmountSelectionController.useCompactFormat(isRangeAmountEnabled); + }); applyAmountSpec(); if (model.isCreateOfferMode()) { diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java index 4c2a8ec26b..cfd63d5787 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java @@ -62,7 +62,7 @@ public TradeWizardAmountView(TradeWizardAmountModel model, headlineLabel.getStyleClass().add("bisq-text-headline-2"); minAmountRoot = minAmountSelectionController.getView().getRoot(); - HBox amountBox = new HBox(30, minAmountRoot, maxOrFixAmountSelectionController.getView().getRoot()); + HBox amountBox = new HBox(minAmountRoot, maxOrFixAmountSelectionController.getView().getRoot()); amountBox.setAlignment(Pos.CENTER); amountLimitInfo = new Label(); From f2c1b97c8f745e336df8415fac7fd899bb51e4f2 Mon Sep 17 00:00:00 2001 From: axpoems <145597137+axpoems@users.noreply.github.com> Date: Wed, 6 Nov 2024 12:46:55 +0100 Subject: [PATCH 13/33] Apply new design for amount ranges --- .../AmountSelectionController.java | 329 ++++++++++++------ .../AmountSelectionModel.java | 22 +- .../amount_selection/AmountSelectionView.java | 136 +++++--- .../amount_input/AmountInput.java | 53 ++- .../amount_input/BigAmountInput.java | 30 +- .../amount_input/SmallAmountInput.java | 17 +- .../amount/TakeOfferAmountController.java | 12 +- .../amount/TradeWizardAmountController.java | 128 +++---- .../amount/TradeWizardAmountView.java | 24 +- .../src/main/resources/css/bisq_easy.css | 100 +++++- .../desktop/src/main/resources/css/text.css | 9 + 11 files changed, 552 insertions(+), 308 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionController.java index a190a3df25..e027d77117 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionController.java @@ -51,33 +51,48 @@ public class AmountSelectionController implements Controller { final AmountSelectionModel model; @Getter private final AmountSelectionView view; - private final BigAmountInput quoteSideAmountInput; - private final SmallAmountInput baseSideAmountInput; - private final ChangeListener baseSideAmountFromModelListener, quoteSideAmountFromModelListener; + private final BigAmountInput maxOrFixedQuoteSideAmountInput, minQuoteSideAmountInput; + private final SmallAmountInput maxOrFixedBaseSideAmountInput, minBaseSideAmountInput; + private final ChangeListener maxOrFixedBaseSideAmountFromModelListener, maxOrFixedQuoteSideAmountFromModelListener, + minBaseSideAmountFromModelListener, minQuoteSideAmountFromModelListener; private final ChangeListener quoteListener; - final PriceInput price; - private final ChangeListener sliderListener; - private Subscription baseAmountFromModelPin, baseAmountFromCompPin, - quoteAmountFromCompPin, priceFromCompPin, minRangeCustomValuePin, maxRangeCustomValuePin, - baseSideAmountValidPin, quoteSideAmountValidPin; + private final PriceInput price; + private final ChangeListener maxOrFixedSliderListener; //, minSliderListener; + private Subscription maxOrFixedBaseAmountFromModelPin, maxOrFixedBaseAmountFromCompPin, maxOrFixedQuoteAmountFromCompPin, + maxOrFixedBaseSideAmountValidPin, maxOrFixedQuoteSideAmountValidPin, minBaseAmountFromModelPin, + minBaseAmountFromCompPin, minQuoteAmountFromCompPin, minBaseSideAmountValidPin, + minQuoteSideAmountValidPin, + + priceFromCompPin, minRangeCustomValuePin, maxRangeCustomValuePin; public AmountSelectionController(ServiceProvider serviceProvider, boolean useQuoteCurrencyForMinMaxRange) { - quoteSideAmountInput = new BigAmountInput(false); - baseSideAmountInput = new SmallAmountInput(true); - baseSideAmountInput.setUseLowPrecision(false); + // max or fixed amount + maxOrFixedQuoteSideAmountInput = new BigAmountInput(false, true); + maxOrFixedBaseSideAmountInput = new SmallAmountInput(true, true); + maxOrFixedBaseSideAmountInput.setUseLowPrecision(false); + + // min amount (only applies when selecting a range) + minQuoteSideAmountInput = new BigAmountInput(false, false); + minBaseSideAmountInput = new SmallAmountInput(true, false); + minBaseSideAmountInput.setUseLowPrecision(false); + price = new PriceInput(serviceProvider.getBondedRolesService().getMarketPriceService()); model = new AmountSelectionModel(useQuoteCurrencyForMinMaxRange); view = new AmountSelectionView(model, this, - baseSideAmountInput, - quoteSideAmountInput); + maxOrFixedBaseSideAmountInput, + maxOrFixedQuoteSideAmountInput, + minBaseSideAmountInput, + minQuoteSideAmountInput); // We delay with runLater to avoid that we get triggered at market change from the component's data changes and // apply the conversion before the other component has processed the market change event. // The order of the event notification is not deterministic. - baseSideAmountFromModelListener = (observable, oldValue, newValue) -> UIThread.runOnNextRenderFrame(this::setQuoteFromBase); - quoteSideAmountFromModelListener = (observable, oldValue, newValue) -> UIThread.runOnNextRenderFrame(this::setBaseFromQuote); + maxOrFixedBaseSideAmountFromModelListener = (observable, oldValue, newValue) -> UIThread.runOnNextRenderFrame(this::setMaxOrFixedQuoteFromBase); + maxOrFixedQuoteSideAmountFromModelListener = (observable, oldValue, newValue) -> UIThread.runOnNextRenderFrame(this::setMaxOrFixedBaseFromQuote); + minBaseSideAmountFromModelListener = (observable, oldValue, newValue) -> UIThread.runOnNextRenderFrame(this::setMinQuoteFromBase); + minQuoteSideAmountFromModelListener = (observable, oldValue, newValue) -> UIThread.runOnNextRenderFrame(this::setMinBaseFromQuote); quoteListener = (observable, oldValue, newValue) -> { model.getMinRangeBaseSideValue().set(null); model.getMaxRangeBaseSideValue().set(null); @@ -86,7 +101,7 @@ public AmountSelectionController(ServiceProvider serviceProvider, applyInitialRangeValues(); UIThread.runOnNextRenderFrame(this::applyQuote); }; - sliderListener = (observable, oldValue, newValue) -> { + maxOrFixedSliderListener = (observable, oldValue, newValue) -> { if (model.getMinRangeQuoteSideValue().get() != null && model.getMinRangeBaseSideValue().get() != null) { double sliderValue = newValue.doubleValue(); long min = model.isUseQuoteCurrencyForMinMaxRange() ? @@ -97,28 +112,44 @@ public AmountSelectionController(ServiceProvider serviceProvider, model.getMaxRangeBaseSideValue().get().getValue(); long value = Math.round(sliderValue * (max - min)) + min; if (model.isUseQuoteCurrencyForMinMaxRange()) { - quoteSideAmountInput.setAmount(Monetary.from(value, model.getMarket().getQuoteCurrencyCode())); + maxOrFixedQuoteSideAmountInput.setAmount(Monetary.from(value, model.getMarket().getQuoteCurrencyCode())); } else { - baseSideAmountInput.setAmount(Monetary.from(value, model.getMarket().getBaseCurrencyCode())); + maxOrFixedBaseSideAmountInput.setAmount(Monetary.from(value, model.getMarket().getBaseCurrencyCode())); } } }; } - public void setBaseSideAmount(Monetary value) { - model.getBaseSideAmount().set(value); + public void setMaxOrFixedBaseSideAmount(Monetary value) { + model.getMaxOrFixedBaseSideAmount().set(value); + } + + public void setMinBaseSideAmount(Monetary value) { + model.getMinBaseSideAmount().set(value); + } + + public void setMaxOrFixedQuoteSideAmount(Monetary value) { + model.getMaxOrFixedQuoteSideAmount().set(value); + } + + public void setMinQuoteSideAmount(Monetary value) { + model.getMinQuoteSideAmount().set(value); } - public void setQuoteSideAmount(Monetary value) { - model.getQuoteSideAmount().set(value); + public ReadOnlyObjectProperty getMaxOrFixedBaseSideAmount() { + return model.getMaxOrFixedBaseSideAmount(); } - public ReadOnlyObjectProperty getBaseSideAmount() { - return model.getBaseSideAmount(); + public ReadOnlyObjectProperty getMinBaseSideAmount() { + return model.getMinBaseSideAmount(); } - public ReadOnlyObjectProperty getQuoteSideAmount() { - return model.getQuoteSideAmount(); + public ReadOnlyObjectProperty getMaxOrFixedQuoteSideAmount() { + return model.getMaxOrFixedQuoteSideAmount(); + } + + public ReadOnlyObjectProperty getMinQuoteSideAmount() { + return model.getMinQuoteSideAmount(); } public void setDirection(Direction direction) { @@ -130,7 +161,8 @@ public void setDirection(Direction direction) { } public void setTooltip(String tooltip) { - baseSideAmountInput.setTooltip(tooltip); + maxOrFixedBaseSideAmountInput.setTooltip(tooltip); + minBaseSideAmountInput.setTooltip(tooltip); } public void setMarket(Market market) { @@ -138,8 +170,10 @@ public void setMarket(Market market) { return; } model.setMarket(market); - baseSideAmountInput.setSelectedMarket(market); - quoteSideAmountInput.setSelectedMarket(market); + maxOrFixedBaseSideAmountInput.setSelectedMarket(market); + maxOrFixedQuoteSideAmountInput.setSelectedMarket(market); + minBaseSideAmountInput.setSelectedMarket(market); + minQuoteSideAmountInput.setSelectedMarket(market); price.setMarket(market); } @@ -174,7 +208,7 @@ public void setRightMarkerQuoteSideValue(Monetary quoteSideAmount) { } public void applyReputationBasedQuoteSideAmount() { - quoteSideAmountInput.setAmount(model.getRightMarkerQuoteSideValue()); + maxOrFixedQuoteSideAmountInput.setAmount(model.getRightMarkerQuoteSideValue()); } public void setQuote(PriceQuote priceQuote) { @@ -183,6 +217,10 @@ public void setQuote(PriceQuote priceQuote) { } } + public void setIsRangeAmountEnabled(boolean isRangeAmountEnabled) { + model.getIsRangeAmountEnabled().set(isRangeAmountEnabled); + } + public ReadOnlyObjectProperty getQuote() { return price.getQuote(); } @@ -191,18 +229,11 @@ public Monetary getRightMarkerQuoteSideValue() { return model.getRightMarkerQuoteSideValue(); } - public void useCompactFormat(boolean useCompactFormat) { - model.getUseCompactFormat().set(useCompactFormat); - } - - public void showHyphenInsteadOfCurrencyCode(boolean showHyphenInsteadOfCurrencyCode) { - quoteSideAmountInput.setShowHyphenInsteadOfCurrencyCode(showHyphenInsteadOfCurrencyCode); - baseSideAmountInput.setShowHyphenInsteadOfCurrencyCode(showHyphenInsteadOfCurrencyCode); - } - public void reset() { - baseSideAmountInput.reset(); - quoteSideAmountInput.reset(); + maxOrFixedBaseSideAmountInput.reset(); + maxOrFixedQuoteSideAmountInput.reset(); + minBaseSideAmountInput.reset(); + minQuoteSideAmountInput.reset(); price.reset(); model.reset(); } @@ -216,74 +247,120 @@ public void onActivate() { model.getDescription().set(Res.get("bisqEasy.tradeWizard.amount.description", model.getMarket().getQuoteCurrencyCode())); applyInitialRangeValues(); - model.getBaseSideAmount().addListener(baseSideAmountFromModelListener); - model.getQuoteSideAmount().addListener(quoteSideAmountFromModelListener); + model.getMaxOrFixedBaseSideAmount().addListener(maxOrFixedBaseSideAmountFromModelListener); + model.getMaxOrFixedQuoteSideAmount().addListener(maxOrFixedQuoteSideAmountFromModelListener); + model.getMinBaseSideAmount().addListener(minBaseSideAmountFromModelListener); + model.getMinQuoteSideAmount().addListener(minQuoteSideAmountFromModelListener); price.getQuote().addListener(quoteListener); - baseSideAmountInput.setAmount(null); - if (model.getQuoteSideAmount().get() == null) { - PriceQuote priceQuote = price.getQuote().get(); - if (priceQuote != null) { - Monetary minRangeQuoteSideValue = model.getMinRangeQuoteSideValue().get(); - Monetary maxRangeQuoteSideValue = model.getMaxRangeQuoteSideValue().get(); - long midValue = minRangeQuoteSideValue.getValue() + (maxRangeQuoteSideValue.getValue() - minRangeQuoteSideValue.getValue()) / 2; - Monetary exactAmount = Fiat.fromValue(midValue, priceQuote.getQuoteSideMonetary().getCode()); - quoteSideAmountInput.setAmount(exactAmount.round(0)); - } else { - log.warn("price.quoteProperty().get() is null. We use a fiat value of 100 as default value."); - Fiat defaultQuoteSideAmount = Fiat.fromFaceValue(100, model.getMarket().getQuoteCurrencyCode()); - quoteSideAmountInput.setAmount(defaultQuoteSideAmount); - } + maxOrFixedBaseSideAmountInput.setAmount(null); + if (model.getMaxOrFixedQuoteSideAmount().get() == null) { + initializeQuoteSideAmount(maxOrFixedQuoteSideAmountInput); + } else { + maxOrFixedQuoteSideAmountInput.setAmount(model.getMaxOrFixedQuoteSideAmount().get()); + } + setMaxOrFixedBaseFromQuote(); + + minBaseSideAmountInput.setAmount(null); + if (model.getMinQuoteSideAmount().get() == null) { + initializeQuoteSideAmount(minQuoteSideAmountInput); } else { - quoteSideAmountInput.setAmount(model.getQuoteSideAmount().get()); + minQuoteSideAmountInput.setAmount(model.getMinQuoteSideAmount().get()); } - setBaseFromQuote(); + setMinBaseFromQuote(); + + maxOrFixedBaseAmountFromModelPin = EasyBind.subscribe(model.getMaxOrFixedBaseSideAmount(), amount -> { + // Only apply value from component to slider if we have no focus on slider (not used) + if (amount != null) { + if (!model.getSliderFocus().get()) { + long min = model.getMinRangeBaseSideValue().get().getValue(); + long max = model.getMaxRangeBaseSideValue().get().getValue(); + double sliderValue = (amount.getValue() - min) / ((double) max - min); + model.getMaxOrFixedSliderValue().set(sliderValue); + } + } + }); - baseAmountFromModelPin = EasyBind.subscribe(model.getBaseSideAmount(), amount -> { + minBaseAmountFromModelPin = EasyBind.subscribe(model.getMinBaseSideAmount(), amount -> { // Only apply value from component to slider if we have no focus on slider (not used) if (amount != null) { if (!model.getSliderFocus().get()) { long min = model.getMinRangeBaseSideValue().get().getValue(); long max = model.getMaxRangeBaseSideValue().get().getValue(); double sliderValue = (amount.getValue() - min) / ((double) max - min); - model.getSliderValue().set(sliderValue); + model.getMinSliderValue().set(sliderValue); } } }); - baseAmountFromCompPin = EasyBind.subscribe(baseSideAmountInput.amountProperty(), + maxOrFixedBaseAmountFromCompPin = EasyBind.subscribe(maxOrFixedBaseSideAmountInput.amountProperty(), + amount -> { + Monetary minRangeValue = model.getMinRangeBaseSideValue().get(); + Monetary maxRangeValue = model.getMaxRangeBaseSideValue().get(); + if (amount != null && amount.getValue() > maxRangeValue.getValue()) { + model.getMaxOrFixedBaseSideAmount().set(maxRangeValue); + setMaxOrFixedQuoteFromBase(); + maxOrFixedBaseSideAmountInput.setAmount(maxRangeValue); + } else if (amount != null && amount.getValue() < minRangeValue.getValue()) { + model.getMaxOrFixedBaseSideAmount().set(minRangeValue); + setMaxOrFixedQuoteFromBase(); + maxOrFixedBaseSideAmountInput.setAmount(minRangeValue); + } else { + model.getMaxOrFixedBaseSideAmount().set(amount); + } + }); + + minBaseAmountFromCompPin = EasyBind.subscribe(minBaseSideAmountInput.amountProperty(), amount -> { Monetary minRangeValue = model.getMinRangeBaseSideValue().get(); Monetary maxRangeValue = model.getMaxRangeBaseSideValue().get(); if (amount != null && amount.getValue() > maxRangeValue.getValue()) { - model.getBaseSideAmount().set(maxRangeValue); - setQuoteFromBase(); - baseSideAmountInput.setAmount(maxRangeValue); + model.getMinBaseSideAmount().set(maxRangeValue); + setMinQuoteFromBase(); + minBaseSideAmountInput.setAmount(maxRangeValue); } else if (amount != null && amount.getValue() < minRangeValue.getValue()) { - model.getBaseSideAmount().set(minRangeValue); - setQuoteFromBase(); - baseSideAmountInput.setAmount(minRangeValue); + model.getMinBaseSideAmount().set(minRangeValue); + setMinQuoteFromBase(); + minBaseSideAmountInput.setAmount(minRangeValue); } else { - model.getBaseSideAmount().set(amount); + model.getMinBaseSideAmount().set(amount); } }); - quoteAmountFromCompPin = EasyBind.subscribe(quoteSideAmountInput.amountProperty(), + maxOrFixedQuoteAmountFromCompPin = EasyBind.subscribe(maxOrFixedQuoteSideAmountInput.amountProperty(), amount -> { Monetary minRangeValue = model.getMinRangeQuoteSideValue().get(); Monetary maxRangeValue = model.getMaxRangeQuoteSideValue().get(); if (maxRangeValue != null && amount != null && amount.getValue() > maxRangeValue.getValue()) { - model.getQuoteSideAmount().set(maxRangeValue); - setBaseFromQuote(); - quoteSideAmountInput.setAmount(maxRangeValue); + model.getMaxOrFixedQuoteSideAmount().set(maxRangeValue); + setMaxOrFixedBaseFromQuote(); + maxOrFixedQuoteSideAmountInput.setAmount(maxRangeValue); } else if (minRangeValue != null && amount != null && amount.getValue() < minRangeValue.getValue()) { - model.getQuoteSideAmount().set(minRangeValue); - setBaseFromQuote(); - quoteSideAmountInput.setAmount(minRangeValue); + model.getMaxOrFixedQuoteSideAmount().set(minRangeValue); + setMaxOrFixedBaseFromQuote(); + maxOrFixedQuoteSideAmountInput.setAmount(minRangeValue); } else { - model.getQuoteSideAmount().set(amount); + model.getMaxOrFixedQuoteSideAmount().set(amount); } }); + + minQuoteAmountFromCompPin = EasyBind.subscribe(minQuoteSideAmountInput.amountProperty(), + amount -> { + Monetary minRangeValue = model.getMinRangeQuoteSideValue().get(); + Monetary maxRangeValue = model.getMaxRangeQuoteSideValue().get(); + if (maxRangeValue != null && amount != null && amount.getValue() > maxRangeValue.getValue()) { + model.getMinQuoteSideAmount().set(maxRangeValue); + setMinBaseFromQuote(); + minQuoteSideAmountInput.setAmount(maxRangeValue); + } else if (minRangeValue != null && amount != null && amount.getValue() < minRangeValue.getValue()) { + model.getMinQuoteSideAmount().set(minRangeValue); + setMinBaseFromQuote(); + minQuoteSideAmountInput.setAmount(minRangeValue); + } else { + model.getMinQuoteSideAmount().set(amount); + } + }); + priceFromCompPin = EasyBind.subscribe(price.getQuote(), quote -> applyInitialRangeValues()); @@ -292,9 +369,26 @@ public void onActivate() { maxRangeCustomValuePin = EasyBind.subscribe(model.getMaxRangeMonetary(), value -> applyInitialRangeValues()); - baseSideAmountValidPin = subscribeToAmountValidity(baseSideAmountInput, this::setBaseFromQuote); - quoteSideAmountValidPin = subscribeToAmountValidity(quoteSideAmountInput, this::setQuoteFromBase); - model.getSliderValue().addListener(sliderListener); + maxOrFixedBaseSideAmountValidPin = subscribeToAmountValidity(maxOrFixedBaseSideAmountInput, this::setMaxOrFixedBaseFromQuote); + minBaseSideAmountValidPin = subscribeToAmountValidity(minBaseSideAmountInput, this::setMinBaseFromQuote); + maxOrFixedQuoteSideAmountValidPin = subscribeToAmountValidity(maxOrFixedQuoteSideAmountInput, this::setMaxOrFixedQuoteFromBase); + minQuoteSideAmountValidPin = subscribeToAmountValidity(minQuoteSideAmountInput, this::setMinQuoteFromBase); + model.getMaxOrFixedSliderValue().addListener(maxOrFixedSliderListener); + } + + private void initializeQuoteSideAmount(BigAmountInput quoteSideAmountInput) { + PriceQuote priceQuote = price.getQuote().get(); + if (priceQuote != null) { + Monetary minRangeQuoteSideValue = model.getMinRangeQuoteSideValue().get(); + Monetary maxRangeQuoteSideValue = model.getMaxRangeQuoteSideValue().get(); + long midValue = minRangeQuoteSideValue.getValue() + (maxRangeQuoteSideValue.getValue() - minRangeQuoteSideValue.getValue()) / 2; + Monetary exactAmount = Fiat.fromValue(midValue, priceQuote.getQuoteSideMonetary().getCode()); + quoteSideAmountInput.setAmount(exactAmount.round(0)); + } else { + log.warn("price.quoteProperty().get() is null. We use a fiat value of 100 as default value."); + Fiat defaultQuoteSideAmount = Fiat.fromFaceValue(100, model.getMarket().getQuoteCurrencyCode()); + quoteSideAmountInput.setAmount(defaultQuoteSideAmount); + } } private Subscription subscribeToAmountValidity(AmountInput amountInput, Runnable autocorrect) { @@ -317,36 +411,28 @@ private void applyInitialRangeValues() { boolean isMinRangeMonetaryFiat = FiatCurrencyRepository.getCurrencyByCodeMap().containsKey(minRangeMonetary.getCode()); boolean isMaxRangeMonetaryFiat = FiatCurrencyRepository.getCurrencyByCodeMap().containsKey(maxRangeMonetary.getCode()); - Monetary minRangeMonetaryAsCoin = !isMinRangeMonetaryFiat ? - minRangeMonetary : - priceQuote.toBaseSideMonetary(minRangeMonetary); + Monetary minRangeMonetaryAsCoin = !isMinRangeMonetaryFiat ? minRangeMonetary : priceQuote.toBaseSideMonetary(minRangeMonetary); model.getMinRangeBaseSideValue().set(minRangeMonetaryAsCoin); if (!model.isUseQuoteCurrencyForMinMaxRange()) { model.getMinRangeValueAsString().set(Res.get("bisqEasy.component.amount.minRangeValue", AmountFormatter.formatAmountWithCode(minRangeMonetaryAsCoin))); } - Monetary maxRangeMonetaryAsCoin = !isMaxRangeMonetaryFiat ? - maxRangeMonetary : - priceQuote.toBaseSideMonetary(maxRangeMonetary); + Monetary maxRangeMonetaryAsCoin = !isMaxRangeMonetaryFiat ? maxRangeMonetary : priceQuote.toBaseSideMonetary(maxRangeMonetary); model.getMaxRangeBaseSideValue().set(maxRangeMonetaryAsCoin); if (!model.isUseQuoteCurrencyForMinMaxRange()) { model.getMaxRangeValueAsString().set(Res.get("bisqEasy.component.amount.maxRangeValue", AmountFormatter.formatAmountWithCode(maxRangeMonetaryAsCoin))); } - Monetary minRangeMonetaryAsFiat = isMinRangeMonetaryFiat ? - minRangeMonetary : - priceQuote.toQuoteSideMonetary(minRangeMonetary).round(0); + Monetary minRangeMonetaryAsFiat = isMinRangeMonetaryFiat ? minRangeMonetary : priceQuote.toQuoteSideMonetary(minRangeMonetary).round(0); model.getMinRangeQuoteSideValue().set(minRangeMonetaryAsFiat); if (model.isUseQuoteCurrencyForMinMaxRange()) { model.getMinRangeValueAsString().set(Res.get("bisqEasy.component.amount.minRangeValue", AmountFormatter.formatAmountWithCode(minRangeMonetaryAsFiat))); } - Monetary maxRangeMonetaryAsFiat = isMaxRangeMonetaryFiat ? - maxRangeMonetary : - priceQuote.toQuoteSideMonetary(maxRangeMonetary).round(0); + Monetary maxRangeMonetaryAsFiat = isMaxRangeMonetaryFiat ? maxRangeMonetary : priceQuote.toQuoteSideMonetary(maxRangeMonetary).round(0); model.getMaxRangeQuoteSideValue().set(maxRangeMonetaryAsFiat); if (model.isUseQuoteCurrencyForMinMaxRange()) { model.getMaxRangeValueAsString().set(Res.get("bisqEasy.component.amount.maxRangeValue", @@ -394,43 +480,68 @@ private void applySliderTrackStyle() { @Override public void onDeactivate() { - model.getBaseSideAmount().removeListener(baseSideAmountFromModelListener); - model.getQuoteSideAmount().removeListener(quoteSideAmountFromModelListener); + model.getMaxOrFixedBaseSideAmount().removeListener(maxOrFixedBaseSideAmountFromModelListener); + model.getMaxOrFixedQuoteSideAmount().removeListener(maxOrFixedQuoteSideAmountFromModelListener); + model.getMinBaseSideAmount().removeListener(minBaseSideAmountFromModelListener); + model.getMinQuoteSideAmount().removeListener(minQuoteSideAmountFromModelListener); price.getQuote().removeListener(quoteListener); - model.getSliderValue().removeListener(sliderListener); - baseAmountFromModelPin.unsubscribe(); - baseAmountFromCompPin.unsubscribe(); - quoteAmountFromCompPin.unsubscribe(); + model.getMaxOrFixedSliderValue().removeListener(maxOrFixedSliderListener); + maxOrFixedBaseAmountFromModelPin.unsubscribe(); + minBaseAmountFromModelPin.unsubscribe(); + maxOrFixedBaseAmountFromCompPin.unsubscribe(); + minBaseAmountFromCompPin.unsubscribe(); + maxOrFixedQuoteAmountFromCompPin.unsubscribe(); + minQuoteAmountFromCompPin.unsubscribe(); priceFromCompPin.unsubscribe(); minRangeCustomValuePin.unsubscribe(); maxRangeCustomValuePin.unsubscribe(); - baseSideAmountValidPin.unsubscribe(); - quoteSideAmountValidPin.unsubscribe(); + maxOrFixedBaseSideAmountValidPin.unsubscribe(); + minBaseSideAmountValidPin.unsubscribe(); + maxOrFixedQuoteSideAmountValidPin.unsubscribe(); + minQuoteSideAmountValidPin.unsubscribe(); model.setLeftMarkerQuoteSideValue(null); model.setRightMarkerQuoteSideValue(null); } - private void setQuoteFromBase() { + private void setMaxOrFixedQuoteFromBase() { + PriceQuote priceQuote = price.getQuote().get(); + if (priceQuote == null) return; + Monetary baseSideAmount = model.getMaxOrFixedBaseSideAmount().get(); + if (baseSideAmount == null) return; + maxOrFixedQuoteSideAmountInput.setAmount(priceQuote.toQuoteSideMonetary(baseSideAmount).round(0)); + } + + private void setMinQuoteFromBase() { PriceQuote priceQuote = price.getQuote().get(); if (priceQuote == null) return; - Monetary baseSideAmount = model.getBaseSideAmount().get(); + Monetary baseSideAmount = model.getMinBaseSideAmount().get(); if (baseSideAmount == null) return; - quoteSideAmountInput.setAmount(priceQuote.toQuoteSideMonetary(baseSideAmount).round(0)); + minQuoteSideAmountInput.setAmount(priceQuote.toQuoteSideMonetary(baseSideAmount).round(0)); + } + + private void setMaxOrFixedBaseFromQuote() { + PriceQuote priceQuote = price.getQuote().get(); + if (priceQuote == null) return; + Monetary quoteSideAmount = model.getMaxOrFixedQuoteSideAmount().get(); + if (quoteSideAmount == null) return; + maxOrFixedBaseSideAmountInput.setAmount(priceQuote.toBaseSideMonetary(quoteSideAmount)); } - private void setBaseFromQuote() { + private void setMinBaseFromQuote() { PriceQuote priceQuote = price.getQuote().get(); if (priceQuote == null) return; - Monetary quoteSideAmount = model.getQuoteSideAmount().get(); + Monetary quoteSideAmount = model.getMinQuoteSideAmount().get(); if (quoteSideAmount == null) return; - baseSideAmountInput.setAmount(priceQuote.toBaseSideMonetary(quoteSideAmount)); + minBaseSideAmountInput.setAmount(priceQuote.toBaseSideMonetary(quoteSideAmount)); } private void applyQuote() { - if (model.getBaseSideAmount() == null) { - setBaseFromQuote(); + if (model.getMaxOrFixedBaseSideAmount() == null) { + setMaxOrFixedBaseFromQuote(); + setMinBaseFromQuote(); } else { - setQuoteFromBase(); + setMaxOrFixedQuoteFromBase(); + setMinQuoteFromBase(); } } } diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionModel.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionModel.java index 494e79f0d1..6faaf6afd8 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionModel.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionModel.java @@ -40,12 +40,16 @@ public class AmountSelectionModel implements Model { private final double sliderMin = 0; private final double sliderMax = 1; - private final ObjectProperty baseSideAmount = new SimpleObjectProperty<>(); - private final ObjectProperty quoteSideAmount = new SimpleObjectProperty<>(); + private final ObjectProperty maxOrFixedBaseSideAmount = new SimpleObjectProperty<>(); + private final ObjectProperty maxOrFixedQuoteSideAmount = new SimpleObjectProperty<>(); + private final ObjectProperty minBaseSideAmount = new SimpleObjectProperty<>(); + private final ObjectProperty minQuoteSideAmount = new SimpleObjectProperty<>(); private final StringProperty spendOrReceiveString = new SimpleStringProperty(); - private final DoubleProperty sliderValue = new SimpleDoubleProperty(); + private final DoubleProperty maxOrFixedSliderValue = new SimpleDoubleProperty(); + private final DoubleProperty minSliderValue = new SimpleDoubleProperty(); private final BooleanProperty sliderFocus = new SimpleBooleanProperty(); + private final BooleanProperty isRangeAmountEnabled = new SimpleBooleanProperty(); @Setter private ObjectProperty minRangeMonetary = new SimpleObjectProperty<>(BisqEasyTradeAmountLimits.DEFAULT_MIN_BTC_TRADE_AMOUNT); @@ -71,21 +75,25 @@ public class AmountSelectionModel implements Model { private final StringProperty description = new SimpleStringProperty(); private final StringProperty minRangeValueAsString = new SimpleStringProperty(); private final StringProperty maxRangeValueAsString = new SimpleStringProperty(); - private final BooleanProperty useCompactFormat = new SimpleBooleanProperty(); + private final BooleanProperty showRangeAmountSelection = new SimpleBooleanProperty(false); public AmountSelectionModel(boolean useQuoteCurrencyForMinMaxRange) { this.useQuoteCurrencyForMinMaxRange = useQuoteCurrencyForMinMaxRange; } void reset() { - baseSideAmount.set(null); - quoteSideAmount.set(null); + maxOrFixedBaseSideAmount.set(null); + maxOrFixedQuoteSideAmount.set(null); + minBaseSideAmount.set(null); + minQuoteSideAmount.set(null); spendOrReceiveString.set(null); - sliderValue.set(0L); + maxOrFixedSliderValue.set(0L); + minSliderValue.set(0L); sliderFocus.set(false); market = MarketRepository.getDefault(); direction = Direction.BUY; leftMarkerQuoteSideValue = null; rightMarkerQuoteSideValue = null; + showRangeAmountSelection.set(false); } } diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java index 799379831d..de70ad5c2f 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java @@ -24,7 +24,6 @@ import bisq.desktop.main.content.bisq_easy.components.amount_selection.amount_input.BigAmountInput; import bisq.desktop.main.content.bisq_easy.components.amount_selection.amount_input.SmallAmountInput; import javafx.beans.property.ReadOnlyBooleanProperty; -import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Parent; import javafx.scene.control.Label; @@ -40,40 +39,65 @@ @Slf4j public class AmountSelectionView extends View { public final static int AMOUNT_BOX_WIDTH = 330; - public final static int AMOUNT_BOX_HEIGHT = 130; + public final static int AMOUNT_BOX_HEIGHT = 120; private final Slider slider = new Slider(); private final Label minRangeValue, maxRangeValue, description; - private final Region selectionLine; - private final SmallAmountInput baseAmount; - private final BigAmountInput quoteAmount; - private Subscription baseAmountFocusPin, quoteAmountFocusPin, sliderTrackStylePin, useCompactFormatPin; + private final Region line, selectionLine; + private final SmallAmountInput maxOrFixedBaseAmount, minBaseAmount; + private final BigAmountInput maxOrFixedQuoteAmount, minQuoteAmount; + private final VBox minAmountVBox, amountSeparatorVBox, sliderBox; + private Subscription maxOrFixedBaseAmountFocusPin, maxOrFixedQuoteAmountFocusPin, + minBaseAmountFocusPin, minQuoteAmountFocusPin, sliderTrackStylePin, isRangeAmountEnabledPin; AmountSelectionView(AmountSelectionModel model, AmountSelectionController controller, - SmallAmountInput baseAmount, - BigAmountInput quoteAmount) { + SmallAmountInput maxOrFixedBaseAmount, + BigAmountInput maxOrFixedQuoteAmount, + SmallAmountInput minBaseAmount, + BigAmountInput minQuoteAmount) { super(new VBox(10), model, controller); - Pane baseAmountRoot = baseAmount.getRoot(); - this.baseAmount = baseAmount; - Pane quoteAmountRoot = quoteAmount.getRoot(); - this.quoteAmount = quoteAmount; + // max or fixed component + Pane maxOrFixedBaseAmountRoot = maxOrFixedBaseAmount.getRoot(); + this.maxOrFixedBaseAmount = maxOrFixedBaseAmount; + Pane maxOrFixedQuoteAmountRoot = maxOrFixedQuoteAmount.getRoot(); + this.maxOrFixedQuoteAmount = maxOrFixedQuoteAmount; + VBox maxOrFixedAmountVBox = new VBox(0, maxOrFixedQuoteAmountRoot, maxOrFixedBaseAmountRoot); + maxOrFixedAmountVBox.getStyleClass().add("max-or-fixed-amount"); + + // min component (only shown when using a range) + Pane minBaseAmountRoot = minBaseAmount.getRoot(); + this.minBaseAmount = minBaseAmount; + Pane minQuoteAmountRoot = minQuoteAmount.getRoot(); + this.minQuoteAmount = minQuoteAmount; + + minAmountVBox = new VBox(0, minQuoteAmountRoot, minBaseAmountRoot); + minAmountVBox.getStyleClass().add("min-amount"); + + // rest of the component description = new Label(); description.getStyleClass().add("description"); description.setMouseTransparent(true); - VBox amountVBox = new VBox(0, description, Spacer.fillVBox(), quoteAmountRoot, - Spacer.fillVBox(), baseAmountRoot); - amountVBox.getStyleClass().add("bisq-dual-amount-bg"); - amountVBox.setMinWidth(AMOUNT_BOX_WIDTH); - amountVBox.setMaxWidth(AMOUNT_BOX_WIDTH); - amountVBox.setMinHeight(AMOUNT_BOX_HEIGHT); - amountVBox.setMaxHeight(AMOUNT_BOX_HEIGHT); - amountVBox.setPadding(new Insets(5, 20, 10, 20)); - - Region line = new Region(); + Label quoteAmountSeparator = new Label("-"); + quoteAmountSeparator.getStyleClass().add("quote-separator"); + Label baseAmountSeparator = new Label("-"); + baseAmountSeparator.getStyleClass().add("base-separator"); + amountSeparatorVBox = new VBox(quoteAmountSeparator, baseAmountSeparator); + amountSeparatorVBox.getStyleClass().add("amount-separator"); + HBox amountInputHBox = new HBox(minAmountVBox, amountSeparatorVBox, maxOrFixedAmountVBox); + amountInputHBox.setMaxWidth(AMOUNT_BOX_WIDTH); + amountInputHBox.setMinWidth(AMOUNT_BOX_WIDTH); + amountInputHBox.setMinHeight(AMOUNT_BOX_HEIGHT - 23); + amountInputHBox.setMaxHeight(AMOUNT_BOX_HEIGHT - 23); + amountInputHBox.getStyleClass().add("amount-input"); + + VBox descriptionAndAmountVBox = new VBox(0, description, Spacer.fillVBox(), amountInputHBox); + descriptionAndAmountVBox.getStyleClass().add("bisq-dual-amount-bg"); + + line = new Region(); line.setPrefHeight(1); line.setPrefWidth(AMOUNT_BOX_WIDTH); line.setLayoutY(AMOUNT_BOX_HEIGHT); @@ -87,8 +111,10 @@ public class AmountSelectionView extends View { - quoteAmount.requestFocus(); - baseAmountFocusPin = EasyBind.subscribe(baseAmount.focusedProperty(), - focus -> onInputTextFieldFocus(quoteAmount.focusedProperty(), focus)); - quoteAmountFocusPin = EasyBind.subscribe(quoteAmount.focusedProperty(), - focus -> onInputTextFieldFocus(baseAmount.focusedProperty(), focus)); + maxOrFixedQuoteAmount.requestFocus(); + maxOrFixedBaseAmountFocusPin = EasyBind.subscribe(maxOrFixedBaseAmount.focusedProperty(), + focus -> onInputTextFieldFocus(maxOrFixedQuoteAmount.focusedProperty(), focus)); + maxOrFixedQuoteAmountFocusPin = EasyBind.subscribe(maxOrFixedQuoteAmount.focusedProperty(), + focus -> onInputTextFieldFocus(maxOrFixedBaseAmount.focusedProperty(), focus)); + minBaseAmountFocusPin = EasyBind.subscribe(minBaseAmount.focusedProperty(), + focus -> onInputTextFieldFocus(minQuoteAmount.focusedProperty(), focus)); + minQuoteAmountFocusPin = EasyBind.subscribe(minQuoteAmount.focusedProperty(), + focus -> onInputTextFieldFocus(minBaseAmount.focusedProperty(), focus)); }).after(700); + isRangeAmountEnabledPin = EasyBind.subscribe(model.getIsRangeAmountEnabled(), isRangeAmountEnabled -> { + root.getStyleClass().clear(); + root.getStyleClass().add("amount-selection"); + root.getStyleClass().add(isRangeAmountEnabled ? "range-amount" : "fixed-amount"); + maxOrFixedQuoteAmount.setUseVerySmallText(isRangeAmountEnabled); + minQuoteAmount.setUseVerySmallText(isRangeAmountEnabled); + }); sliderTrackStylePin = EasyBind.subscribe(model.getSliderTrackStyle(), slider::setStyle); - slider.valueProperty().bindBidirectional(model.getSliderValue()); + slider.valueProperty().bindBidirectional(model.getMaxOrFixedSliderValue()); model.getSliderFocus().bind(slider.focusedProperty()); description.textProperty().bind(model.getDescription()); minRangeValue.textProperty().bind(model.getMinRangeValueAsString()); maxRangeValue.textProperty().bind(model.getMaxRangeValueAsString()); - - useCompactFormatPin = EasyBind.subscribe(model.getUseCompactFormat(), useCompactFormat -> { - - }); + minAmountVBox.visibleProperty().bind(model.getIsRangeAmountEnabled()); + minAmountVBox.managedProperty().bind(model.getIsRangeAmountEnabled()); + amountSeparatorVBox.visibleProperty().bind(model.getIsRangeAmountEnabled()); + amountSeparatorVBox.managedProperty().bind(model.getIsRangeAmountEnabled()); // Needed to trigger focusOut event on amount components // We handle all parents mouse events. @@ -140,20 +175,35 @@ protected void onViewAttached() { @Override protected void onViewDetached() { - if (baseAmountFocusPin != null) { - baseAmountFocusPin.unsubscribe(); + if (maxOrFixedBaseAmountFocusPin != null) { + maxOrFixedBaseAmountFocusPin.unsubscribe(); + } + if (maxOrFixedQuoteAmountFocusPin != null) { + maxOrFixedQuoteAmountFocusPin.unsubscribe(); } - if (quoteAmountFocusPin != null) { - quoteAmountFocusPin.unsubscribe(); + if (minBaseAmountFocusPin != null) { + minBaseAmountFocusPin.unsubscribe(); } + if (minQuoteAmountFocusPin != null) { + minQuoteAmountFocusPin.unsubscribe(); + } + isRangeAmountEnabledPin.unsubscribe(); sliderTrackStylePin.unsubscribe(); - slider.valueProperty().unbindBidirectional(model.getSliderValue()); + slider.valueProperty().unbindBidirectional(model.getMaxOrFixedSliderValue()); model.getSliderFocus().unbind(); description.textProperty().unbind(); minRangeValue.textProperty().unbind(); maxRangeValue.textProperty().unbind(); - baseAmount.isAmountValidProperty().set(true); - quoteAmount.isAmountValidProperty().set(true); + minAmountVBox.visibleProperty().unbind(); + minAmountVBox.managedProperty().unbind(); + amountSeparatorVBox.visibleProperty().unbind(); + amountSeparatorVBox.managedProperty().unbind(); + + maxOrFixedBaseAmount.isAmountValidProperty().set(true); + maxOrFixedQuoteAmount.isAmountValidProperty().set(true); + minBaseAmount.isAmountValidProperty().set(true); + minQuoteAmount.isAmountValidProperty().set(true); + Parent node = root; while (node.getParent() != null) { node.setOnMousePressed(null); diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/AmountInput.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/AmountInput.java index afc2ae1918..0847ceec0f 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/AmountInput.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/AmountInput.java @@ -41,13 +41,15 @@ import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; +import org.fxmisc.easybind.EasyBind; +import org.fxmisc.easybind.Subscription; @Slf4j public abstract class AmountInput { protected final Controller controller; - public AmountInput(boolean isBaseCurrency) { - controller = new Controller(isBaseCurrency); + public AmountInput(boolean isBaseCurrency, boolean showCurrencyCode) { + controller = new Controller(isBaseCurrency, showCurrencyCode); } public ReadOnlyObjectProperty amountProperty() { @@ -84,8 +86,8 @@ public void requestFocus() { textInput.selectRange(textInput.getLength(), textInput.getLength()); } - public void setShowHyphenInsteadOfCurrencyCode(boolean showHyphenInsteadOfCurrencyCode) { - controller.model.showHyphenInsteadOfCurrencyCode.set(showHyphenInsteadOfCurrencyCode); + public void setUseVerySmallText(boolean useVerySmallText) { + controller.setUseVerySmallText(useVerySmallText); } protected static class Controller implements bisq.desktop.common.view.Controller { @@ -96,8 +98,8 @@ protected static class Controller implements bisq.desktop.common.view.Controller protected View view; protected final NumberValidator validator = new NumberValidator(); - private Controller(boolean isBaseCurrency) { - model = new Model(isBaseCurrency); + private Controller(boolean isBaseCurrency, boolean showCurrencyCode) { + model = new Model(isBaseCurrency, showCurrencyCode); view = new View(model, this); } @@ -151,6 +153,10 @@ private void setAmountValid() { model.isAmountValid.set(true); } + private void setUseVerySmallText(boolean useVerySmallText) { + model.useVerySmallText.set(useVerySmallText); + } + private void updateAmountIfNotFocused(String value) { if (!model.hasFocus) { model.amount.set(AmountParser.parse(value, model.code.get())); @@ -166,32 +172,31 @@ private void updateModel() { ? model.selectedMarket.getBaseCurrencyCode() : model.selectedMarket.getQuoteCurrencyCode()); } - - protected void adjustTextFieldStyle() { - } } protected static class Model implements bisq.desktop.common.view.Model { protected final boolean isBaseCurrency; + protected final boolean showCurrencyCode; protected final ObjectProperty amount = new SimpleObjectProperty<>(); protected final StringProperty code = new SimpleStringProperty(); + protected final BooleanProperty useVerySmallText = new SimpleBooleanProperty(); protected Market selectedMarket; protected boolean hasFocus; @Setter protected boolean useLowPrecision = true; - protected final BooleanProperty showHyphenInsteadOfCurrencyCode = new SimpleBooleanProperty(false); private final BooleanProperty isAmountValid = new SimpleBooleanProperty(true); - protected Model(boolean isBaseCurrency) { + protected Model(boolean isBaseCurrency, boolean showCurrencyCode) { this.isBaseCurrency = isBaseCurrency; + this.showCurrencyCode = showCurrencyCode; } void reset() { amount.set(null); code.set(null); + useVerySmallText.set(false); selectedMarket = null; hasFocus = false; - showHyphenInsteadOfCurrencyCode.set(false); isAmountValid.set(false); } } @@ -200,15 +205,17 @@ protected static class View extends bisq.desktop.common.view.View focusListener; protected final ChangeListener amountListener; protected final TextField textInput; - protected final Label hyphenLabel, codeLabel; + protected final Label codeLabel; + private Subscription useVerySmallTextPin; protected View(Model model, Controller controller) { super(new HBox(), model, controller); textInput = createTextInput(); - hyphenLabel = createHyphenLabel(); codeLabel = createCodeLabel(); - root.getChildren().addAll(textInput, hyphenLabel, codeLabel); + codeLabel.setVisible(model.showCurrencyCode); + codeLabel.setManaged(model.showCurrencyCode); + root.getChildren().addAll(textInput, codeLabel); focusListener = this::onFocusChanged; amountListener = this::onAmountChanged; initView(); @@ -218,10 +225,6 @@ protected TextField createTextInput() { return new TextField(); } - protected Label createHyphenLabel() { - return new Label("-"); - } - protected Label createCodeLabel() { return new Label(); } @@ -254,11 +257,7 @@ protected void adjustTextFieldStyle() { @Override protected void onViewAttached() { - hyphenLabel.visibleProperty().bind(model.showHyphenInsteadOfCurrencyCode); - hyphenLabel.managedProperty().bind(model.showHyphenInsteadOfCurrencyCode); codeLabel.textProperty().bind(model.code); - codeLabel.visibleProperty().bind(model.showHyphenInsteadOfCurrencyCode.not()); - codeLabel.managedProperty().bind(model.showHyphenInsteadOfCurrencyCode.not()); textInput.focusedProperty().addListener(focusListener); model.amount.addListener(amountListener); @@ -266,18 +265,18 @@ protected void onViewAttached() { applyAmount(model.amount.get()); textInput.requestFocus(); textInput.selectRange(textInput.getLength(), textInput.getLength()); + + useVerySmallTextPin = EasyBind.subscribe(model.useVerySmallText, useVerySmallText -> adjustTextFieldStyle()); } @Override protected void onViewDetached() { - hyphenLabel.visibleProperty().unbind(); - hyphenLabel.managedProperty().unbind(); codeLabel.textProperty().unbind(); - codeLabel.visibleProperty().unbind(); - codeLabel.managedProperty().unbind(); textInput.focusedProperty().removeListener(focusListener); model.amount.removeListener(amountListener); + + useVerySmallTextPin.unsubscribe(); } } } diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/BigAmountInput.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/BigAmountInput.java index c2c7cf2e31..9f50e2c90f 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/BigAmountInput.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/BigAmountInput.java @@ -17,35 +17,30 @@ package bisq.desktop.main.content.bisq_easy.components.amount_selection.amount_input; -import javafx.geometry.Insets; -import javafx.geometry.Pos; import javafx.scene.control.Label; import javafx.scene.control.TextField; -import javafx.scene.layout.HBox; import lombok.extern.slf4j.Slf4j; @Slf4j public class BigAmountInput extends AmountInput { - private static final double TEXT_INPUT_PREF_WIDTH = 250; private static final String BIG_TEXT_INPUT_ID = "base-amount-text-field"; private static final String SMALL_TEXT_INPUT_ID = "base-amount-text-field-small"; + private static final String VERY_SMALL_TEXT_INPUT_ID = "base-amount-text-field-very-small"; private static final int TEXT_LENGTH_THRESHOLD = 9; - public BigAmountInput(boolean isBaseCurrency) { - super(isBaseCurrency); - this.controller.setView(new BigAmountInputView(controller.model, controller)); + public BigAmountInput(boolean isBaseCurrency, boolean showCurrencyCode) { + super(isBaseCurrency, showCurrencyCode); + + controller.setView(new BigAmountInputView(controller.model, controller)); } private static class BigAmountInputView extends View { - protected BigAmountInputView(Model model, Controller controller) { super(model, controller); } @Override public void initView() { - HBox.setMargin(textInput, new Insets(0, 0, 0, -30)); - root.setAlignment(Pos.BASELINE_CENTER); root.setSpacing(10); root.getStyleClass().add("big-amount-input"); } @@ -53,30 +48,27 @@ public void initView() { @Override protected TextField createTextInput() { var textInput = new TextField(); - textInput.setPrefWidth(TEXT_INPUT_PREF_WIDTH); textInput.setId(BIG_TEXT_INPUT_ID); - textInput.setAlignment(Pos.BASELINE_RIGHT); textInput.getStyleClass().add("text-input"); - textInput.setPadding(new Insets(0, 0, 5, 0)); return textInput; } @Override protected Label createCodeLabel() { var codeLabel = new Label(); - codeLabel.setPadding(new Insets(0, -20, 0, 0)); codeLabel.getStyleClass().add("currency-code"); - codeLabel.setAlignment(Pos.BASELINE_LEFT); return codeLabel; } @Override protected void adjustTextFieldStyle() { - if (textInput.getText().length() > TEXT_LENGTH_THRESHOLD) { - textInput.setId(SMALL_TEXT_INPUT_ID); + if (model.useVerySmallText.get()) { + textInput.setId(VERY_SMALL_TEXT_INPUT_ID); } else { - textInput.setId(BIG_TEXT_INPUT_ID); + textInput.setId(textInput.getText().length() > TEXT_LENGTH_THRESHOLD + ? SMALL_TEXT_INPUT_ID + : BIG_TEXT_INPUT_ID); } } } -} \ No newline at end of file +} diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/SmallAmountInput.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/SmallAmountInput.java index 0f417e9b56..b503de58c6 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/SmallAmountInput.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/SmallAmountInput.java @@ -37,10 +37,10 @@ public class SmallAmountInput extends AmountInput { private static final String DEFAULT_TOOLTIP = "bisqEasy.component.amount.baseSide.tooltip.btcAmount.marketPrice"; private static final String QUOTE_AMOUNT_ID = "quote-amount-text-field"; - public SmallAmountInput(boolean isBaseCurrency) { - super(isBaseCurrency); + public SmallAmountInput(boolean isBaseCurrency, boolean showCurrencyCode) { + super(isBaseCurrency, showCurrencyCode); - this.controller.setModel(new SmallAmountInputModel(isBaseCurrency)); + this.controller.setModel(new SmallAmountInputModel(isBaseCurrency, showCurrencyCode)); this.controller.setView(new SmallAmountInputView(controller.model, controller)); } @@ -58,6 +58,9 @@ private static class SmallAmountInputView extends View { protected SmallAmountInputView(Model model, Controller controller) { super(model, controller); + + iconButton.setVisible(model.showCurrencyCode); + iconButton.setManaged(model.showCurrencyCode); } private Button createIconButton() { @@ -102,8 +105,6 @@ protected void onViewAttached() { super.onViewAttached(); tooltip.textProperty().bind(((SmallAmountInputModel) model).tooltipProperty()); - iconButton.visibleProperty().bind(model.showHyphenInsteadOfCurrencyCode); - iconButton.managedProperty().bind(model.showHyphenInsteadOfCurrencyCode); } @Override @@ -111,16 +112,14 @@ protected void onViewDetached() { super.onViewDetached(); tooltip.textProperty().unbind(); - iconButton.visibleProperty().unbind(); - iconButton.managedProperty().unbind(); } } private static class SmallAmountInputModel extends Model { private final StringProperty tooltip = new SimpleStringProperty(Res.get(DEFAULT_TOOLTIP)); - protected SmallAmountInputModel(boolean isBaseCurrency) { - super(isBaseCurrency); + protected SmallAmountInputModel(boolean isBaseCurrency, boolean showCurrencyCode) { + super(isBaseCurrency, showCurrencyCode); } public StringProperty tooltipProperty() { diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/take_offer/amount/TakeOfferAmountController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/take_offer/amount/TakeOfferAmountController.java index ee103144e8..c0e4f1c5a7 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/take_offer/amount/TakeOfferAmountController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/take_offer/amount/TakeOfferAmountController.java @@ -127,9 +127,9 @@ public ReadOnlyObjectProperty getTakersBaseSideAmount() { @Override public void onActivate() { - baseSideAmountPin = EasyBind.subscribe(amountSelectionController.getBaseSideAmount(), + baseSideAmountPin = EasyBind.subscribe(amountSelectionController.getMaxOrFixedBaseSideAmount(), amount -> model.getTakersBaseSideAmount().set(amount)); - quoteSideAmountPin = EasyBind.subscribe(amountSelectionController.getQuoteSideAmount(), + quoteSideAmountPin = EasyBind.subscribe(amountSelectionController.getMaxOrFixedQuoteSideAmount(), amount -> { model.getTakersQuoteSideAmount().set(amount); if (amount != null) { @@ -149,7 +149,7 @@ public void onDeactivate() { } void onSetReputationBasedAmount() { - amountSelectionController.setQuoteSideAmount(amountSelectionController.getRightMarkerQuoteSideValue().round(0)); + amountSelectionController.setMaxOrFixedQuoteSideAmount(amountSelectionController.getRightMarkerQuoteSideValue().round(0)); } void onShowAmountLimitInfoOverlay() { @@ -194,7 +194,7 @@ private void applyQuoteSideMinMaxRange(Monetary minRangeValue, Monetary maxRange if (reputationBasedQuoteSideAmount.isLessThan(maxRangeValue)) { model.getIsAmountLimitInfoVisible().set(true); amountSelectionController.setRightMarkerQuoteSideValue(reputationBasedQuoteSideAmount); - amountSelectionController.setQuoteSideAmount(reputationBasedQuoteSideAmount); + amountSelectionController.setMaxOrFixedQuoteSideAmount(reputationBasedQuoteSideAmount); String formattedAmount = AmountFormatter.formatAmountWithCode(reputationBasedQuoteSideAmount); if (sellersReputationScore <= MIN_REPUTAION_SCORE) { @@ -230,7 +230,7 @@ private void applyQuoteSideMinMaxRange(Monetary minRangeValue, Monetary maxRange model.setLinkToWikiText(Res.get("bisqEasy.tradeWizard.amount.seller.limitInfo.overlay.linkToWikiText")); String myProfileId = userIdentityService.getSelectedUserIdentity().getUserProfile().getId(); long myReputationScore = reputationService.getReputationScore(myProfileId).getTotalScore(); - Monetary quoteSideAmount = amountSelectionController.getQuoteSideAmount().get(); + Monetary quoteSideAmount = amountSelectionController.getMaxOrFixedQuoteSideAmount().get(); BisqEasyTradeAmountLimits.getReputationBasedQuoteSideAmount(marketPriceService, market, myReputationScore) .ifPresent(myReputationBasedQuoteSideAmount -> { @@ -275,7 +275,7 @@ private void applyQuoteSideMinMaxRange(Monetary minRangeValue, Monetary maxRange } private void applyReputationBasedQuoteSideAmount() { - amountSelectionController.setQuoteSideAmount(amountSelectionController.getRightMarkerQuoteSideValue().round(0)); + amountSelectionController.setMaxOrFixedQuoteSideAmount(amountSelectionController.getRightMarkerQuoteSideValue().round(0)); } private void maxOrFixedQuoteSideAmountChanged(Monetary value) { diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java index 9d1405e013..3ff796cf80 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java @@ -84,7 +84,7 @@ public class TradeWizardAmountController implements Controller { private final TradeWizardAmountModel model; @Getter private final TradeWizardAmountView view; - private final AmountSelectionController minAmountSelectionController, maxOrFixAmountSelectionController; + private final AmountSelectionController amountSelectionController; private final SettingsService settingsService; private final MarketPriceService marketPriceService; private final BisqEasyOfferbookChannelService bisqEasyOfferbookChannelService; @@ -107,13 +107,8 @@ public TradeWizardAmountController(ServiceProvider serviceProvider, Region owner this.owner = owner; model = new TradeWizardAmountModel(); - minAmountSelectionController = new AmountSelectionController(serviceProvider, true); - minAmountSelectionController.showHyphenInsteadOfCurrencyCode(true); - maxOrFixAmountSelectionController = new AmountSelectionController(serviceProvider, true); - - view = new TradeWizardAmountView(model, this, - minAmountSelectionController, - maxOrFixAmountSelectionController); + amountSelectionController = new AmountSelectionController(serviceProvider, true); + view = new TradeWizardAmountView(model, this, amountSelectionController); } public void setIsCreateOfferMode(boolean isCreateOfferMode) { @@ -129,16 +124,14 @@ public void setDirection(Direction direction) { return; } model.setDirection(direction); - minAmountSelectionController.setDirection(direction); - maxOrFixAmountSelectionController.setDirection(direction); + amountSelectionController.setDirection(direction); } public void setMarket(Market market) { if (market == null) { return; } - minAmountSelectionController.setMarket(market); - maxOrFixAmountSelectionController.setMarket(market); + amountSelectionController.setMarket(market); model.setMarket(market); applyQuoteSideMinMaxRange(); } @@ -187,16 +180,14 @@ public void updateQuoteSideAmountSpecWithPriceSpec(PriceSpec priceSpec) { return; } model.getPriceQuote().set(priceQuote.get()); - minAmountSelectionController.setQuote(priceQuote.get()); - maxOrFixAmountSelectionController.setQuote(priceQuote.get()); + amountSelectionController.setQuote(priceQuote.get()); OfferAmountUtil.updateQuoteSideAmountSpecWithPriceSpec(marketPriceService, amountSpec, priceSpec, market) .ifPresent(quoteSideAmountSpec -> model.getQuoteSideAmountSpec().set(quoteSideAmountSpec)); } public void reset() { - minAmountSelectionController.reset(); - maxOrFixAmountSelectionController.reset(); + amountSelectionController.reset(); model.reset(); } @@ -208,54 +199,54 @@ public ReadOnlyObjectProperty getQuoteSideAmountSpec() { public void onActivate() { applyQuoteSideMinMaxRange(); - if (model.getPriceQuote().get() == null && minAmountSelectionController.getQuote().get() != null) { - model.getPriceQuote().set(minAmountSelectionController.getQuote().get()); + if (model.getPriceQuote().get() == null && amountSelectionController.getQuote().get() != null) { + model.getPriceQuote().set(amountSelectionController.getQuote().get()); } - model.setHeadline(model.getDirection().isBuy() ? - Res.get("bisqEasy.tradeWizard.amount.headline.buyer") : - Res.get("bisqEasy.tradeWizard.amount.headline.seller")); + model.setHeadline(model.getDirection().isBuy() + ? Res.get("bisqEasy.tradeWizard.amount.headline.buyer") + : Res.get("bisqEasy.tradeWizard.amount.headline.seller")); Boolean cookieValue = settingsService.getCookie().asBoolean(CookieKey.CREATE_BISQ_EASY_OFFER_IS_MIN_AMOUNT_ENABLED).orElse(false); model.getIsRangeAmountEnabled().set(cookieValue && model.getShowRangeAmounts().get()); - minAmountCompBaseSideAmountPin = EasyBind.subscribe(minAmountSelectionController.getBaseSideAmount(), + minAmountCompBaseSideAmountPin = EasyBind.subscribe(amountSelectionController.getMinBaseSideAmount(), value -> { if (model.getIsRangeAmountEnabled().get()) { - if (value != null && maxOrFixAmountSelectionController.getBaseSideAmount().get() != null && - value.getValue() > maxOrFixAmountSelectionController.getBaseSideAmount().get().getValue()) { - maxOrFixAmountSelectionController.setBaseSideAmount(value); + if (value != null && amountSelectionController.getMaxOrFixedBaseSideAmount().get() != null && + value.getValue() > amountSelectionController.getMaxOrFixedBaseSideAmount().get().getValue()) { + amountSelectionController.setMaxOrFixedBaseSideAmount(value); } } }); - maxOrFixAmountCompBaseSideAmountPin = EasyBind.subscribe(maxOrFixAmountSelectionController.getBaseSideAmount(), + maxOrFixAmountCompBaseSideAmountPin = EasyBind.subscribe(amountSelectionController.getMaxOrFixedBaseSideAmount(), value -> { if (value != null && model.getIsRangeAmountEnabled().get() && - minAmountSelectionController.getBaseSideAmount().get() != null && - value.getValue() < minAmountSelectionController.getBaseSideAmount().get().getValue()) { - minAmountSelectionController.setBaseSideAmount(value); + amountSelectionController.getMinBaseSideAmount().get() != null && + value.getValue() < amountSelectionController.getMinBaseSideAmount().get().getValue()) { + amountSelectionController.setMinBaseSideAmount(value); } }); - minAmountCompQuoteSideAmountPin = EasyBind.subscribe(minAmountSelectionController.getQuoteSideAmount(), + minAmountCompQuoteSideAmountPin = EasyBind.subscribe(amountSelectionController.getMinQuoteSideAmount(), value -> { if (value != null) { if (model.getIsRangeAmountEnabled().get() && - maxOrFixAmountSelectionController.getQuoteSideAmount().get() != null && - value.getValue() > maxOrFixAmountSelectionController.getQuoteSideAmount().get().getValue()) { - maxOrFixAmountSelectionController.setQuoteSideAmount(value); + amountSelectionController.getMaxOrFixedQuoteSideAmount().get() != null && + value.getValue() > amountSelectionController.getMaxOrFixedQuoteSideAmount().get().getValue()) { + amountSelectionController.setMaxOrFixedQuoteSideAmount(value); } applyAmountSpec(); quoteSideAmountsChanged(false); } }); - maxAmountCompQuoteSideAmountPin = EasyBind.subscribe(maxOrFixAmountSelectionController.getQuoteSideAmount(), + maxAmountCompQuoteSideAmountPin = EasyBind.subscribe(amountSelectionController.getMaxOrFixedQuoteSideAmount(), value -> { if (value != null) { if (model.getIsRangeAmountEnabled().get() && - minAmountSelectionController.getQuoteSideAmount().get() != null && - value.getValue() < minAmountSelectionController.getQuoteSideAmount().get().getValue()) { - minAmountSelectionController.setQuoteSideAmount(value); + amountSelectionController.getMinQuoteSideAmount().get() != null && + value.getValue() < amountSelectionController.getMinQuoteSideAmount().get().getValue()) { + amountSelectionController.setMinQuoteSideAmount(value); } applyAmountSpec(); quoteSideAmountsChanged(true); @@ -264,16 +255,14 @@ public void onActivate() { isRangeAmountEnabledPin = EasyBind.subscribe(model.getIsRangeAmountEnabled(), isRangeAmountEnabled -> { applyAmountSpec(); - minAmountSelectionController.useCompactFormat(isRangeAmountEnabled); - maxOrFixAmountSelectionController.useCompactFormat(isRangeAmountEnabled); + amountSelectionController.setIsRangeAmountEnabled(isRangeAmountEnabled); }); applyAmountSpec(); if (model.isCreateOfferMode()) { Optional marketPriceQuote = getMarketPriceQuote(); - if (model.getPriceQuote().get() != null && - marketPriceQuote.isPresent() && - !model.getPriceQuote().get().equals(marketPriceQuote.get())) { + if (model.getPriceQuote().get() != null && marketPriceQuote.isPresent() + && !model.getPriceQuote().get().equals(marketPriceQuote.get())) { model.getPriceTooltip().set(Res.get("bisqEasy.component.amount.baseSide.tooltip.btcAmount.selectedPrice")); } else { model.getPriceTooltip().set(Res.get("bisqEasy.component.amount.baseSide.tooltip.btcAmount.marketPrice")); @@ -293,8 +282,7 @@ public void onActivate() { priceTooltipPin = EasyBind.subscribe(model.getPriceTooltip(), priceTooltip -> { if (priceTooltip != null) { - minAmountSelectionController.setTooltip(priceTooltip); - maxOrFixAmountSelectionController.setTooltip(priceTooltip); + amountSelectionController.setTooltip(priceTooltip); } }); } @@ -348,17 +336,17 @@ private void updateIsRangeAmountEnabled(boolean useRangeAmount) { } private void applyAmountSpec() { - Long maxOrFixAmount = getAmountValue(maxOrFixAmountSelectionController.getQuoteSideAmount()); + Long maxOrFixAmount = getAmountValue(amountSelectionController.getMaxOrFixedQuoteSideAmount()); if (maxOrFixAmount == null) { return; } if (model.getIsRangeAmountEnabled().get()) { - Long minAmount = getAmountValue(minAmountSelectionController.getQuoteSideAmount()); + Long minAmount = getAmountValue(amountSelectionController.getMinQuoteSideAmount()); checkNotNull(minAmount); if (maxOrFixAmount.compareTo(minAmount) < 0) { - minAmountSelectionController.setQuoteSideAmount(maxOrFixAmountSelectionController.getQuoteSideAmount().get()); - minAmount = getAmountValue(minAmountSelectionController.getQuoteSideAmount()); + amountSelectionController.setMinQuoteSideAmount(amountSelectionController.getMaxOrFixedQuoteSideAmount().get()); + minAmount = getAmountValue(amountSelectionController.getMinQuoteSideAmount()); } applyRangeOrFixedAmountSpec(minAmount, maxOrFixAmount); } else { @@ -415,12 +403,12 @@ private Optional findBestOfferQuote() { ? priceQuoteStream.min(Comparator.comparing(PriceQuote::getValue)) : priceQuoteStream.max(Comparator.comparing(PriceQuote::getValue)); if (bestOffersPrice.isPresent()) { - maxOrFixAmountSelectionController.setQuote(bestOffersPrice.get()); + amountSelectionController.setQuote(bestOffersPrice.get()); } else { - getMarketPriceQuote().ifPresent(maxOrFixAmountSelectionController::setQuote); + getMarketPriceQuote().ifPresent(amountSelectionController::setQuote); } AmountSpecUtil.findQuoteSideFixedAmountFromSpec(model.getQuoteSideAmountSpec().get(), model.getMarket().getQuoteCurrencyCode()) - .ifPresent(amount -> UIThread.runOnNextRenderFrame(() -> maxOrFixAmountSelectionController.setQuoteSideAmount(amount))); + .ifPresent(amount -> UIThread.runOnNextRenderFrame(() -> amountSelectionController.setMaxOrFixedQuoteSideAmount(amount))); return bestOffersPrice; } @@ -493,12 +481,12 @@ private Optional getMarketPriceQuote() { } private void quoteSideAmountsChanged(boolean maxAmountChanged) { - Monetary minQuoteSideAmount = minAmountSelectionController.getQuoteSideAmount().get(); - Monetary maxOrFixedQuoteSideAmount = maxOrFixAmountSelectionController.getQuoteSideAmount().get(); + Monetary minQuoteSideAmount = amountSelectionController.getMinQuoteSideAmount().get(); + Monetary maxOrFixedQuoteSideAmount = amountSelectionController.getMaxOrFixedQuoteSideAmount().get(); model.getIsAmountHyperLinkDisabled().set(false); - boolean insecureValue = maxOrFixAmountSelectionController.getRightMarkerQuoteSideValue() != null && - maxOrFixedQuoteSideAmount.isGreaterThan(maxOrFixAmountSelectionController.getRightMarkerQuoteSideValue().round(0)); + boolean insecureValue = amountSelectionController.getRightMarkerQuoteSideValue() != null && + maxOrFixedQuoteSideAmount.isGreaterThan(amountSelectionController.getRightMarkerQuoteSideValue().round(0)); model.getIsWarningIconVisible().set(insecureValue); long highestScore = reputationService.getScoreByUserProfileId().entrySet().stream() @@ -667,21 +655,20 @@ private void applyQuoteSideMinMaxRange() { boolean isCreateOfferMode = model.isCreateOfferMode(); if (isCreateOfferMode) { model.getIsLearnMoreVisible().set(true); - minAmountSelectionController.setMinMaxRange(minRangeValue, maxRangeValue); - maxOrFixAmountSelectionController.setMinMaxRange(minRangeValue, maxRangeValue); + amountSelectionController.setMinMaxRange(minRangeValue, maxRangeValue); } else { // Wizard applyMarkerRange(); model.getIsLearnMoreVisible().set(model.getDirection().isSell()); if (model.getDirection().isBuy()) { - maxOrFixAmountSelectionController.setMinMaxRange(minRangeValue, maxRangeValue); + amountSelectionController.setMinMaxRange(minRangeValue, maxRangeValue); } else { - maxOrFixAmountSelectionController.setMinMaxRange(minRangeValue, model.getReputationBasedMaxAmount().round(0)); + amountSelectionController.setMinMaxRange(minRangeValue, model.getReputationBasedMaxAmount().round(0)); } - if (maxOrFixAmountSelectionController.getQuoteSideAmount().get() == null) { - maxOrFixAmountSelectionController.setQuoteSideAmount(defaultFiatAmount); + if (amountSelectionController.getMaxOrFixedQuoteSideAmount().get() == null) { + amountSelectionController.setMaxOrFixedQuoteSideAmount(defaultFiatAmount); } } @@ -697,13 +684,11 @@ private void applyQuoteSideMinMaxRange() { .max() .orElse(0L); Monetary highestPossibleUsdAmount = BisqEasyTradeAmountLimits.getUsdAmountFromReputationScore(highestScore); - if (isCreateOfferMode) { - minAmountSelectionController.setRightMarkerQuoteSideValue(highestPossibleUsdAmount); - maxOrFixAmountSelectionController.setRightMarkerQuoteSideValue(highestPossibleUsdAmount); + amountSelectionController.setRightMarkerQuoteSideValue(highestPossibleUsdAmount); } - if (maxOrFixAmountSelectionController.getQuoteSideAmount().get() == null) { - maxOrFixAmountSelectionController.setQuoteSideAmount(defaultFiatAmount); + if (amountSelectionController.getMaxOrFixedQuoteSideAmount().get() == null) { + amountSelectionController.setMaxOrFixedQuoteSideAmount(defaultFiatAmount); } } else { // Seller case @@ -714,8 +699,7 @@ private void applyQuoteSideMinMaxRange() { Monetary reputationBasedQuoteSideAmount = model.getReputationBasedMaxAmount(); long myReputationScore = model.getMyReputationScore(); model.getAmountLimitInfo().set(Res.get("bisqEasy.tradeWizard.amount.seller.limitInfo", myReputationScore)); - minAmountSelectionController.setRightMarkerQuoteSideValue(reputationBasedQuoteSideAmount); - maxOrFixAmountSelectionController.setRightMarkerQuoteSideValue(reputationBasedQuoteSideAmount); + amountSelectionController.setRightMarkerQuoteSideValue(reputationBasedQuoteSideAmount); String formattedAmount = formatAmountWithCode(reputationBasedQuoteSideAmount); model.getAmountLimitInfoAmount().set(Res.get("bisqEasy.tradeWizard.amount.seller.limitInfoAmount", formattedAmount)); @@ -728,7 +712,7 @@ private void applyQuoteSideMinMaxRange() { model.setAmountLimitInfoLink(Res.get("bisqEasy.tradeWizard.amount.seller.limitInfo.link")); Monetary reputationBasedQuoteSideAmount = model.getReputationBasedMaxAmount(); - maxOrFixAmountSelectionController.setQuoteSideAmount(reputationBasedQuoteSideAmount); + amountSelectionController.setMaxOrFixedQuoteSideAmount(reputationBasedQuoteSideAmount); long myReputationScore = model.getMyReputationScore(); model.getAmountLimitInfo().set(Res.get("bisqEasy.tradeWizard.amount.seller.limitInfo", myReputationScore)); String formattedAmount = formatAmountWithCode(reputationBasedQuoteSideAmount); @@ -743,13 +727,13 @@ private void applyQuoteSideMinMaxRange() { private void applyMarkerRange() { Pair, Optional> availableOfferAmountRange = getLowestAndHighestAmountInAvailableOffers(); - maxOrFixAmountSelectionController.setLeftMarkerQuoteSideValue(availableOfferAmountRange.getFirst().orElse(null)); - maxOrFixAmountSelectionController.setRightMarkerQuoteSideValue(availableOfferAmountRange.getSecond().orElse(null)); + amountSelectionController.setLeftMarkerQuoteSideValue(availableOfferAmountRange.getFirst().orElse(null)); + amountSelectionController.setRightMarkerQuoteSideValue(availableOfferAmountRange.getSecond().orElse(null)); } private void applyReputationBasedQuoteSideAmount() { if (model.isCreateOfferMode()) { - maxOrFixAmountSelectionController.setQuoteSideAmount(maxOrFixAmountSelectionController.getRightMarkerQuoteSideValue().round(0)); + amountSelectionController.setMaxOrFixedQuoteSideAmount(amountSelectionController.getRightMarkerQuoteSideValue().round(0)); } } diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java index cfd63d5787..6f6a99f576 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java @@ -43,27 +43,32 @@ @Slf4j public class TradeWizardAmountView extends View { private static final String SELECTED_PRICE_MODEL_STYLE_CLASS = "selected-model"; + private static final String RANGE_AMOUNT_STYLE_CLASS = "range-amount"; + private static final String FIXED_AMOUNT_STYLE_CLASS = "fixed-amount"; + private final AmountSelectionController amountSelectionController; private final Label headlineLabel, amountLimitInfo, amountLimitInfoLeadLine, amountLimitInfoOverlayInfo, linkToWikiText, warningIcon; private final Hyperlink amountLimitInfoAmount, learnMoreHyperLink, linkToWiki; - private final VBox minAmountRoot, content, amountLimitInfoOverlay; + private final VBox amountSelectionRoot, content, amountLimitInfoOverlay; private final Button closeOverlayButton, fixedAmount, rangeAmount; - private final HBox amountLimitInfoHBox, amountModelsBox; - private final HBox amountLimitInfoWithWarnIcon; + private final HBox amountLimitInfoHBox, amountModelsBox, amountLimitInfoWithWarnIcon, amountBox; private Subscription isAmountLimitInfoVisiblePin, amountLimitInfoLeadLinePin, isRangeAmountEnabledPin; public TradeWizardAmountView(TradeWizardAmountModel model, TradeWizardAmountController controller, - AmountSelectionController minAmountSelectionController, - AmountSelectionController maxOrFixAmountSelectionController) { + AmountSelectionController amountSelectionController) { super(new StackPane(), model, controller); + this.amountSelectionController = amountSelectionController; + headlineLabel = new Label(); headlineLabel.getStyleClass().add("bisq-text-headline-2"); - minAmountRoot = minAmountSelectionController.getView().getRoot(); - HBox amountBox = new HBox(minAmountRoot, maxOrFixAmountSelectionController.getView().getRoot()); + amountSelectionRoot = amountSelectionController.getView().getRoot(); + amountSelectionRoot.getStyleClass().add("min-amount"); + amountBox = new HBox(0, amountSelectionRoot); amountBox.setAlignment(Pos.CENTER); + amountBox.getStyleClass().add("amount-box"); amountLimitInfo = new Label(); amountLimitInfo.getStyleClass().add("trade-wizard-amount-limit-info"); @@ -140,8 +145,6 @@ protected void onViewAttached() { warningIcon.visibleProperty().bind(model.getIsWarningIconVisible()); amountLimitInfoAmount.visibleProperty().bind(model.getAmountLimitInfoAmount().isEmpty().not()); amountLimitInfoAmount.managedProperty().bind(model.getAmountLimitInfoAmount().isEmpty().not()); - minAmountRoot.visibleProperty().bind(model.getIsRangeAmountEnabled()); - minAmountRoot.managedProperty().bind(model.getIsRangeAmountEnabled()); amountModelsBox.visibleProperty().bind(model.getShowRangeAmounts()); amountModelsBox.managedProperty().bind(model.getShowRangeAmounts()); @@ -177,6 +180,7 @@ protected void onViewAttached() { } else { fixedAmount.getStyleClass().add(SELECTED_PRICE_MODEL_STYLE_CLASS); } + amountSelectionController.setIsRangeAmountEnabled(isRangeAmountEnabled); }); amountLimitInfoAmount.setOnAction(e -> controller.onSetReputationBasedAmount()); @@ -198,8 +202,6 @@ protected void onViewDetached() { learnMoreHyperLink.visibleProperty().unbind(); learnMoreHyperLink.managedProperty().unbind(); warningIcon.visibleProperty().unbind(); - minAmountRoot.visibleProperty().unbind(); - minAmountRoot.managedProperty().unbind(); amountLimitInfoAmount.visibleProperty().unbind(); amountLimitInfoAmount.managedProperty().unbind(); amountModelsBox.visibleProperty().unbind(); diff --git a/apps/desktop/desktop/src/main/resources/css/bisq_easy.css b/apps/desktop/desktop/src/main/resources/css/bisq_easy.css index 1800756d96..e8308a96c7 100644 --- a/apps/desktop/desktop/src/main/resources/css/bisq_easy.css +++ b/apps/desktop/desktop/src/main/resources/css/bisq_easy.css @@ -716,30 +716,120 @@ * * ******************************************************************************/ -.amount-component .description { +.amount-selection .description { -fx-fill: -fx-mid-text-color; -fx-text-fill: -fx-mid-text-color; -fx-font-size: 1em; -fx-font-family: "IBM Plex Sans Light"; -fx-wrap-text: true; + -fx-padding: 5 0 0 20; } -.small-amount-input { - -fx-padding: -7 55 0 0; +.amount-selection { + -fx-padding: 0 0 20 0; +} + +.range-amount .max-or-fixed-amount .big-amount-input { + -fx-alignment: left; + /*-fx-background-color: red !important;*/ +} + +.range-amount .max-or-fixed-amount .big-amount-input .text-input { + /*-fx-background-color: green !important;*/ + -fx-padding: 0 -35 0 10; +} + +.range-amount .max-or-fixed-amount .big-amount-input .currency-code { + /*-fx-background-color: cyan;*/ + -fx-padding: 5 0 0 -10; +} + +.range-amount .max-or-fixed-amount .big-amount-input .text-input, +.range-amount .max-or-fixed-amount .big-amount-input .currency-code { + -fx-alignment: baseline-left; +} + +.range-amount .min-amount { + -fx-padding: 23 0 0 0; +} + +.range-amount .max-or-fixed-amount { + -fx-padding: 30 0 0 0; +} + +.range-amount .big-amount-input .text-input { + -fx-alignment: baseline-right; +} + +.range-amount .max-or-fixed-amount .small-amount-input { + -fx-padding: 10 25 0 0; +} + +.range-amount .min-amount .small-amount-input { + -fx-padding: 4 0 0 0; +} + +.range-amount .quote-separator { + -fx-padding: 15 0 0 0; +} + +.range-amount .base-separator { + -fx-padding: 5 0 0 0; +} + +.fixed-amount .big-amount-input { + -fx-alignment: baseline-center; + /*-fx-background-color: blue;*/ +} + +.fixed-amount .big-amount-input .text-input { + /*-fx-background-color: green !important;*/ + -fx-min-width: 250; + -fx-padding: 0 +} + +.big-amount-input .currency-code { + -fx-min-width: 30; +} + +.fixed-amount .big-amount-input .text-input { + -fx-alignment: baseline-right; + -fx-padding: 0 0 0 -30; +} + +.fixed-amount .big-amount-input { + -fx-padding: 0 30 0 0; + /*-fx-background-color: pink;*/ +} + +.fixed-amount .small-amount-input { + -fx-padding: 0 70 0 0; + /*-fx-background-color: pink;*/ } .small-amount-input .text-input, -.small-amount-input .currency-code { +.small-amount-input .currency-code, +.amount-separator .base-separator { -fx-fill: -fx-mid-text-color !important; -fx-text-fill: -fx-mid-text-color !important; -fx-font-family: "IBM Plex Sans Light" !important; } -.small-amount-input .text-input { +.small-amount-input .text-input, +.amount-separator .base-separator { -fx-font-size: 1.25em !important; -fx-alignment: baseline-right; } +.amount-separator .quote-separator { + -fx-font-size: 2em; + -fx-font-family: "IBM Plex Sans Thin"; +} + +.amount-separator { + -fx-alignment: center; +} + .small-amount-input .currency-code { -fx-font-size: 0.95em !important; -fx-alignment: baseline-left; diff --git a/apps/desktop/desktop/src/main/resources/css/text.css b/apps/desktop/desktop/src/main/resources/css/text.css index 1a3c3ccf2e..2bf6241a19 100644 --- a/apps/desktop/desktop/src/main/resources/css/text.css +++ b/apps/desktop/desktop/src/main/resources/css/text.css @@ -435,6 +435,15 @@ -fx-font-family: "IBM Plex Sans Thin"; } +#base-amount-text-field-very-small { + -fx-background-color: transparent; + -fx-border-style: none; + -fx-text-fill: -fx-light-text-color; + -fx-highlight-fill: -bisq2-green; + -fx-font-size: 1.5em; + -fx-font-family: "IBM Plex Sans Thin"; +} + #quote-amount-text-field { -fx-background-color: transparent; -fx-border-style: none; From 5e1e7824f3405ba7e82c7fe789e4945164125bd5 Mon Sep 17 00:00:00 2001 From: axpoems <145597137+axpoems@users.noreply.github.com> Date: Mon, 9 Dec 2024 23:17:16 +0100 Subject: [PATCH 14/33] Several improvements --- .../amount_selection/AmountSelectionView.java | 236 +++++++++++++---- .../amount_input/AmountInput.java | 43 +--- .../amount_input/BigAmountInput.java | 20 +- .../src/main/resources/css/bisq_easy.css | 238 ++++++++++++++---- .../desktop/src/main/resources/css/text.css | 2 +- 5 files changed, 387 insertions(+), 152 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java index de70ad5c2f..e7e6a633ce 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java @@ -24,31 +24,47 @@ import bisq.desktop.main.content.bisq_easy.components.amount_selection.amount_input.BigAmountInput; import bisq.desktop.main.content.bisq_easy.components.amount_selection.amount_input.SmallAmountInput; import javafx.beans.property.ReadOnlyBooleanProperty; +import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Parent; import javafx.scene.control.Label; import javafx.scene.control.Slider; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Pane; -import javafx.scene.layout.Region; -import javafx.scene.layout.VBox; +import javafx.scene.layout.*; import lombok.extern.slf4j.Slf4j; import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.Subscription; @Slf4j public class AmountSelectionView extends View { - public final static int AMOUNT_BOX_WIDTH = 330; + public final static int AMOUNT_BOX_WIDTH = 300; public final static int AMOUNT_BOX_HEIGHT = 120; + private final static String INPUT_TEXT_9_STYLE_CLASS = "input-text-9"; + private final static String INPUT_TEXT_10_STYLE_CLASS = "input-text-10"; + private final static String INPUT_TEXT_11_STYLE_CLASS = "input-text-11"; + private final static String INPUT_TEXT_12_STYLE_CLASS = "input-text-12"; + private final static String INPUT_TEXT_13_STYLE_CLASS = "input-text-13"; + private final static String INPUT_TEXT_14_STYLE_CLASS = "input-text-14"; + private final static String INPUT_TEXT_15_STYLE_CLASS = "input-text-15"; + private final static String INPUT_TEXT_16_STYLE_CLASS = "input-text-16"; + private final static String INPUT_TEXT_17_STYLE_CLASS = "input-text-17"; + private final static String INPUT_TEXT_18_STYLE_CLASS = "input-text-18"; + private final static String INPUT_TEXT_19_STYLE_CLASS = "input-text-19"; + @SuppressWarnings("UnnecessaryUnicodeEscape") + public static final String EN_DASH_SYMBOL = "\u2013"; // Unicode for "–" private final Slider slider = new Slider(); - private final Label minRangeValue, maxRangeValue, description; - private final Region line, selectionLine; + private final Label minRangeValue, maxRangeValue, description, quoteAmountSeparator, + baseAmountSeparator; + private final Region selectionLine; private final SmallAmountInput maxOrFixedBaseAmount, minBaseAmount; private final BigAmountInput maxOrFixedQuoteAmount, minQuoteAmount; - private final VBox minAmountVBox, amountSeparatorVBox, sliderBox; + private final Pane minQuoteAmountRoot; + private final Pane minBaseAmountRoot; + private final VBox sliderBox; + private final HBox quoteAmountSelectionHBox; private Subscription maxOrFixedBaseAmountFocusPin, maxOrFixedQuoteAmountFocusPin, - minBaseAmountFocusPin, minQuoteAmountFocusPin, sliderTrackStylePin, isRangeAmountEnabledPin; + minBaseAmountFocusPin, minQuoteAmountFocusPin, sliderTrackStylePin, isRangeAmountEnabledPin, + maxOrFixedQuoteAmountLengthPin, minQuoteAmountLengthPin; AmountSelectionView(AmountSelectionModel model, AmountSelectionController controller, @@ -64,43 +80,54 @@ public class AmountSelectionView extends View onInputTextFieldFocus(minQuoteAmount.focusedProperty(), focus)); minQuoteAmountFocusPin = EasyBind.subscribe(minQuoteAmount.focusedProperty(), focus -> onInputTextFieldFocus(minBaseAmount.focusedProperty(), focus)); + maxOrFixedQuoteAmountLengthPin = EasyBind.subscribe(maxOrFixedQuoteAmount.lengthProperty(), length -> { + applyFontStyle(); + applyPrefWidth(); + }); + minQuoteAmountLengthPin = EasyBind.subscribe(minQuoteAmount.lengthProperty(), length -> { + applyFontStyle(); + applyPrefWidth(); + }); }).after(700); isRangeAmountEnabledPin = EasyBind.subscribe(model.getIsRangeAmountEnabled(), isRangeAmountEnabled -> { root.getStyleClass().clear(); root.getStyleClass().add("amount-selection"); root.getStyleClass().add(isRangeAmountEnabled ? "range-amount" : "fixed-amount"); - maxOrFixedQuoteAmount.setUseVerySmallText(isRangeAmountEnabled); - minQuoteAmount.setUseVerySmallText(isRangeAmountEnabled); + applyFontStyle(); + applyPrefWidth(); }); sliderTrackStylePin = EasyBind.subscribe(model.getSliderTrackStyle(), slider::setStyle); + slider.valueProperty().bindBidirectional(model.getMaxOrFixedSliderValue()); model.getSliderFocus().bind(slider.focusedProperty()); description.textProperty().bind(model.getDescription()); minRangeValue.textProperty().bind(model.getMinRangeValueAsString()); maxRangeValue.textProperty().bind(model.getMaxRangeValueAsString()); - minAmountVBox.visibleProperty().bind(model.getIsRangeAmountEnabled()); - minAmountVBox.managedProperty().bind(model.getIsRangeAmountEnabled()); - amountSeparatorVBox.visibleProperty().bind(model.getIsRangeAmountEnabled()); - amountSeparatorVBox.managedProperty().bind(model.getIsRangeAmountEnabled()); + quoteAmountSeparator.visibleProperty().bind(model.getIsRangeAmountEnabled()); + quoteAmountSeparator.managedProperty().bind(model.getIsRangeAmountEnabled()); + baseAmountSeparator.visibleProperty().bind(model.getIsRangeAmountEnabled()); + baseAmountSeparator.managedProperty().bind(model.getIsRangeAmountEnabled()); + minQuoteAmountRoot.visibleProperty().bind(model.getIsRangeAmountEnabled()); + minQuoteAmountRoot.managedProperty().bind(model.getIsRangeAmountEnabled()); + minBaseAmountRoot.visibleProperty().bind(model.getIsRangeAmountEnabled()); + minBaseAmountRoot.managedProperty().bind(model.getIsRangeAmountEnabled()); // Needed to trigger focusOut event on amount components // We handle all parents mouse events. @@ -187,6 +228,12 @@ protected void onViewDetached() { if (minQuoteAmountFocusPin != null) { minQuoteAmountFocusPin.unsubscribe(); } + if (maxOrFixedQuoteAmountLengthPin != null) { + maxOrFixedQuoteAmountLengthPin.unsubscribe(); + } + if (minQuoteAmountLengthPin != null) { + minQuoteAmountLengthPin.unsubscribe(); + } isRangeAmountEnabledPin.unsubscribe(); sliderTrackStylePin.unsubscribe(); slider.valueProperty().unbindBidirectional(model.getMaxOrFixedSliderValue()); @@ -194,10 +241,14 @@ protected void onViewDetached() { description.textProperty().unbind(); minRangeValue.textProperty().unbind(); maxRangeValue.textProperty().unbind(); - minAmountVBox.visibleProperty().unbind(); - minAmountVBox.managedProperty().unbind(); - amountSeparatorVBox.visibleProperty().unbind(); - amountSeparatorVBox.managedProperty().unbind(); + quoteAmountSeparator.visibleProperty().unbind(); + quoteAmountSeparator.managedProperty().unbind(); + baseAmountSeparator.visibleProperty().unbind(); + baseAmountSeparator.managedProperty().unbind(); + minQuoteAmountRoot.visibleProperty().unbind(); + minQuoteAmountRoot.managedProperty().unbind(); + minBaseAmountRoot.visibleProperty().unbind(); + minBaseAmountRoot.managedProperty().unbind(); maxOrFixedBaseAmount.isAmountValidProperty().set(true); maxOrFixedQuoteAmount.isAmountValidProperty().set(true); @@ -215,11 +266,98 @@ private void onInputTextFieldFocus(ReadOnlyBooleanProperty other, boolean focus) if (focus) { selectionLine.setPrefWidth(0); selectionLine.setOpacity(1); - Transitions.animateWidth(selectionLine, AMOUNT_BOX_WIDTH); + Transitions.animateWidth(selectionLine, AMOUNT_BOX_WIDTH + 40); } else if (!other.get()) { // If switching between the 2 fields we want to avoid to get the fadeout called that's why // we do the check with !other.get() Transitions.fadeOut(selectionLine, 200); } } + + private void applyPrefWidth() { + int charCount = model.getIsRangeAmountEnabled().get() + ? minQuoteAmount.getTextInputLength() + maxOrFixedQuoteAmount.getTextInputLength() + 1 // for the dash + : maxOrFixedQuoteAmount.getTextInputLength(); + + int length = minQuoteAmount.getTextInputLength(); + minQuoteAmount.setTextInputPrefWidth(length == 0 ? 1 : length * getFontCharWidth(charCount)); + + length = maxOrFixedQuoteAmount.getTextInputLength(); + maxOrFixedQuoteAmount.setTextInputPrefWidth(length == 0 ? 1 : length * getFontCharWidth(charCount)); + } + + private void applyFontStyle() { + quoteAmountSelectionHBox.getStyleClass().clear(); + quoteAmountSelectionHBox.getStyleClass().add("quote-amount"); + + int charCount = model.getIsRangeAmountEnabled().get() + ? minQuoteAmount.getTextInputLength() + maxOrFixedQuoteAmount.getTextInputLength() + 1 // for the dash + : maxOrFixedQuoteAmount.getTextInputLength(); + quoteAmountSelectionHBox.getStyleClass().add(getFontStyle(charCount)); + } + + private int getFontCharWidth(int charCount) { + if (charCount < 10) { + return 31; + } + if (charCount == 10) { + return 28; + } + if (charCount == 11) { + return 25; + } + if (charCount == 12) { + return 23; + } + if (charCount == 13) { + return 21; + } + if (charCount == 14) { + return 19; + } + if (charCount == 15) { + return 18; + } + if (charCount == 16) { + return 17; + } + if (charCount == 17) { + return 16; + } + return 15; + } + + private String getFontStyle(int charCount) { + if (charCount < 10) { + return INPUT_TEXT_9_STYLE_CLASS; + } + if (charCount == 10) { + return INPUT_TEXT_10_STYLE_CLASS; + } + if (charCount == 11) { + return INPUT_TEXT_11_STYLE_CLASS; + } + if (charCount == 12) { + return INPUT_TEXT_12_STYLE_CLASS; + } + if (charCount == 13) { + return INPUT_TEXT_13_STYLE_CLASS; + } + if (charCount == 14) { + return INPUT_TEXT_14_STYLE_CLASS; + } + if (charCount == 15) { + return INPUT_TEXT_15_STYLE_CLASS; + } + if (charCount == 16) { + return INPUT_TEXT_16_STYLE_CLASS; + } + if (charCount == 17) { + return INPUT_TEXT_17_STYLE_CLASS; + } + if (charCount == 18) { + return INPUT_TEXT_18_STYLE_CLASS; + } + return INPUT_TEXT_19_STYLE_CLASS; + } } diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/AmountInput.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/AmountInput.java index 0847ceec0f..b923c5a268 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/AmountInput.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/AmountInput.java @@ -24,14 +24,7 @@ import bisq.desktop.components.controls.validator.NumberValidator; import bisq.presentation.formatters.AmountFormatter; import bisq.presentation.parser.AmountParser; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.ReadOnlyBooleanProperty; -import javafx.beans.property.ReadOnlyObjectProperty; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.property.StringProperty; +import javafx.beans.property.*; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.scene.control.Label; @@ -41,8 +34,6 @@ import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; -import org.fxmisc.easybind.EasyBind; -import org.fxmisc.easybind.Subscription; @Slf4j public abstract class AmountInput { @@ -76,6 +67,18 @@ public ReadOnlyBooleanProperty focusedProperty() { return controller.view.textInput.focusedProperty(); } + public ReadOnlyIntegerProperty lengthProperty() { + return controller.view.textInput.lengthProperty(); + } + + public int getTextInputLength() { + return controller.view.textInput.getLength(); + } + + public void setTextInputPrefWidth(int prefWidth) { + controller.view.textInput.setPrefWidth(prefWidth); + } + public void reset() { controller.model.reset(); } @@ -86,10 +89,6 @@ public void requestFocus() { textInput.selectRange(textInput.getLength(), textInput.getLength()); } - public void setUseVerySmallText(boolean useVerySmallText) { - controller.setUseVerySmallText(useVerySmallText); - } - protected static class Controller implements bisq.desktop.common.view.Controller { @Setter protected Model model; @@ -153,10 +152,6 @@ private void setAmountValid() { model.isAmountValid.set(true); } - private void setUseVerySmallText(boolean useVerySmallText) { - model.useVerySmallText.set(useVerySmallText); - } - private void updateAmountIfNotFocused(String value) { if (!model.hasFocus) { model.amount.set(AmountParser.parse(value, model.code.get())); @@ -179,7 +174,6 @@ protected static class Model implements bisq.desktop.common.view.Model { protected final boolean showCurrencyCode; protected final ObjectProperty amount = new SimpleObjectProperty<>(); protected final StringProperty code = new SimpleStringProperty(); - protected final BooleanProperty useVerySmallText = new SimpleBooleanProperty(); protected Market selectedMarket; protected boolean hasFocus; @Setter @@ -194,7 +188,6 @@ protected Model(boolean isBaseCurrency, boolean showCurrencyCode) { void reset() { amount.set(null); code.set(null); - useVerySmallText.set(false); selectedMarket = null; hasFocus = false; isAmountValid.set(false); @@ -206,7 +199,6 @@ protected static class View extends bisq.desktop.common.view.View amountListener; protected final TextField textInput; protected final Label codeLabel; - private Subscription useVerySmallTextPin; protected View(Model model, Controller controller) { super(new HBox(), model, controller); @@ -248,11 +240,6 @@ private void onAmountChanged(ObservableValue observable, protected void applyAmount(Monetary newValue) { textInput.setText(newValue == null ? "" : AmountFormatter.formatAmount(newValue, model.useLowPrecision)); textInput.selectRange(textInput.getLength(), textInput.getLength()); - adjustTextFieldStyle(); - } - - - protected void adjustTextFieldStyle() { } @Override @@ -265,8 +252,6 @@ protected void onViewAttached() { applyAmount(model.amount.get()); textInput.requestFocus(); textInput.selectRange(textInput.getLength(), textInput.getLength()); - - useVerySmallTextPin = EasyBind.subscribe(model.useVerySmallText, useVerySmallText -> adjustTextFieldStyle()); } @Override @@ -275,8 +260,6 @@ protected void onViewDetached() { textInput.focusedProperty().removeListener(focusListener); model.amount.removeListener(amountListener); - - useVerySmallTextPin.unsubscribe(); } } } diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/BigAmountInput.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/BigAmountInput.java index 9f50e2c90f..0b12c3c226 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/BigAmountInput.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/BigAmountInput.java @@ -19,15 +19,12 @@ import javafx.scene.control.Label; import javafx.scene.control.TextField; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; import lombok.extern.slf4j.Slf4j; @Slf4j public class BigAmountInput extends AmountInput { - private static final String BIG_TEXT_INPUT_ID = "base-amount-text-field"; - private static final String SMALL_TEXT_INPUT_ID = "base-amount-text-field-small"; - private static final String VERY_SMALL_TEXT_INPUT_ID = "base-amount-text-field-very-small"; - private static final int TEXT_LENGTH_THRESHOLD = 9; - public BigAmountInput(boolean isBaseCurrency, boolean showCurrencyCode) { super(isBaseCurrency, showCurrencyCode); @@ -43,12 +40,12 @@ protected BigAmountInputView(Model model, Controller controller) { public void initView() { root.setSpacing(10); root.getStyleClass().add("big-amount-input"); +// HBox.setHgrow(textInput, Priority.ALWAYS); } @Override protected TextField createTextInput() { var textInput = new TextField(); - textInput.setId(BIG_TEXT_INPUT_ID); textInput.getStyleClass().add("text-input"); return textInput; } @@ -59,16 +56,5 @@ protected Label createCodeLabel() { codeLabel.getStyleClass().add("currency-code"); return codeLabel; } - - @Override - protected void adjustTextFieldStyle() { - if (model.useVerySmallText.get()) { - textInput.setId(VERY_SMALL_TEXT_INPUT_ID); - } else { - textInput.setId(textInput.getText().length() > TEXT_LENGTH_THRESHOLD - ? SMALL_TEXT_INPUT_ID - : BIG_TEXT_INPUT_ID); - } - } } } diff --git a/apps/desktop/desktop/src/main/resources/css/bisq_easy.css b/apps/desktop/desktop/src/main/resources/css/bisq_easy.css index e8308a96c7..1d74789ccd 100644 --- a/apps/desktop/desktop/src/main/resources/css/bisq_easy.css +++ b/apps/desktop/desktop/src/main/resources/css/bisq_easy.css @@ -722,112 +722,240 @@ -fx-font-size: 1em; -fx-font-family: "IBM Plex Sans Light"; -fx-wrap-text: true; - -fx-padding: 5 0 0 20; } -.amount-selection { - -fx-padding: 0 0 20 0; +.description-and-amount-box { + -fx-padding: 8 20 8 20; } -.range-amount .max-or-fixed-amount .big-amount-input { - -fx-alignment: left; +.range-amount .quote-separator { + -fx-alignment: center; + -fx-text-alignment: center; /*-fx-background-color: red !important;*/ + -fx-pref-height: 40; + -fx-max-height: 40; + -fx-min-height: 40; } -.range-amount .max-or-fixed-amount .big-amount-input .text-input { - /*-fx-background-color: green !important;*/ - -fx-padding: 0 -35 0 10; +.range-amount .base-separator { + -fx-alignment: center; } -.range-amount .max-or-fixed-amount .big-amount-input .currency-code { - /*-fx-background-color: cyan;*/ - -fx-padding: 5 0 0 -10; +.range-amount .base-separator { + -fx-min-width: 10; } -.range-amount .max-or-fixed-amount .big-amount-input .text-input, -.range-amount .max-or-fixed-amount .big-amount-input .currency-code { +.range-amount .base-amount .max-or-fixed-base-amount { + -fx-min-width: 165; + -fx-max-width: 165; +} + +.range-amount .base-amount .max-or-fixed-base-amount, +.range-amount .base-amount .min-base-amount { -fx-alignment: baseline-left; } -.range-amount .min-amount { - -fx-padding: 23 0 0 0; +.fixed-amount .quote-amount .big-amount-input .text-input, +.range-amount .quote-amount .min-quote-amount .text-input { + -fx-alignment: bottom-right; } -.range-amount .max-or-fixed-amount { - -fx-padding: 30 0 0 0; +.range-amount .quote-amount .max-or-fixed-quote-amount .text-input { + -fx-alignment: bottom-left; } -.range-amount .big-amount-input .text-input { - -fx-alignment: baseline-right; +.quote-amount .big-amount-input .text-input { + -fx-padding: 0; + -fx-min-height: 70; } -.range-amount .max-or-fixed-amount .small-amount-input { - -fx-padding: 10 25 0 0; +.quote-amount .big-amount-input .currency-code { + -fx-min-width: 30; + -fx-max-width: 30; + -fx-min-height: 70; + -fx-padding: 0 0 10 0; + -fx-alignment: bottom-left; } -.range-amount .min-amount .small-amount-input { - -fx-padding: 4 0 0 0; +.quote-amount { + -fx-alignment: center-right; } -.range-amount .quote-separator { - -fx-padding: 15 0 0 0; +.fixed-amount .small-amount-input { + -fx-padding: 0 60 0 0; } -.range-amount .base-separator { - -fx-padding: 5 0 0 0; +.range-amount .base-amount .max-or-fixed-base-amount .text-input { + -fx-padding: 0 5 0 0; + -fx-min-width: 105; + -fx-max-width: 105; } -.fixed-amount .big-amount-input { - -fx-alignment: baseline-center; - /*-fx-background-color: blue;*/ +.quote-amount .text-input, +.quote-separator { + -fx-background-color: transparent; + -fx-border-style: none; + -fx-text-fill: -fx-light-text-color; + -fx-highlight-fill: -bisq2-green; + -fx-font-family: "IBM Plex Sans Thin"; } -.fixed-amount .big-amount-input .text-input { - /*-fx-background-color: green !important;*/ - -fx-min-width: 250; - -fx-padding: 0 +/******** ALL SIZES ********/ +.input-text-9 .text-input, +.input-text-9 .quote-separator { + -fx-font-size: 4em !important; } -.big-amount-input .currency-code { - -fx-min-width: 30; +.input-text-10 .text-input, +.input-text-10 .quote-separator { + -fx-font-size: 3.58em !important; } -.fixed-amount .big-amount-input .text-input { - -fx-alignment: baseline-right; - -fx-padding: 0 0 0 -30; +.input-text-11 .text-input, +.input-text-11 .quote-separator { + -fx-font-size: 3.20em !important; } -.fixed-amount .big-amount-input { - -fx-padding: 0 30 0 0; - /*-fx-background-color: pink;*/ +.input-text-12 .text-input, +.input-text-12 .quote-separator { + -fx-font-size: 2.90em !important; } -.fixed-amount .small-amount-input { - -fx-padding: 0 70 0 0; - /*-fx-background-color: pink;*/ +.input-text-13 .text-input, +.input-text-13 .quote-separator { + -fx-font-size: 2.65em !important; +} + +.input-text-14 .text-input, +.input-text-14 .quote-separator { + -fx-font-size: 2.45em !important; +} + +.input-text-15 .text-input, +.input-text-15 .quote-separator { + -fx-font-size: 2.30em !important; +} + +.input-text-16 .text-input, +.input-text-16 .quote-separator { + -fx-font-size: 2.15em !important; +} + +.input-text-17 .text-input, +.input-text-17 .quote-separator { + -fx-font-size: 2em !important; +} + +.input-text-18 .text-input, +.input-text-18 .quote-separator { + -fx-font-size: 1.90em !important; +} + +.input-text-19 .text-input, +.input-text-19 .quote-separator { + -fx-font-size: 1.80em !important; +} +/***************************/ + +/******** PADDINGS *********/ +.input-text-9 .text-input { + -fx-padding: 0 0 -1 0 !important; +} + +.input-text-10 .text-input { + -fx-padding: 0 0 1 0 !important; } +.input-text-11 .text-input { + -fx-padding: 0 0 2 0 !important; +} + +.input-text-12 .text-input { + -fx-padding: 0 0 3 0 !important; +} + +.input-text-13 .text-input { + -fx-padding: 0 0 4 0 !important; +} + +.input-text-14 .text-input { + -fx-padding: 0 0 5 0 !important; +} + +.input-text-15 .text-input, +.input-text-16 .text-input, +.input-text-17 .text-input { + -fx-padding: 0 0 6 0 !important; +} + +.input-text-18 .text-input { + -fx-padding: 0 0 7 0 !important; +} + +.input-text-19 .text-input { + -fx-padding: 0 0 8 0 !important; +} + +.input-text-9 .quote-separator { + -fx-padding: -16 0 0 0 !important; +} + +.input-text-10 .quote-separator { + -fx-padding: -9 0 0 0 !important; +} + +.input-text-11 .quote-separator { + -fx-padding: -5 0 0 0 !important; +} + +.input-text-12 .quote-separator { + -fx-padding: 0 0 0 0 !important; +} + +.input-text-13 .quote-separator { + -fx-padding: 2 0 -2 0 !important; +} + +.input-text-14 .quote-separator { + -fx-padding: 6 0 -6 0 !important; +} + +.input-text-15 .quote-separator { + -fx-padding: 7 0 -7 0 !important; +} + +.input-text-16 .quote-separator { + -fx-padding: 9 0 -9 0 !important; +} + +.input-text-17 .quote-separator { + -fx-padding: 10 0 -10 0 !important; +} + +.input-text-18 .quote-separator { + -fx-padding: 11 0 -11 0 !important; +} + +.input-text-19 .quote-separator { + -fx-padding: 12 0 -12 0 !important; +} +/***************************/ + .small-amount-input .text-input, .small-amount-input .currency-code, -.amount-separator .base-separator { +.base-separator { -fx-fill: -fx-mid-text-color !important; -fx-text-fill: -fx-mid-text-color !important; -fx-font-family: "IBM Plex Sans Light" !important; } .small-amount-input .text-input, -.amount-separator .base-separator { +.base-separator { -fx-font-size: 1.25em !important; - -fx-alignment: baseline-right; } -.amount-separator .quote-separator { - -fx-font-size: 2em; - -fx-font-family: "IBM Plex Sans Thin"; -} - -.amount-separator { - -fx-alignment: center; +.small-amount-input .text-input { + -fx-alignment: baseline-right; } .small-amount-input .currency-code { diff --git a/apps/desktop/desktop/src/main/resources/css/text.css b/apps/desktop/desktop/src/main/resources/css/text.css index 2bf6241a19..92e7ca8ba0 100644 --- a/apps/desktop/desktop/src/main/resources/css/text.css +++ b/apps/desktop/desktop/src/main/resources/css/text.css @@ -440,7 +440,7 @@ -fx-border-style: none; -fx-text-fill: -fx-light-text-color; -fx-highlight-fill: -bisq2-green; - -fx-font-size: 1.5em; + -fx-font-size: 2em; -fx-font-family: "IBM Plex Sans Thin"; } From 25164eb52a629934b44095427b9c984da86fc8d6 Mon Sep 17 00:00:00 2001 From: axpoems <145597137+axpoems@users.noreply.github.com> Date: Wed, 11 Dec 2024 16:09:07 +0100 Subject: [PATCH 15/33] Add double slider to select amount range --- .../AmountSelectionController.java | 98 ++++++++++--------- .../AmountSelectionModel.java | 14 +-- .../amount_selection/AmountSelectionView.java | 35 +++++-- .../amount_input/AmountInput.java | 10 +- .../src/main/resources/css/bisq_easy.css | 20 ++++ .../src/main/resources/css/controls.css | 2 +- 6 files changed, 115 insertions(+), 64 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionController.java index e027d77117..755fc853eb 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionController.java @@ -57,7 +57,7 @@ public class AmountSelectionController implements Controller { minBaseSideAmountFromModelListener, minQuoteSideAmountFromModelListener; private final ChangeListener quoteListener; private final PriceInput price; - private final ChangeListener maxOrFixedSliderListener; //, minSliderListener; + private final ChangeListener maxOrFixedSliderListener, minSliderListener; private Subscription maxOrFixedBaseAmountFromModelPin, maxOrFixedBaseAmountFromCompPin, maxOrFixedQuoteAmountFromCompPin, maxOrFixedBaseSideAmountValidPin, maxOrFixedQuoteSideAmountValidPin, minBaseAmountFromModelPin, minBaseAmountFromCompPin, minQuoteAmountFromCompPin, minBaseSideAmountValidPin, @@ -101,23 +101,10 @@ public AmountSelectionController(ServiceProvider serviceProvider, applyInitialRangeValues(); UIThread.runOnNextRenderFrame(this::applyQuote); }; - maxOrFixedSliderListener = (observable, oldValue, newValue) -> { - if (model.getMinRangeQuoteSideValue().get() != null && model.getMinRangeBaseSideValue().get() != null) { - double sliderValue = newValue.doubleValue(); - long min = model.isUseQuoteCurrencyForMinMaxRange() ? - model.getMinRangeQuoteSideValue().get().getValue() : - model.getMinRangeBaseSideValue().get().getValue(); - long max = model.isUseQuoteCurrencyForMinMaxRange() ? - model.getMaxRangeQuoteSideValue().get().getValue() : - model.getMaxRangeBaseSideValue().get().getValue(); - long value = Math.round(sliderValue * (max - min)) + min; - if (model.isUseQuoteCurrencyForMinMaxRange()) { - maxOrFixedQuoteSideAmountInput.setAmount(Monetary.from(value, model.getMarket().getQuoteCurrencyCode())); - } else { - maxOrFixedBaseSideAmountInput.setAmount(Monetary.from(value, model.getMarket().getBaseCurrencyCode())); - } - } - }; + maxOrFixedSliderListener = (observable, oldValue, newValue) -> + applySliderValue(newValue.doubleValue(), maxOrFixedQuoteSideAmountInput, maxOrFixedBaseSideAmountInput); + minSliderListener = (observable, oldValue, newValue) -> + applySliderValue(newValue.doubleValue(), minQuoteSideAmountInput, minBaseSideAmountInput); } public void setMaxOrFixedBaseSideAmount(Monetary value) { @@ -272,11 +259,11 @@ public void onActivate() { maxOrFixedBaseAmountFromModelPin = EasyBind.subscribe(model.getMaxOrFixedBaseSideAmount(), amount -> { // Only apply value from component to slider if we have no focus on slider (not used) if (amount != null) { - if (!model.getSliderFocus().get()) { + if (!model.getMaxOrFixedAmountSliderFocus().get()) { long min = model.getMinRangeBaseSideValue().get().getValue(); long max = model.getMaxRangeBaseSideValue().get().getValue(); double sliderValue = (amount.getValue() - min) / ((double) max - min); - model.getMaxOrFixedSliderValue().set(sliderValue); + model.getMaxOrFixedAmountSliderValue().set(sliderValue); } } }); @@ -284,11 +271,11 @@ public void onActivate() { minBaseAmountFromModelPin = EasyBind.subscribe(model.getMinBaseSideAmount(), amount -> { // Only apply value from component to slider if we have no focus on slider (not used) if (amount != null) { - if (!model.getSliderFocus().get()) { + if (!model.getMinAmountSliderFocus().get()) { long min = model.getMinRangeBaseSideValue().get().getValue(); long max = model.getMaxRangeBaseSideValue().get().getValue(); double sliderValue = (amount.getValue() - min) / ((double) max - min); - model.getMinSliderValue().set(sliderValue); + model.getMinAmountSliderValue().set(sliderValue); } } }); @@ -373,7 +360,34 @@ public void onActivate() { minBaseSideAmountValidPin = subscribeToAmountValidity(minBaseSideAmountInput, this::setMinBaseFromQuote); maxOrFixedQuoteSideAmountValidPin = subscribeToAmountValidity(maxOrFixedQuoteSideAmountInput, this::setMaxOrFixedQuoteFromBase); minQuoteSideAmountValidPin = subscribeToAmountValidity(minQuoteSideAmountInput, this::setMinQuoteFromBase); - model.getMaxOrFixedSliderValue().addListener(maxOrFixedSliderListener); + model.getMaxOrFixedAmountSliderValue().addListener(maxOrFixedSliderListener); + model.getMinAmountSliderValue().addListener(minSliderListener); + } + + @Override + public void onDeactivate() { + model.getMaxOrFixedBaseSideAmount().removeListener(maxOrFixedBaseSideAmountFromModelListener); + model.getMaxOrFixedQuoteSideAmount().removeListener(maxOrFixedQuoteSideAmountFromModelListener); + model.getMinBaseSideAmount().removeListener(minBaseSideAmountFromModelListener); + model.getMinQuoteSideAmount().removeListener(minQuoteSideAmountFromModelListener); + price.getQuote().removeListener(quoteListener); + model.getMaxOrFixedAmountSliderValue().removeListener(maxOrFixedSliderListener); + model.getMinAmountSliderValue().removeListener(minSliderListener); + maxOrFixedBaseAmountFromModelPin.unsubscribe(); + minBaseAmountFromModelPin.unsubscribe(); + maxOrFixedBaseAmountFromCompPin.unsubscribe(); + minBaseAmountFromCompPin.unsubscribe(); + maxOrFixedQuoteAmountFromCompPin.unsubscribe(); + minQuoteAmountFromCompPin.unsubscribe(); + priceFromCompPin.unsubscribe(); + minRangeCustomValuePin.unsubscribe(); + maxRangeCustomValuePin.unsubscribe(); + maxOrFixedBaseSideAmountValidPin.unsubscribe(); + minBaseSideAmountValidPin.unsubscribe(); + maxOrFixedQuoteSideAmountValidPin.unsubscribe(); + minQuoteSideAmountValidPin.unsubscribe(); + model.setLeftMarkerQuoteSideValue(null); + model.setRightMarkerQuoteSideValue(null); } private void initializeQuoteSideAmount(BigAmountInput quoteSideAmountInput) { @@ -478,29 +492,21 @@ private void applySliderTrackStyle() { model.getSliderTrackStyle().set(style); } - @Override - public void onDeactivate() { - model.getMaxOrFixedBaseSideAmount().removeListener(maxOrFixedBaseSideAmountFromModelListener); - model.getMaxOrFixedQuoteSideAmount().removeListener(maxOrFixedQuoteSideAmountFromModelListener); - model.getMinBaseSideAmount().removeListener(minBaseSideAmountFromModelListener); - model.getMinQuoteSideAmount().removeListener(minQuoteSideAmountFromModelListener); - price.getQuote().removeListener(quoteListener); - model.getMaxOrFixedSliderValue().removeListener(maxOrFixedSliderListener); - maxOrFixedBaseAmountFromModelPin.unsubscribe(); - minBaseAmountFromModelPin.unsubscribe(); - maxOrFixedBaseAmountFromCompPin.unsubscribe(); - minBaseAmountFromCompPin.unsubscribe(); - maxOrFixedQuoteAmountFromCompPin.unsubscribe(); - minQuoteAmountFromCompPin.unsubscribe(); - priceFromCompPin.unsubscribe(); - minRangeCustomValuePin.unsubscribe(); - maxRangeCustomValuePin.unsubscribe(); - maxOrFixedBaseSideAmountValidPin.unsubscribe(); - minBaseSideAmountValidPin.unsubscribe(); - maxOrFixedQuoteSideAmountValidPin.unsubscribe(); - minQuoteSideAmountValidPin.unsubscribe(); - model.setLeftMarkerQuoteSideValue(null); - model.setRightMarkerQuoteSideValue(null); + private void applySliderValue(double sliderValue, BigAmountInput bigAmountInput, SmallAmountInput smallAmountInput) { + if (model.getMinRangeQuoteSideValue().get() != null && model.getMinRangeBaseSideValue().get() != null) { + long min = model.isUseQuoteCurrencyForMinMaxRange() ? + model.getMinRangeQuoteSideValue().get().getValue() : + model.getMinRangeBaseSideValue().get().getValue(); + long max = model.isUseQuoteCurrencyForMinMaxRange() ? + model.getMaxRangeQuoteSideValue().get().getValue() : + model.getMaxRangeBaseSideValue().get().getValue(); + long value = Math.round(sliderValue * (max - min)) + min; + if (model.isUseQuoteCurrencyForMinMaxRange()) { + bigAmountInput.setAmount(Monetary.from(value, model.getMarket().getQuoteCurrencyCode())); + } else { + smallAmountInput.setAmount(Monetary.from(value, model.getMarket().getBaseCurrencyCode())); + } + } } private void setMaxOrFixedQuoteFromBase() { diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionModel.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionModel.java index 6faaf6afd8..a539ef9fa5 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionModel.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionModel.java @@ -46,9 +46,10 @@ public class AmountSelectionModel implements Model { private final ObjectProperty minQuoteSideAmount = new SimpleObjectProperty<>(); private final StringProperty spendOrReceiveString = new SimpleStringProperty(); - private final DoubleProperty maxOrFixedSliderValue = new SimpleDoubleProperty(); - private final DoubleProperty minSliderValue = new SimpleDoubleProperty(); - private final BooleanProperty sliderFocus = new SimpleBooleanProperty(); + private final DoubleProperty maxOrFixedAmountSliderValue = new SimpleDoubleProperty(); + private final DoubleProperty minAmountSliderValue = new SimpleDoubleProperty(); + private final BooleanProperty maxOrFixedAmountSliderFocus = new SimpleBooleanProperty(); + private final BooleanProperty minAmountSliderFocus = new SimpleBooleanProperty(); private final BooleanProperty isRangeAmountEnabled = new SimpleBooleanProperty(); @Setter @@ -87,9 +88,10 @@ void reset() { minBaseSideAmount.set(null); minQuoteSideAmount.set(null); spendOrReceiveString.set(null); - maxOrFixedSliderValue.set(0L); - minSliderValue.set(0L); - sliderFocus.set(false); + maxOrFixedAmountSliderValue.set(0L); + minAmountSliderValue.set(0L); + maxOrFixedAmountSliderFocus.set(false); + minAmountSliderFocus.set(false); market = MarketRepository.getDefault(); direction = Direction.BUY; leftMarkerQuoteSideValue = null; diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java index e7e6a633ce..6cafef9042 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java @@ -52,7 +52,7 @@ public class AmountSelectionView extends View Date: Wed, 11 Dec 2024 17:04:16 +0100 Subject: [PATCH 16/33] Improve slider labels --- .../AmountSelectionController.java | 16 ++++----- .../AmountSelectionModel.java | 19 ++++++++-- .../amount_selection/AmountSelectionView.java | 35 +++++++++++++++---- .../src/main/resources/css/bisq_easy.css | 19 ++++++++++ i18n/src/main/resources/bisq_easy.properties | 4 +-- 5 files changed, 75 insertions(+), 18 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionController.java index 755fc853eb..c42d9076d6 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionController.java @@ -428,29 +428,29 @@ private void applyInitialRangeValues() { Monetary minRangeMonetaryAsCoin = !isMinRangeMonetaryFiat ? minRangeMonetary : priceQuote.toBaseSideMonetary(minRangeMonetary); model.getMinRangeBaseSideValue().set(minRangeMonetaryAsCoin); if (!model.isUseQuoteCurrencyForMinMaxRange()) { - model.getMinRangeValueAsString().set(Res.get("bisqEasy.component.amount.minRangeValue", - AmountFormatter.formatAmountWithCode(minRangeMonetaryAsCoin))); + model.getMinRangeValueAsString().set(AmountFormatter.formatAmount(minRangeMonetaryAsCoin)); + model.getMinRangeCodeAsString().set(minRangeMonetaryAsCoin.getCode()); } Monetary maxRangeMonetaryAsCoin = !isMaxRangeMonetaryFiat ? maxRangeMonetary : priceQuote.toBaseSideMonetary(maxRangeMonetary); model.getMaxRangeBaseSideValue().set(maxRangeMonetaryAsCoin); if (!model.isUseQuoteCurrencyForMinMaxRange()) { - model.getMaxRangeValueAsString().set(Res.get("bisqEasy.component.amount.maxRangeValue", - AmountFormatter.formatAmountWithCode(maxRangeMonetaryAsCoin))); + model.getMaxRangeValueAsString().set(AmountFormatter.formatAmount(maxRangeMonetaryAsCoin)); + model.getMaxRangeCodeAsString().set(maxRangeMonetaryAsCoin.getCode()); } Monetary minRangeMonetaryAsFiat = isMinRangeMonetaryFiat ? minRangeMonetary : priceQuote.toQuoteSideMonetary(minRangeMonetary).round(0); model.getMinRangeQuoteSideValue().set(minRangeMonetaryAsFiat); if (model.isUseQuoteCurrencyForMinMaxRange()) { - model.getMinRangeValueAsString().set(Res.get("bisqEasy.component.amount.minRangeValue", - AmountFormatter.formatAmountWithCode(minRangeMonetaryAsFiat))); + model.getMinRangeValueAsString().set(AmountFormatter.formatAmount(minRangeMonetaryAsFiat)); + model.getMinRangeCodeAsString().set(minRangeMonetaryAsFiat.getCode()); } Monetary maxRangeMonetaryAsFiat = isMaxRangeMonetaryFiat ? maxRangeMonetary : priceQuote.toQuoteSideMonetary(maxRangeMonetary).round(0); model.getMaxRangeQuoteSideValue().set(maxRangeMonetaryAsFiat); if (model.isUseQuoteCurrencyForMinMaxRange()) { - model.getMaxRangeValueAsString().set(Res.get("bisqEasy.component.amount.maxRangeValue", - AmountFormatter.formatAmountWithCode(maxRangeMonetaryAsFiat))); + model.getMaxRangeValueAsString().set(AmountFormatter.formatAmount(maxRangeMonetaryAsFiat)); + model.getMaxRangeCodeAsString().set(maxRangeMonetaryAsFiat.getCode()); } applySliderTrackStyle(); diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionModel.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionModel.java index a539ef9fa5..ade718d9d6 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionModel.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionModel.java @@ -75,7 +75,9 @@ public class AmountSelectionModel implements Model { private Direction direction = Direction.BUY; private final StringProperty description = new SimpleStringProperty(); private final StringProperty minRangeValueAsString = new SimpleStringProperty(); + private final StringProperty minRangeCodeAsString = new SimpleStringProperty(); private final StringProperty maxRangeValueAsString = new SimpleStringProperty(); + private final StringProperty maxRangeCodeAsString = new SimpleStringProperty(); private final BooleanProperty showRangeAmountSelection = new SimpleBooleanProperty(false); public AmountSelectionModel(boolean useQuoteCurrencyForMinMaxRange) { @@ -92,10 +94,23 @@ void reset() { minAmountSliderValue.set(0L); maxOrFixedAmountSliderFocus.set(false); minAmountSliderFocus.set(false); - market = MarketRepository.getDefault(); - direction = Direction.BUY; + isRangeAmountEnabled.set(false); + minRangeMonetary.set(BisqEasyTradeAmountLimits.DEFAULT_MIN_BTC_TRADE_AMOUNT); + maxRangeMonetary.set(BisqEasyTradeAmountLimits.DEFAULT_MAX_BTC_TRADE_AMOUNT); + minRangeBaseSideValue.set(null); + maxRangeBaseSideValue.set(null); + minRangeQuoteSideValue.set(null); + maxRangeQuoteSideValue.set(null); leftMarkerQuoteSideValue = null; rightMarkerQuoteSideValue = null; + sliderTrackStyle.set(null); + market = MarketRepository.getDefault(); + direction = Direction.BUY; + description.set(null); + minRangeValueAsString.set(null); + minRangeCodeAsString.set(null); + maxRangeValueAsString.set(null); + maxRangeCodeAsString.set(null); showRangeAmountSelection.set(false); } } diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java index 6cafef9042..180a1c8dfc 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java @@ -23,6 +23,7 @@ import bisq.desktop.components.containers.Spacer; import bisq.desktop.main.content.bisq_easy.components.amount_selection.amount_input.BigAmountInput; import bisq.desktop.main.content.bisq_easy.components.amount_selection.amount_input.SmallAmountInput; +import bisq.i18n.Res; import javafx.beans.property.ReadOnlyBooleanProperty; import javafx.geometry.Insets; import javafx.geometry.Pos; @@ -53,7 +54,7 @@ public class AmountSelectionView extends View Date: Wed, 11 Dec 2024 19:52:15 +0100 Subject: [PATCH 17/33] Fix amount limit info --- .../amount/TradeWizardAmountView.java | 18 +++++++++++++----- .../src/main/resources/css/bisq_easy.css | 14 ++++++++++---- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java index 6f6a99f576..842a5beb60 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java @@ -34,6 +34,7 @@ import javafx.scene.control.Hyperlink; import javafx.scene.control.Label; import javafx.scene.layout.HBox; +import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import lombok.extern.slf4j.Slf4j; @@ -43,8 +44,7 @@ @Slf4j public class TradeWizardAmountView extends View { private static final String SELECTED_PRICE_MODEL_STYLE_CLASS = "selected-model"; - private static final String RANGE_AMOUNT_STYLE_CLASS = "range-amount"; - private static final String FIXED_AMOUNT_STYLE_CLASS = "fixed-amount"; + private static final int MAX_WIDTH = 360; private final AmountSelectionController amountSelectionController; private final Label headlineLabel, amountLimitInfo, amountLimitInfoLeadLine, amountLimitInfoOverlayInfo, linkToWikiText, warningIcon; @@ -61,6 +61,7 @@ public TradeWizardAmountView(TradeWizardAmountModel model, this.amountSelectionController = amountSelectionController; + // TODO: remove headline headlineLabel = new Label(); headlineLabel.getStyleClass().add("bisq-text-headline-2"); @@ -71,19 +72,25 @@ public TradeWizardAmountView(TradeWizardAmountModel model, amountBox.getStyleClass().add("amount-box"); amountLimitInfo = new Label(); - amountLimitInfo.getStyleClass().add("trade-wizard-amount-limit-info"); + amountLimitInfo.getStyleClass().addAll("trade-wizard-amount-limit-info", "wrap-text"); + amountLimitInfo.setMinHeight(Label.USE_PREF_SIZE); + amountLimitInfo.setMaxWidth(MAX_WIDTH); amountLimitInfoAmount = new Hyperlink(); amountLimitInfoAmount.getStyleClass().add("trade-wizard-amount-limit-info-overlay-link"); + amountLimitInfoAmount.setMinWidth(Hyperlink.USE_PREF_SIZE); learnMoreHyperLink = new Hyperlink(); learnMoreHyperLink.getStyleClass().add("trade-wizard-amount-limit-info-overlay-link"); + learnMoreHyperLink.setMinWidth(Hyperlink.USE_PREF_SIZE); amountLimitInfoHBox = new HBox(2.5, amountLimitInfo, amountLimitInfoAmount, learnMoreHyperLink); amountLimitInfoHBox.setAlignment(Pos.BASELINE_CENTER); amountLimitInfoLeadLine = new Label(); - amountLimitInfoLeadLine.getStyleClass().add("trade-wizard-amount-limit-info"); + amountLimitInfoLeadLine.getStyleClass().addAll("trade-wizard-amount-limit-info", "wrap-text"); + amountLimitInfoLeadLine.setMinHeight(Label.USE_PREF_SIZE); + amountLimitInfoLeadLine.setMaxWidth(MAX_WIDTH); VBox amountLimitInfoVBox = new VBox(-2.5, amountLimitInfoLeadLine, amountLimitInfoHBox); warningIcon = new Label(); @@ -92,6 +99,7 @@ public TradeWizardAmountView(TradeWizardAmountModel model, amountLimitInfoWithWarnIcon = new HBox(10, warningIcon, amountLimitInfoVBox); amountLimitInfoWithWarnIcon.setAlignment(Pos.CENTER); + warningIcon.setMinWidth(Label.USE_PREF_SIZE); // Amount model selection fixedAmount = new Button(Res.get("bisqEasy.tradeWizard.amount.amountModel.fixedAmount")); @@ -114,7 +122,7 @@ public TradeWizardAmountView(TradeWizardAmountModel model, // VBox.setMargin(amountLimitInfoWithWarnIcon, new Insets(15, 0, 15, 0)); content = new VBox(20); content.setAlignment(Pos.TOP_CENTER); - content.getChildren().addAll(Spacer.fillVBox(), headlineLabel, amountModelsBox, amountBox, amountLimitInfoWithWarnIcon, Spacer.fillVBox()); + content.getChildren().addAll(Spacer.fillVBox(), amountModelsBox, amountBox, amountLimitInfoWithWarnIcon, Spacer.fillVBox()); content.getStyleClass().add("bisq-easy-trade-wizard-amount-step"); amountLimitInfoOverlayInfo = new Label(); diff --git a/apps/desktop/desktop/src/main/resources/css/bisq_easy.css b/apps/desktop/desktop/src/main/resources/css/bisq_easy.css index 4d893b6f53..8c2d9befae 100644 --- a/apps/desktop/desktop/src/main/resources/css/bisq_easy.css +++ b/apps/desktop/desktop/src/main/resources/css/bisq_easy.css @@ -1002,6 +1002,12 @@ -fx-font-size: 0.8em; } +.bisq-easy-trade-wizard-amount-step { + -fx-max-width: 340; + -fx-min-width: 340; + -fx-pref-width: 340; +} + .bisq-easy-trade-wizard-price-step .price-content { -fx-alignment: center; } @@ -1240,9 +1246,9 @@ } .trade-wizard-amount-limit-info { - -fx-fill: -fx-mid-text-color; - -fx-text-fill: -fx-mid-text-color; - -fx-font-size: 1.15em; + -fx-fill: -fx-light-text-color; + -fx-text-fill: -fx-light-text-color; + -fx-font-size: 1em; -fx-font-family: "IBM Plex Sans Light"; } @@ -1254,7 +1260,7 @@ -fx-border-width: 1px; -fx-text-fill: -bisq2-green; -fx-underline: true; - -fx-font-size: 1.15em; + -fx-font-size: 0.9em; -fx-font-family: "IBM Plex Sans Light"; } .trade-wizard-amount-limit-info-overlay-link.hyperlink:hover, From 1d755f1e908bff3adf8a7b110e78295417e847a7 Mon Sep 17 00:00:00 2001 From: axpoems <145597137+axpoems@users.noreply.github.com> Date: Thu, 12 Dec 2024 11:42:00 +0100 Subject: [PATCH 18/33] Separate info and warnings section from main amount component --- .../amount_input/BigAmountInput.java | 3 -- .../amount/TradeWizardAmountView.java | 34 +++++++++---------- .../TradeWizardAmountAndPriceController.java | 3 +- .../TradeWizardAmountAndPriceView.java | 13 +++++-- .../src/main/resources/css/bisq_easy.css | 2 +- 5 files changed, 30 insertions(+), 25 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/BigAmountInput.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/BigAmountInput.java index 0b12c3c226..30707ab8e1 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/BigAmountInput.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/amount_input/BigAmountInput.java @@ -19,8 +19,6 @@ import javafx.scene.control.Label; import javafx.scene.control.TextField; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Priority; import lombok.extern.slf4j.Slf4j; @Slf4j @@ -40,7 +38,6 @@ protected BigAmountInputView(Model model, Controller controller) { public void initView() { root.setSpacing(10); root.getStyleClass().add("big-amount-input"); -// HBox.setHgrow(textInput, Priority.ALWAYS); } @Override diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java index 842a5beb60..41d0e94031 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java @@ -34,9 +34,9 @@ import javafx.scene.control.Hyperlink; import javafx.scene.control.Label; import javafx.scene.layout.HBox; -import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; +import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.Subscription; @@ -44,14 +44,15 @@ @Slf4j public class TradeWizardAmountView extends View { private static final String SELECTED_PRICE_MODEL_STYLE_CLASS = "selected-model"; - private static final int MAX_WIDTH = 360; private final AmountSelectionController amountSelectionController; private final Label headlineLabel, amountLimitInfo, amountLimitInfoLeadLine, amountLimitInfoOverlayInfo, linkToWikiText, warningIcon; private final Hyperlink amountLimitInfoAmount, learnMoreHyperLink, linkToWiki; - private final VBox amountSelectionRoot, content, amountLimitInfoOverlay; + private final VBox content, amountLimitInfoOverlay; private final Button closeOverlayButton, fixedAmount, rangeAmount; - private final HBox amountLimitInfoHBox, amountModelsBox, amountLimitInfoWithWarnIcon, amountBox; + private final HBox amountModelsBox; + @Getter + private final HBox amountLimitInfoWithWarnIcon; private Subscription isAmountLimitInfoVisiblePin, amountLimitInfoLeadLinePin, isRangeAmountEnabledPin; public TradeWizardAmountView(TradeWizardAmountModel model, @@ -61,20 +62,19 @@ public TradeWizardAmountView(TradeWizardAmountModel model, this.amountSelectionController = amountSelectionController; - // TODO: remove headline + // TODO: Only show at take offer headlineLabel = new Label(); headlineLabel.getStyleClass().add("bisq-text-headline-2"); - amountSelectionRoot = amountSelectionController.getView().getRoot(); + VBox amountSelectionRoot = amountSelectionController.getView().getRoot(); amountSelectionRoot.getStyleClass().add("min-amount"); - amountBox = new HBox(0, amountSelectionRoot); - amountBox.setAlignment(Pos.CENTER); + HBox amountBox = new HBox(0, amountSelectionRoot); + amountBox.setAlignment(Pos.BASELINE_LEFT); amountBox.getStyleClass().add("amount-box"); amountLimitInfo = new Label(); - amountLimitInfo.getStyleClass().addAll("trade-wizard-amount-limit-info", "wrap-text"); + amountLimitInfo.getStyleClass().add("trade-wizard-amount-limit-info"); amountLimitInfo.setMinHeight(Label.USE_PREF_SIZE); - amountLimitInfo.setMaxWidth(MAX_WIDTH); amountLimitInfoAmount = new Hyperlink(); amountLimitInfoAmount.getStyleClass().add("trade-wizard-amount-limit-info-overlay-link"); @@ -84,22 +84,22 @@ public TradeWizardAmountView(TradeWizardAmountModel model, learnMoreHyperLink.getStyleClass().add("trade-wizard-amount-limit-info-overlay-link"); learnMoreHyperLink.setMinWidth(Hyperlink.USE_PREF_SIZE); - amountLimitInfoHBox = new HBox(2.5, amountLimitInfo, amountLimitInfoAmount, learnMoreHyperLink); - amountLimitInfoHBox.setAlignment(Pos.BASELINE_CENTER); + HBox amountLimitInfoHBox = new HBox(2.5, amountLimitInfo, amountLimitInfoAmount, learnMoreHyperLink); + amountLimitInfoHBox.setAlignment(Pos.BASELINE_LEFT); amountLimitInfoLeadLine = new Label(); amountLimitInfoLeadLine.getStyleClass().addAll("trade-wizard-amount-limit-info", "wrap-text"); amountLimitInfoLeadLine.setMinHeight(Label.USE_PREF_SIZE); - amountLimitInfoLeadLine.setMaxWidth(MAX_WIDTH); VBox amountLimitInfoVBox = new VBox(-2.5, amountLimitInfoLeadLine, amountLimitInfoHBox); warningIcon = new Label(); Icons.getIconForLabel(AwesomeIcon.WARNING_SIGN, warningIcon, "1.15em"); warningIcon.getStyleClass().add("overlay-icon-warning"); + warningIcon.setMinWidth(Label.USE_PREF_SIZE); + // TODO: Only show at take offer amountLimitInfoWithWarnIcon = new HBox(10, warningIcon, amountLimitInfoVBox); - amountLimitInfoWithWarnIcon.setAlignment(Pos.CENTER); - warningIcon.setMinWidth(Label.USE_PREF_SIZE); + amountLimitInfoWithWarnIcon.setAlignment(Pos.BASELINE_LEFT); // Amount model selection fixedAmount = new Button(Res.get("bisqEasy.tradeWizard.amount.amountModel.fixedAmount")); @@ -120,9 +120,9 @@ public TradeWizardAmountView(TradeWizardAmountModel model, VBox.setMargin(headlineLabel, new Insets(-10, 0, 0, 0)); // VBox.setMargin(amountLimitInfoWithWarnIcon, new Insets(15, 0, 15, 0)); - content = new VBox(20); + content = new VBox(10); content.setAlignment(Pos.TOP_CENTER); - content.getChildren().addAll(Spacer.fillVBox(), amountModelsBox, amountBox, amountLimitInfoWithWarnIcon, Spacer.fillVBox()); + content.getChildren().addAll(/*headlineLabel,*/ amountModelsBox, amountBox/*amountLimitInfoWithWarnIcon,*/); content.getStyleClass().add("bisq-easy-trade-wizard-amount-step"); amountLimitInfoOverlayInfo = new Label(); diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceController.java index 7fcd6b2398..f5595208eb 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceController.java @@ -43,7 +43,8 @@ public TradeWizardAmountAndPriceController(ServiceProvider serviceProvider, Regi tradeWizardAmountController = new TradeWizardAmountController(serviceProvider, owner); model = new TradeWizardAmountAndPriceModel(); - view = new TradeWizardAmountAndPriceView(model, this, tradeWizardAmountController.getView().getRoot()); + view = new TradeWizardAmountAndPriceView(model, this, tradeWizardAmountController.getView().getRoot(), + tradeWizardAmountController.getView().getAmountLimitInfoWithWarnIcon()); } @Override diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java index fba4084c58..2fb3d7491b 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java @@ -18,10 +18,12 @@ package bisq.desktop.main.content.bisq_easy.trade_wizard.amount_and_price; import bisq.desktop.common.view.View; +import javafx.geometry.Pos; import javafx.scene.control.Label; import javafx.scene.layout.HBox; import javafx.scene.layout.Pane; import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; import lombok.extern.slf4j.Slf4j; @Slf4j @@ -30,11 +32,16 @@ public class TradeWizardAmountAndPriceView extends View Date: Thu, 12 Dec 2024 16:03:19 +0100 Subject: [PATCH 19/33] Add price component into amountAndPrice --- .../trade_wizard/TradeWizardController.java | 2 +- .../TradeWizardAmountAndPriceController.java | 19 ++++++++++++++++--- .../TradeWizardAmountAndPriceView.java | 5 +++-- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardController.java index e8673f3cae..d549abad67 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardController.java @@ -165,7 +165,7 @@ public void onActivate() { tradeWizardAmountController.setMarket(market); updateNextButtonDisabledState(); }); - amountSpecPin = EasyBind.subscribe(tradeWizardAmountController.getQuoteSideAmountSpec(), + amountSpecPin = EasyBind.subscribe(tradeWizardAmountAndPriceController.getQuoteSideAmountSpec(), tradeWizardSelectOfferController::setQuoteSideAmountSpec); priceSpecPin = EasyBind.subscribe(tradeWizardPriceController.getPriceSpec(), priceSpec -> { diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceController.java index f5595208eb..cbebb9f7ea 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceController.java @@ -21,6 +21,7 @@ import bisq.desktop.ServiceProvider; import bisq.desktop.common.view.Controller; import bisq.desktop.main.content.bisq_easy.trade_wizard.amount.TradeWizardAmountController; +import bisq.desktop.main.content.bisq_easy.trade_wizard.price.TradeWizardPriceController; import bisq.offer.Direction; import bisq.offer.amount.spec.QuoteSideAmountSpec; import bisq.offer.price.spec.PriceSpec; @@ -37,14 +38,19 @@ public class TradeWizardAmountAndPriceController implements Controller { private final TradeWizardAmountAndPriceView view; private final Region owner; private final TradeWizardAmountController tradeWizardAmountController; + private final TradeWizardPriceController tradeWizardPriceController; public TradeWizardAmountAndPriceController(ServiceProvider serviceProvider, Region owner) { this.owner = owner; tradeWizardAmountController = new TradeWizardAmountController(serviceProvider, owner); + tradeWizardPriceController = new TradeWizardPriceController(serviceProvider, owner); model = new TradeWizardAmountAndPriceModel(); - view = new TradeWizardAmountAndPriceView(model, this, tradeWizardAmountController.getView().getRoot(), - tradeWizardAmountController.getView().getAmountLimitInfoWithWarnIcon()); + view = new TradeWizardAmountAndPriceView(model, + this, + tradeWizardAmountController.getView().getRoot(), + tradeWizardAmountController.getView().getAmountLimitInfoWithWarnIcon(), + tradeWizardPriceController.getView().getRoot()); } @Override @@ -56,7 +62,8 @@ public void onDeactivate() { } public void reset() { - model.reset(); + tradeWizardAmountController.reset(); + tradeWizardPriceController.reset(); } public void setIsCreateOfferMode(boolean isCreateOfferMode) { @@ -65,10 +72,12 @@ public void setIsCreateOfferMode(boolean isCreateOfferMode) { public void setDirection(Direction direction) { tradeWizardAmountController.setDirection(direction); + tradeWizardPriceController.setDirection(direction); } public void setMarket(Market market) { tradeWizardAmountController.setMarket(market); + tradeWizardPriceController.setMarket(market); } public void updateQuoteSideAmountSpecWithPriceSpec(PriceSpec priceSpec) { @@ -82,4 +91,8 @@ public ReadOnlyObjectProperty getQuoteSideAmountSpec() { public boolean validate() { return tradeWizardAmountController.validate(); } + + public ReadOnlyObjectProperty getPriceSpec() { + return tradeWizardPriceController.getPriceSpec(); + } } diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java index 2fb3d7491b..4ed5ef1524 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java @@ -33,12 +33,13 @@ public class TradeWizardAmountAndPriceView extends View Date: Sun, 15 Dec 2024 12:58:11 +0100 Subject: [PATCH 20/33] Align amount and price input box design --- .../controls/MaterialTextField.java | 2 +- .../bisq_easy/components/PriceInput.java | 14 ++- .../bisq_easy/components/PriceInputBox.java | 99 +++++++++++++++++++ .../components/TextInputFontUtils.java | 66 +++++++++++++ .../amount_selection/AmountSelectionView.java | 56 ++--------- .../amount_input/AmountInput.java | 3 +- .../amount_input/BigAmountInput.java | 16 --- .../amount_input/SmallAmountInput.java | 2 - .../TradeWizardAmountAndPriceView.java | 2 +- .../price/TradeWizardPriceView.java | 13 +-- .../src/main/resources/css/bisq_easy.css | 39 +++++++- i18n/src/main/resources/bisq_easy.properties | 3 - 12 files changed, 224 insertions(+), 91 deletions(-) create mode 100644 apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInputBox.java create mode 100644 apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/TextInputFontUtils.java diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/components/controls/MaterialTextField.java b/apps/desktop/desktop/src/main/java/bisq/desktop/components/controls/MaterialTextField.java index 909845a242..378323022a 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/components/controls/MaterialTextField.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/components/controls/MaterialTextField.java @@ -62,7 +62,7 @@ public class MaterialTextField extends Pane { @Getter protected final Label errorLabel = new Label(); @Getter - private final BisqIconButton iconButton = new BisqIconButton(); + protected final BisqIconButton iconButton = new BisqIconButton(); protected final ValidationControl validationControl; private final BooleanProperty isValid = new SimpleBooleanProperty(false); private Optional> stringConverter = Optional.empty(); diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInput.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInput.java index 714a42def4..6ba4dd923c 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInput.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInput.java @@ -145,7 +145,9 @@ public void onActivate() { marketPricePin = marketPriceService.getMarketPriceByCurrencyMap().addObserver(() -> { // We only set it initially - if (model.priceQuote.get() != null) return; + if (model.priceQuote.get() != null) { + return; + } UIThread.run(this::setQuoteFromMarketPrice); }); @@ -196,7 +198,9 @@ private void onFocusedChanged(boolean isFocused) { } private void setQuoteFromMarketPrice() { - if (model.market == null) return; + if (model.market == null) { + return; + } marketPriceService.findMarketPrice(model.market) .ifPresent(marketPrice -> model.priceQuote.set(marketPrice.getPriceQuote())); } @@ -228,13 +232,13 @@ public void reset() { public static class View extends bisq.desktop.common.view.View { private final static int WIDTH = 250; - private final MaterialTextField textInput; + private final PriceInputBox textInput; private Subscription focusedPin, doResetValidationPin; private View(Model model, Controller controller, NumberValidator validator) { super(new VBox(), model, controller); - textInput = new MaterialTextField(model.description.get(), Res.get("component.priceInput.prompt")); + textInput = new PriceInputBox(model.description.get(), Res.get("component.priceInput.prompt")); textInput.setPrefWidth(WIDTH); textInput.setValidator(validator); @@ -245,6 +249,7 @@ private View(Model model, Controller controller, NumberValidator validator) { protected void onViewAttached() { textInput.descriptionProperty().bind(model.description); textInput.textProperty().bindBidirectional(model.priceString); + textInput.initialize(); focusedPin = EasyBind.subscribe(textInput.textInputFocusedProperty(), controller::onFocusedChanged); doResetValidationPin = EasyBind.subscribe(model.doResetValidation, doResetValidation -> { if (doResetValidation != null && doResetValidation) { @@ -259,6 +264,7 @@ protected void onViewDetached() { textInput.descriptionProperty().unbind(); textInput.textProperty().unbindBidirectional(model.priceString); textInput.resetValidation(); + textInput.dispose(); focusedPin.unsubscribe(); doResetValidationPin.unsubscribe(); } diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInputBox.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInputBox.java new file mode 100644 index 0000000000..9021988d32 --- /dev/null +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInputBox.java @@ -0,0 +1,99 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.desktop.main.content.bisq_easy.components; + +import bisq.desktop.components.controls.MaterialTextField; +import javafx.beans.value.ChangeListener; +import javafx.geometry.Insets; +import javafx.scene.control.Label; +import javafx.scene.layout.HBox; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class PriceInputBox extends MaterialTextField { + public final static int AMOUNT_BOX_WIDTH = 340; + public final static int AMOUNT_BOX_HEIGHT = 127; + + private final Label textInputUnitsLabel, conversionPriceLabel, conversionPriceUnitsLabel; + private final HBox textInputAndUnitsHBox; + private final ChangeListener textInputLengthListener; + + public PriceInputBox(String description, String prompt) { + super(description, prompt); + + bg.getStyleClass().setAll("bisq-dual-amount-bg"); + + descriptionLabel.setLayoutX(20); + descriptionLabel.setPadding(new Insets(2, 0, 0, 0)); + textInputUnitsLabel = new Label("tst"); + textInputUnitsLabel.getStyleClass().add("text-input-units"); + textInputAndUnitsHBox = new HBox(10, textInputControl, textInputUnitsLabel); + textInputAndUnitsHBox.setLayoutY(27); + + conversionPriceLabel = new Label("test"); + conversionPriceUnitsLabel = new Label("123"); + HBox conversionPriceBox = new HBox(10, conversionPriceLabel, conversionPriceUnitsLabel); + conversionPriceBox.setLayoutY(100); + + getChildren().setAll(bg, conversionPriceBox, line, selectionLine, descriptionLabel, textInputAndUnitsHBox, iconButton, helpLabel, errorLabel); + getStyleClass().add("price-input-box"); + + textInputLengthListener = (observable, oldValue, newValue) -> applyFontStyle(newValue.intValue()); + + initialize(); + } + + void initialize() { + textInputControl.lengthProperty().addListener(textInputLengthListener); + } + + void dispose() { + textInputControl.lengthProperty().removeListener(textInputLengthListener); + } + + void setTextInputUnitsLabel(String textInputUnits) { + textInputUnitsLabel.setText(textInputUnits.toUpperCase()); + } + + void setConversionPriceLabel(String conversionPriceLabel) { + this.conversionPriceLabel.setText(conversionPriceLabel); + } + + void setConversionPriceUnitsLabel(String conversionPriceUnitsLabel) { + this.conversionPriceUnitsLabel.setText(conversionPriceUnitsLabel.toUpperCase()); + } + + private void applyFontStyle(int length) { + textInputAndUnitsHBox.getStyleClass().clear(); + textInputAndUnitsHBox.getStyleClass().addAll("text-input-and-units-box", + TextInputFontUtils.getFontStyleBasedOnTextLength(length)); + } + + @Override + protected double getBgHeight() { + return AMOUNT_BOX_HEIGHT; + } + + @Override + protected void doLayout() { + super.doLayout(); + + setMinWidth(AMOUNT_BOX_WIDTH); + setMaxWidth(AMOUNT_BOX_WIDTH); + } +} diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/TextInputFontUtils.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/TextInputFontUtils.java new file mode 100644 index 0000000000..0fcaf8bb7a --- /dev/null +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/TextInputFontUtils.java @@ -0,0 +1,66 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.desktop.main.content.bisq_easy.components; + +public class TextInputFontUtils { + private final static String INPUT_TEXT_9_STYLE_CLASS = "input-text-9"; + private final static String INPUT_TEXT_10_STYLE_CLASS = "input-text-10"; + private final static String INPUT_TEXT_11_STYLE_CLASS = "input-text-11"; + private final static String INPUT_TEXT_12_STYLE_CLASS = "input-text-12"; + private final static String INPUT_TEXT_13_STYLE_CLASS = "input-text-13"; + private final static String INPUT_TEXT_14_STYLE_CLASS = "input-text-14"; + private final static String INPUT_TEXT_15_STYLE_CLASS = "input-text-15"; + private final static String INPUT_TEXT_16_STYLE_CLASS = "input-text-16"; + private final static String INPUT_TEXT_17_STYLE_CLASS = "input-text-17"; + private final static String INPUT_TEXT_18_STYLE_CLASS = "input-text-18"; + private final static String INPUT_TEXT_19_STYLE_CLASS = "input-text-19"; + + public static String getFontStyleBasedOnTextLength(int charCount) { + if (charCount < 10) { + return INPUT_TEXT_9_STYLE_CLASS; + } + if (charCount == 10) { + return INPUT_TEXT_10_STYLE_CLASS; + } + if (charCount == 11) { + return INPUT_TEXT_11_STYLE_CLASS; + } + if (charCount == 12) { + return INPUT_TEXT_12_STYLE_CLASS; + } + if (charCount == 13) { + return INPUT_TEXT_13_STYLE_CLASS; + } + if (charCount == 14) { + return INPUT_TEXT_14_STYLE_CLASS; + } + if (charCount == 15) { + return INPUT_TEXT_15_STYLE_CLASS; + } + if (charCount == 16) { + return INPUT_TEXT_16_STYLE_CLASS; + } + if (charCount == 17) { + return INPUT_TEXT_17_STYLE_CLASS; + } + if (charCount == 18) { + return INPUT_TEXT_18_STYLE_CLASS; + } + return INPUT_TEXT_19_STYLE_CLASS; + } +} diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java index 180a1c8dfc..fb4a527004 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java @@ -21,6 +21,7 @@ import bisq.desktop.common.threading.UIScheduler; import bisq.desktop.common.view.View; import bisq.desktop.components.containers.Spacer; +import bisq.desktop.main.content.bisq_easy.components.TextInputFontUtils; import bisq.desktop.main.content.bisq_easy.components.amount_selection.amount_input.BigAmountInput; import bisq.desktop.main.content.bisq_easy.components.amount_selection.amount_input.SmallAmountInput; import bisq.i18n.Res; @@ -39,17 +40,6 @@ public class AmountSelectionView extends View { public final static int AMOUNT_BOX_WIDTH = 300; public final static int AMOUNT_BOX_HEIGHT = 120; - private final static String INPUT_TEXT_9_STYLE_CLASS = "input-text-9"; - private final static String INPUT_TEXT_10_STYLE_CLASS = "input-text-10"; - private final static String INPUT_TEXT_11_STYLE_CLASS = "input-text-11"; - private final static String INPUT_TEXT_12_STYLE_CLASS = "input-text-12"; - private final static String INPUT_TEXT_13_STYLE_CLASS = "input-text-13"; - private final static String INPUT_TEXT_14_STYLE_CLASS = "input-text-14"; - private final static String INPUT_TEXT_15_STYLE_CLASS = "input-text-15"; - private final static String INPUT_TEXT_16_STYLE_CLASS = "input-text-16"; - private final static String INPUT_TEXT_17_STYLE_CLASS = "input-text-17"; - private final static String INPUT_TEXT_18_STYLE_CLASS = "input-text-18"; - private final static String INPUT_TEXT_19_STYLE_CLASS = "input-text-19"; @SuppressWarnings("UnnecessaryUnicodeEscape") public static final String EN_DASH_SYMBOL = "\u2013"; // Unicode for "–" @@ -95,6 +85,9 @@ public class AmountSelectionView extends View Date: Sun, 15 Dec 2024 13:47:29 +0100 Subject: [PATCH 21/33] Fix price text input font size selection --- .../bisq_easy/components/PriceInput.java | 5 ++ .../bisq_easy/components/PriceInputBox.java | 34 ++++++++-- .../components/TextInputFontUtils.java | 66 ------------------- .../amount_selection/AmountSelectionView.java | 56 ++++++++++++++-- .../src/main/resources/css/bisq_easy.css | 7 +- 5 files changed, 91 insertions(+), 77 deletions(-) delete mode 100644 apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/TextInputFontUtils.java diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInput.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInput.java index 6ba4dd923c..9d59bf1b50 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInput.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInput.java @@ -132,6 +132,7 @@ public void setQuote(PriceQuote priceQuote) { private void updateFromMarketPrice() { if (model.market != null && model.description.get() == null) { model.description.set(Res.get("component.priceInput.description", model.market.getMarketCodes())); + model.textInputUnits.set(model.market.getMarketCodes()); } if (model.isEditable) { setQuoteFromMarketPrice(); @@ -213,6 +214,7 @@ private static class Model implements bisq.desktop.common.view.Model { private Market market; private boolean isFocused; private final StringProperty description = new SimpleStringProperty(); + private final StringProperty textInputUnits = new SimpleStringProperty(); private boolean isEditable = true; private final BooleanProperty isPriceValid = new SimpleBooleanProperty(); private final BooleanProperty doResetValidation = new SimpleBooleanProperty(); @@ -226,6 +228,7 @@ public void reset() { market = null; isFocused = false; description.set(null); + textInputUnits.set(null); isEditable = true; } } @@ -248,6 +251,7 @@ private View(Model model, Controller controller, NumberValidator validator) { @Override protected void onViewAttached() { textInput.descriptionProperty().bind(model.description); + textInput.textInputUnitsLabelTextProperty().bind(model.textInputUnits); textInput.textProperty().bindBidirectional(model.priceString); textInput.initialize(); focusedPin = EasyBind.subscribe(textInput.textInputFocusedProperty(), controller::onFocusedChanged); @@ -262,6 +266,7 @@ protected void onViewAttached() { @Override protected void onViewDetached() { textInput.descriptionProperty().unbind(); + textInput.textInputUnitsLabelTextProperty().unbind(); textInput.textProperty().unbindBidirectional(model.priceString); textInput.resetValidation(); textInput.dispose(); diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInputBox.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInputBox.java index 9021988d32..5e61c41cf7 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInputBox.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInputBox.java @@ -18,6 +18,7 @@ package bisq.desktop.main.content.bisq_easy.components; import bisq.desktop.components.controls.MaterialTextField; +import javafx.beans.property.StringProperty; import javafx.beans.value.ChangeListener; import javafx.geometry.Insets; import javafx.scene.control.Label; @@ -28,6 +29,12 @@ public class PriceInputBox extends MaterialTextField { public final static int AMOUNT_BOX_WIDTH = 340; public final static int AMOUNT_BOX_HEIGHT = 127; + private final static String INPUT_TEXT_9_STYLE_CLASS = "input-text-9"; + private final static String INPUT_TEXT_10_STYLE_CLASS = "input-text-10"; + private final static String INPUT_TEXT_11_STYLE_CLASS = "input-text-11"; + private final static String INPUT_TEXT_12_STYLE_CLASS = "input-text-12"; + private final static String INPUT_TEXT_13_STYLE_CLASS = "input-text-13"; + private final static String INPUT_TEXT_14_STYLE_CLASS = "input-text-14"; private final Label textInputUnitsLabel, conversionPriceLabel, conversionPriceUnitsLabel; private final HBox textInputAndUnitsHBox; @@ -40,7 +47,7 @@ public PriceInputBox(String description, String prompt) { descriptionLabel.setLayoutX(20); descriptionLabel.setPadding(new Insets(2, 0, 0, 0)); - textInputUnitsLabel = new Label("tst"); + textInputUnitsLabel = new Label(); textInputUnitsLabel.getStyleClass().add("text-input-units"); textInputAndUnitsHBox = new HBox(10, textInputControl, textInputUnitsLabel); textInputAndUnitsHBox.setLayoutY(27); @@ -66,8 +73,8 @@ void dispose() { textInputControl.lengthProperty().removeListener(textInputLengthListener); } - void setTextInputUnitsLabel(String textInputUnits) { - textInputUnitsLabel.setText(textInputUnits.toUpperCase()); + final StringProperty textInputUnitsLabelTextProperty() { + return textInputUnitsLabel.textProperty(); } void setConversionPriceLabel(String conversionPriceLabel) { @@ -81,7 +88,7 @@ void setConversionPriceUnitsLabel(String conversionPriceUnitsLabel) { private void applyFontStyle(int length) { textInputAndUnitsHBox.getStyleClass().clear(); textInputAndUnitsHBox.getStyleClass().addAll("text-input-and-units-box", - TextInputFontUtils.getFontStyleBasedOnTextLength(length)); + getFontStyleBasedOnTextLength(length)); } @Override @@ -96,4 +103,23 @@ protected void doLayout() { setMinWidth(AMOUNT_BOX_WIDTH); setMaxWidth(AMOUNT_BOX_WIDTH); } + + private static String getFontStyleBasedOnTextLength(int charCount) { + if (charCount < 9) { + return INPUT_TEXT_9_STYLE_CLASS; + } + if (charCount == 9) { + return INPUT_TEXT_10_STYLE_CLASS; + } + if (charCount == 10) { + return INPUT_TEXT_11_STYLE_CLASS; + } + if (charCount == 11) { + return INPUT_TEXT_12_STYLE_CLASS; + } + if (charCount == 12) { + return INPUT_TEXT_13_STYLE_CLASS; + } + return INPUT_TEXT_14_STYLE_CLASS; + } } diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/TextInputFontUtils.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/TextInputFontUtils.java deleted file mode 100644 index 0fcaf8bb7a..0000000000 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/TextInputFontUtils.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.desktop.main.content.bisq_easy.components; - -public class TextInputFontUtils { - private final static String INPUT_TEXT_9_STYLE_CLASS = "input-text-9"; - private final static String INPUT_TEXT_10_STYLE_CLASS = "input-text-10"; - private final static String INPUT_TEXT_11_STYLE_CLASS = "input-text-11"; - private final static String INPUT_TEXT_12_STYLE_CLASS = "input-text-12"; - private final static String INPUT_TEXT_13_STYLE_CLASS = "input-text-13"; - private final static String INPUT_TEXT_14_STYLE_CLASS = "input-text-14"; - private final static String INPUT_TEXT_15_STYLE_CLASS = "input-text-15"; - private final static String INPUT_TEXT_16_STYLE_CLASS = "input-text-16"; - private final static String INPUT_TEXT_17_STYLE_CLASS = "input-text-17"; - private final static String INPUT_TEXT_18_STYLE_CLASS = "input-text-18"; - private final static String INPUT_TEXT_19_STYLE_CLASS = "input-text-19"; - - public static String getFontStyleBasedOnTextLength(int charCount) { - if (charCount < 10) { - return INPUT_TEXT_9_STYLE_CLASS; - } - if (charCount == 10) { - return INPUT_TEXT_10_STYLE_CLASS; - } - if (charCount == 11) { - return INPUT_TEXT_11_STYLE_CLASS; - } - if (charCount == 12) { - return INPUT_TEXT_12_STYLE_CLASS; - } - if (charCount == 13) { - return INPUT_TEXT_13_STYLE_CLASS; - } - if (charCount == 14) { - return INPUT_TEXT_14_STYLE_CLASS; - } - if (charCount == 15) { - return INPUT_TEXT_15_STYLE_CLASS; - } - if (charCount == 16) { - return INPUT_TEXT_16_STYLE_CLASS; - } - if (charCount == 17) { - return INPUT_TEXT_17_STYLE_CLASS; - } - if (charCount == 18) { - return INPUT_TEXT_18_STYLE_CLASS; - } - return INPUT_TEXT_19_STYLE_CLASS; - } -} diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java index fb4a527004..5f15cdbcfd 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java @@ -21,7 +21,6 @@ import bisq.desktop.common.threading.UIScheduler; import bisq.desktop.common.view.View; import bisq.desktop.components.containers.Spacer; -import bisq.desktop.main.content.bisq_easy.components.TextInputFontUtils; import bisq.desktop.main.content.bisq_easy.components.amount_selection.amount_input.BigAmountInput; import bisq.desktop.main.content.bisq_easy.components.amount_selection.amount_input.SmallAmountInput; import bisq.i18n.Res; @@ -31,7 +30,11 @@ import javafx.scene.Parent; import javafx.scene.control.Label; import javafx.scene.control.Slider; -import javafx.scene.layout.*; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Pane; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; +import javafx.scene.layout.VBox; import lombok.extern.slf4j.Slf4j; import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.Subscription; @@ -40,6 +43,17 @@ public class AmountSelectionView extends View { public final static int AMOUNT_BOX_WIDTH = 300; public final static int AMOUNT_BOX_HEIGHT = 120; + private final static String INPUT_TEXT_9_STYLE_CLASS = "input-text-9"; + private final static String INPUT_TEXT_10_STYLE_CLASS = "input-text-10"; + private final static String INPUT_TEXT_11_STYLE_CLASS = "input-text-11"; + private final static String INPUT_TEXT_12_STYLE_CLASS = "input-text-12"; + private final static String INPUT_TEXT_13_STYLE_CLASS = "input-text-13"; + private final static String INPUT_TEXT_14_STYLE_CLASS = "input-text-14"; + private final static String INPUT_TEXT_15_STYLE_CLASS = "input-text-15"; + private final static String INPUT_TEXT_16_STYLE_CLASS = "input-text-16"; + private final static String INPUT_TEXT_17_STYLE_CLASS = "input-text-17"; + private final static String INPUT_TEXT_18_STYLE_CLASS = "input-text-18"; + private final static String INPUT_TEXT_19_STYLE_CLASS = "input-text-19"; @SuppressWarnings("UnnecessaryUnicodeEscape") public static final String EN_DASH_SYMBOL = "\u2013"; // Unicode for "–" @@ -321,10 +335,10 @@ private void applyFontStyle() { int charCount = model.getIsRangeAmountEnabled().get() ? minQuoteAmount.getTextInputLength() + maxOrFixedQuoteAmount.getTextInputLength() + 1 // for the dash : maxOrFixedQuoteAmount.getTextInputLength(); - quoteAmountSelectionHBox.getStyleClass().add(TextInputFontUtils.getFontStyleBasedOnTextLength(charCount)); + quoteAmountSelectionHBox.getStyleClass().add(getFontStyleBasedOnTextLength(charCount)); } - private int getFontCharWidth(int charCount) { + private static int getFontCharWidth(int charCount) { if (charCount < 10) { return 31; } @@ -354,4 +368,38 @@ private int getFontCharWidth(int charCount) { } return 15; } + + private static String getFontStyleBasedOnTextLength(int charCount) { + if (charCount < 10) { + return INPUT_TEXT_9_STYLE_CLASS; + } + if (charCount == 10) { + return INPUT_TEXT_10_STYLE_CLASS; + } + if (charCount == 11) { + return INPUT_TEXT_11_STYLE_CLASS; + } + if (charCount == 12) { + return INPUT_TEXT_12_STYLE_CLASS; + } + if (charCount == 13) { + return INPUT_TEXT_13_STYLE_CLASS; + } + if (charCount == 14) { + return INPUT_TEXT_14_STYLE_CLASS; + } + if (charCount == 15) { + return INPUT_TEXT_15_STYLE_CLASS; + } + if (charCount == 16) { + return INPUT_TEXT_16_STYLE_CLASS; + } + if (charCount == 17) { + return INPUT_TEXT_17_STYLE_CLASS; + } + if (charCount == 18) { + return INPUT_TEXT_18_STYLE_CLASS; + } + return INPUT_TEXT_19_STYLE_CLASS; + } } diff --git a/apps/desktop/desktop/src/main/resources/css/bisq_easy.css b/apps/desktop/desktop/src/main/resources/css/bisq_easy.css index daa99e895f..6f7d8956ed 100644 --- a/apps/desktop/desktop/src/main/resources/css/bisq_easy.css +++ b/apps/desktop/desktop/src/main/resources/css/bisq_easy.css @@ -1022,22 +1022,23 @@ -fx-border-style: none; -fx-text-fill: -fx-light-text-color; -fx-highlight-fill: -bisq2-green; - -fx-font-family: "IBM Plex Sans Thin"; } .bisq-easy-trade-wizard-price-step .price-input-box .text-input-and-units-box .text-input { -fx-alignment: bottom-right; -fx-padding: 0; -fx-min-height: 70; + -fx-font-family: "IBM Plex Sans Thin"; /*-fx-background-color: green !important;*/ } .bisq-easy-trade-wizard-price-step .price-input-box .text-input-and-units-box .text-input-units { - -fx-min-width: 50; - -fx-max-width: 50; + -fx-min-width: 80; + -fx-max-width: 80; -fx-min-height: 70; -fx-padding: 0 0 10 0; -fx-alignment: bottom-left; + -fx-font-family: "IBM Plex Sans Light"; /*-fx-background-color: pink !important;*/ } From b6e83a25a1cd43275ecd4e8aa5558e6f27cec5fe Mon Sep 17 00:00:00 2001 From: axpoems <145597137+axpoems@users.noreply.github.com> Date: Sun, 15 Dec 2024 14:28:48 +0100 Subject: [PATCH 22/33] Set conversion price --- .../bisq_easy/components/PriceInput.java | 37 +++++++++++---- .../bisq_easy/components/PriceInputBox.java | 46 ++++++++++--------- .../price/TradeWizardPriceController.java | 8 +++- .../src/main/resources/css/bisq_easy.css | 26 +++++++++-- 4 files changed, 81 insertions(+), 36 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInput.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInput.java index 9d59bf1b50..a425abc271 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInput.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInput.java @@ -23,12 +23,20 @@ import bisq.common.observable.Pin; import bisq.common.util.MathUtils; import bisq.desktop.common.threading.UIThread; -import bisq.desktop.components.controls.MaterialTextField; import bisq.desktop.components.controls.validator.NumberValidator; import bisq.i18n.Res; +import bisq.presentation.formatters.PercentageFormatter; import bisq.presentation.formatters.PriceFormatter; import bisq.presentation.parser.PriceParser; -import javafx.beans.property.*; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.ReadOnlyBooleanProperty; +import javafx.beans.property.ReadOnlyObjectProperty; +import javafx.beans.property.ReadOnlyStringProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; import javafx.scene.layout.Pane; import javafx.scene.layout.VBox; import lombok.Getter; @@ -66,6 +74,10 @@ public void setQuote(PriceQuote priceQuote) { controller.setQuote(priceQuote); } + public void setPercentage(double percentage) { + controller.setPercentage(percentage); + } + public void setIsTakeOffer() { controller.model.isEditable = false; } @@ -129,10 +141,14 @@ public void setQuote(PriceQuote priceQuote) { model.priceQuote.set(priceQuote); } + public void setPercentage(double percentage) { + model.percentagePriceString.set(PercentageFormatter.formatToPercent(percentage)); + } + private void updateFromMarketPrice() { if (model.market != null && model.description.get() == null) { model.description.set(Res.get("component.priceInput.description", model.market.getMarketCodes())); - model.textInputUnits.set(model.market.getMarketCodes()); + model.textInputCurrencyCodes.set(model.market.getMarketCodes()); } if (model.isEditable) { setQuoteFromMarketPrice(); @@ -214,7 +230,8 @@ private static class Model implements bisq.desktop.common.view.Model { private Market market; private boolean isFocused; private final StringProperty description = new SimpleStringProperty(); - private final StringProperty textInputUnits = new SimpleStringProperty(); + private final StringProperty textInputCurrencyCodes = new SimpleStringProperty(); + private final StringProperty percentagePriceString = new SimpleStringProperty(); private boolean isEditable = true; private final BooleanProperty isPriceValid = new SimpleBooleanProperty(); private final BooleanProperty doResetValidation = new SimpleBooleanProperty(); @@ -228,7 +245,8 @@ public void reset() { market = null; isFocused = false; description.set(null); - textInputUnits.set(null); + textInputCurrencyCodes.set(null); + percentagePriceString.set(null); isEditable = true; } } @@ -244,6 +262,7 @@ private View(Model model, Controller controller, NumberValidator validator) { textInput = new PriceInputBox(model.description.get(), Res.get("component.priceInput.prompt")); textInput.setPrefWidth(WIDTH); textInput.setValidator(validator); + textInput.conversionPriceSymbolTextProperty().set("%"); root.getChildren().add(textInput); } @@ -251,7 +270,8 @@ private View(Model model, Controller controller, NumberValidator validator) { @Override protected void onViewAttached() { textInput.descriptionProperty().bind(model.description); - textInput.textInputUnitsLabelTextProperty().bind(model.textInputUnits); + textInput.textInputSymbolTextProperty().bind(model.textInputCurrencyCodes); + textInput.conversionPriceTextProperty().bind(model.percentagePriceString); textInput.textProperty().bindBidirectional(model.priceString); textInput.initialize(); focusedPin = EasyBind.subscribe(textInput.textInputFocusedProperty(), controller::onFocusedChanged); @@ -266,7 +286,8 @@ protected void onViewAttached() { @Override protected void onViewDetached() { textInput.descriptionProperty().unbind(); - textInput.textInputUnitsLabelTextProperty().unbind(); + textInput.textInputSymbolTextProperty().unbind(); + textInput.conversionPriceTextProperty().unbind(); textInput.textProperty().unbindBidirectional(model.priceString); textInput.resetValidation(); textInput.dispose(); @@ -274,4 +295,4 @@ protected void onViewDetached() { doResetValidationPin.unsubscribe(); } } -} \ No newline at end of file +} diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInputBox.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInputBox.java index 5e61c41cf7..c196690422 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInputBox.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInputBox.java @@ -36,8 +36,8 @@ public class PriceInputBox extends MaterialTextField { private final static String INPUT_TEXT_13_STYLE_CLASS = "input-text-13"; private final static String INPUT_TEXT_14_STYLE_CLASS = "input-text-14"; - private final Label textInputUnitsLabel, conversionPriceLabel, conversionPriceUnitsLabel; - private final HBox textInputAndUnitsHBox; + private final Label textInputSymbolLabel, conversionPriceLabel, conversionPriceLabelSymbol; + private final HBox textInputAndSymbolHBox; private final ChangeListener textInputLengthListener; public PriceInputBox(String description, String prompt) { @@ -47,21 +47,23 @@ public PriceInputBox(String description, String prompt) { descriptionLabel.setLayoutX(20); descriptionLabel.setPadding(new Insets(2, 0, 0, 0)); - textInputUnitsLabel = new Label(); - textInputUnitsLabel.getStyleClass().add("text-input-units"); - textInputAndUnitsHBox = new HBox(10, textInputControl, textInputUnitsLabel); - textInputAndUnitsHBox.setLayoutY(27); - - conversionPriceLabel = new Label("test"); - conversionPriceUnitsLabel = new Label("123"); - HBox conversionPriceBox = new HBox(10, conversionPriceLabel, conversionPriceUnitsLabel); - conversionPriceBox.setLayoutY(100); - - getChildren().setAll(bg, conversionPriceBox, line, selectionLine, descriptionLabel, textInputAndUnitsHBox, iconButton, helpLabel, errorLabel); + textInputSymbolLabel = new Label(); + textInputSymbolLabel.getStyleClass().add("text-input-symbol"); + textInputAndSymbolHBox = new HBox(10, textInputControl, textInputSymbolLabel); + textInputAndSymbolHBox.setLayoutY(27); + + conversionPriceLabel = new Label(); + conversionPriceLabel.getStyleClass().add("conversion-price"); + conversionPriceLabelSymbol = new Label(); + conversionPriceLabelSymbol.getStyleClass().add("conversion-price-symbol"); + HBox conversionPriceBox = new HBox(7, conversionPriceLabel, conversionPriceLabelSymbol); + conversionPriceBox.getStyleClass().add("conversion-price-box"); + conversionPriceBox.setLayoutY(97); + + getChildren().setAll(bg, conversionPriceBox, line, selectionLine, descriptionLabel, textInputAndSymbolHBox, iconButton, helpLabel, errorLabel); getStyleClass().add("price-input-box"); textInputLengthListener = (observable, oldValue, newValue) -> applyFontStyle(newValue.intValue()); - initialize(); } @@ -73,21 +75,21 @@ void dispose() { textInputControl.lengthProperty().removeListener(textInputLengthListener); } - final StringProperty textInputUnitsLabelTextProperty() { - return textInputUnitsLabel.textProperty(); + final StringProperty textInputSymbolTextProperty() { + return textInputSymbolLabel.textProperty(); } - void setConversionPriceLabel(String conversionPriceLabel) { - this.conversionPriceLabel.setText(conversionPriceLabel); + final StringProperty conversionPriceTextProperty() { + return conversionPriceLabel.textProperty(); } - void setConversionPriceUnitsLabel(String conversionPriceUnitsLabel) { - this.conversionPriceUnitsLabel.setText(conversionPriceUnitsLabel.toUpperCase()); + final StringProperty conversionPriceSymbolTextProperty() { + return conversionPriceLabelSymbol.textProperty(); } private void applyFontStyle(int length) { - textInputAndUnitsHBox.getStyleClass().clear(); - textInputAndUnitsHBox.getStyleClass().addAll("text-input-and-units-box", + textInputAndSymbolHBox.getStyleClass().clear(); + textInputAndSymbolHBox.getStyleClass().addAll("text-input-and-units-box", getFontStyleBasedOnTextLength(length)); } diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/price/TradeWizardPriceController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/price/TradeWizardPriceController.java index ff58754257..c8286093a0 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/price/TradeWizardPriceController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/price/TradeWizardPriceController.java @@ -53,7 +53,7 @@ public class TradeWizardPriceController implements Controller { private final Region owner; private final MarketPriceService marketPriceService; private final SettingsService settingsService; - private Subscription priceInputPin, isPriceInvalidPin, priceSpecPin, percentageInputPin; + private Subscription priceInputPin, isPriceInvalidPin, priceSpecPin, percentageInputPin, percentagePin; public TradeWizardPriceController(ServiceProvider serviceProvider, Region owner) { marketPriceService = serviceProvider.getBondedRolesService().getMarketPriceService(); @@ -122,6 +122,11 @@ public void onActivate() { onPercentageInput(percentageInput); } }); + percentagePin = EasyBind.subscribe(model.getPercentage(), percentage -> { + if (percentage != null) { + priceInput.setPercentage(percentage.doubleValue()); + } + }); String marketCodes = model.getMarket().getMarketCodes(); priceInput.setDescription(Res.get("bisqEasy.price.tradePrice.inputBoxText", marketCodes)); @@ -139,6 +144,7 @@ public void onDeactivate() { isPriceInvalidPin.unsubscribe(); priceSpecPin.unsubscribe(); percentageInputPin.unsubscribe(); + percentagePin.unsubscribe(); view.getRoot().setOnKeyPressed(null); } diff --git a/apps/desktop/desktop/src/main/resources/css/bisq_easy.css b/apps/desktop/desktop/src/main/resources/css/bisq_easy.css index 6f7d8956ed..cc927869ff 100644 --- a/apps/desktop/desktop/src/main/resources/css/bisq_easy.css +++ b/apps/desktop/desktop/src/main/resources/css/bisq_easy.css @@ -1008,7 +1008,6 @@ } .bisq-easy-trade-wizard-price-step .price-input-box .text-input-and-units-box { - /*-fx-background-color: blue !important;*/ -fx-max-width: 340; -fx-min-width: 340; -fx-max-height: 70; @@ -1017,7 +1016,7 @@ } .bisq-easy-trade-wizard-price-step .price-input-box .text-input-and-units-box .text-input, -.bisq-easy-trade-wizard-price-step .price-input-box .text-input-and-units-box .text-input-units { +.bisq-easy-trade-wizard-price-step .price-input-box .text-input-and-units-box .text-input-symbol { -fx-background-color: transparent; -fx-border-style: none; -fx-text-fill: -fx-light-text-color; @@ -1029,22 +1028,39 @@ -fx-padding: 0; -fx-min-height: 70; -fx-font-family: "IBM Plex Sans Thin"; - /*-fx-background-color: green !important;*/ } -.bisq-easy-trade-wizard-price-step .price-input-box .text-input-and-units-box .text-input-units { +.bisq-easy-trade-wizard-price-step .price-input-box .text-input-and-units-box .text-input-symbol { -fx-min-width: 80; -fx-max-width: 80; -fx-min-height: 70; -fx-padding: 0 0 10 0; -fx-alignment: bottom-left; -fx-font-family: "IBM Plex Sans Light"; - /*-fx-background-color: pink !important;*/ } +.bisq-easy-trade-wizard-price-step .price-input-box .conversion-price-box { + -fx-max-width: 340; + -fx-min-width: 340; + -fx-alignment: baseline-center; +} +.bisq-easy-trade-wizard-price-step .price-input-box .conversion-price-box .conversion-price, +.bisq-easy-trade-wizard-price-step .price-input-box .conversion-price-box .conversion-price-symbol { + -fx-fill: -fx-mid-text-color; + -fx-text-fill: -fx-mid-text-color; + -fx-font-family: "IBM Plex Sans Light"; +} +.bisq-easy-trade-wizard-price-step .price-input-box .conversion-price-box .conversion-price { + -fx-font-size: 1.25em !important; + -fx-alignment: baseline-right; +} +.bisq-easy-trade-wizard-price-step .price-input-box .conversion-price-box .conversion-price-symbol { + -fx-font-size: 0.95em !important; + -fx-alignment: baseline-left; +} .bisq-easy-trade-wizard-price-step .price-content { -fx-alignment: center; From d7ecb6405b1d50b81cc63187af884fef2168194c Mon Sep 17 00:00:00 2001 From: axpoems <145597137+axpoems@users.noreply.github.com> Date: Sun, 15 Dec 2024 14:48:48 +0100 Subject: [PATCH 23/33] Use same input box for percentage price selection --- .../content/bisq_easy/components/PriceInput.java | 7 +++---- .../bisq_easy/components/PriceInputBox.java | 10 +++++++--- .../price/TradeWizardPriceController.java | 14 +++++--------- .../trade_wizard/price/TradeWizardPriceView.java | 13 +++++++++---- 4 files changed, 24 insertions(+), 20 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInput.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInput.java index a425abc271..2fecf1b377 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInput.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInput.java @@ -25,7 +25,6 @@ import bisq.desktop.common.threading.UIThread; import bisq.desktop.components.controls.validator.NumberValidator; import bisq.i18n.Res; -import bisq.presentation.formatters.PercentageFormatter; import bisq.presentation.formatters.PriceFormatter; import bisq.presentation.parser.PriceParser; import javafx.beans.property.BooleanProperty; @@ -74,7 +73,7 @@ public void setQuote(PriceQuote priceQuote) { controller.setQuote(priceQuote); } - public void setPercentage(double percentage) { + public void setPercentage(String percentage) { controller.setPercentage(percentage); } @@ -141,8 +140,8 @@ public void setQuote(PriceQuote priceQuote) { model.priceQuote.set(priceQuote); } - public void setPercentage(double percentage) { - model.percentagePriceString.set(PercentageFormatter.formatToPercent(percentage)); + public void setPercentage(String percentage) { + model.percentagePriceString.set(percentage); } private void updateFromMarketPrice() { diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInputBox.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInputBox.java index c196690422..04105fd7c1 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInputBox.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInputBox.java @@ -67,6 +67,10 @@ public PriceInputBox(String description, String prompt) { initialize(); } + public PriceInputBox(String description) { + this(description, null); + } + void initialize() { textInputControl.lengthProperty().addListener(textInputLengthListener); } @@ -75,15 +79,15 @@ void dispose() { textInputControl.lengthProperty().removeListener(textInputLengthListener); } - final StringProperty textInputSymbolTextProperty() { + public final StringProperty textInputSymbolTextProperty() { return textInputSymbolLabel.textProperty(); } - final StringProperty conversionPriceTextProperty() { + public final StringProperty conversionPriceTextProperty() { return conversionPriceLabel.textProperty(); } - final StringProperty conversionPriceSymbolTextProperty() { + public final StringProperty conversionPriceSymbolTextProperty() { return conversionPriceLabelSymbol.textProperty(); } diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/price/TradeWizardPriceController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/price/TradeWizardPriceController.java index c8286093a0..9b5dd369b7 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/price/TradeWizardPriceController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/price/TradeWizardPriceController.java @@ -29,6 +29,7 @@ import bisq.offer.Direction; import bisq.offer.price.PriceUtil; import bisq.offer.price.spec.*; +import bisq.presentation.formatters.PercentageFormatter; import bisq.presentation.formatters.PriceFormatter; import bisq.settings.CookieKey; import bisq.settings.SettingsService; @@ -53,7 +54,7 @@ public class TradeWizardPriceController implements Controller { private final Region owner; private final MarketPriceService marketPriceService; private final SettingsService settingsService; - private Subscription priceInputPin, isPriceInvalidPin, priceSpecPin, percentageInputPin, percentagePin; + private Subscription priceInputPin, isPriceInvalidPin, priceSpecPin, percentageInputPin; public TradeWizardPriceController(ServiceProvider serviceProvider, Region owner) { marketPriceService = serviceProvider.getBondedRolesService().getMarketPriceService(); @@ -120,13 +121,9 @@ public void onActivate() { percentageInputPin = EasyBind.subscribe(model.getPercentageInput(), percentageInput -> { if (percentageInput != null) { onPercentageInput(percentageInput); + priceInput.setPercentage(percentageInput); } }); - percentagePin = EasyBind.subscribe(model.getPercentage(), percentage -> { - if (percentage != null) { - priceInput.setPercentage(percentage.doubleValue()); - } - }); String marketCodes = model.getMarket().getMarketCodes(); priceInput.setDescription(Res.get("bisqEasy.price.tradePrice.inputBoxText", marketCodes)); @@ -144,7 +141,6 @@ public void onDeactivate() { isPriceInvalidPin.unsubscribe(); priceSpecPin.unsubscribe(); percentageInputPin.unsubscribe(); - percentagePin.unsubscribe(); view.getRoot().setOnKeyPressed(null); } @@ -153,7 +149,7 @@ void onPercentageFocussed(boolean focussed) { if (!focussed) { try { double percentage = parse(model.getPercentageInput().get()); - String percentageAsString = formatToPercentWithSymbol(percentage); + String percentageAsString = PercentageFormatter.formatToPercent(percentage); // Need to change the value first otherwise it does not trigger an update model.getPercentageInput().set(""); model.getPercentageInput().set(percentageAsString); @@ -272,7 +268,7 @@ private void onQuoteInput(PriceQuote priceQuote) { private void applyPercentageFromQuote(PriceQuote priceQuote) { double percentage = getPercentage(priceQuote); model.getPercentage().set(percentage); - model.getPercentageInput().set(formatToPercentWithSymbol(percentage)); + model.getPercentageInput().set(PercentageFormatter.formatToPercent(percentage)); } private boolean validateQuote(PriceQuote priceQuote) { diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/price/TradeWizardPriceView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/price/TradeWizardPriceView.java index 49b7a44443..6a2540cf73 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/price/TradeWizardPriceView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/price/TradeWizardPriceView.java @@ -24,6 +24,7 @@ import bisq.desktop.components.controls.UnorderedList; import bisq.desktop.components.controls.validator.PercentageValidator; import bisq.desktop.main.content.bisq_easy.components.PriceInput; +import bisq.desktop.main.content.bisq_easy.components.PriceInputBox; import bisq.i18n.Res; import javafx.geometry.Insets; import javafx.geometry.Pos; @@ -42,7 +43,7 @@ public class TradeWizardPriceView extends View { private static final String SELECTED_PRICE_MODEL_STYLE_CLASS = "selected-model"; - private final MaterialTextField percentageInput; + private final PriceInputBox percentageInput; private final VBox fieldsBox, learnWhyOverlay, content; private final PriceInput priceInput; private final Button percentagePrice, fixedPrice, showLearnWhyButton, closeLearnWhyButton; @@ -75,8 +76,9 @@ public TradeWizardPriceView(TradeWizardPriceModel model, TradeWizardPriceControl pricingModels.getStyleClass().addAll("selection-models", "bisq-text-3"); // Input box - percentageInput = new MaterialTextField(Res.get("bisqEasy.price.percentage.inputBoxText")); + percentageInput = new PriceInputBox(Res.get("bisqEasy.price.percentage.inputBoxText")); percentageInput.setValidator(new PercentageValidator()); + percentageInput.textInputSymbolTextProperty().set("%"); fieldsBox = new VBox(20); fieldsBox.setAlignment(Pos.TOP_CENTER); fieldsBox.setMinWidth(350); @@ -105,6 +107,8 @@ public TradeWizardPriceView(TradeWizardPriceModel model, TradeWizardPriceControl @Override protected void onViewAttached() { percentageInput.textProperty().bindBidirectional(model.getPercentageInput()); + percentageInput.conversionPriceTextProperty().bind(model.getPriceAsString()); + percentageInput.conversionPriceSymbolTextProperty().set(model.getMarket().getMarketCodes()); feedbackSentence.textProperty().bind(model.getFeedbackSentence()); feedbackBox.visibleProperty().bind(model.getShouldShowFeedback()); feedbackBox.managedProperty().bind(model.getShouldShowFeedback()); @@ -145,6 +149,7 @@ protected void onViewAttached() { @Override protected void onViewDetached() { percentageInput.textProperty().unbindBidirectional(model.getPercentageInput()); + percentageInput.conversionPriceTextProperty().unbind(); feedbackSentence.textProperty().unbind(); feedbackBox.visibleProperty().unbind(); feedbackBox.managedProperty().unbind(); @@ -170,7 +175,7 @@ private void updateFieldsBox() { percentagePrice.getStyleClass().remove(SELECTED_PRICE_MODEL_STYLE_CLASS); if (model.getUseFixPrice().get()) { fixedPrice.getStyleClass().add(SELECTED_PRICE_MODEL_STYLE_CLASS); - fieldsBox.getChildren().setAll(priceInput.getRoot(), percentageInput); + fieldsBox.getChildren().setAll(priceInput.getRoot()); percentageInput.deselect(); percentageInput.setEditable(false); percentageInput.resetValidation(); @@ -178,7 +183,7 @@ private void updateFieldsBox() { priceInput.requestFocus(); } else { percentagePrice.getStyleClass().add(SELECTED_PRICE_MODEL_STYLE_CLASS); - fieldsBox.getChildren().setAll(percentageInput, priceInput.getRoot()); + fieldsBox.getChildren().setAll(percentageInput); priceInput.deselect(); priceInput.setEditable(false); priceInput.resetValidation(); From afd2c6834bc84de9aad4baefd8b39332a312f673 Mon Sep 17 00:00:00 2001 From: axpoems <145597137+axpoems@users.noreply.github.com> Date: Mon, 16 Dec 2024 12:21:11 +0100 Subject: [PATCH 24/33] Adjust visibilities depending on whether is create or select offer --- .../trade_wizard/TradeWizardController.java | 43 ++++--------------- .../trade_wizard/TradeWizardModel.java | 6 ++- .../trade_wizard/TradeWizardView.java | 39 +++-------------- .../amount/TradeWizardAmountController.java | 3 -- .../amount/TradeWizardAmountModel.java | 3 -- .../amount/TradeWizardAmountView.java | 12 +----- .../TradeWizardAmountAndPriceController.java | 31 ++++++++++++- .../TradeWizardAmountAndPriceModel.java | 12 +++++- .../TradeWizardAmountAndPriceView.java | 17 +++++--- .../java/bisq/bisq_easy/NavigationTarget.java | 2 - i18n/src/main/resources/bisq_easy.properties | 12 ++++-- 11 files changed, 80 insertions(+), 100 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardController.java index d549abad67..a9d79df844 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardController.java @@ -26,11 +26,9 @@ import bisq.desktop.common.view.InitWithDataController; import bisq.desktop.common.view.Navigation; import bisq.desktop.common.view.NavigationController; -import bisq.desktop.main.content.bisq_easy.trade_wizard.amount.TradeWizardAmountController; import bisq.desktop.main.content.bisq_easy.trade_wizard.amount_and_price.TradeWizardAmountAndPriceController; import bisq.desktop.main.content.bisq_easy.trade_wizard.direction_and_market.TradeWizardDirectionAndMarketController; import bisq.desktop.main.content.bisq_easy.trade_wizard.payment_methods.TradeWizardPaymentMethodsController; -import bisq.desktop.main.content.bisq_easy.trade_wizard.price.TradeWizardPriceController; import bisq.desktop.main.content.bisq_easy.trade_wizard.review.TradeWizardReviewController; import bisq.desktop.main.content.bisq_easy.trade_wizard.select_offer.TradeWizardSelectOfferController; import bisq.desktop.overlay.OverlayController; @@ -70,8 +68,6 @@ public InitData(boolean isCreateOfferMode) { private final TradeWizardView view; private final TradeWizardDirectionAndMarketController tradeWizardDirectionAndMarketController; private final TradeWizardAmountAndPriceController tradeWizardAmountAndPriceController; - private final TradeWizardPriceController tradeWizardPriceController; - private final TradeWizardAmountController tradeWizardAmountController; private final TradeWizardPaymentMethodsController tradeWizardPaymentMethodsController; private final TradeWizardSelectOfferController tradeWizardSelectOfferController; private final TradeWizardReviewController tradeWizardReviewController; @@ -95,8 +91,6 @@ public TradeWizardController(ServiceProvider serviceProvider) { this::setMainButtonsVisibleState, this::closeAndNavigateTo); tradeWizardAmountAndPriceController = new TradeWizardAmountAndPriceController(serviceProvider, view.getRoot()); - tradeWizardPriceController = new TradeWizardPriceController(serviceProvider, view.getRoot()); - tradeWizardAmountController = new TradeWizardAmountController(serviceProvider, view.getRoot()); tradeWizardPaymentMethodsController = new TradeWizardPaymentMethodsController(serviceProvider, view.getRoot(), this::onNext); tradeWizardSelectOfferController = new TradeWizardSelectOfferController(serviceProvider, this::onBack, @@ -121,8 +115,9 @@ public void initWithData(InitData initData) { boolean isCreateOfferMode = initData.isCreateOfferMode(); model.setCreateOfferMode(isCreateOfferMode); tradeWizardAmountAndPriceController.setIsCreateOfferMode(isCreateOfferMode); - tradeWizardAmountController.setIsCreateOfferMode(isCreateOfferMode); - model.getPriceProgressItemVisible().set(isCreateOfferMode); + model.setAmountAtPriceString(isCreateOfferMode + ? Res.get("bisqEasy.tradeWizard.progress.amountAndPrice.createOffer") + : Res.get("bisqEasy.tradeWizard.progress.amountAndPrice.selectOffer")); } @Override @@ -136,41 +131,27 @@ public void onActivate() { model.getChildTargets().addAll(List.of( NavigationTarget.TRADE_WIZARD_DIRECTION_AND_MARKET, NavigationTarget.TRADE_WIZARD_AMOUNT_AND_PRICE, - NavigationTarget.TRADE_WIZARD_AMOUNT, NavigationTarget.TRADE_WIZARD_PAYMENT_METHODS, NavigationTarget.TRADE_WIZARD_TAKE_OFFER_OFFER, NavigationTarget.TRADE_WIZARD_REVIEW_OFFER )); - // TODO: for take offer wizard we only want to add amount component - - if (model.getPriceProgressItemVisible().get()) { - model.getChildTargets().add(3, NavigationTarget.TRADE_WIZARD_PRICE); - } else { - model.getChildTargets().remove(NavigationTarget.TRADE_WIZARD_PRICE); - } - directionPin = EasyBind.subscribe(tradeWizardDirectionAndMarketController.getDirection(), direction -> { tradeWizardSelectOfferController.setDirection(direction); tradeWizardAmountAndPriceController.setDirection(direction); - tradeWizardAmountController.setDirection(direction); tradeWizardPaymentMethodsController.setDirection(direction); - tradeWizardPriceController.setDirection(direction); }); marketPin = EasyBind.subscribe(tradeWizardDirectionAndMarketController.getMarket(), market -> { tradeWizardSelectOfferController.setMarket(market); tradeWizardPaymentMethodsController.setMarket(market); tradeWizardAmountAndPriceController.setMarket(market); - tradeWizardPriceController.setMarket(market); - tradeWizardAmountController.setMarket(market); updateNextButtonDisabledState(); }); amountSpecPin = EasyBind.subscribe(tradeWizardAmountAndPriceController.getQuoteSideAmountSpec(), tradeWizardSelectOfferController::setQuoteSideAmountSpec); - priceSpecPin = EasyBind.subscribe(tradeWizardPriceController.getPriceSpec(), + priceSpecPin = EasyBind.subscribe(tradeWizardAmountAndPriceController.getPriceSpec(), priceSpec -> { tradeWizardAmountAndPriceController.updateQuoteSideAmountSpecWithPriceSpec(priceSpec); - tradeWizardAmountController.updateQuoteSideAmountSpecWithPriceSpec(priceSpec); tradeWizardSelectOfferController.setPriceSpec(priceSpec); }); selectedBisqEasyOfferPin = EasyBind.subscribe(tradeWizardSelectOfferController.getSelectedBisqEasyOffer(), @@ -212,12 +193,12 @@ protected void onStartProcessNavigationTarget(NavigationTarget navigationTarget, tradeWizardPaymentMethodsController.getBitcoinPaymentMethods(), tradeWizardPaymentMethodsController.getFiatPaymentMethods(), tradeWizardAmountAndPriceController.getQuoteSideAmountSpec().get(), - tradeWizardPriceController.getPriceSpec().get() + tradeWizardAmountAndPriceController.getPriceSpec().get() ); model.getNextButtonText().set(Res.get("bisqEasy.tradeWizard.review.nextButton.createOffer")); } else { tradeWizardReviewController.setDataForTakeOffer(tradeWizardSelectOfferController.getSelectedBisqEasyOffer().get(), - tradeWizardAmountController.getQuoteSideAmountSpec().get(), + tradeWizardAmountAndPriceController.getQuoteSideAmountSpec().get(), tradeWizardPaymentMethodsController.getBitcoinPaymentMethods(), tradeWizardPaymentMethodsController.getFiatPaymentMethods() ); @@ -244,9 +225,7 @@ protected Optional createController(NavigationTarget navig return switch (navigationTarget) { case TRADE_WIZARD_DIRECTION_AND_MARKET -> Optional.of(tradeWizardDirectionAndMarketController); case TRADE_WIZARD_AMOUNT_AND_PRICE -> Optional.of(tradeWizardAmountAndPriceController); - case TRADE_WIZARD_PRICE -> Optional.of(tradeWizardPriceController); case TRADE_WIZARD_PAYMENT_METHODS -> Optional.of(tradeWizardPaymentMethodsController); - case TRADE_WIZARD_AMOUNT -> Optional.of(tradeWizardAmountController); case TRADE_WIZARD_TAKE_OFFER_OFFER -> Optional.of(tradeWizardSelectOfferController); case TRADE_WIZARD_REVIEW_OFFER -> Optional.of(tradeWizardReviewController); default -> Optional.empty(); @@ -311,10 +290,6 @@ void onBack() { private boolean validate(boolean calledFromNext) { if (model.getSelectedChildTarget().get() == NavigationTarget.TRADE_WIZARD_AMOUNT_AND_PRICE) { return tradeWizardAmountAndPriceController.validate(); - } else if (model.getSelectedChildTarget().get() == NavigationTarget.TRADE_WIZARD_PRICE) { - return tradeWizardPriceController.validate(); - } else if (model.getSelectedChildTarget().get() == NavigationTarget.TRADE_WIZARD_AMOUNT) { - return tradeWizardAmountController.validate(); } else if (calledFromNext && model.getSelectedChildTarget().get() == NavigationTarget.TRADE_WIZARD_PAYMENT_METHODS) { // For PaymentMethod we tolerate to go back without having one selected return tradeWizardPaymentMethodsController.validate(); @@ -342,8 +317,6 @@ private void reset() { tradeWizardDirectionAndMarketController.reset(); tradeWizardAmountAndPriceController.reset(); - tradeWizardPriceController.reset(); - tradeWizardAmountController.reset(); tradeWizardPaymentMethodsController.reset(); tradeWizardSelectOfferController.reset(); tradeWizardReviewController.reset(); @@ -375,14 +348,14 @@ private void setMainButtonsVisibleState(boolean value) { private void handleFiatPaymentMethodsUpdate() { ObservableList fiatPaymentMethods = tradeWizardPaymentMethodsController.getFiatPaymentMethods(); tradeWizardSelectOfferController.setFiatPaymentMethods(fiatPaymentMethods); - tradeWizardAmountController.setFiatPaymentMethods(fiatPaymentMethods); + tradeWizardAmountAndPriceController.setFiatPaymentMethods(fiatPaymentMethods); tradeWizardReviewController.setFiatPaymentMethods(fiatPaymentMethods); } private void handleBitcoinPaymentMethodsUpdate() { ObservableList bitcoinPaymentMethods = tradeWizardPaymentMethodsController.getBitcoinPaymentMethods(); tradeWizardSelectOfferController.setBitcoinPaymentMethods(bitcoinPaymentMethods); - tradeWizardAmountController.setBitcoinPaymentMethods(bitcoinPaymentMethods); + tradeWizardAmountAndPriceController.setBitcoinPaymentMethods(bitcoinPaymentMethods); tradeWizardReviewController.setBitcoinPaymentMethods(bitcoinPaymentMethods); } } diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardModel.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardModel.java index dac94ea61c..b22349dccf 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardModel.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardModel.java @@ -39,6 +39,8 @@ public class TradeWizardModel extends NavigationModel { @Setter private boolean isCreateOfferMode; + @Setter + private String amountAtPriceString; private final IntegerProperty currentIndex = new SimpleIntegerProperty(); private final StringProperty nextButtonText = new SimpleStringProperty(); private final StringProperty backButtonText = new SimpleStringProperty(); @@ -46,7 +48,6 @@ public class TradeWizardModel extends NavigationModel { private final BooleanProperty nextButtonVisible = new SimpleBooleanProperty(true); private final BooleanProperty nextButtonDisabled = new SimpleBooleanProperty(true); private final BooleanProperty backButtonVisible = new SimpleBooleanProperty(true); - private final BooleanProperty priceProgressItemVisible = new SimpleBooleanProperty(true); private final List childTargets = new ArrayList<>(); private final ObjectProperty selectedChildTarget = new SimpleObjectProperty<>(); @Setter @@ -62,6 +63,8 @@ public NavigationTarget getDefaultNavigationTarget() { } public void reset() { + isCreateOfferMode = false; + amountAtPriceString = ""; currentIndex.set(0); nextButtonText.set(null); backButtonText.set(null); @@ -69,7 +72,6 @@ public void reset() { nextButtonVisible.set(true); nextButtonDisabled.set(true); backButtonVisible.set(true); - priceProgressItemVisible.set(true); childTargets.clear(); selectedChildTarget.set(null); animateRightOut = true; diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardView.java index ff41e70988..4a20993c29 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardView.java @@ -41,8 +41,6 @@ import javafx.scene.layout.VBox; import javafx.scene.text.TextAlignment; import lombok.extern.slf4j.Slf4j; -import org.fxmisc.easybind.EasyBind; -import org.fxmisc.easybind.Subscription; import java.util.ArrayList; import java.util.List; @@ -57,14 +55,11 @@ public class TradeWizardView extends NavigationView progressLabelList; - private final HBox progressItemsBox; private final Button nextButton, backButton, closeButton; private final VBox content; private final ChangeListener currentIndexListener; private final ChangeListener> viewChangeListener; - private Label priceProgressItemLabel, takeOfferProgressItem; - private Region priceProgressItemLine; - private Subscription priceProgressItemVisiblePin; + private Label takeOfferProgressItem, amountAtPrice; private Region takeOfferProgressLine; private UIScheduler progressLabelAnimationScheduler; private FadeTransition progressLabelAnimation; @@ -76,7 +71,7 @@ public TradeWizardView(TradeWizardModel model, TradeWizardController controller) root.setPrefHeight(POPUP_HEIGHT); Triple> triple = getProgressItems(); - progressItemsBox = triple.getFirst(); + HBox progressItemsBox = triple.getFirst(); closeButton = triple.getSecond(); progressLabelList = triple.getThird(); @@ -121,6 +116,7 @@ public TradeWizardView(TradeWizardModel model, TradeWizardController controller) @Override protected void onViewAttached() { + amountAtPrice.textProperty().set(model.getAmountAtPriceString().toUpperCase()); takeOfferProgressItem.setVisible(!model.isCreateOfferMode()); takeOfferProgressItem.setManaged(!model.isCreateOfferMode()); takeOfferProgressLine.setVisible(!model.isCreateOfferMode()); @@ -143,24 +139,6 @@ protected void onViewAttached() { model.getCurrentIndex().addListener(currentIndexListener); model.getView().addListener(viewChangeListener); - priceProgressItemVisiblePin = EasyBind.subscribe(model.getPriceProgressItemVisible(), isVisible -> { - if (isVisible) { - if (!progressItemsBox.getChildren().contains(priceProgressItemLine)) { - progressItemsBox.getChildren().add(7, priceProgressItemLine); - } - if (!progressItemsBox.getChildren().contains(priceProgressItemLabel)) { - progressItemsBox.getChildren().add(7, priceProgressItemLabel); - } - if (!progressLabelList.contains(priceProgressItemLabel)) { - progressLabelList.add(3, priceProgressItemLabel); - } - } else { - progressItemsBox.getChildren().remove(priceProgressItemLine); - progressItemsBox.getChildren().remove(priceProgressItemLabel); - progressLabelList.remove(priceProgressItemLabel); - } - }); - nextButton.setOnAction(e -> controller.onNext()); backButton.setOnAction(evt -> controller.onBack()); closeButton.setOnAction(e -> controller.onClose()); @@ -186,8 +164,6 @@ protected void onViewDetached() { model.getCurrentIndex().removeListener(currentIndexListener); model.getView().removeListener(viewChangeListener); - priceProgressItemVisiblePin.unsubscribe(); - nextButton.setOnAction(null); backButton.setOnAction(null); closeButton.setOnAction(null); @@ -205,10 +181,7 @@ protected void onViewDetached() { private Triple> getProgressItems() { Label directionAndMarket = createAndGetProgressLabel(Res.get("bisqEasy.tradeWizard.progress.directionAndMarket")); - priceProgressItemLabel = createAndGetProgressLabel(Res.get("bisqEasy.tradeWizard.progress.price")); - priceProgressItemLine = getHLine(); - Label amountAtPrice = createAndGetProgressLabel(Res.get("bisqEasy.tradeWizard.progress.amountAndPrice")); - Label amount = createAndGetProgressLabel(Res.get("bisqEasy.tradeWizard.progress.amount")); + amountAtPrice = createAndGetProgressLabel(""); Label paymentMethods = createAndGetProgressLabel(Res.get("bisqEasy.tradeWizard.progress.paymentMethods")); takeOfferProgressItem = createAndGetProgressLabel(Res.get("bisqEasy.tradeWizard.progress.takeOffer")); takeOfferProgressLine = getHLine(); @@ -228,8 +201,6 @@ private Triple> getProgressItems() { getHLine(), amountAtPrice, getHLine(), - amount, - getHLine(), paymentMethods, takeOfferProgressLine, takeOfferProgressItem, @@ -238,7 +209,7 @@ private Triple> getProgressItems() { Spacer.fillHBox(), closeButton); - return new Triple<>(hBox, closeButton, new ArrayList<>(List.of(directionAndMarket, amountAtPrice, amount, + return new Triple<>(hBox, closeButton, new ArrayList<>(List.of(directionAndMarket, amountAtPrice, paymentMethods, takeOfferProgressItem, review))); } diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java index 3ff796cf80..9e1da45bf9 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java @@ -202,9 +202,6 @@ public void onActivate() { if (model.getPriceQuote().get() == null && amountSelectionController.getQuote().get() != null) { model.getPriceQuote().set(amountSelectionController.getQuote().get()); } - model.setHeadline(model.getDirection().isBuy() - ? Res.get("bisqEasy.tradeWizard.amount.headline.buyer") - : Res.get("bisqEasy.tradeWizard.amount.headline.seller")); Boolean cookieValue = settingsService.getCookie().asBoolean(CookieKey.CREATE_BISQ_EASY_OFFER_IS_MIN_AMOUNT_ENABLED).orElse(false); model.getIsRangeAmountEnabled().set(cookieValue && model.getShowRangeAmounts().get()); diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountModel.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountModel.java index 94e8bd8d75..2dc8e15584 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountModel.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountModel.java @@ -49,8 +49,6 @@ public class TradeWizardAmountModel implements Model { private List bitcoinPaymentMethods = new ArrayList<>(); @Setter private List fiatPaymentMethods = new ArrayList<>(); - @Setter - private String headline; private final StringProperty amountLimitInfo = new SimpleStringProperty(); private final StringProperty amountLimitInfoLeadLine = new SimpleStringProperty(); private final StringProperty amountLimitInfoAmount = new SimpleStringProperty(); @@ -83,7 +81,6 @@ public void reset() { market = MarketRepository.getDefault(); bitcoinPaymentMethods = new ArrayList<>(); fiatPaymentMethods = new ArrayList<>(); - headline = null; amountLimitInfo.set(null); amountLimitInfoAmount.set(null); amountLimitInfoOverlayInfo.set(null); diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java index 41d0e94031..618ecda73b 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java @@ -46,7 +46,7 @@ public class TradeWizardAmountView extends View getQuoteSideAmountSpec() { return tradeWizardAmountController.getQuoteSideAmountSpec(); } + public void setBitcoinPaymentMethods(List bitcoinPaymentMethods) { + tradeWizardAmountController.setBitcoinPaymentMethods(bitcoinPaymentMethods); + } + + public void setFiatPaymentMethods(List fiatPaymentMethods) { + tradeWizardAmountController.setFiatPaymentMethods(fiatPaymentMethods); + } + public boolean validate() { - return tradeWizardAmountController.validate(); + return tradeWizardAmountController.validate() + && tradeWizardPriceController.validate(); } public ReadOnlyObjectProperty getPriceSpec() { return tradeWizardPriceController.getPriceSpec(); } + + private String getHeadline() { + if (model.isCreateOfferMode()) { + return Res.get("bisqEasy.tradeWizard.amountAtPrice.headline"); + } + + return model.getDirection().isBuy() + ? Res.get("bisqEasy.tradeWizard.amount.headline.buyer") + : Res.get("bisqEasy.tradeWizard.amount.headline.seller"); + } } diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceModel.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceModel.java index 7f46fc1bc7..aad35ef4ad 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceModel.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceModel.java @@ -18,14 +18,24 @@ package bisq.desktop.main.content.bisq_easy.trade_wizard.amount_and_price; import bisq.desktop.common.view.Model; +import bisq.offer.Direction; import lombok.Getter; +import lombok.Setter; import lombok.extern.slf4j.Slf4j; +@Setter @Slf4j @Getter public class TradeWizardAmountAndPriceModel implements Model { + private boolean isCreateOfferMode; + private boolean showPriceSelection; + private String headline; + private Direction direction; public void reset() { - + isCreateOfferMode = false; + showPriceSelection = false; + headline = ""; + direction = null; } } diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java index bc2fe12b57..3d626fe936 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java @@ -28,7 +28,8 @@ @Slf4j public class TradeWizardAmountAndPriceView extends View { - + private final Label headline, amountAtPriceSymbol; + private final Pane priceSelection; public TradeWizardAmountAndPriceView(TradeWizardAmountAndPriceModel model, TradeWizardAmountAndPriceController controller, @@ -37,21 +38,25 @@ public TradeWizardAmountAndPriceView(TradeWizardAmountAndPriceModel model, Pane priceSelection) { super(new StackPane(), model, controller); - Label headline = new Label("Headline"); - Label amountAtPriceSymbol = new Label("@"); + this.priceSelection = priceSelection; + headline = new Label(); + amountAtPriceSymbol = new Label("@"); HBox amountAndPriceHBox = new HBox(amountSelection, amountAtPriceSymbol, priceSelection); - VBox contentVBox = new VBox(20, /*headline,*/ amountAndPriceHBox, infoAndWarningsSection); + VBox contentVBox = new VBox(20, headline, amountAndPriceHBox, infoAndWarningsSection); contentVBox.setAlignment(Pos.TOP_CENTER); root.getChildren().add(contentVBox); } @Override protected void onViewAttached() { - + headline.textProperty().set(model.getHeadline()); + amountAtPriceSymbol.visibleProperty().set(model.isShowPriceSelection()); + amountAtPriceSymbol.managedProperty().set(model.isShowPriceSelection()); + priceSelection.visibleProperty().set(model.isShowPriceSelection()); + priceSelection.managedProperty().set(model.isShowPriceSelection()); } @Override protected void onViewDetached() { - } } diff --git a/bisq-easy/src/main/java/bisq/bisq_easy/NavigationTarget.java b/bisq-easy/src/main/java/bisq/bisq_easy/NavigationTarget.java index 9d095d47af..814716eab8 100644 --- a/bisq-easy/src/main/java/bisq/bisq_easy/NavigationTarget.java +++ b/bisq-easy/src/main/java/bisq/bisq_easy/NavigationTarget.java @@ -53,8 +53,6 @@ public enum NavigationTarget { TRADE_WIZARD(OVERLAY, false), TRADE_WIZARD_DIRECTION_AND_MARKET(TRADE_WIZARD, false), TRADE_WIZARD_AMOUNT_AND_PRICE(TRADE_WIZARD, false), - TRADE_WIZARD_PRICE(TRADE_WIZARD, false), - TRADE_WIZARD_AMOUNT(TRADE_WIZARD, false), TRADE_WIZARD_PAYMENT_METHODS(TRADE_WIZARD, false), TRADE_WIZARD_TAKE_OFFER_OFFER(TRADE_WIZARD, false), TRADE_WIZARD_REVIEW_OFFER(TRADE_WIZARD, false), diff --git a/i18n/src/main/resources/bisq_easy.properties b/i18n/src/main/resources/bisq_easy.properties index 541b4a88a1..69363dc8b6 100644 --- a/i18n/src/main/resources/bisq_easy.properties +++ b/i18n/src/main/resources/bisq_easy.properties @@ -52,9 +52,8 @@ bisqEasy.onboarding.right.button=Open offerbook ################################################################################ bisqEasy.tradeWizard.progress.directionAndMarket=Offer type -bisqEasy.tradeWizard.progress.amountAndPrice=Amount @ price -bisqEasy.tradeWizard.progress.price=Price -bisqEasy.tradeWizard.progress.amount=Amount +bisqEasy.tradeWizard.progress.amountAndPrice.createOffer=Amount @ price +bisqEasy.tradeWizard.progress.amountAndPrice.selectOffer=Amount bisqEasy.tradeWizard.progress.paymentMethods=Payment methods bisqEasy.tradeWizard.progress.takeOffer=Select offer bisqEasy.tradeWizard.progress.review=Review @@ -93,6 +92,13 @@ bisqEasy.tradeWizard.market.columns.numOffers=Num. offers bisqEasy.tradeWizard.market.columns.numPeers=Online peers +################################################################################ +# Create offer / Amount @ Price +################################################################################ + +bisqEasy.tradeWizard.amountAtPrice.headline=What amount and price do you want to trade at? + + ################################################################################ # Create offer / Price ################################################################################ From c1d1bf3b71fde86f1a9f2d2ea8bfd510db53cc8f Mon Sep 17 00:00:00 2001 From: axpoems <145597137+axpoems@users.noreply.github.com> Date: Tue, 17 Dec 2024 16:37:07 +0100 Subject: [PATCH 25/33] Fix overlapping issues --- .../amount_selection/AmountSelectionView.java | 2 + .../amount/TradeWizardAmountView.java | 7 +-- .../TradeWizardAmountAndPriceView.java | 20 +++++--- .../price/TradeWizardPriceView.java | 9 ++-- .../src/main/resources/css/bisq_easy.css | 49 ++++++++++++++++--- 5 files changed, 64 insertions(+), 23 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java index 5f15cdbcfd..2f18f13bc8 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java @@ -182,8 +182,10 @@ public class AmountSelectionView extends View { +public class TradeWizardAmountView extends View { private static final String SELECTED_PRICE_MODEL_STYLE_CLASS = "selected-model"; private final AmountSelectionController amountSelectionController; @@ -58,7 +58,7 @@ public class TradeWizardAmountView extends View { private final Label headline, amountAtPriceSymbol; - private final Pane priceSelection; + private final VBox priceSelection; public TradeWizardAmountAndPriceView(TradeWizardAmountAndPriceModel model, TradeWizardAmountAndPriceController controller, - Pane amountSelection, + VBox amountSelection, Pane infoAndWarningsSection, - Pane priceSelection) { + VBox priceSelection) { super(new StackPane(), model, controller); this.priceSelection = priceSelection; headline = new Label(); + headline.getStyleClass().add("bisq-text-headline-2"); amountAtPriceSymbol = new Label("@"); - HBox amountAndPriceHBox = new HBox(amountSelection, amountAtPriceSymbol, priceSelection); + amountAtPriceSymbol.getStyleClass().add("amount-at-price-symbol"); + + HBox amountAndPriceHBox = new HBox(30, amountSelection, amountAtPriceSymbol, priceSelection); + amountAndPriceHBox.getStyleClass().add("amount-and-price-box"); + VBox contentVBox = new VBox(20, headline, amountAndPriceHBox, infoAndWarningsSection); - contentVBox.setAlignment(Pos.TOP_CENTER); - root.getChildren().add(contentVBox); + contentVBox.getStyleClass().add("content-box"); + + root.getChildren().addAll(contentVBox); + root.getStyleClass().add("amount-and-price-step"); } @Override diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/price/TradeWizardPriceView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/price/TradeWizardPriceView.java index 6a2540cf73..19d741d17d 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/price/TradeWizardPriceView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/price/TradeWizardPriceView.java @@ -20,7 +20,6 @@ import bisq.desktop.common.Transitions; import bisq.desktop.common.threading.UIScheduler; import bisq.desktop.common.view.View; -import bisq.desktop.components.controls.MaterialTextField; import bisq.desktop.components.controls.UnorderedList; import bisq.desktop.components.controls.validator.PercentageValidator; import bisq.desktop.main.content.bisq_easy.components.PriceInput; @@ -34,7 +33,6 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; -import javafx.scene.text.TextAlignment; import lombok.extern.slf4j.Slf4j; import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.Subscription; @@ -81,9 +79,9 @@ public TradeWizardPriceView(TradeWizardPriceModel model, TradeWizardPriceControl percentageInput.textInputSymbolTextProperty().set("%"); fieldsBox = new VBox(20); fieldsBox.setAlignment(Pos.TOP_CENTER); - fieldsBox.setMinWidth(350); - fieldsBox.setPrefWidth(350); - fieldsBox.setMaxWidth(350); + fieldsBox.setMinWidth(340); + fieldsBox.setPrefWidth(340); + fieldsBox.setMaxWidth(340); // Feedback sentence feedbackSentence = new Label(); @@ -102,6 +100,7 @@ public TradeWizardPriceView(TradeWizardPriceModel model, TradeWizardPriceControl StackPane layeredContent = new StackPane(content, learnWhyOverlay); layeredContent.getStyleClass().add("bisq-easy-trade-wizard-price-step"); root.getChildren().addAll(layeredContent); + root.getStyleClass().add("bisq-easy-trade-wizard-price-step-pane"); } @Override diff --git a/apps/desktop/desktop/src/main/resources/css/bisq_easy.css b/apps/desktop/desktop/src/main/resources/css/bisq_easy.css index cc927869ff..e3f36dc2b4 100644 --- a/apps/desktop/desktop/src/main/resources/css/bisq_easy.css +++ b/apps/desktop/desktop/src/main/resources/css/bisq_easy.css @@ -716,6 +716,38 @@ * * ******************************************************************************/ +.amount-and-price-step { + -fx-alignment: top-center; + -fx-spacing: 50; +} + +.amount-and-price-step .amount-and-price-box { + -fx-alignment: top-center; +} + +.bisq-easy-trade-wizard-amount-step-pane, +.bisq-easy-trade-wizard-price-step-pane { + -fx-pref-width: 340; + -fx-max-width: 340; + -fx-min-width: 340; +} + +.amount-and-price-step .content-box { + -fx-padding: 20 0 0 0; + -fx-max-height: 340; + -fx-min-height: 340; + -fx-alignment: top-center; +} + +.amount-and-price-step .amount-at-price-symbol { + -fx-padding: 93 0 0 0; + -fx-fill: -fx-mid-text-color; + -fx-text-fill: -fx-mid-text-color; + -fx-font-size: 3.5em; + -fx-font-family: "IBM Plex Sans Thin"; + -fx-alignment: center; +} + .amount-selection .description { -fx-fill: -fx-mid-text-color; -fx-text-fill: -fx-mid-text-color; @@ -1001,7 +1033,8 @@ -fx-font-size: 0.8em; } -.bisq-easy-trade-wizard-amount-step { +.bisq-easy-trade-wizard-amount-step, +.bisq-easy-trade-wizard-price-step { -fx-max-width: 340; -fx-min-width: 340; -fx-pref-width: 340; @@ -1064,19 +1097,18 @@ .bisq-easy-trade-wizard-price-step .price-content { -fx-alignment: center; + -fx-max-width: 340; + -fx-min-width: 340; + -fx-pref-width: 340; } .bisq-easy-trade-wizard-price-step .selection-models, .bisq-easy-trade-wizard-amount-step .selection-models { -fx-alignment: center; -fx-padding: 10 0 10 0; -} - -.bisq-easy-trade-wizard-price-step .selection-models .model-selection-item-box, -.bisq-easy-trade-wizard-amount-step .selection-models .model-selection-item-box { - -fx-max-width: 300; - -fx-min-width: 300; - -fx-pref-width: 300; + -fx-max-width: 340; + -fx-min-width: 340; + -fx-pref-width: 340; } .bisq-easy-trade-wizard-price-step .selection-models .model-selection-item-box .model-selection-item, @@ -1085,6 +1117,7 @@ -fx-background-color: transparent; -fx-fill: -fx-mid-text-color; -fx-text-fill: -fx-mid-text-color; + -fx-font-size: 1em; } .bisq-easy-trade-wizard-price-step .selected-model, From c60542784cca2b1c189b7e3d68b53660bc7a1d5b Mon Sep 17 00:00:00 2001 From: axpoems <145597137+axpoems@users.noreply.github.com> Date: Tue, 17 Dec 2024 17:32:32 +0100 Subject: [PATCH 26/33] Open overlay from amountAtPrice --- .../amount/TradeWizardAmountController.java | 5 ++ .../amount/TradeWizardAmountView.java | 50 ++++--------------- .../TradeWizardAmountAndPriceController.java | 4 +- .../TradeWizardAmountAndPriceModel.java | 4 ++ .../TradeWizardAmountAndPriceView.java | 38 +++++++++++--- .../src/main/resources/css/bisq_easy.css | 3 -- 6 files changed, 52 insertions(+), 52 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java index 9e1da45bf9..1c613ffd69 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountController.java @@ -60,6 +60,7 @@ import bisq.user.profile.UserProfile; import bisq.user.profile.UserProfileService; import bisq.user.reputation.ReputationService; +import javafx.beans.property.ReadOnlyBooleanProperty; import javafx.beans.property.ReadOnlyObjectProperty; import javafx.scene.layout.Region; import lombok.Getter; @@ -195,6 +196,10 @@ public ReadOnlyObjectProperty getQuoteSideAmountSpec() { return model.getQuoteSideAmountSpec(); } + public ReadOnlyBooleanProperty getIsAmountOverlayVisible() { + return model.getIsAmountLimitInfoOverlayVisible(); + } + @Override public void onActivate() { applyQuoteSideMinMaxRange(); diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java index b7c3b97fc5..0cdcb02e0e 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount/TradeWizardAmountView.java @@ -20,12 +20,10 @@ import bisq.common.util.StringUtils; import bisq.desktop.common.Browser; import bisq.desktop.common.Icons; -import bisq.desktop.common.Transitions; import bisq.desktop.common.view.View; import bisq.desktop.components.containers.Spacer; import bisq.desktop.components.controls.BisqTooltip; import bisq.desktop.main.content.bisq_easy.components.amount_selection.AmountSelectionController; -import bisq.desktop.main.content.bisq_easy.trade_wizard.TradeWizardView; import bisq.i18n.Res; import de.jensd.fx.fontawesome.AwesomeIcon; import javafx.geometry.Insets; @@ -34,7 +32,6 @@ import javafx.scene.control.Hyperlink; import javafx.scene.control.Label; import javafx.scene.layout.HBox; -import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -48,17 +45,18 @@ public class TradeWizardAmountView extends View { - if (isAmountLimitInfoVisible) { - amountLimitInfoOverlay.setVisible(true); - amountLimitInfoOverlay.setOpacity(1); - Transitions.blurStrong(content, 0); - Transitions.slideInTop(amountLimitInfoOverlay, 450); - } else { - Transitions.removeEffect(content); - if (amountLimitInfoOverlay.isVisible()) { - Transitions.fadeOut(amountLimitInfoOverlay, Transitions.DEFAULT_DURATION / 2, - () -> amountLimitInfoOverlay.setVisible(false)); - } - } - }); - isRangeAmountEnabledPin = EasyBind.subscribe(model.getIsRangeAmountEnabled(), isRangeAmountEnabled -> { fixedAmount.getStyleClass().remove(SELECTED_PRICE_MODEL_STYLE_CLASS); rangeAmount.getStyleClass().remove(SELECTED_PRICE_MODEL_STYLE_CLASS); @@ -209,7 +180,6 @@ protected void onViewDetached() { amountModelsBox.managedProperty().unbind(); amountLimitInfoLeadLinePin.unsubscribe(); - isAmountLimitInfoVisiblePin.unsubscribe(); isRangeAmountEnabledPin.unsubscribe(); amountLimitInfoAmount.setOnAction(null); diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceController.java index 2c4cef1a36..29854ca6d9 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceController.java @@ -37,7 +37,6 @@ @Slf4j public class TradeWizardAmountAndPriceController implements Controller { - private final TradeWizardAmountAndPriceModel model; @Getter private final TradeWizardAmountAndPriceView view; @@ -55,16 +54,19 @@ public TradeWizardAmountAndPriceController(ServiceProvider serviceProvider, Regi this, tradeWizardAmountController.getView().getRoot(), tradeWizardAmountController.getView().getAmountLimitInfoWithWarnIcon(), + tradeWizardAmountController.getView().getAmountLimitInfoOverlay(), tradeWizardPriceController.getView().getRoot()); } @Override public void onActivate() { model.setHeadline(getHeadline()); + model.getIsAmountOverlayVisible().bind(tradeWizardAmountController.getIsAmountOverlayVisible()); } @Override public void onDeactivate() { + model.getIsAmountOverlayVisible().unbind(); } public void reset() { diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceModel.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceModel.java index aad35ef4ad..a6e32a3db3 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceModel.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceModel.java @@ -19,6 +19,8 @@ import bisq.desktop.common.view.Model; import bisq.offer.Direction; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; @@ -31,11 +33,13 @@ public class TradeWizardAmountAndPriceModel implements Model { private boolean showPriceSelection; private String headline; private Direction direction; + private final BooleanProperty isAmountOverlayVisible = new SimpleBooleanProperty(); public void reset() { isCreateOfferMode = false; showPriceSelection = false; headline = ""; direction = null; + isAmountOverlayVisible.set(false); } } diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java index 984534b518..01ad37309c 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java @@ -17,26 +17,31 @@ package bisq.desktop.main.content.bisq_easy.trade_wizard.amount_and_price; +import bisq.desktop.common.Transitions; import bisq.desktop.common.view.View; import javafx.scene.control.Label; import javafx.scene.layout.HBox; -import javafx.scene.layout.Pane; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import lombok.extern.slf4j.Slf4j; +import org.fxmisc.easybind.EasyBind; +import org.fxmisc.easybind.Subscription; @Slf4j -public class TradeWizardAmountAndPriceView extends View { +public class TradeWizardAmountAndPriceView extends View { private final Label headline, amountAtPriceSymbol; - private final VBox priceSelection; + private final VBox priceSelection, content, amountOverlay; + private Subscription isAmountOverlayVisiblePin; public TradeWizardAmountAndPriceView(TradeWizardAmountAndPriceModel model, TradeWizardAmountAndPriceController controller, VBox amountSelection, - Pane infoAndWarningsSection, + HBox infoAndWarningsSection, + VBox amountOverlay, VBox priceSelection) { - super(new StackPane(), model, controller); + super(new VBox(), model, controller); + this.amountOverlay = amountOverlay; this.priceSelection = priceSelection; headline = new Label(); headline.getStyleClass().add("bisq-text-headline-2"); @@ -46,10 +51,11 @@ public TradeWizardAmountAndPriceView(TradeWizardAmountAndPriceModel model, HBox amountAndPriceHBox = new HBox(30, amountSelection, amountAtPriceSymbol, priceSelection); amountAndPriceHBox.getStyleClass().add("amount-and-price-box"); - VBox contentVBox = new VBox(20, headline, amountAndPriceHBox, infoAndWarningsSection); - contentVBox.getStyleClass().add("content-box"); + content = new VBox(10, headline, amountAndPriceHBox, infoAndWarningsSection); + content.getStyleClass().add("content-box"); - root.getChildren().addAll(contentVBox); + StackPane layeredContent = new StackPane(content, amountOverlay); + root.getChildren().addAll(layeredContent); root.getStyleClass().add("amount-and-price-step"); } @@ -60,9 +66,25 @@ protected void onViewAttached() { amountAtPriceSymbol.managedProperty().set(model.isShowPriceSelection()); priceSelection.visibleProperty().set(model.isShowPriceSelection()); priceSelection.managedProperty().set(model.isShowPriceSelection()); + + isAmountOverlayVisiblePin = EasyBind.subscribe(model.getIsAmountOverlayVisible(), isAmountOverlayVisible -> { + if (isAmountOverlayVisible) { + amountOverlay.setVisible(true); + amountOverlay.setOpacity(1); + Transitions.blurStrong(content, 0); + Transitions.slideInTop(amountOverlay, 450); + } else { + Transitions.removeEffect(content); + if (amountOverlay.isVisible()) { + Transitions.fadeOut(amountOverlay, Transitions.DEFAULT_DURATION / 2, + () -> amountOverlay.setVisible(false)); + } + } + }); } @Override protected void onViewDetached() { + isAmountOverlayVisiblePin.unsubscribe(); } } diff --git a/apps/desktop/desktop/src/main/resources/css/bisq_easy.css b/apps/desktop/desktop/src/main/resources/css/bisq_easy.css index e3f36dc2b4..19414afbc9 100644 --- a/apps/desktop/desktop/src/main/resources/css/bisq_easy.css +++ b/apps/desktop/desktop/src/main/resources/css/bisq_easy.css @@ -725,7 +725,6 @@ -fx-alignment: top-center; } -.bisq-easy-trade-wizard-amount-step-pane, .bisq-easy-trade-wizard-price-step-pane { -fx-pref-width: 340; -fx-max-width: 340; @@ -734,8 +733,6 @@ .amount-and-price-step .content-box { -fx-padding: 20 0 0 0; - -fx-max-height: 340; - -fx-min-height: 340; -fx-alignment: top-center; } From 3b3331f523fe7561cc039b85fda51798d7548e01 Mon Sep 17 00:00:00 2001 From: axpoems <145597137+axpoems@users.noreply.github.com> Date: Tue, 17 Dec 2024 17:44:34 +0100 Subject: [PATCH 27/33] Fix range amount focus --- .../amount_selection/AmountSelectionView.java | 44 ++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java index 2f18f13bc8..67050ab57b 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java @@ -24,7 +24,6 @@ import bisq.desktop.main.content.bisq_easy.components.amount_selection.amount_input.BigAmountInput; import bisq.desktop.main.content.bisq_easy.components.amount_selection.amount_input.SmallAmountInput; import bisq.i18n.Res; -import javafx.beans.property.ReadOnlyBooleanProperty; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Parent; @@ -197,20 +196,35 @@ protected void onViewAttached() { UIScheduler.run(() -> { maxOrFixedQuoteAmount.requestFocus(); maxOrFixedBaseAmountFocusPin = EasyBind.subscribe(maxOrFixedBaseAmount.focusedProperty(), - focus -> onInputTextFieldFocus(maxOrFixedQuoteAmount.focusedProperty(), focus)); + focus -> onInputTextFieldFocus( + maxOrFixedQuoteAmount.focusedProperty().get() + || minQuoteAmount.focusedProperty().get() + || minBaseAmount.focusedProperty().get() + , focus)); maxOrFixedQuoteAmountFocusPin = EasyBind.subscribe(maxOrFixedQuoteAmount.focusedProperty(), - focus -> onInputTextFieldFocus(maxOrFixedBaseAmount.focusedProperty(), focus)); + focus -> onInputTextFieldFocus( + maxOrFixedBaseAmount.focusedProperty().get() + || minQuoteAmount.focusedProperty().get() + || minBaseAmount.focusedProperty().get() + , focus)); minBaseAmountFocusPin = EasyBind.subscribe(minBaseAmount.focusedProperty(), - focus -> onInputTextFieldFocus(minQuoteAmount.focusedProperty(), focus)); + focus -> onInputTextFieldFocus( + minQuoteAmount.focusedProperty().get() + || maxOrFixedQuoteAmount.focusedProperty().get() + || maxOrFixedBaseAmount.focusedProperty().get() + , focus)); minQuoteAmountFocusPin = EasyBind.subscribe(minQuoteAmount.focusedProperty(), - focus -> onInputTextFieldFocus(minBaseAmount.focusedProperty(), focus)); + focus -> onInputTextFieldFocus(minBaseAmount.focusedProperty().get() + || maxOrFixedQuoteAmount.focusedProperty().get() + || maxOrFixedBaseAmount.focusedProperty().get() + , focus)); maxOrFixedQuoteAmountLengthPin = EasyBind.subscribe(maxOrFixedQuoteAmount.lengthProperty(), length -> { - applyFontStyle(); - applyPrefWidth(); + applyTextInputFontStyle(); + applyTextInputPrefWidth(); }); minQuoteAmountLengthPin = EasyBind.subscribe(minQuoteAmount.lengthProperty(), length -> { - applyFontStyle(); - applyPrefWidth(); + applyTextInputFontStyle(); + applyTextInputPrefWidth(); }); }).after(700); @@ -218,8 +232,8 @@ protected void onViewAttached() { root.getStyleClass().clear(); root.getStyleClass().add("amount-selection"); root.getStyleClass().add(isRangeAmountEnabled ? "range-amount" : "fixed-amount"); - applyFontStyle(); - applyPrefWidth(); + applyTextInputFontStyle(); + applyTextInputPrefWidth(); }); sliderTrackStylePin = EasyBind.subscribe(model.getSliderTrackStyle(), maxOrFixedAmountSlider::setStyle); @@ -306,19 +320,19 @@ protected void onViewDetached() { } } - private void onInputTextFieldFocus(ReadOnlyBooleanProperty other, boolean focus) { + private void onInputTextFieldFocus(boolean isOtherFocused, boolean focus) { if (focus) { selectionLine.setPrefWidth(0); selectionLine.setOpacity(1); Transitions.animateWidth(selectionLine, AMOUNT_BOX_WIDTH + 40); - } else if (!other.get()) { + } else if (!isOtherFocused) { // If switching between the 2 fields we want to avoid to get the fadeout called that's why // we do the check with !other.get() Transitions.fadeOut(selectionLine, 200); } } - private void applyPrefWidth() { + private void applyTextInputPrefWidth() { int charCount = model.getIsRangeAmountEnabled().get() ? minQuoteAmount.getTextInputLength() + maxOrFixedQuoteAmount.getTextInputLength() + 1 // for the dash : maxOrFixedQuoteAmount.getTextInputLength(); @@ -330,7 +344,7 @@ private void applyPrefWidth() { maxOrFixedQuoteAmount.setTextInputPrefWidth(length == 0 ? 1 : length * getFontCharWidth(charCount)); } - private void applyFontStyle() { + private void applyTextInputFontStyle() { quoteAmountSelectionHBox.getStyleClass().clear(); quoteAmountSelectionHBox.getStyleClass().add("quote-amount"); From cba1fb4d450a83378d8879f3ea166674c66f9a2f Mon Sep 17 00:00:00 2001 From: axpoems <145597137+axpoems@users.noreply.github.com> Date: Tue, 17 Dec 2024 18:21:23 +0100 Subject: [PATCH 28/33] Add style improvements --- .../components/amount_selection/AmountSelectionView.java | 4 ++-- .../amount_and_price/TradeWizardAmountAndPriceView.java | 2 +- apps/desktop/desktop/src/main/resources/css/bisq_easy.css | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java index 67050ab57b..f2b65b2015 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java @@ -136,9 +136,9 @@ public class AmountSelectionView extends View Date: Wed, 18 Dec 2024 10:51:10 +0100 Subject: [PATCH 29/33] Remove min/max labels in slider --- .../amount_selection/AmountSelectionView.java | 10 +--------- .../desktop/src/main/resources/css/bisq_easy.css | 7 +------ 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java index f2b65b2015..6cbeed6dea 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java @@ -163,10 +163,6 @@ public class AmountSelectionView extends View Date: Wed, 18 Dec 2024 11:32:10 +0100 Subject: [PATCH 30/33] Fix position of slider indicators --- .../amount_selection/AmountSelectionView.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java index 6cbeed6dea..031898cf94 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/amount_selection/AmountSelectionView.java @@ -23,7 +23,6 @@ import bisq.desktop.components.containers.Spacer; import bisq.desktop.main.content.bisq_easy.components.amount_selection.amount_input.BigAmountInput; import bisq.desktop.main.content.bisq_easy.components.amount_selection.amount_input.SmallAmountInput; -import bisq.i18n.Res; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Parent; @@ -42,6 +41,8 @@ public class AmountSelectionView extends View { public final static int AMOUNT_BOX_WIDTH = 300; public final static int AMOUNT_BOX_HEIGHT = 120; + private final static Insets SLIDER_INDICATORS_RANGE_MARGIN = new Insets(-15, 0, 0, 0); + private final static Insets SLIDER_INDICATORS_FIXED_MARGIN = new Insets(2.5, 0, 0, 0); private final static String INPUT_TEXT_9_STYLE_CLASS = "input-text-9"; private final static String INPUT_TEXT_10_STYLE_CLASS = "input-text-10"; private final static String INPUT_TEXT_11_STYLE_CLASS = "input-text-11"; @@ -54,7 +55,7 @@ public class AmountSelectionView extends View Date: Wed, 18 Dec 2024 12:22:12 +0100 Subject: [PATCH 31/33] Fix issue with percentage price not sticking --- .../bisq_easy/components/PriceInputBox.java | 12 ++---------- .../trade_wizard/price/TradeWizardPriceView.java | 15 +++++++++++---- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInputBox.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInputBox.java index 04105fd7c1..70ed552666 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInputBox.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/components/PriceInputBox.java @@ -71,11 +71,11 @@ public PriceInputBox(String description) { this(description, null); } - void initialize() { + public void initialize() { textInputControl.lengthProperty().addListener(textInputLengthListener); } - void dispose() { + public void dispose() { textInputControl.lengthProperty().removeListener(textInputLengthListener); } @@ -102,14 +102,6 @@ protected double getBgHeight() { return AMOUNT_BOX_HEIGHT; } - @Override - protected void doLayout() { - super.doLayout(); - - setMinWidth(AMOUNT_BOX_WIDTH); - setMaxWidth(AMOUNT_BOX_WIDTH); - } - private static String getFontStyleBasedOnTextLength(int charCount) { if (charCount < 9) { return INPUT_TEXT_9_STYLE_CLASS; diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/price/TradeWizardPriceView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/price/TradeWizardPriceView.java index 19d741d17d..12884de5de 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/price/TradeWizardPriceView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/price/TradeWizardPriceView.java @@ -77,7 +77,7 @@ public TradeWizardPriceView(TradeWizardPriceModel model, TradeWizardPriceControl percentageInput = new PriceInputBox(Res.get("bisqEasy.price.percentage.inputBoxText")); percentageInput.setValidator(new PercentageValidator()); percentageInput.textInputSymbolTextProperty().set("%"); - fieldsBox = new VBox(20); + fieldsBox = new VBox(20, priceInput.getRoot(), percentageInput); fieldsBox.setAlignment(Pos.TOP_CENTER); fieldsBox.setMinWidth(340); fieldsBox.setPrefWidth(340); @@ -108,13 +108,13 @@ protected void onViewAttached() { percentageInput.textProperty().bindBidirectional(model.getPercentageInput()); percentageInput.conversionPriceTextProperty().bind(model.getPriceAsString()); percentageInput.conversionPriceSymbolTextProperty().set(model.getMarket().getMarketCodes()); + percentageInput.initialize(); feedbackSentence.textProperty().bind(model.getFeedbackSentence()); feedbackBox.visibleProperty().bind(model.getShouldShowFeedback()); feedbackBox.managedProperty().bind(model.getShouldShowFeedback()); percentageFocussedPin = EasyBind.subscribe(percentageInput.textInputFocusedProperty(), controller::onPercentageFocussed); - // FIXME: The very first time this component is used when starting the app requestFocus() is not applied. useFixPricePin = EasyBind.subscribe(model.getUseFixPrice(), useFixPrice -> UIScheduler.run(this::updateFieldsBox).after(100)); @@ -149,6 +149,7 @@ protected void onViewAttached() { protected void onViewDetached() { percentageInput.textProperty().unbindBidirectional(model.getPercentageInput()); percentageInput.conversionPriceTextProperty().unbind(); + percentageInput.dispose(); feedbackSentence.textProperty().unbind(); feedbackBox.visibleProperty().unbind(); feedbackBox.managedProperty().unbind(); @@ -174,7 +175,10 @@ private void updateFieldsBox() { percentagePrice.getStyleClass().remove(SELECTED_PRICE_MODEL_STYLE_CLASS); if (model.getUseFixPrice().get()) { fixedPrice.getStyleClass().add(SELECTED_PRICE_MODEL_STYLE_CLASS); - fieldsBox.getChildren().setAll(priceInput.getRoot()); + priceInput.getRoot().visibleProperty().set(true); + priceInput.getRoot().managedProperty().set(true); + percentageInput.visibleProperty().set(false); + percentageInput.managedProperty().set(false); percentageInput.deselect(); percentageInput.setEditable(false); percentageInput.resetValidation(); @@ -182,7 +186,10 @@ private void updateFieldsBox() { priceInput.requestFocus(); } else { percentagePrice.getStyleClass().add(SELECTED_PRICE_MODEL_STYLE_CLASS); - fieldsBox.getChildren().setAll(percentageInput); + priceInput.getRoot().visibleProperty().set(false); + priceInput.getRoot().managedProperty().set(false); + percentageInput.visibleProperty().set(true); + percentageInput.managedProperty().set(true); priceInput.deselect(); priceInput.setEditable(false); priceInput.resetValidation(); From 3f9aac3e56d704f738d6606f7eb5848db9aa7349 Mon Sep 17 00:00:00 2001 From: axpoems <145597137+axpoems@users.noreply.github.com> Date: Wed, 18 Dec 2024 12:53:19 +0100 Subject: [PATCH 32/33] Only apply price spec in select offer wizard --- .../bisq_easy/trade_wizard/TradeWizardController.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardController.java index a9d79df844..8329cee4a7 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/TradeWizardController.java @@ -151,8 +151,10 @@ public void onActivate() { tradeWizardSelectOfferController::setQuoteSideAmountSpec); priceSpecPin = EasyBind.subscribe(tradeWizardAmountAndPriceController.getPriceSpec(), priceSpec -> { - tradeWizardAmountAndPriceController.updateQuoteSideAmountSpecWithPriceSpec(priceSpec); - tradeWizardSelectOfferController.setPriceSpec(priceSpec); + if (!model.isCreateOfferMode()) { + tradeWizardAmountAndPriceController.updateQuoteSideAmountSpecWithPriceSpec(priceSpec); + tradeWizardSelectOfferController.setPriceSpec(priceSpec); + } }); selectedBisqEasyOfferPin = EasyBind.subscribe(tradeWizardSelectOfferController.getSelectedBisqEasyOffer(), selectedBisqEasyOffer -> { From dcdeb099b70afb7abcb5b98cf0db4573adc5b079 Mon Sep 17 00:00:00 2001 From: axpoems <145597137+axpoems@users.noreply.github.com> Date: Wed, 18 Dec 2024 13:27:01 +0100 Subject: [PATCH 33/33] Adjust paddings --- .../bisq_easy/take_offer/amount/TakeOfferAmountView.java | 2 +- .../amount_and_price/TradeWizardAmountAndPriceView.java | 2 +- apps/desktop/desktop/src/main/resources/css/bisq_easy.css | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/take_offer/amount/TakeOfferAmountView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/take_offer/amount/TakeOfferAmountView.java index 3225595998..326557365c 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/take_offer/amount/TakeOfferAmountView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/take_offer/amount/TakeOfferAmountView.java @@ -77,7 +77,7 @@ public TakeOfferAmountView(TakeOfferAmountModel model, amountLimitInfoHBox = new HBox(5, warningIcon, amountLimitInfo, amountLimitInfoAmount, learnMore); amountLimitInfoHBox.setAlignment(Pos.BASELINE_CENTER); - VBox.setMargin(headlineLabel, new Insets(-10, 0, 0, 0)); + VBox.setMargin(headlineLabel, new Insets(-10, 0, 40, 0)); VBox.setMargin(amountLimitInfoHBox, new Insets(15, 0, 15, 0)); content.getChildren().addAll(Spacer.fillVBox(), headlineLabel, amountComponentRoot, amountLimitInfoHBox, Spacer.fillVBox()); diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java index fcaef092f7..1fcfe2c392 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/amount_and_price/TradeWizardAmountAndPriceView.java @@ -51,7 +51,7 @@ public TradeWizardAmountAndPriceView(TradeWizardAmountAndPriceModel model, HBox amountAndPriceHBox = new HBox(20, amountSelection, amountAtPriceSymbol, priceSelection); amountAndPriceHBox.getStyleClass().add("amount-and-price-box"); - content = new VBox(10, headline, amountAndPriceHBox, infoAndWarningsSection); + content = new VBox(20, headline, amountAndPriceHBox, infoAndWarningsSection); content.getStyleClass().add("content-box"); StackPane layeredContent = new StackPane(content, amountOverlay); diff --git a/apps/desktop/desktop/src/main/resources/css/bisq_easy.css b/apps/desktop/desktop/src/main/resources/css/bisq_easy.css index 4a82c1331d..046b44b560 100644 --- a/apps/desktop/desktop/src/main/resources/css/bisq_easy.css +++ b/apps/desktop/desktop/src/main/resources/css/bisq_easy.css @@ -732,7 +732,7 @@ } .amount-and-price-step .content-box { - -fx-padding: 20 0 0 0; + -fx-padding: 40 0 0 0; -fx-alignment: top-center; }