diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/MainController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/MainController.java index 996a8e164d..997c686439 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/MainController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/MainController.java @@ -20,6 +20,7 @@ import bisq.application.ApplicationService; import bisq.bisq_easy.NavigationTarget; import bisq.bonded_roles.security_manager.alert.AlertService; +import bisq.bonded_roles.security_manager.alert.AlertType; import bisq.bonded_roles.security_manager.alert.AuthorizedAlertData; import bisq.common.observable.collection.CollectionObserver; import bisq.desktop.ServiceProvider; @@ -28,6 +29,7 @@ import bisq.desktop.common.view.Navigation; import bisq.desktop.common.view.NavigationController; import bisq.desktop.components.overlay.Popup; +import bisq.desktop.main.alert.AlertBannerController; import bisq.desktop.main.content.ContentController; import bisq.desktop.main.left.LeftNavController; import bisq.desktop.main.notification.NotificationPanelController; @@ -53,6 +55,7 @@ public class MainController extends NavigationController { private final SettingsService settingsService; private final UpdaterService updaterService; private final ApplicationService.Config config; + private final AlertBannerController alertBannerController; public MainController(ServiceProvider serviceProvider) { super(NavigationTarget.MAIN); @@ -66,11 +69,13 @@ public MainController(ServiceProvider serviceProvider) { leftNavController = new LeftNavController(serviceProvider); TopPanelController topPanelController = new TopPanelController(serviceProvider); NotificationPanelController notificationPanelController = new NotificationPanelController(serviceProvider); + alertBannerController = new AlertBannerController(); view = new MainView(model, this, leftNavController.getView().getRoot(), topPanelController.getView().getRoot(), - notificationPanelController.getView().getRoot()); + notificationPanelController.getView().getRoot(), + alertBannerController.getView().getRoot()); } @Override @@ -105,18 +110,12 @@ public void add(AuthorizedAlertData authorizedAlertData) { } settingsService.getConsumedAlertIds().add(authorizedAlertData.getId()); Optional optionalMessage = authorizedAlertData.getMessage(); - switch (authorizedAlertData.getAlertType()) { - case INFO: - optionalMessage.ifPresentOrElse(message -> new Popup().attention(message).show(), - () -> log.warn("optionalMessage not present")); - break; - case WARN: - case EMERGENCY: - optionalMessage.ifPresentOrElse(message -> new Popup().warning(message).show(), - () -> log.warn("optionalMessage not present")); - break; - case BAN: - break; + + if (optionalMessage.isPresent()) { + log.info("Showing alert with message {}", optionalMessage.get()); + alertBannerController.showAlert(optionalMessage.get(), authorizedAlertData.getAlertType()); + } else { + log.warn("optionalMessage not present"); } }); } diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/MainView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/MainView.java index 125f1099a9..adbe2827f7 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/MainView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/MainView.java @@ -34,12 +34,13 @@ public MainView(MainModel model, MainController controller, AnchorPane leftNav, HBox topPanel, - BorderPane notificationPanel) { + BorderPane notificationPanel, + BorderPane alertBanner) { super(new HBox(), model, controller); anchorPane = new AnchorPane(); VBox.setVgrow(anchorPane, Priority.ALWAYS); - VBox vBox = new VBox(topPanel, notificationPanel, anchorPane); + VBox vBox = new VBox(topPanel, notificationPanel, alertBanner, anchorPane); vBox.setFillWidth(true); HBox.setHgrow(vBox, Priority.ALWAYS); diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/alert/AlertBannerController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/alert/AlertBannerController.java new file mode 100644 index 0000000000..169f214abc --- /dev/null +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/alert/AlertBannerController.java @@ -0,0 +1,53 @@ +/* + * 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.alert; + +import bisq.bonded_roles.security_manager.alert.AlertType; +import bisq.desktop.common.view.Controller; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class AlertBannerController implements Controller { + private final AlertBannerModel model; + @Getter + private final AlertBannerView view; + + public AlertBannerController() { + model = new AlertBannerModel(); + view = new AlertBannerView(model, this); + } + + @Override + public void onActivate() { + } + + @Override + public void onDeactivate() { + } + + public void showAlert(String message, AlertType alertType) { + model.getMessage().set(message); + model.getAlertType().set(alertType); + model.getIsAlertVisible().set(true); + } + + void onClose() { + model.getIsAlertVisible().set(false); + } +} diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/alert/AlertBannerModel.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/alert/AlertBannerModel.java new file mode 100644 index 0000000000..f01312828a --- /dev/null +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/alert/AlertBannerModel.java @@ -0,0 +1,33 @@ +/* + * 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.alert; + +import bisq.bonded_roles.security_manager.alert.AlertType; +import bisq.desktop.common.view.Model; +import javafx.beans.property.*; +import lombok.Getter; + +@Getter +public class AlertBannerModel implements Model { + private final BooleanProperty isAlertVisible = new SimpleBooleanProperty(); + private final StringProperty message = new SimpleStringProperty(); + private final ObjectProperty alertType = new SimpleObjectProperty<>(); + + public AlertBannerModel() { + } +} diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/alert/AlertBannerView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/alert/AlertBannerView.java new file mode 100644 index 0000000000..9835a8055b --- /dev/null +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/alert/AlertBannerView.java @@ -0,0 +1,133 @@ +/* + * 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.alert; + +import bisq.bonded_roles.security_manager.alert.AlertType; +import bisq.desktop.common.Transitions; +import bisq.desktop.common.view.View; +import bisq.desktop.components.containers.Spacer; +import bisq.desktop.components.controls.BisqIconButton; +import javafx.animation.Timeline; +import javafx.beans.value.ChangeListener; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.layout.*; +import lombok.extern.slf4j.Slf4j; +import org.fxmisc.easybind.EasyBind; +import org.fxmisc.easybind.Subscription; + +@Slf4j +public class AlertBannerView extends View { + public static final int DURATION = Transitions.DEFAULT_DURATION / 2; + + Label content = new Label(); + private final Button closeButton; + private final HBox banner; + private final ChangeListener contentHeightListener; + private Timeline slideInRightTimeline, slideOutTopTimeline; + private Subscription isVisiblePin, alertTypePin; + + public AlertBannerView(AlertBannerModel model, AlertBannerController controller) { + super(new BorderPane(), model, controller); + + root.setManaged(false); + root.setVisible(false); + + content.setWrapText(true); + + closeButton = BisqIconButton.createIconButton("close-white"); + + banner = new HBox(content, Spacer.fillHBox(), closeButton); + banner.setAlignment(Pos.TOP_CENTER); + banner.setPadding(new Insets(10, 10, 10, 15)); + + contentHeightListener = ((observable, oldValue, newValue) -> banner.setMinHeight(newValue.doubleValue() + 25)); // padding = 25 + + root.setCenter(banner); + root.setPadding(new Insets(20, 40, 20, 40)); + } + + @Override + protected void onViewAttached() { + content.textProperty().bind(model.getMessage()); + + isVisiblePin = EasyBind.subscribe(model.getIsAlertVisible(), isVisible -> { + if (slideInRightTimeline != null) { + slideInRightTimeline.stop(); + slideInRightTimeline = null; + root.setTranslateX(0); + root.setOpacity(1); + } + if (slideOutTopTimeline != null) { + slideOutTopTimeline.stop(); + slideOutTopTimeline = null; + root.setTranslateY(0); + root.setOpacity(0); + root.setManaged(false); + root.setVisible(false); + } + if (isVisible) { + root.setManaged(true); + root.setVisible(true); + root.setTranslateY(0); + slideInRightTimeline = Transitions.slideInRight(root, DURATION, () -> { + }); + } else { + root.setTranslateX(0); + root.setTranslateY(0); + slideOutTopTimeline = Transitions.slideAndFadeOutTop(root, DURATION, () -> { + root.setManaged(false); + root.setVisible(false); + }); + } + }); + + alertTypePin = EasyBind.subscribe(model.getAlertType(), this::addAlertTypeStyleClass); + + content.heightProperty().addListener(contentHeightListener); + + closeButton.setOnAction(e -> controller.onClose()); + } + + @Override + protected void onViewDetached() { + content.textProperty().unbind(); + + isVisiblePin.unsubscribe(); + alertTypePin.unsubscribe(); + + content.heightProperty().removeListener(contentHeightListener); + + closeButton.setOnAction(null); + } + + private void addAlertTypeStyleClass(AlertType alertType) { + banner.getStyleClass().clear(); + String alertTypeClass; + if (alertType == AlertType.INFO) { + alertTypeClass = "info-banner"; + } else if (alertType == AlertType.WARN) { + alertTypeClass = "warn-banner"; + } else { + alertTypeClass = "emergency-banner"; + } + banner.getStyleClass().addAll("alert-banner", alertTypeClass); + } +} diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/offerbook/BisqEasyOfferbookController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/offerbook/BisqEasyOfferbookController.java index f5fe699c02..a63165eead 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/offerbook/BisqEasyOfferbookController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/offerbook/BisqEasyOfferbookController.java @@ -149,6 +149,7 @@ public void onActivate() { settingsService.setCookie(CookieKey.MARKETS_FILTER, model.getSelectedMarketsFilter().get().name()); updateFilteredMarketChannelItems(); } + model.getShouldShowAppliedFilters().set(filter == Filters.Markets.WITH_OFFERS || filter == Filters.Markets.FAVOURITES); }); marketPriceByCurrencyMapPin = marketPriceService.getMarketPriceByCurrencyMap().addObserver(() -> { @@ -320,7 +321,7 @@ private void updateFilteredMarketChannelItems() { private void updateFavouriteMarketChannelItems() { model.getFavouriteMarketChannelItems().setPredicate(item -> model.getFavouriteMarkets().contains(item.getMarket())); - double padding = 15; + double padding = 21; double tableViewHeight = (model.getFavouriteMarketChannelItems().size() * MARKET_SELECTION_LIST_CELL_HEIGHT) + padding; model.getFavouritesTableViewHeight().set(tableViewHeight); } diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/offerbook/BisqEasyOfferbookModel.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/offerbook/BisqEasyOfferbookModel.java index a190ecb4e7..5751562de0 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/offerbook/BisqEasyOfferbookModel.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/offerbook/BisqEasyOfferbookModel.java @@ -38,7 +38,7 @@ public final class BisqEasyOfferbookModel extends ChatModel { private final BooleanProperty offerOnly = new SimpleBooleanProperty(); private final BooleanProperty isTradeChannelVisible = new SimpleBooleanProperty(); - private final BooleanProperty showFilterOverlay = new SimpleBooleanProperty(); // TODO: remove this + private final BooleanProperty shouldShowAppliedFilters = new SimpleBooleanProperty(); private final ObservableList marketChannelItems = FXCollections.observableArrayList(p -> new Observable[]{p.getNumOffers()}); private final FilteredList filteredMarketChannelItems = new FilteredList<>(marketChannelItems); private final SortedList sortedMarketChannelItems = new SortedList<>(filteredMarketChannelItems); diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/offerbook/BisqEasyOfferbookView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/offerbook/BisqEasyOfferbookView.java index aa6e727a86..d9d2473fdb 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/offerbook/BisqEasyOfferbookView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/offerbook/BisqEasyOfferbookView.java @@ -57,19 +57,21 @@ public final class BisqEasyOfferbookView extends ChatView filterShowAll, filterWithOffers; + private DropdownFilterMenuItem filterShowAll, filterWithOffers, filterFavourites; private DropdownFilterMenuItem>> allOffers, myOffers, buyOffers, sellOffers, allReputations, fiveStars, atLeastFourStars, atLeastThreeStars, atLeastTwoStars, atLeastOneStar; private DropdownTitleMenuItem atLeastTitle; private CheckBox hideUserMessagesCheckbox; - private Label channelHeaderIcon, marketPrice, removeWithOffersFilter; - private HBox withOffersDisplayHint; - private ImageView defaultCloseIcon, activeCloseIcon; + private Label channelHeaderIcon, marketPrice, removeWithOffersFilter, removeFavouritesFilter; + private HBox appliedFiltersSection, withOffersDisplayHint, onlyFavouritesDisplayHint; + private ImageView withOffersRemoveFilterDefaultIcon, withOffersRemoveFilterActiveIcon, + favouritesRemoveFilterDefaultIcon, favouritesRemoveFilterActiveIcon; public BisqEasyOfferbookView(BisqEasyOfferbookModel model, BisqEasyOfferbookController controller, @@ -123,11 +125,12 @@ protected void onViewAttached() { marketPrice.textProperty().bind(getModel().getMarketPrice()); withOffersDisplayHint.visibleProperty().bind(getModel().getSelectedMarketsFilter().isEqualTo(Filters.Markets.WITH_OFFERS)); withOffersDisplayHint.managedProperty().bind(getModel().getSelectedMarketsFilter().isEqualTo(Filters.Markets.WITH_OFFERS)); + onlyFavouritesDisplayHint.visibleProperty().bind(getModel().getSelectedMarketsFilter().isEqualTo(Filters.Markets.FAVOURITES)); + onlyFavouritesDisplayHint.managedProperty().bind(getModel().getSelectedMarketsFilter().isEqualTo(Filters.Markets.FAVOURITES)); favouritesTableView.visibleProperty().bind(Bindings.isNotEmpty(getModel().getFavouriteMarketChannelItems())); favouritesTableView.managedProperty().bind(Bindings.isNotEmpty(getModel().getFavouriteMarketChannelItems())); selectedModelItemPin = EasyBind.subscribe(getModel().getSelectedMarketChannelItem(), this::updateTableViewSelection); - marketsTableViewSelectionPin = EasyBind.subscribe(marketsTableView.getSelectionModel().selectedItemProperty(), item -> { if (item != null) { getController().onSelectMarketChannelItem(item); @@ -150,9 +153,10 @@ protected void onViewAttached() { selectedPeerReputationFilterPin = EasyBind.subscribe(getModel().getSelectedPeerReputationFilter(), filter -> updateSelectedFilterInDropdownMenu(filter, filterOffersByPeerReputationMenu)); selectedMarketSortTypePin = EasyBind.subscribe(getModel().getSelectedMarketSortType(), this::updateMarketSortType); - favouritesTableViewHeightPin = EasyBind.subscribe(getModel().getFavouritesTableViewHeight(), height -> updateFavouritesTableViewHeight(height.doubleValue())); + shouldShowAppliedFiltersPin = EasyBind.subscribe(getModel().getShouldShowAppliedFilters(), + this::updateAppliedFiltersSectionStyles); sortByMostOffers.setOnAction(e -> getController().onSortMarkets(MarketSortType.NUM_OFFERS)); sortByNameAZ.setOnAction(e -> getController().onSortMarkets(MarketSortType.ASC)); @@ -160,6 +164,7 @@ protected void onViewAttached() { filterWithOffers.setOnAction(e -> getModel().getSelectedMarketsFilter().set(Filters.Markets.WITH_OFFERS)); filterShowAll.setOnAction(e -> getModel().getSelectedMarketsFilter().set(Filters.Markets.ALL)); + filterFavourites.setOnAction(e -> getModel().getSelectedMarketsFilter().set(Filters.Markets.FAVOURITES)); allOffers.setOnAction(e -> setOfferDirectionOrOwnerFilter(allOffers)); myOffers.setOnAction(e -> setOfferDirectionOrOwnerFilter(myOffers)); @@ -176,8 +181,12 @@ protected void onViewAttached() { createOfferButton.setOnAction(e -> getController().onCreateOffer()); removeWithOffersFilter.setOnMouseClicked(e -> getModel().getSelectedMarketsFilter().set(Filters.Markets.ALL)); - withOffersDisplayHint.setOnMouseEntered(e -> removeWithOffersFilter.setGraphic(activeCloseIcon)); - withOffersDisplayHint.setOnMouseExited(e -> removeWithOffersFilter.setGraphic(defaultCloseIcon)); + withOffersDisplayHint.setOnMouseEntered(e -> removeWithOffersFilter.setGraphic(withOffersRemoveFilterActiveIcon)); + withOffersDisplayHint.setOnMouseExited(e -> removeWithOffersFilter.setGraphic(withOffersRemoveFilterDefaultIcon)); + + removeFavouritesFilter.setOnMouseClicked(e -> getModel().getSelectedMarketsFilter().set(Filters.Markets.ALL)); + onlyFavouritesDisplayHint.setOnMouseEntered(e -> removeFavouritesFilter.setGraphic(favouritesRemoveFilterActiveIcon)); + onlyFavouritesDisplayHint.setOnMouseExited(e -> removeFavouritesFilter.setGraphic(favouritesRemoveFilterDefaultIcon)); } private void updateTableViewSelection(MarketChannelItem selectedItem) { @@ -188,7 +197,9 @@ private void updateTableViewSelection(MarketChannelItem selectedItem) { } private void updateFavouritesTableViewHeight(double height) { + favouritesTableView.setMinHeight(height); favouritesTableView.setPrefHeight(height); + favouritesTableView.setMaxHeight(height); } private void setOfferDirectionOrOwnerFilter(DropdownFilterMenuItem filterMenuItem) { @@ -208,6 +219,8 @@ protected void onViewDetached() { marketPrice.textProperty().unbind(); withOffersDisplayHint.visibleProperty().unbind(); withOffersDisplayHint.managedProperty().unbind(); + onlyFavouritesDisplayHint.visibleProperty().unbind(); + onlyFavouritesDisplayHint.managedProperty().unbind(); favouritesTableView.visibleProperty().unbind(); favouritesTableView.managedProperty().unbind(); @@ -221,12 +234,14 @@ protected void onViewDetached() { selectedPeerReputationFilterPin.unsubscribe(); selectedMarketSortTypePin.unsubscribe(); favouritesTableViewHeightPin.unsubscribe(); + shouldShowAppliedFiltersPin.unsubscribe(); sortByMostOffers.setOnAction(null); sortByNameAZ.setOnAction(null); sortByNameZA.setOnAction(null); filterWithOffers.setOnAction(null); filterShowAll.setOnAction(null); + filterFavourites.setOnAction(null); allOffers.setOnAction(null); myOffers.setOnAction(null); buyOffers.setOnAction(null); @@ -243,6 +258,10 @@ protected void onViewDetached() { withOffersDisplayHint.setOnMouseEntered(null); withOffersDisplayHint.setOnMouseExited(null); + removeFavouritesFilter.setOnMouseClicked(null); + onlyFavouritesDisplayHint.setOnMouseEntered(null); + onlyFavouritesDisplayHint.setOnMouseExited(null); + getModel().getFavouriteMarketChannelItems().removeListener(listChangeListener); } @@ -270,10 +289,29 @@ private void addMarketSelectionList() { subheader.setAlignment(Pos.CENTER); subheader.getStyleClass().add("market-selection-subheader"); - setUpWithOffersFiltersDisplayHint(); - HBox appliedFiltersSection = new HBox(withOffersDisplayHint); + // TODO: Introduce new icons with proper scale + withOffersRemoveFilterDefaultIcon = ImageUtil.getImageViewById("close"); + withOffersRemoveFilterDefaultIcon.setScaleX(0.4); + withOffersRemoveFilterDefaultIcon.setScaleY(0.4); + withOffersRemoveFilterActiveIcon = ImageUtil.getImageViewById("close-white"); + withOffersRemoveFilterActiveIcon.setScaleX(0.4); + withOffersRemoveFilterActiveIcon.setScaleY(0.4); + removeWithOffersFilter = createAndGetRemoveFilterLabel(withOffersRemoveFilterDefaultIcon); + withOffersDisplayHint = createAndGetDisplayHintHBox( + Res.get("bisqEasy.offerbook.dropdownMenu.sortAndFilterMarkets.withOffers"), removeWithOffersFilter); + + favouritesRemoveFilterDefaultIcon = ImageUtil.getImageViewById("close"); + favouritesRemoveFilterDefaultIcon.setScaleX(0.4); + favouritesRemoveFilterDefaultIcon.setScaleY(0.4); + favouritesRemoveFilterActiveIcon = ImageUtil.getImageViewById("close-white"); + favouritesRemoveFilterActiveIcon.setScaleX(0.4); + favouritesRemoveFilterActiveIcon.setScaleY(0.4); + removeFavouritesFilter = createAndGetRemoveFilterLabel(favouritesRemoveFilterDefaultIcon); + onlyFavouritesDisplayHint = createAndGetDisplayHintHBox( + Res.get("bisqEasy.offerbook.dropdownMenu.sortAndFilterMarkets.favourites"), removeFavouritesFilter); + + appliedFiltersSection = new HBox(withOffersDisplayHint, onlyFavouritesDisplayHint); appliedFiltersSection.setAlignment(Pos.CENTER_RIGHT); - appliedFiltersSection.getStyleClass().add("market-selection-applied-filters"); HBox.setHgrow(appliedFiltersSection, Priority.ALWAYS); favouritesTableView = new BisqTableView<>(getModel().getFavouriteMarketChannelItems()); @@ -288,6 +326,7 @@ private void addMarketSelectionList() { marketsTableView.allowVerticalScrollbar(); marketsTableView.hideHorizontalScrollbar(); marketsTableView.setFixedCellSize(getController().getMarketSelectionListCellHeight()); + marketsTableView.setPlaceholder(new Label()); configTableView(marketsTableView); VBox.setVgrow(marketsTableView, Priority.ALWAYS); @@ -299,21 +338,20 @@ private void addMarketSelectionList() { marketSelectionList.getStyleClass().add("chat-container"); } - private void setUpWithOffersFiltersDisplayHint() { - Label withOffersLabel = new Label(Res.get("bisqEasy.offerbook.dropdownMenu.sortAndFilterMarkets.withOffers")); - withOffersLabel.getStyleClass().add("small-text"); - removeWithOffersFilter = new Label(); - defaultCloseIcon = ImageUtil.getImageViewById("close"); - defaultCloseIcon.setScaleX(0.4); - defaultCloseIcon.setScaleY(0.4); - activeCloseIcon = ImageUtil.getImageViewById("close-white"); - activeCloseIcon.setScaleX(0.4); - activeCloseIcon.setScaleY(0.4); - removeWithOffersFilter.setGraphic(defaultCloseIcon); - removeWithOffersFilter.setCursor(Cursor.HAND); - withOffersDisplayHint = new HBox(withOffersLabel, removeWithOffersFilter); - withOffersDisplayHint.setAlignment(Pos.CENTER); - withOffersDisplayHint.getStyleClass().add("filter-display-hint"); + private Label createAndGetRemoveFilterLabel(ImageView defaultCloseIcon) { + Label removeFilterLabel = new Label(); + removeFilterLabel.setGraphic(defaultCloseIcon); + removeFilterLabel.setCursor(Cursor.HAND); + return removeFilterLabel; + } + + private HBox createAndGetDisplayHintHBox(String labelText, Label removeFilter) { + Label label = new Label(labelText); + label.getStyleClass().add("small-text"); + HBox displayHintHBox = new HBox(label, removeFilter); + displayHintHBox.setAlignment(Pos.CENTER); + displayHintHBox.getStyleClass().add("filter-display-hint"); + return displayHintHBox; } private DropdownMenu createAndGetSortAndFilterMarketsMenu() { @@ -342,11 +380,13 @@ private DropdownMenu createAndGetSortAndFilterMarketsMenu() { Res.get("bisqEasy.offerbook.dropdownMenu.sortAndFilterMarkets.filterTitle")); filterWithOffers = new DropdownFilterMenuItem<>("check-white", "check-white", Res.get("bisqEasy.offerbook.dropdownMenu.sortAndFilterMarkets.withOffers"), Filters.Markets.WITH_OFFERS); + filterFavourites = new DropdownFilterMenuItem<>("check-white", "check-white", + Res.get("bisqEasy.offerbook.dropdownMenu.sortAndFilterMarkets.favourites"), Filters.Markets.FAVOURITES); filterShowAll = new DropdownFilterMenuItem<>("check-white", "check-white", Res.get("bisqEasy.offerbook.dropdownMenu.sortAndFilterMarkets.all"), Filters.Markets.ALL); dropdownMenu.addMenuItems(sortTitle, sortByMostOffers, sortByNameAZ, sortByNameZA, separator, filterTitle, - filterWithOffers, filterShowAll); + filterWithOffers, filterFavourites, filterShowAll); return dropdownMenu; } @@ -467,6 +507,8 @@ private void updateSelectedMarketFilter(Filters.Markets marketFilter) { .filter(menuItem -> menuItem instanceof DropdownFilterMenuItem) .map(menuItem -> (DropdownFilterMenuItem) menuItem) .forEach(menuItem -> menuItem.updateSelection(marketFilter == menuItem.getFilter())); + + marketsTableView.getSelectionModel().select(getModel().getSelectedMarketChannelItem().get()); } private void updateMarketSortType(MarketSortType marketSortType) { @@ -500,6 +542,13 @@ private void updateSelectedFilterInDropdownMenu(T selectedFilter, DropdownMe }); } + private void updateAppliedFiltersSectionStyles(boolean shouldShowAppliedFilters) { + appliedFiltersSection.getStyleClass().clear(); + appliedFiltersSection.getStyleClass().add(shouldShowAppliedFilters + ? "market-selection-show-applied-filters" + : "market-selection-no-filters"); + } + private String createPeerReputationLabel(Filters.PeerReputation filter, String label) { switch (filter) { case AT_LEAST_FOUR_STARS: diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/chat/priv/PrivateChatsView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/chat/priv/PrivateChatsView.java index 01fb322a76..1e77507561 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/chat/priv/PrivateChatsView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/chat/priv/PrivateChatsView.java @@ -170,6 +170,7 @@ private void addOpenChatsSelectionList() { tableView = new BisqTableView<>(getModel().getSortedList()); tableView.getStyleClass().add("private-chats-selection-list"); tableView.allowVerticalScrollbar(); + tableView.hideHorizontalScrollbar(); configTableView(); VBox.setVgrow(tableView, Priority.ALWAYS); diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/notification/NotificationPanelView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/notification/NotificationPanelView.java index 8c6245ae21..c5602a5f28 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/notification/NotificationPanelView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/notification/NotificationPanelView.java @@ -36,6 +36,7 @@ @Slf4j public class NotificationPanelView extends View { public static final int DURATION = Transitions.DEFAULT_DURATION / 2; + private final Label notificationHeadline; private final Button closeButton; private final Hyperlink hyperlink; diff --git a/apps/desktop/desktop/src/main/resources/css/application.css b/apps/desktop/desktop/src/main/resources/css/application.css index 2e3b8d2db4..06089c4dce 100644 --- a/apps/desktop/desktop/src/main/resources/css/application.css +++ b/apps/desktop/desktop/src/main/resources/css/application.css @@ -116,9 +116,39 @@ -fx-background-color: -bisq-dark-grey-20; } +/******************************************************************************* + * AlertBanner * + ******************************************************************************/ + +.alert-banner { + -fx-fill: -bisq-dark-grey-50; + -fx-text-fill: -bisq-dark-grey-50; + -fx-font-size: 1.15em; + -fx-font-family: "IBM Plex Sans"; +} + +.info-banner, +.warn-banner, +.emergency-banner { + -fx-background-radius: 8; + -fx-border-color: transparent; +} + +.info-banner { + -fx-background-color: -bisq-mid-grey-10; +} + +.warn-banner { + -fx-background-color: -bisq2-yellow-dim-50; +} + +.emergency-banner { + -fx-background-color: -bisq2-red-dim-50; +} + /******************************************************************************* - * NotificationPane * + * NotificationPane * ******************************************************************************/ .notification-pane { 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 06b08ecdd5..71a6e27f99 100644 --- a/apps/desktop/desktop/src/main/resources/css/bisq_easy.css +++ b/apps/desktop/desktop/src/main/resources/css/bisq_easy.css @@ -217,12 +217,18 @@ -fx-text-fill: -fx-light-text-color; } -.market-selection-applied-filters { +.market-selection-no-filters { + -fx-padding: 10 0 0 0; +} + +.market-selection-show-applied-filters { + -fx-min-height: 35; -fx-pref-height: 35; + -fx-max-height: 35; -fx-padding: 5; } -.market-selection-applied-filters .filter-display-hint { +.market-selection-show-applied-filters .filter-display-hint { -fx-background-color: transparent; -fx-border-color: -bisq-mid-grey-20; -fx-border-width: 1; @@ -233,15 +239,15 @@ -fx-padding: 0 0 0 5; } -.market-selection-applied-filters .filter-display-hint:hover { +.market-selection-show-applied-filters .filter-display-hint:hover { -fx-border-color: -bisq-white; } -.market-selection-applied-filters .filter-display-hint:hover .label { +.market-selection-show-applied-filters .filter-display-hint:hover .label { -fx-text-fill: -bisq-white; } -.market-selection-applied-filters .filter-display-hint .label { +.market-selection-show-applied-filters .filter-display-hint .label { -fx-text-fill: -fx-mid-text-color; } @@ -285,6 +291,7 @@ .favourites-list { -fx-padding: 0 0 10 0; -fx-border-width: 0 0 1 0; + -fx-border-insets: 0 0 10 0; -fx-border-color: -bisq-dark-grey-50; } diff --git a/i18n/src/main/resources/bisq_easy.properties b/i18n/src/main/resources/bisq_easy.properties index ce07b1ffc0..43e6427c66 100644 --- a/i18n/src/main/resources/bisq_easy.properties +++ b/i18n/src/main/resources/bisq_easy.properties @@ -395,7 +395,7 @@ bisqEasy.offerbook.dropdownMenu.sortAndFilterMarkets.nameAZ=Name A-Z bisqEasy.offerbook.dropdownMenu.sortAndFilterMarkets.nameZA=Name Z-A bisqEasy.offerbook.dropdownMenu.sortAndFilterMarkets.filterTitle=Show markets: bisqEasy.offerbook.dropdownMenu.sortAndFilterMarkets.withOffers=With offers -bisqEasy.offerbook.dropdownMenu.sortAndFilterMarkets.favourites=Favourites +bisqEasy.offerbook.dropdownMenu.sortAndFilterMarkets.favourites=Only favourites bisqEasy.offerbook.dropdownMenu.sortAndFilterMarkets.all=All bisqEasy.offerbook.dropdownMenu.filterOffersByDirectionOrOwner.tooltip=Filter by offer type