Merge pull request #4845 from jmacxx/fix_issue_4641

Show price deviation in portfolio open offers and history view
This commit is contained in:
Christoph Atteneder 2020-11-26 15:33:50 +01:00 committed by GitHub
commit 4e4711a6f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 156 additions and 46 deletions

View File

@ -71,6 +71,7 @@ shared.amountWithCur=Amount in {0}
shared.volumeWithCur=Volume in {0}
shared.currency=Currency
shared.market=Market
shared.deviation=Deviation
shared.paymentMethod=Payment method
shared.tradeCurrency=Trade currency
shared.offerType=Offer type
@ -560,6 +561,8 @@ portfolio.tab.history=History
portfolio.tab.failed=Failed
portfolio.tab.editOpenOffer=Edit offer
portfolio.closedTrades.deviation.help=Percentage price deviation from market
portfolio.pending.invalidDelayedPayoutTx=There is an issue with a missing or invalid transaction.\n\n\
Please do NOT send the fiat or altcoin payment. Contact Bisq \
developers on Keybase [HYPERLINK:https://keybase.io/team/bisq] or on the \

View File

@ -34,17 +34,18 @@
<TableView fx:id="tableView" VBox.vgrow="ALWAYS">
<columns>
<TableColumn fx:id="tradeIdColumn" minWidth="120" maxWidth="120"/>
<TableColumn fx:id="dateColumn" minWidth="180"/>
<TableColumn fx:id="marketColumn" minWidth="100"/>
<TableColumn fx:id="tradeIdColumn" minWidth="110" maxWidth="120"/>
<TableColumn fx:id="dateColumn" minWidth="170"/>
<TableColumn fx:id="marketColumn" minWidth="75"/>
<TableColumn fx:id="priceColumn" minWidth="100"/>
<TableColumn fx:id="amountColumn" minWidth="130"/>
<TableColumn fx:id="volumeColumn" minWidth="130"/>
<TableColumn fx:id="deviationColumn" minWidth="70"/>
<TableColumn fx:id="amountColumn" minWidth="110"/>
<TableColumn fx:id="volumeColumn" minWidth="110"/>
<TableColumn fx:id="txFeeColumn" visible="false"/>
<TableColumn fx:id="tradeFeeColumn" visible="false"/>
<TableColumn fx:id="buyerSecurityDepositColumn" visible="false"/>
<TableColumn fx:id="sellerSecurityDepositColumn" visible="false"/>
<TableColumn fx:id="directionColumn" minWidth="80"/>
<TableColumn fx:id="directionColumn" minWidth="70"/>
<TableColumn fx:id="stateColumn" minWidth="80"/>
<TableColumn fx:id="avatarColumn" minWidth="40" maxWidth="40"/>
</columns>

View File

@ -21,6 +21,7 @@ import bisq.desktop.common.view.ActivatableViewAndModel;
import bisq.desktop.common.view.FxmlView;
import bisq.desktop.components.AutoTooltipButton;
import bisq.desktop.components.AutoTooltipLabel;
import bisq.desktop.components.AutoTooltipTableColumn;
import bisq.desktop.components.HyperlinkWithIcon;
import bisq.desktop.components.InputTextField;
import bisq.desktop.components.PeerInfoIcon;
@ -79,10 +80,37 @@ import java.util.function.Function;
public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTradesViewModel> {
private final boolean useDevPrivilegeKeys;
private enum ColumnNames {
TRADE_ID(Res.get("shared.tradeId")),
DATE(Res.get("shared.dateTime")),
MARKET(Res.get("shared.market")),
PRICE(Res.get("shared.price")),
DEVIATION(Res.get("shared.deviation")),
AMOUNT(Res.get("shared.amountWithCur", Res.getBaseCurrencyCode())),
VOLUME(Res.get("shared.amount")),
TX_FEE(Res.get("shared.txFee")),
TRADE_FEE(Res.get("shared.tradeFee")),
BUYER_SEC(Res.get("shared.buyerSecurityDeposit")),
SELLER_SEC(Res.get("shared.sellerSecurityDeposit")),
OFFER_TYPE(Res.get("shared.offerType")),
STATUS(Res.get("shared.state"));
private final String text;
ColumnNames(String text) {
this.text = text;
}
@Override
public String toString() {
return text;
}
}
@FXML
TableView<ClosedTradableListItem> tableView;
@FXML
TableColumn<ClosedTradableListItem, ClosedTradableListItem> priceColumn, amountColumn, volumeColumn, txFeeColumn, tradeFeeColumn, buyerSecurityDepositColumn, sellerSecurityDepositColumn,
TableColumn<ClosedTradableListItem, ClosedTradableListItem> priceColumn, deviationColumn, amountColumn, volumeColumn,
txFeeColumn, tradeFeeColumn, buyerSecurityDepositColumn, sellerSecurityDepositColumn,
marketColumn, directionColumn, dateColumn, tradeIdColumn, stateColumn, avatarColumn;
@FXML
HBox footerBox;
@ -120,18 +148,20 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
@Override
public void initialize() {
txFeeColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.txFee")));
tradeFeeColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.tradeFee")));
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")));
marketColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.market")));
directionColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.offerType")));
dateColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.dateTime")));
tradeIdColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.tradeId")));
stateColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.state")));
txFeeColumn.setGraphic(new AutoTooltipLabel(ColumnNames.TX_FEE.toString()));
tradeFeeColumn.setGraphic(new AutoTooltipLabel(ColumnNames.TRADE_FEE.toString()));
buyerSecurityDepositColumn.setGraphic(new AutoTooltipLabel(ColumnNames.BUYER_SEC.toString()));
sellerSecurityDepositColumn.setGraphic(new AutoTooltipLabel(ColumnNames.SELLER_SEC.toString()));
priceColumn.setGraphic(new AutoTooltipLabel(ColumnNames.PRICE.toString()));
deviationColumn.setGraphic(new AutoTooltipTableColumn<>(ColumnNames.DEVIATION.toString(),
Res.get("portfolio.closedTrades.deviation.help")).getGraphic());
amountColumn.setGraphic(new AutoTooltipLabel(ColumnNames.AMOUNT.toString()));
volumeColumn.setGraphic(new AutoTooltipLabel(ColumnNames.VOLUME.toString()));
marketColumn.setGraphic(new AutoTooltipLabel(ColumnNames.MARKET.toString()));
directionColumn.setGraphic(new AutoTooltipLabel(ColumnNames.OFFER_TYPE.toString()));
dateColumn.setGraphic(new AutoTooltipLabel(ColumnNames.DATE.toString()));
tradeIdColumn.setGraphic(new AutoTooltipLabel(ColumnNames.TRADE_ID.toString()));
stateColumn.setGraphic(new AutoTooltipLabel(ColumnNames.STATUS.toString()));
avatarColumn.setText("");
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
@ -145,6 +175,7 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
setBuyerSecurityDepositColumnCellFactory();
setSellerSecurityDepositColumnCellFactory();
setPriceColumnCellFactory();
setDeviationColumnCellFactory();
setVolumeColumnCellFactory();
setDateColumnCellFactory();
setMarketColumnCellFactory();
@ -159,6 +190,9 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
priceColumn.setComparator(nullsFirstComparing(o ->
o instanceof Trade ? ((Trade) o).getTradePrice() : o.getOffer().getPrice()
));
deviationColumn.setComparator(Comparator.comparing(o ->
o.getTradable().getOffer().isUseMarketBasedPrice() ? o.getTradable().getOffer().getMarketPriceMargin() : 1,
Comparator.nullsFirst(Comparator.naturalOrder())));
volumeColumn.setComparator(nullsFirstComparingAsTrade(Trade::getTradeVolume));
amountColumn.setComparator(nullsFirstComparingAsTrade(Trade::getTradeAmount));
avatarColumn.setComparator(nullsFirstComparingAsTrade(o ->
@ -217,25 +251,27 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
exportButton.setOnAction(event -> {
final ObservableList<TableColumn<ClosedTradableListItem, ?>> tableColumns = tableView.getColumns();
CSVEntryConverter<ClosedTradableListItem> headerConverter = transactionsListItem -> {
String[] columns = new String[12];
for (int i = 0; i < columns.length; i++)
columns[i] = ((AutoTooltipLabel) tableColumns.get(i).getGraphic()).getText();
String[] columns = new String[ColumnNames.values().length];
for (ColumnNames m : ColumnNames.values()) {
columns[m.ordinal()] = m.toString();
}
return columns;
};
CSVEntryConverter<ClosedTradableListItem> contentConverter = item -> {
String[] columns = new String[12];
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);
String[] columns = new String[ColumnNames.values().length];
columns[ColumnNames.TRADE_ID.ordinal()] = model.getTradeId(item);
columns[ColumnNames.DATE.ordinal()] = model.getDate(item);
columns[ColumnNames.MARKET.ordinal()] = model.getMarketLabel(item);
columns[ColumnNames.PRICE.ordinal()] = model.getPrice(item);
columns[ColumnNames.DEVIATION.ordinal()] = model.getPriceDeviation(item);
columns[ColumnNames.AMOUNT.ordinal()] = model.getAmount(item);
columns[ColumnNames.VOLUME.ordinal()] = model.getVolume(item);
columns[ColumnNames.TX_FEE.ordinal()] = model.getTxFee(item);
columns[ColumnNames.TRADE_FEE.ordinal()] = model.getMakerFee(item);
columns[ColumnNames.BUYER_SEC.ordinal()] = model.getBuyerSecurityDeposit(item);
columns[ColumnNames.SELLER_SEC.ordinal()] = model.getSellerSecurityDeposit(item);
columns[ColumnNames.OFFER_TYPE.ordinal()] = model.getDirectionLabel(item);
columns[ColumnNames.STATUS.ordinal()] = model.getState(item);
return columns;
};
@ -461,6 +497,24 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
});
}
private void setDeviationColumnCellFactory() {
deviationColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
deviationColumn.setCellFactory(
new Callback<>() {
@Override
public TableCell<ClosedTradableListItem, ClosedTradableListItem> call(
TableColumn<ClosedTradableListItem, ClosedTradableListItem> column) {
return new TableCell<>() {
@Override
public void updateItem(final ClosedTradableListItem item, boolean empty) {
super.updateItem(item, empty);
setGraphic(new AutoTooltipLabel(model.getPriceDeviation(item)));
}
};
}
});
}
private void setVolumeColumnCellFactory() {
volumeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
volumeColumn.setCellFactory(

View File

@ -78,6 +78,17 @@ class ClosedTradesViewModel extends ActivatableWithDataModel<ClosedTradesDataMod
return FormattingUtils.formatPrice(tradable.getOffer().getPrice());
}
String getPriceDeviation(ClosedTradableListItem item) {
if (item == null)
return "";
Tradable tradable = item.getTradable();
if (tradable.getOffer().isUseMarketBasedPrice()) {
return FormattingUtils.formatPercentagePrice(tradable.getOffer().getMarketPriceMargin());
} else {
return Res.get("shared.na");
}
}
String getVolume(ClosedTradableListItem item) {
if (item != null && item.getTradable() instanceof Trade)
return DisplayUtils.formatVolumeWithCode(((Trade) item.getTradable()).getTradeVolume());

View File

@ -29,14 +29,15 @@
<TableView fx:id="tableView" VBox.vgrow="ALWAYS">
<columns>
<TableColumn fx:id="offerIdColumn" minWidth="110" maxWidth="130"/>
<TableColumn fx:id="dateColumn" minWidth="180"/>
<TableColumn fx:id="offerIdColumn" minWidth="110" maxWidth="120"/>
<TableColumn fx:id="dateColumn" minWidth="170"/>
<TableColumn fx:id="marketColumn" minWidth="75"/>
<TableColumn fx:id="priceColumn" minWidth="110"/>
<TableColumn fx:id="amountColumn" minWidth="100"/>
<TableColumn fx:id="volumeColumn" minWidth="150"/>
<TableColumn fx:id="priceColumn" minWidth="100"/>
<TableColumn fx:id="deviationColumn" minWidth="70"/>
<TableColumn fx:id="amountColumn" minWidth="110"/>
<TableColumn fx:id="volumeColumn" minWidth="110"/>
<TableColumn fx:id="paymentMethodColumn" minWidth="120" maxWidth="170"/>
<TableColumn fx:id="directionColumn" minWidth="80"/>
<TableColumn fx:id="directionColumn" minWidth="70"/>
<TableColumn fx:id="deactivateItemColumn" minWidth="60" maxWidth="60" sortable="false"/>
<TableColumn fx:id="editItemColumn" minWidth="50" maxWidth="60" sortable="false"/>
<TableColumn fx:id="removeItemColumn" minWidth="50" maxWidth="60" sortable="false"/>

View File

@ -22,6 +22,7 @@ import bisq.desktop.common.view.ActivatableViewAndModel;
import bisq.desktop.common.view.FxmlView;
import bisq.desktop.components.AutoTooltipCheckBox;
import bisq.desktop.components.AutoTooltipLabel;
import bisq.desktop.components.AutoTooltipTableColumn;
import bisq.desktop.components.HyperlinkWithIcon;
import bisq.desktop.main.MainView;
import bisq.desktop.main.funds.FundsView;
@ -67,7 +68,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
@FXML
TableView<OpenOfferListItem> tableView;
@FXML
TableColumn<OpenOfferListItem, OpenOfferListItem> priceColumn, amountColumn, volumeColumn,
TableColumn<OpenOfferListItem, OpenOfferListItem> priceColumn, deviationColumn, amountColumn, volumeColumn,
marketColumn, directionColumn, dateColumn, offerIdColumn, deactivateItemColumn,
removeItemColumn, editItemColumn, paymentMethodColumn;
private final Navigation navigation;
@ -86,6 +87,8 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
public void initialize() {
paymentMethodColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.paymentMethod")));
priceColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.price")));
deviationColumn.setGraphic(new AutoTooltipTableColumn<>(Res.get("shared.deviation"),
Res.get("portfolio.closedTrades.deviation.help")).getGraphic());
amountColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.BTCMinMax")));
volumeColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.amountMinMax")));
marketColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.market")));
@ -100,6 +103,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
setDirectionColumnCellFactory();
setMarketColumnCellFactory();
setPriceColumnCellFactory();
setDeviationColumnCellFactory();
setAmountColumnCellFactory();
setVolumeColumnCellFactory();
setPaymentMethodColumnCellFactory();
@ -116,6 +120,9 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
marketColumn.setComparator(Comparator.comparing(model::getMarketLabel));
amountColumn.setComparator(Comparator.comparing(o -> o.getOffer().getAmount()));
priceColumn.setComparator(Comparator.comparing(o -> o.getOffer().getPrice(), Comparator.nullsFirst(Comparator.naturalOrder())));
deviationColumn.setComparator(Comparator.comparing(o ->
o.getOffer().isUseMarketBasedPrice() ? o.getOffer().getMarketPriceMargin() : 1,
Comparator.nullsFirst(Comparator.naturalOrder())));
volumeColumn.setComparator(Comparator.comparing(o -> o.getOffer().getVolume(), Comparator.nullsFirst(Comparator.naturalOrder())));
dateColumn.setComparator(Comparator.comparing(o -> o.getOffer().getDate()));
paymentMethodColumn.setComparator(Comparator.comparing(o -> o.getOffer().getPaymentMethod().getId()));
@ -308,6 +315,31 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
});
}
private void setDeviationColumnCellFactory() {
deviationColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
deviationColumn.setCellFactory(
new Callback<>() {
@Override
public TableCell<OpenOfferListItem, OpenOfferListItem> call(
TableColumn<OpenOfferListItem, OpenOfferListItem> column) {
return new TableCell<>() {
@Override
public void updateItem(final OpenOfferListItem item, boolean empty) {
super.updateItem(item, empty);
getStyleClass().removeAll("offer-disabled");
if (item != null) {
if (model.isDeactivated(item)) getStyleClass().add("offer-disabled");
setGraphic(new AutoTooltipLabel(model.getPriceDeviation(item)));
} else {
setGraphic(null);
}
}
};
}
});
}
private void setVolumeColumnCellFactory() {
volumeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
volumeColumn.setCellFactory(

View File

@ -93,10 +93,18 @@ class OpenOffersViewModel extends ActivatableWithDataModel<OpenOffersDataModel>
Offer offer = item.getOffer();
Price price = offer.getPrice();
if (price != null) {
String postFix = "";
if (offer.isUseMarketBasedPrice())
postFix = " (" + FormattingUtils.formatPercentagePrice(offer.getMarketPriceMargin()) + ")";
return FormattingUtils.formatPrice(price) + postFix;
return FormattingUtils.formatPrice(price);
} else {
return Res.get("shared.na");
}
}
String getPriceDeviation(OpenOfferListItem item) {
if ((item == null))
return "";
Offer offer = item.getOffer();
if (offer.isUseMarketBasedPrice()) {
return FormattingUtils.formatPercentagePrice(offer.getMarketPriceMargin());
} else {
return Res.get("shared.na");
}