diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/offerbook/offerbook_list/OfferbookListController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/offerbook/offerbook_list/OfferbookListController.java index 81f7b38fd6..26d0496960 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/offerbook/offerbook_list/OfferbookListController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/offerbook/offerbook_list/OfferbookListController.java @@ -33,6 +33,7 @@ import bisq.i18n.Res; import bisq.settings.CookieKey; import bisq.settings.SettingsService; +import bisq.user.identity.UserIdentityService; import bisq.user.profile.UserProfile; import bisq.user.profile.UserProfileService; import bisq.user.reputation.ReputationService; @@ -57,8 +58,9 @@ public class OfferbookListController implements bisq.desktop.common.view.Control private final UserProfileService userProfileService; private final MarketPriceService marketPriceService; private final ReputationService reputationService; - private Pin showBuyOffersPin, showOfferListExpandedSettingsPin, offerMessagesPin; - private Subscription showBuyOffersFromModelPin, activeMarketPaymentsCountPin; + private final UserIdentityService userIdentityService; + private Pin showBuyOffersPin, showOfferListExpandedSettingsPin, offerMessagesPin, showMyOffersOnlyPin, userIdentityPin; + private Subscription showBuyOffersFromModelPin, activeMarketPaymentsCountPin, showMyOffersOnlyFromModelPin; public OfferbookListController(ServiceProvider serviceProvider, ChatMessageContainerController chatMessageContainerController) { @@ -67,6 +69,7 @@ public OfferbookListController(ServiceProvider serviceProvider, userProfileService = serviceProvider.getUserService().getUserProfileService(); marketPriceService = serviceProvider.getBondedRolesService().getMarketPriceService(); reputationService = serviceProvider.getUserService().getReputationService(); + userIdentityService = serviceProvider.getUserService().getUserIdentityService(); model = new OfferbookListModel(); view = new OfferbookListView(model, this); } @@ -85,6 +88,9 @@ public void onActivate() { model.getPaymentFilterTitle().set(Res.get("bisqEasy.offerbook.offerList.table.filters.paymentMethods.title", hint)); applyPredicate(); }); + showMyOffersOnlyPin = FxBindings.bindBiDir(model.getShowMyOffersOnly()).to(settingsService.getShowMyOffersOnly()); + showMyOffersOnlyFromModelPin = EasyBind.subscribe(model.getShowMyOffersOnly(), showMyOffersOnly -> applyPredicate()); + userIdentityPin = userIdentityService.getSelectedUserIdentityObservable().addObserver(userIdentity -> UIThread.run(this::applyPredicate)); } @Override @@ -98,6 +104,9 @@ public void onDeactivate() { if (offerMessagesPin != null) { offerMessagesPin.unbind(); } + showMyOffersOnlyPin.unbind(); + showMyOffersOnlyFromModelPin.unsubscribe(); + userIdentityPin.unbind(); } public void setSelectedChannel(BisqEasyOfferbookChannel channel) { @@ -242,7 +251,10 @@ private boolean shouldShowListItem(OfferbookListItem item) { boolean matchesPaymentFilters = paymentFiltersApplied && item.getFiatPaymentMethods().stream() .anyMatch(payment -> (payment.isCustomPaymentMethod() && model.getIsCustomPaymentsSelected().get()) || model.getSelectedMarketPayments().contains(payment)); - return matchesDirection && (!paymentFiltersApplied || matchesPaymentFilters); + boolean myOffersOnly = model.getShowMyOffersOnly().get(); + UserProfile selectedUserProfile = userIdentityService.getSelectedUserIdentity().getUserProfile(); + boolean isMyOffer = item.getUserProfile().equals(selectedUserProfile); + return matchesDirection && (!paymentFiltersApplied || matchesPaymentFilters) && (!myOffersOnly || isMyOffer); } private String getCookieSubKey() { diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/offerbook/offerbook_list/OfferbookListModel.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/offerbook/offerbook_list/OfferbookListModel.java index c3e6c6ca65..b5bfb02526 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/offerbook/offerbook_list/OfferbookListModel.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/offerbook/offerbook_list/OfferbookListModel.java @@ -47,6 +47,7 @@ class OfferbookListModel implements bisq.desktop.common.view.Model { private final BooleanProperty isCustomPaymentsSelected = new SimpleBooleanProperty(); private final IntegerProperty activeMarketPaymentsCount = new SimpleIntegerProperty(); private final SimpleObjectProperty channel = new SimpleObjectProperty<>(); + private final BooleanProperty showMyOffersOnly = new SimpleBooleanProperty(); OfferbookListModel() { } diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/offerbook/offerbook_list/OfferbookListView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/offerbook/offerbook_list/OfferbookListView.java index 9a841eac6c..84a1dec560 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/offerbook/offerbook_list/OfferbookListView.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/offerbook/offerbook_list/OfferbookListView.java @@ -43,11 +43,7 @@ import javafx.geometry.Pos; import javafx.scene.Cursor; import javafx.scene.Node; -import javafx.scene.control.Label; -import javafx.scene.control.SeparatorMenuItem; -import javafx.scene.control.TableCell; -import javafx.scene.control.TableColumn; -import javafx.scene.control.Tooltip; +import javafx.scene.control.*; import javafx.scene.effect.ColorAdjust; import javafx.scene.image.ImageView; import javafx.scene.layout.HBox; @@ -69,19 +65,20 @@ public class OfferbookListView extends bisq.desktop.common.view.View tableView; private final BisqTooltip titleTooltip; - private final HBox header; + private final HBox header, showOnlyMyMessagesHBox; private final ImageView offerListWhiteIcon, offerListGreyIcon, offerListGreenIcon; private final DropdownMenu offerDirectionFilterMenu, paymentsFilterMenu; private final ListChangeListener availablePaymentsChangeListener; private final SetChangeListener selectedPaymentsChangeListener; + private final CheckBox showOnlyMyMessages; private DropdownBisqMenuItem buyFromOffers, sellToOffers; private Label offerDirectionFilterLabel, paymentsFilterLabel; - private Subscription showOfferListExpandedPin, showBuyFromOffersPin, + private Subscription showOfferListExpandedPin, showBuyFromOffersPin, showMyOffersOnlyPin, offerListTableViewSelectionPin, activeMarketPaymentsCountPin, isCustomPaymentsSelectedPin; OfferbookListView(OfferbookListModel model, OfferbookListController controller) { @@ -107,11 +104,16 @@ public class OfferbookListView extends bisq.desktop.common.view.View updatePaymentsSelection(); offerDirectionFilterMenu = createAndGetOffersDirectionFilterMenu(); paymentsFilterMenu = createAndGetPaymentsFilterDropdownMenu(); + showMyOffersOnlyLabel = new Label(Res.get("bisqEasy.offerbook.offerList.table.filters.showMyOffersOnly")); + showOnlyMyMessages = new CheckBox(); + showOnlyMyMessagesHBox = new HBox(5, showOnlyMyMessages, showMyOffersOnlyLabel); + showOnlyMyMessagesHBox.getStyleClass().add("offerbook-subheader-checkbox"); + showOnlyMyMessagesHBox.setAlignment(Pos.CENTER); HBox subheader = new HBox(10); subheader.setAlignment(Pos.CENTER_LEFT); subheader.getStyleClass().add("offer-list-subheader"); - subheader.getChildren().addAll(offerDirectionFilterMenu, paymentsFilterMenu); + subheader.getChildren().addAll(offerDirectionFilterMenu, paymentsFilterMenu, showOnlyMyMessagesHBox); tableView = new BisqTableView<>(model.getSortedOfferbookListItems()); tableView.getStyleClass().add("offers-list"); @@ -128,6 +130,7 @@ public class OfferbookListView extends bisq.desktop.common.view.View { if (showOfferListExpanded != null) { @@ -147,7 +150,12 @@ protected void onViewAttached() { root.getStyleClass().add("chat-container"); title.setText(Res.get("bisqEasy.offerbook.offerList")); titleTooltip.setText(Res.get("bisqEasy.offerbook.offerList.expandedList.tooltip")); - Transitions.expansionAnimation(root, COLLAPSED_LIST_WIDTH + 20, EXPANDED_OFFER_LIST_WIDTH); + Transitions.expansionAnimation(root, COLLAPSED_LIST_WIDTH + 20, EXPANDED_OFFER_LIST_WIDTH, () -> { + paymentsFilterMenu.setVisible(true); + paymentsFilterMenu.setManaged(true); + showOnlyMyMessagesHBox.setVisible(true); + showOnlyMyMessagesHBox.setManaged(true); + }); title.setOnMouseExited(e -> title.setGraphic(offerListGreenIcon)); } else { Transitions.expansionAnimation(root, EXPANDED_OFFER_LIST_WIDTH, COLLAPSED_LIST_WIDTH + 20, () -> { @@ -163,6 +171,10 @@ protected void onViewAttached() { titleTooltip.setText(Res.get("bisqEasy.offerbook.offerList.collapsedList.tooltip")); title.setGraphic(offerListGreyIcon); title.setOnMouseExited(e -> title.setGraphic(offerListGreyIcon)); + paymentsFilterMenu.setVisible(false); + paymentsFilterMenu.setManaged(false); + showOnlyMyMessagesHBox.setVisible(false); + showOnlyMyMessagesHBox.setManaged(false); }); } } @@ -186,17 +198,27 @@ protected void onViewAttached() { activeMarketPaymentsCountPin = EasyBind.subscribe(model.getActiveMarketPaymentsCount(), count -> { if (count.intValue() != 0) { - if (!paymentsFilterLabel.getStyleClass().contains(ACTIVE_PAYMENT_FILTER_CLASS)) { - paymentsFilterLabel.getStyleClass().add(ACTIVE_PAYMENT_FILTER_CLASS); + if (!paymentsFilterLabel.getStyleClass().contains(ACTIVE_FILTER_CLASS)) { + paymentsFilterLabel.getStyleClass().add(ACTIVE_FILTER_CLASS); } } else { - paymentsFilterLabel.getStyleClass().remove(ACTIVE_PAYMENT_FILTER_CLASS); + paymentsFilterLabel.getStyleClass().remove(ACTIVE_FILTER_CLASS); } }); isCustomPaymentsSelectedPin = EasyBind.subscribe(model.getIsCustomPaymentsSelected(), isSelected -> updatePaymentsSelection()); + showMyOffersOnlyPin = EasyBind.subscribe(model.getShowMyOffersOnly(), showMyOffers -> { + if (showMyOffers) { + if (!showMyOffersOnlyLabel.getStyleClass().contains(ACTIVE_FILTER_CLASS)) { + showMyOffersOnlyLabel.getStyleClass().add(ACTIVE_FILTER_CLASS); + } + } else { + showMyOffersOnlyLabel.getStyleClass().remove(ACTIVE_FILTER_CLASS); + } + }); + model.getAvailableMarketPayments().addListener(availablePaymentsChangeListener); updateMarketPaymentFilters(); model.getSelectedMarketPayments().addListener(selectedPaymentsChangeListener); @@ -213,6 +235,7 @@ protected void onViewAttached() { @Override protected void onViewDetached() { paymentsFilterLabel.textProperty().unbind(); + showOnlyMyMessages.selectedProperty().unbindBidirectional(model.getShowMyOffersOnly()); showOfferListExpandedPin.unsubscribe(); offerListTableViewSelectionPin.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 f4e9239a8f..436580cdfc 100644 --- a/apps/desktop/desktop/src/main/resources/css/bisq_easy.css +++ b/apps/desktop/desktop/src/main/resources/css/bisq_easy.css @@ -182,6 +182,23 @@ -fx-padding: 0 25 0 25; } +.offerbook-subheader-checkbox .check-box { + -fx-scale-x: 0.6; + -fx-scale-y: 0.6; + -fx-cursor: hand; +} + +.offerbook-subheader-checkbox .label { + -fx-text-fill: -fx-mid-text-color; +} + +.offerbook-subheader-checkbox .check-box > .box { + -fx-background-color: transparent; + -fx-background-radius: 0; + -fx-border-color: -bisq-mid-grey-20; + -fx-border-width: 1; +} + .offerbook-subheader .dropdown-offers-filter-menu { -fx-padding: 0 10 0 10; } @@ -333,7 +350,7 @@ -fx-padding: 0 5 0 5; } -.active-payment-filter { +.active-filter { -fx-text-fill: -fx-light-text-color !important; } diff --git a/i18n/src/main/resources/bisq_easy.properties b/i18n/src/main/resources/bisq_easy.properties index 4f8257e055..0bdda46b07 100644 --- a/i18n/src/main/resources/bisq_easy.properties +++ b/i18n/src/main/resources/bisq_easy.properties @@ -456,6 +456,7 @@ bisqEasy.offerbook.offerList.table.filters.paymentMethods.title=Payments ({0}) bisqEasy.offerbook.offerList.table.filters.paymentMethods.title.all=All bisqEasy.offerbook.offerList.table.filters.paymentMethods.customPayments=Custom payments bisqEasy.offerbook.offerList.table.filters.paymentMethods.clearFilters=Clear filters +bisqEasy.offerbook.offerList.table.filters.showMyOffersOnly=My offers only bisqEasy.offerbook.offerList.table.columns.price.tooltip.fixPrice=Fixed price: {0}\nPercentage from current market price: {1} bisqEasy.offerbook.offerList.table.columns.price.tooltip.marketPrice=Market price: {0} diff --git a/settings/src/main/java/bisq/settings/SettingsService.java b/settings/src/main/java/bisq/settings/SettingsService.java index 4733c20e2b..39483bd19d 100644 --- a/settings/src/main/java/bisq/settings/SettingsService.java +++ b/settings/src/main/java/bisq/settings/SettingsService.java @@ -89,6 +89,7 @@ public CompletableFuture initialize() { getShowOfferListExpanded().addObserver(value -> persist()); getShowMarketSelectionListCollapsed().addObserver(value -> persist()); getBackupLocation().addObserver(value -> persist()); + getShowMyOffersOnly().addObserver(value -> persist()); isInitialized = true; @@ -223,6 +224,10 @@ public Observable getBackupLocation() { return persistableStore.backupLocation; } + public Observable getShowMyOffersOnly() { + return persistableStore.showMyOffersOnly; + } + /////////////////////////////////////////////////////////////////////////////////////////////////// // DontShowAgainMap diff --git a/settings/src/main/java/bisq/settings/SettingsStore.java b/settings/src/main/java/bisq/settings/SettingsStore.java index 902314f2be..b87beb36e2 100644 --- a/settings/src/main/java/bisq/settings/SettingsStore.java +++ b/settings/src/main/java/bisq/settings/SettingsStore.java @@ -59,6 +59,7 @@ public final class SettingsStore implements PersistableStore { final Observable showOfferListExpanded = new Observable<>(); final Observable showMarketSelectionListCollapsed = new Observable<>(); final Observable backupLocation = new Observable<>(); + final Observable showMyOffersOnly = new Observable<>(); public SettingsStore() { this(new Cookie(), @@ -83,7 +84,8 @@ public SettingsStore() { false, false, false, - PlatformUtils.getHomeDirectory()); + PlatformUtils.getHomeDirectory(), + false); } public SettingsStore(Cookie cookie, @@ -108,7 +110,8 @@ public SettingsStore(Cookie cookie, boolean showBuyOffers, boolean showOfferListExpanded, boolean showMarketSelectionListCollapsed, - String backupLocation) { + String backupLocation, + boolean showMyOffersOnly) { this.cookie = cookie; this.dontShowAgainMap.putAll(dontShowAgainMap); this.useAnimations.set(useAnimations); @@ -132,6 +135,7 @@ public SettingsStore(Cookie cookie, this.showOfferListExpanded.set(showOfferListExpanded); this.showMarketSelectionListCollapsed.set(showMarketSelectionListCollapsed); this.backupLocation.set(backupLocation); + this.showMyOffersOnly.set(showMyOffersOnly); } @Override @@ -159,7 +163,8 @@ public bisq.settings.protobuf.SettingsStore.Builder getBuilder(boolean serialize .setShowBuyOffers(showBuyOffers.get()) .setShowOfferListExpanded(showOfferListExpanded.get()) .setShowMarketSelectionListCollapsed(showMarketSelectionListCollapsed.get()) - .setBackupLocation(backupLocation.get()); + .setBackupLocation(backupLocation.get()) + .setShowMyOffersOnly(showMyOffersOnly.get()); } @Override @@ -199,7 +204,8 @@ public static SettingsStore fromProto(bisq.settings.protobuf.SettingsStore proto proto.getShowBuyOffers(), proto.getShowOfferListExpanded(), proto.getShowMarketSelectionListCollapsed(), - proto.getBackupLocation()); + proto.getBackupLocation(), + proto.getShowMyOffersOnly()); } @Override @@ -237,7 +243,8 @@ public SettingsStore getClone() { showBuyOffers.get(), showOfferListExpanded.get(), showMarketSelectionListCollapsed.get(), - backupLocation.get()); + backupLocation.get(), + showMyOffersOnly.get()); } @Override @@ -266,6 +273,7 @@ public void applyPersisted(SettingsStore persisted) { showOfferListExpanded.set(persisted.showOfferListExpanded.get()); showMarketSelectionListCollapsed.set(persisted.showMarketSelectionListCollapsed.get()); backupLocation.set(persisted.backupLocation.get()); + showMyOffersOnly.set(persisted.showMyOffersOnly.get()); } catch (Exception e) { log.error("Exception at applyPersisted", e); } diff --git a/settings/src/main/proto/settings.proto b/settings/src/main/proto/settings.proto index 4b92e3f352..525291d865 100644 --- a/settings/src/main/proto/settings.proto +++ b/settings/src/main/proto/settings.proto @@ -62,4 +62,5 @@ message SettingsStore { bool showOfferListExpanded = 21; bool showMarketSelectionListCollapsed = 22; string backupLocation = 23; + bool showMyOffersOnly = 24; }