diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index ccced5fd067..1ac8021137e 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -62,8 +62,10 @@ shared.priceWithCur=Price in {0} shared.priceInCurForCur=Price in {0} for 1 {1} shared.fixedPriceInCurForCur=Fixed price in {0} for 1 {1} shared.amount=Amount -shared.txFee=Transaction Fee -shared.makerFee=Maker Fee +shared.txFee=Maker mining fee +shared.takerFee=Taker mining fee +shared.takerTradingFee=Taker trading fee +shared.makerTradingFee=Maker trading fee shared.buyerSecurityDeposit=Buyer Deposit shared.sellerSecurityDeposit=Seller Deposit shared.amountWithCur=Amount in {0} diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/closedtrades/ClosedTradesView.fxml b/desktop/src/main/java/bisq/desktop/main/portfolio/closedtrades/ClosedTradesView.fxml index 04ed87f4bad..08c8d424ac8 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/closedtrades/ClosedTradesView.fxml +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/closedtrades/ClosedTradesView.fxml @@ -40,8 +40,10 @@ - - + + + + diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/closedtrades/ClosedTradesView.java b/desktop/src/main/java/bisq/desktop/main/portfolio/closedtrades/ClosedTradesView.java index 5970aa49b50..75ffca4841c 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/closedtrades/ClosedTradesView.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/closedtrades/ClosedTradesView.java @@ -32,6 +32,8 @@ import bisq.core.alert.PrivateNotificationManager; import bisq.core.app.AppOptionKeys; import bisq.core.locale.Res; +import bisq.core.monetary.Price; +import bisq.core.monetary.Volume; import bisq.core.offer.Offer; import bisq.core.offer.OpenOffer; import bisq.core.trade.Contract; @@ -46,6 +48,8 @@ import javax.inject.Inject; import javax.inject.Named; +import org.bitcoinj.core.Coin; + import javafx.fxml.FXML; import javafx.stage.Stage; @@ -77,12 +81,15 @@ @FxmlView public class ClosedTradesView extends ActivatableViewAndModel { private final boolean useDevPrivilegeKeys; - + private final OfferDetailsWindow offerDetailsWindow; + private final TradeDetailsWindow tradeDetailsWindow; + private final PrivateNotificationManager privateNotificationManager; @FXML TableView tableView; @FXML - TableColumn priceColumn, amountColumn, volumeColumn, txFeeColumn, makerFeeColumn, buyerSecurityDepositColumn, sellerSecurityDepositColumn, - marketColumn, directionColumn, dateColumn, tradeIdColumn, stateColumn, avatarColumn; + TableColumn priceColumn, amountColumn, volumeColumn, + makerMiningFeeColumn, takerMiningFeeColumn, makerTradingFeeColumn, takerTradingFeeColumn, buyerSecurityDepositColumn, + sellerSecurityDepositColumn, marketColumn, directionColumn, dateColumn, tradeIdColumn, stateColumn, avatarColumn; @FXML HBox footerBox; @FXML @@ -93,11 +100,7 @@ public class ClosedTradesView extends ActivatableViewAndModel sortedList; private FilteredList filteredList; private ChangeListener filterTextFieldListener; @@ -117,12 +120,14 @@ public ClosedTradesView(ClosedTradesViewModel model, this.useDevPrivilegeKeys = useDevPrivilegeKeys; } - @Override - public void initialize() { - txFeeColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.txFee"))); - makerFeeColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.makerFee"))); - buyerSecurityDepositColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.buyerSecurityDeposit"))); - sellerSecurityDepositColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.sellerSecurityDeposit"))); + @Override + public void initialize() { + makerMiningFeeColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.txFee"))); + takerMiningFeeColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.takerFee"))); + makerTradingFeeColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.makerTradingFee"))); + takerTradingFeeColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.takerTradingFee"))); + buyerSecurityDepositColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.buyerSecurityDeposit"))); + sellerSecurityDepositColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.sellerSecurityDeposit"))); priceColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.price"))); amountColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.amountWithCur", Res.getBaseCurrencyCode()))); volumeColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.amount"))); @@ -139,10 +144,13 @@ public void initialize() { setTradeIdColumnCellFactory(); setDirectionColumnCellFactory(); setAmountColumnCellFactory(); - setTxFeeColumnCellFactory(); - setMakerFeeColumnCellFactory(); - setBuyerSecurityDepositColumnCellFactory(); - setSellerSecurityDepositColumnCellFactory(); + setMakerMiningFeeColumnCellFactory(); + setTakerMiningFeeColumnCellFactory(); + setMakerTradingFeeColumnCellFactory(); + setTakerTradingFeeColumnCellFactory(); + setTakerMiningFeeColumnCellFactory(); + setBuyerSecurityDepositColumnCellFactory(); + setSellerSecurityDepositColumnCellFactory(); setPriceColumnCellFactory(); setVolumeColumnCellFactory(); setDateColumnCellFactory(); @@ -155,26 +163,79 @@ public void initialize() { directionColumn.setComparator(Comparator.comparing(o -> o.getTradable().getOffer().getDirection())); marketColumn.setComparator(Comparator.comparing(model::getMarketLabel)); - priceColumn.setComparator(nullsFirstComparing(o -> - o instanceof Trade ? ((Trade) o).getTradePrice() : o.getOffer().getPrice() - )); - volumeColumn.setComparator(nullsFirstComparingAsTrade(Trade::getTradeVolume)); - amountColumn.setComparator(nullsFirstComparingAsTrade(Trade::getTradeAmount)); - avatarColumn.setComparator(nullsFirstComparingAsTrade(o -> - o.getTradingPeerNodeAddress() != null ? o.getTradingPeerNodeAddress().getFullAddress() : null - )); - txFeeColumn.setComparator(nullsFirstComparing(o -> - o instanceof Trade ? ((Trade) o).getTxFee() : o.getOffer().getTxFee() - )); - makerFeeColumn.setComparator(nullsFirstComparing(o -> - o instanceof Trade ? ((Trade) o).getTakerFee() : o.getOffer().getMakerFee() - )); - buyerSecurityDepositColumn.setComparator(nullsFirstComparing(o -> - o.getOffer() != null ? o.getOffer().getBuyerSecurityDeposit() : null - )); - sellerSecurityDepositColumn.setComparator(nullsFirstComparing(o -> - o.getOffer() != null ? o.getOffer().getSellerSecurityDeposit() : null - )); + priceColumn.setComparator((o1, o2) -> { + final Tradable tradable1 = o1.getTradable(); + final Tradable tradable2 = o2.getTradable(); + Price price1 = null; + Price price2 = null; + if (tradable1 != null) + price1 = tradable1 instanceof Trade ? ((Trade) tradable1).getTradePrice() : tradable1.getOffer().getPrice(); + if (tradable2 != null) + price2 = tradable2 instanceof Trade ? ((Trade) tradable2).getTradePrice() : tradable2.getOffer().getPrice(); + return price1 != null && price2 != null ? price1.compareTo(price2) : 0; + }); + volumeColumn.setComparator((o1, o2) -> { + if (o1.getTradable() instanceof Trade && o2.getTradable() instanceof Trade) { + Volume tradeVolume1 = ((Trade) o1.getTradable()).getTradeVolume(); + Volume tradeVolume2 = ((Trade) o2.getTradable()).getTradeVolume(); + return tradeVolume1 != null && tradeVolume2 != null ? tradeVolume1.compareTo(tradeVolume2) : 0; + } else + return 0; + }); + amountColumn.setComparator((o1, o2) -> { + if (o1.getTradable() instanceof Trade && o2.getTradable() instanceof Trade) { + Coin amount1 = ((Trade) o1.getTradable()).getTradeAmount(); + Coin amount2 = ((Trade) o2.getTradable()).getTradeAmount(); + return amount1 != null && amount2 != null ? amount1.compareTo(amount2) : 0; + } else + return 0; + }); + avatarColumn.setComparator((o1, o2) -> { + if (o1.getTradable() instanceof Trade && o2.getTradable() instanceof Trade) { + NodeAddress tradingPeerNodeAddress1 = ((Trade) o1.getTradable()).getTradingPeerNodeAddress(); + NodeAddress tradingPeerNodeAddress2 = ((Trade) o2.getTradable()).getTradingPeerNodeAddress(); + String address1 = tradingPeerNodeAddress1 != null ? tradingPeerNodeAddress1.getFullAddress() : ""; + String address2 = tradingPeerNodeAddress2 != null ? tradingPeerNodeAddress2.getFullAddress() : ""; + return address1.compareTo(address2); + } else + return 0; + }); + + makerMiningFeeColumn.setComparator(Comparator.comparing(model::getMakerMiningFee)); + makerMiningFeeColumn.setSortType(TableColumn.SortType.ASCENDING); + + takerMiningFeeColumn.setComparator(Comparator.comparing(model::getTakerMiningFee)); + takerMiningFeeColumn.setSortType(TableColumn.SortType.ASCENDING); + + makerTradingFeeColumn.setComparator(Comparator.comparing(model::getMakerTradingFee)); + makerTradingFeeColumn.setSortType(TableColumn.SortType.ASCENDING); + + takerTradingFeeColumn.setComparator(Comparator.comparing(model::getTakerTradingFee)); + takerTradingFeeColumn.setSortType(TableColumn.SortType.ASCENDING); + + buyerSecurityDepositColumn.setComparator((o1, o2) -> { + final Tradable tradable1 = o1.getTradable(); + final Tradable tradable2 = o2.getTradable(); + Coin txFee1 = null; + Coin txFee2 = null; + if (tradable1 != null && tradable1.getOffer() != null) + txFee1 = tradable1.getOffer().getBuyerSecurityDeposit(); + if (tradable2 != null && tradable2.getOffer() != null) + txFee2 = tradable2.getOffer().getBuyerSecurityDeposit(); + return txFee1 != null && txFee2 != null ? txFee1.compareTo(txFee2) : 0; + }); + sellerSecurityDepositColumn.setComparator((o1, o2) -> { + final Tradable tradable1 = o1.getTradable(); + final Tradable tradable2 = o2.getTradable(); + Coin txFee1 = null; + Coin txFee2 = null; + if (tradable1 != null && tradable1.getOffer() != null) + txFee1 = tradable1.getOffer().getSellerSecurityDeposit(); + if (tradable2 != null && tradable2.getOffer() != null) + txFee2 = tradable2.getOffer().getSellerSecurityDeposit(); + return txFee1 != null && txFee2 != null ? txFee1.compareTo(txFee2) : 0; + }); + stateColumn.setComparator(Comparator.comparing(model::getState)); dateColumn.setSortType(TableColumn.SortType.DESCENDING); @@ -190,20 +251,6 @@ public void initialize() { HBox.setMargin(exportButton, new Insets(0, 10, 0, 0)); } - private static > Comparator nullsFirstComparing(Function keyExtractor) { - return Comparator.comparing( - o -> o.getTradable() != null ? keyExtractor.apply(o.getTradable()) : null, - Comparator.nullsFirst(Comparator.naturalOrder()) - ); - } - - private static > Comparator nullsFirstComparingAsTrade(Function keyExtractor) { - return Comparator.comparing( - o -> o.getTradable() instanceof Trade ? keyExtractor.apply((Trade) o.getTradable()) : null, - Comparator.nullsFirst(Comparator.naturalOrder()) - ); - } - @Override protected void activate() { filteredList = new FilteredList<>(model.getList()); @@ -216,25 +263,27 @@ protected void activate() { exportButton.setOnAction(event -> { final ObservableList> tableColumns = tableView.getColumns(); CSVEntryConverter headerConverter = transactionsListItem -> { - String[] columns = new String[12]; + String[] columns = new String[14]; for (int i = 0; i < columns.length; i++) columns[i] = ((AutoTooltipLabel) tableColumns.get(i).getGraphic()).getText(); return columns; }; CSVEntryConverter contentConverter = item -> { - String[] columns = new String[12]; + String[] columns = new String[14]; columns[0] = model.getTradeId(item); columns[1] = model.getDate(item); columns[2] = model.getMarketLabel(item); columns[3] = model.getPrice(item); columns[4] = model.getAmount(item); - columns[5] = model.getVolume(item); - columns[6] = model.getTxFee(item); - columns[7] = model.getMakerFee(item); - columns[8] = model.getBuyerSecurityDeposit(item); - columns[9] = model.getSellerSecurityDeposit(item); - columns[10] = model.getDirectionLabel(item); - columns[11] = model.getState(item); + columns[5] = model.getVolume(item); + columns[6] = model.getMakerMiningFee(item); + columns[7] = model.getTakerMiningFee(item); + columns[8] = model.getMakerTradingFee(item); + columns[9] = model.getTakerTradingFee(item); + columns[10] = model.getBuyerSecurityDeposit(item); + columns[11] = model.getSellerSecurityDeposit(item); + columns[12] = model.getDirectionLabel(item); + columns[13] = model.getState(item); return columns; }; @@ -499,9 +548,27 @@ public void updateItem(final ClosedTradableListItem item, boolean empty) { }); } - private void setTxFeeColumnCellFactory() { - txFeeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue())); - txFeeColumn.setCellFactory( + private void setMakerMiningFeeColumnCellFactory() { + makerMiningFeeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue())); + makerMiningFeeColumn.setCellFactory( + new Callback<>() { + @Override + public TableCell call( + TableColumn column) { + return new TableCell<>() { + @Override + public void updateItem(final ClosedTradableListItem item, boolean empty) { + super.updateItem(item, empty); + setGraphic(new AutoTooltipLabel(model.getMakerMiningFee(item))); + } + }; + } + }); + } + + private void setTakerMiningFeeColumnCellFactory() { + takerMiningFeeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue())); + takerMiningFeeColumn.setCellFactory( new Callback<>() { @Override public TableCell call( @@ -510,16 +577,16 @@ public TableCell call( @Override public void updateItem(final ClosedTradableListItem item, boolean empty) { super.updateItem(item, empty); - setGraphic(new AutoTooltipLabel(model.getTxFee(item))); + setGraphic(new AutoTooltipLabel(model.getTakerMiningFee(item))); } }; } }); - } + } - private void setMakerFeeColumnCellFactory() { - makerFeeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue())); - makerFeeColumn.setCellFactory( + private void setMakerTradingFeeColumnCellFactory() { + makerTradingFeeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue())); + makerTradingFeeColumn.setCellFactory( new Callback<>() { @Override public TableCell call( @@ -528,16 +595,34 @@ public TableCell call( @Override public void updateItem(final ClosedTradableListItem item, boolean empty) { super.updateItem(item, empty); - setGraphic(new AutoTooltipLabel(model.getMakerFee(item))); + setGraphic(new AutoTooltipLabel(model.getMakerTradingFee(item))); } }; } }); - } + } - private void setBuyerSecurityDepositColumnCellFactory() { - buyerSecurityDepositColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue())); - buyerSecurityDepositColumn.setCellFactory( + private void setTakerTradingFeeColumnCellFactory() { + takerTradingFeeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue())); + takerTradingFeeColumn.setCellFactory( + new Callback<>() { + @Override + public TableCell call( + TableColumn column) { + return new TableCell<>() { + @Override + public void updateItem(final ClosedTradableListItem item, boolean empty) { + super.updateItem(item, empty); + setGraphic(new AutoTooltipLabel(model.getTakerTradingFee(item))); + } + }; + } + }); + } + + private void setBuyerSecurityDepositColumnCellFactory() { + buyerSecurityDepositColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue())); + buyerSecurityDepositColumn.setCellFactory( new Callback<>() { @Override public TableCell call( @@ -551,11 +636,11 @@ public void updateItem(final ClosedTradableListItem item, boolean empty) { }; } }); - } + } - private void setSellerSecurityDepositColumnCellFactory() { - sellerSecurityDepositColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue())); - sellerSecurityDepositColumn.setCellFactory( + private void setSellerSecurityDepositColumnCellFactory() { + sellerSecurityDepositColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue())); + sellerSecurityDepositColumn.setCellFactory( new Callback<>() { @Override public TableCell call( @@ -569,6 +654,6 @@ public void updateItem(final ClosedTradableListItem item, boolean empty) { }; } }); - } + } } diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/closedtrades/ClosedTradesViewModel.java b/desktop/src/main/java/bisq/desktop/main/portfolio/closedtrades/ClosedTradesViewModel.java index 26ae7a903d7..ef1595a53e2 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/closedtrades/ClosedTradesViewModel.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/closedtrades/ClosedTradesViewModel.java @@ -25,6 +25,7 @@ import bisq.core.locale.CurrencyUtil; import bisq.core.locale.Res; import bisq.core.offer.OpenOffer; +import bisq.core.provider.fee.FeeService; import bisq.core.trade.Tradable; import bisq.core.trade.Trade; import bisq.core.util.FormattingUtils; @@ -39,8 +40,8 @@ import java.util.stream.Collectors; class ClosedTradesViewModel extends ActivatableWithDataModel implements ViewModel { - private final CoinFormatter formatter; final AccountAgeWitnessService accountAgeWitnessService; + private final CoinFormatter formatter; @Inject public ClosedTradesViewModel(ClosedTradesDataModel dataModel, @@ -87,7 +88,7 @@ else if (item != null && item.getTradable() instanceof OpenOffer) return ""; } - String getTxFee(ClosedTradableListItem item) { + String getMakerMiningFee(ClosedTradableListItem item) { if (item == null) return ""; Tradable tradable = item.getTradable(); @@ -97,14 +98,26 @@ String getTxFee(ClosedTradableListItem item) { return formatter.formatCoin(tradable.getOffer().getTxFee()); } - String getMakerFee(ClosedTradableListItem item) { + String getTakerMiningFee(ClosedTradableListItem item) { if (item == null) return ""; Tradable tradable = item.getTradable(); if (tradable instanceof Trade) return formatter.formatCoin(((Trade) tradable).getTakerFee()); else - return formatter.formatCoin(tradable.getOffer().getMakerFee()); + return formatter.formatCoin(tradable.getOffer().getTxFee().multiply(3L)); + } + + String getMakerTradingFee(ClosedTradableListItem item) { + if (item == null) + return ""; + return formatter.formatCoin(FeeService.getMakerFeePerBtc(true)); + } + + String getTakerTradingFee(ClosedTradableListItem item) { + if (item == null) + return ""; + return formatter.formatCoin(FeeService.getTakerFeePerBtc(true)); } String getBuyerSecurityDeposit(ClosedTradableListItem item) {