Adapt offer book chart view to new navigational structure

This commit is contained in:
Christoph Atteneder 2022-04-01 13:30:40 +02:00
parent 98f355d3fa
commit 875e5f4e87
No known key found for this signature in database
GPG key ID: CD5DC1C529CDFD3B
4 changed files with 89 additions and 91 deletions

View file

@ -301,10 +301,10 @@ market.tabs.spreadPayment=Offers by Payment Method
market.tabs.trades=Trades
# OfferBookChartView
market.offerBook.buyAltcoin=Buy {0} (sell {1})
market.offerBook.sellAltcoin=Sell {0} (buy {1})
market.offerBook.buyWithFiat=Buy {0}
market.offerBook.sellWithFiat=Sell {0}
market.offerBook.buyAltcoin=Buy {0}
market.offerBook.sellAltcoin=Sell {0}
market.offerBook.buyWith=Buy {0}
market.offerBook.sellWith=Sell {0}
market.offerBook.sellOffersHeaderLabel=Sell {0} to
market.offerBook.buyOffersHeaderLabel=Buy {0} from
market.offerBook.buy=I want to buy bitcoin

View file

@ -29,7 +29,14 @@ import bisq.desktop.components.PeerInfoIconSmall;
import bisq.desktop.main.MainView;
import bisq.desktop.main.offer.BuyOfferView;
import bisq.desktop.main.offer.SellOfferView;
import bisq.desktop.main.offer.offerbook.BsqOfferBookView;
import bisq.desktop.main.offer.offerbook.BsqOfferBookViewModel;
import bisq.desktop.main.offer.offerbook.BtcOfferBookView;
import bisq.desktop.main.offer.offerbook.OfferBookListItem;
import bisq.desktop.main.offer.offerbook.OfferBookView;
import bisq.desktop.main.offer.offerbook.OtherOfferBookView;
import bisq.desktop.main.offer.offerbook.TopAltcoinOfferBookView;
import bisq.desktop.main.offer.offerbook.TopAltcoinOfferBookViewModel;
import bisq.desktop.util.CurrencyListItem;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.GUIUtil;
@ -85,9 +92,7 @@ import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.util.Callback;
import javafx.util.StringConverter;
@ -118,19 +123,19 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
private Subscription tradeCurrencySubscriber;
private final StringProperty volumeColumnLabel = new SimpleStringProperty();
private final StringProperty priceColumnLabel = new SimpleStringProperty();
private AutoTooltipButton leftButton;
private AutoTooltipButton rightButton;
private AutoTooltipButton sellButton;
private AutoTooltipButton buyButton;
private ChangeListener<Number> selectedTabIndexListener;
private SingleSelectionModel<Tab> tabPaneSelectionModel;
private Label leftHeaderLabel, rightHeaderLabel;
private Label sellHeaderLabel, buyHeaderLabel;
private ChangeListener<OfferListItem> sellTableRowSelectionListener, buyTableRowSelectionListener;
private HBox bottomHBox;
private ListChangeListener<OfferBookListItem> changeListener;
private ListChangeListener<CurrencyListItem> currencyListItemsListener;
private final double dataLimitFactor = 3;
private final double initialOfferTableViewHeight = 121;
private final double pixelsPerOfferTableRow = (initialOfferTableViewHeight - 30) / 5.0; // initial visible row count=5, header height=30
private final Function<Double, Double> offerTableViewHeight = (screenSize) -> {
// initial visible row count=5, header height=30
double pixelsPerOfferTableRow = (initialOfferTableViewHeight - 30) / 5.0;
int extraRows = screenSize <= INITIAL_WINDOW_HEIGHT ? 0 : (int) ((screenSize - INITIAL_WINDOW_HEIGHT) / pixelsPerOfferTableRow);
return extraRows == 0 ? initialOfferTableViewHeight : Math.ceil(initialOfferTableViewHeight + ((extraRows + 1) * pixelsPerOfferTableRow));
};
@ -169,13 +174,13 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
buyOfferTableView = tupleBuy.first;
sellOfferTableView = tupleSell.first;
leftButton = (AutoTooltipButton) tupleBuy.third;
rightButton = (AutoTooltipButton) tupleSell.third;
sellButton = (AutoTooltipButton) tupleBuy.third;
buyButton = (AutoTooltipButton) tupleSell.third;
leftHeaderLabel = tupleBuy.fourth;
rightHeaderLabel = tupleSell.fourth;
sellHeaderLabel = tupleBuy.fourth;
buyHeaderLabel = tupleSell.fourth;
bottomHBox = new HBox();
HBox bottomHBox = new HBox();
bottomHBox.setSpacing(20); //30
bottomHBox.setAlignment(Pos.CENTER);
VBox.setMargin(bottomHBox, new Insets(-5, 0, 0, 0));
@ -225,15 +230,15 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
String code = tradeCurrency.getCode();
volumeColumnLabel.set(Res.get("offerbook.volume", code));
xAxis.setTickLabelFormatter(new StringConverter<>() {
int cryptoPrecision = 3;
DecimalFormat df = new DecimalFormat(",###");
final int cryptoPrecision = 3;
final DecimalFormat df = new DecimalFormat(",###");
@Override
public String toString(Number object) {
final double doubleValue = (double) object;
if (CurrencyUtil.isCryptoCurrency(model.getCurrencyCode())) {
final String withCryptoPrecision = FormattingUtils.formatRoundedDoubleWithPrecision(doubleValue, cryptoPrecision);
if (withCryptoPrecision.substring(0, 3).equals("0.0")) {
if (withCryptoPrecision.startsWith("0.0")) {
return FormattingUtils.formatRoundedDoubleWithPrecision(doubleValue, 8).replaceFirst("0+$", "");
} else {
return withCryptoPrecision.replaceFirst("0+$", "");
@ -249,37 +254,21 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
}
});
if (CurrencyUtil.isCryptoCurrency(code)) {
if (bottomHBox.getChildren().size() == 2 && bottomHBox.getChildren().get(0).getUserData().equals(OfferDirection.BUY.name())) {
bottomHBox.getChildren().get(0).toFront();
reverseTableColumns();
}
String viewBaseCurrencyCode = CurrencyUtil.isCryptoCurrency(code) ? code : Res.getBaseCurrencyCode();
String viewPriceCurrencyCode = CurrencyUtil.isCryptoCurrency(code) ? Res.getBaseCurrencyCode() : code;
leftHeaderLabel.setText(Res.get("market.offerBook.buyOffersHeaderLabel", code));
leftButton.updateText(Res.get("market.offerBook.buyAltcoin", code, Res.getBaseCurrencyCode()));
sellHeaderLabel.setText(Res.get("market.offerBook.sellOffersHeaderLabel", viewBaseCurrencyCode));
sellButton.updateText(Res.get("market.offerBook.sellWith", viewBaseCurrencyCode, viewPriceCurrencyCode));
rightHeaderLabel.setText(Res.get("market.offerBook.sellOffersHeaderLabel", code));
rightButton.updateText(Res.get("market.offerBook.sellAltcoin", code, Res.getBaseCurrencyCode()));
buyHeaderLabel.setText(Res.get("market.offerBook.buyOffersHeaderLabel", viewBaseCurrencyCode));
buyButton.updateText(Res.get("market.offerBook.buyWith", viewBaseCurrencyCode, viewPriceCurrencyCode));
priceColumnLabel.set(Res.get("shared.priceWithCur", Res.getBaseCurrencyCode()));
} else {
if (bottomHBox.getChildren().size() == 2 && bottomHBox.getChildren().get(0).getUserData().equals(OfferDirection.SELL.name())) {
bottomHBox.getChildren().get(0).toFront();
reverseTableColumns();
}
priceColumnLabel.set(Res.get("shared.priceWithCur", viewPriceCurrencyCode));
leftHeaderLabel.setText(Res.get("market.offerBook.sellOffersHeaderLabel", Res.getBaseCurrencyCode()));
leftButton.updateText(Res.get("market.offerBook.sellWithFiat", Res.getBaseCurrencyCode(), code));
rightHeaderLabel.setText(Res.get("market.offerBook.buyOffersHeaderLabel", Res.getBaseCurrencyCode()));
rightButton.updateText(Res.get("market.offerBook.buyWithFiat", Res.getBaseCurrencyCode(), code));
priceColumnLabel.set(Res.get("shared.priceWithCur", code));
}
xAxis.setLabel(CurrencyUtil.getPriceWithCurrencyCode(code));
seriesBuy.setName(leftHeaderLabel.getText() + " ");
seriesSell.setName(rightHeaderLabel.getText());
seriesBuy.setName(sellHeaderLabel.getText() + " ");
seriesSell.setName(buyHeaderLabel.getText());
});
buyOfferTableView.setItems(model.getTopBuyOfferList());
@ -295,7 +284,7 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
}
static class CurrencyListItemStringConverter extends StringConverter<CurrencyListItem> {
private ComboBox<CurrencyListItem> comboBox;
private final ComboBox<CurrencyListItem> comboBox;
CurrencyListItemStringConverter(ComboBox<CurrencyListItem> comboBox) {
this.comboBox = comboBox;
@ -390,33 +379,30 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
seriesSell.getData().clear();
areaChart.getData().clear();
boolean isCrypto = CurrencyUtil.isCryptoCurrency(model.getCurrencyCode());
// crypto: left-sell, right-buy. fiat: left-buy, right-sell
seriesBuy.getData().addAll(filterOutliersBuy(model.getBuyData(), isCrypto));
seriesSell.getData().addAll(filterOutliersSell(model.getSellData(), isCrypto));
seriesBuy.getData().addAll(filterOutliersBuy(model.getBuyData()));
seriesSell.getData().addAll(filterOutliersSell(model.getSellData()));
areaChart.getData().addAll(List.of(seriesBuy, seriesSell));
}
List<XYChart.Data<Number, Number>> filterOutliersBuy(List<XYChart.Data<Number, Number>> buy, boolean isCrypto) {
List<Double> mnmx = isCrypto ? minMaxFilterRight(buy) : minMaxFilterLeft(buy);
if (mnmx.get(0).doubleValue() == Double.MAX_VALUE ||
mnmx.get(1).doubleValue() == Double.MIN_VALUE) { // no filtering
List<XYChart.Data<Number, Number>> filterOutliersBuy(List<XYChart.Data<Number, Number>> buy) {
List<Double> mnmx = minMaxFilterLeft(buy);
if (mnmx.get(0) == Double.MAX_VALUE ||
mnmx.get(1) == Double.MIN_VALUE) { // no filtering
return buy;
}
// apply filtering
return isCrypto ? filterRight(buy, mnmx.get(0)) : filterLeft(buy, mnmx.get(1));
return filterLeft(buy, mnmx.get(1));
}
List<XYChart.Data<Number, Number>> filterOutliersSell(List<XYChart.Data<Number, Number>> sell, boolean isCrypto) {
List<Double> mnmx = isCrypto ? minMaxFilterLeft(sell) : minMaxFilterRight(sell);
if (mnmx.get(0).doubleValue() == Double.MAX_VALUE ||
mnmx.get(1).doubleValue() == Double.MIN_VALUE) { // no filtering
List<XYChart.Data<Number, Number>> filterOutliersSell(List<XYChart.Data<Number, Number>> sell) {
List<Double> mnmx = minMaxFilterRight(sell);
if (mnmx.get(0) == Double.MAX_VALUE ||
mnmx.get(1) == Double.MIN_VALUE) { // no filtering
return sell;
}
// apply filtering
return isCrypto ? filterLeft(sell, mnmx.get(1)) : filterRight(sell, mnmx.get(0));
return filterRight(sell, mnmx.get(0));
}
private List<Double> minMaxFilterLeft(List<XYChart.Data<Number, Number>> data) {
@ -674,12 +660,35 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
button.setMinHeight(32);
button.setId(isSellOffer ? "buy-button-big" : "sell-button-big");
button.setOnAction(e -> {
if (isSellOffer) {
model.preferences.setBuyScreenCurrencyCode(model.getCurrencyCode());
navigation.navigateTo(MainView.class, BuyOfferView.class);
Class<? extends OfferBookView<?, ?>> offerBookViewClazz;
if (CurrencyUtil.isFiatCurrency(model.getCurrencyCode())) {
offerBookViewClazz = BtcOfferBookView.class;
} else if (model.getCurrencyCode().equals(BsqOfferBookViewModel.BSQ.getCode())) {
offerBookViewClazz = BsqOfferBookView.class;
} else if (model.getCurrencyCode().equals(TopAltcoinOfferBookViewModel.TOP_ALTCOIN.getCode())) {
offerBookViewClazz = TopAltcoinOfferBookView.class;
} else {
model.preferences.setSellScreenCurrencyCode(model.getCurrencyCode());
navigation.navigateTo(MainView.class, SellOfferView.class);
offerBookViewClazz = OtherOfferBookView.class;
}
if (isSellOffer) {
if (CurrencyUtil.isFiatCurrency(model.getCurrencyCode())) {
model.preferences.setBuyScreenCurrencyCode(model.getCurrencyCode());
} else if (!model.getCurrencyCode().equals(BsqOfferBookViewModel.BSQ.getCode()) &&
model.getCurrencyCode().equals(TopAltcoinOfferBookViewModel.TOP_ALTCOIN.getCode())) {
model.preferences.setBuyScreenCryptoCurrencyCode(model.getCurrencyCode());
}
navigation.navigateTo(MainView.class, BuyOfferView.class, offerBookViewClazz);
} else {
if (CurrencyUtil.isFiatCurrency(model.getCurrencyCode())) {
model.preferences.setSellScreenCurrencyCode(model.getCurrencyCode());
} else if (!model.getCurrencyCode().equals(BsqOfferBookViewModel.BSQ.getCode()) &&
model.getCurrencyCode().equals(TopAltcoinOfferBookViewModel.TOP_ALTCOIN.getCode())) {
model.preferences.setSellScreenCryptoCurrencyCode(model.getCurrencyCode());
}
navigation.navigateTo(MainView.class, SellOfferView.class, offerBookViewClazz);
}
});
@ -700,18 +709,6 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
return new Tuple4<>(tableView, vBox, button, titleLabel);
}
private void reverseTableColumns() {
ObservableList<TableColumn<OfferListItem, ?>> columns = FXCollections.observableArrayList(buyOfferTableView.getColumns());
buyOfferTableView.getColumns().clear();
FXCollections.reverse(columns);
buyOfferTableView.getColumns().addAll(columns);
columns = FXCollections.observableArrayList(sellOfferTableView.getColumns());
sellOfferTableView.getColumns().clear();
FXCollections.reverse(columns);
sellOfferTableView.getColumns().addAll(columns);
}
private void layout() {
UserThread.runAfter(() -> {
if (root.getScene() != null) {

View file

@ -293,7 +293,7 @@ class OfferBookChartViewModel extends ActivatableViewModel {
// the buy column is actually the sell column and vice versa. To maintain the expected
// ordering, we have to reverse the price comparator.
boolean isCrypto = CurrencyUtil.isCryptoCurrency(getCurrencyCode());
if (isCrypto) offerPriceComparator = offerPriceComparator.reversed();
// if (isCrypto) offerPriceComparator = offerPriceComparator.reversed();
// Offer amounts are used for the secondary sort. They are sorted from high to low.
Comparator<Offer> offerAmountComparator = Comparator.comparing(Offer::getAmount).reversed();
@ -305,10 +305,12 @@ class OfferBookChartViewModel extends ActivatableViewModel {
offerPriceComparator
.thenComparing(offerAmountComparator);
OfferDirection buyOfferDirection = isCrypto ? OfferDirection.SELL : OfferDirection.BUY;
List<Offer> allBuyOffers = offerBookListItems.stream()
.map(OfferBookListItem::getOffer)
.filter(e -> e.getCurrencyCode().equals(selectedTradeCurrencyProperty.get().getCode())
&& e.getDirection().equals(OfferDirection.BUY))
&& e.getDirection().equals(buyOfferDirection))
.sorted(buyOfferSortComparator)
.collect(Collectors.toList());
@ -334,10 +336,12 @@ class OfferBookChartViewModel extends ActivatableViewModel {
buildChartAndTableEntries(allBuyOffers, OfferDirection.BUY, buyData, topBuyOfferList);
OfferDirection sellOfferDirection = isCrypto ? OfferDirection.BUY : OfferDirection.SELL;
List<Offer> allSellOffers = offerBookListItems.stream()
.map(OfferBookListItem::getOffer)
.filter(e -> e.getCurrencyCode().equals(selectedTradeCurrencyProperty.get().getCode())
&& e.getDirection().equals(OfferDirection.SELL))
&& e.getDirection().equals(sellOfferDirection))
.sorted(sellOfferSortComparator)
.collect(Collectors.toList());
@ -377,17 +381,10 @@ class OfferBookChartViewModel extends ActivatableViewModel {
offerTableListTemp.add(new OfferListItem(offer, accumulatedAmount));
double priceAsDouble = (double) price.getValue() / LongMath.pow(10, price.smallestUnitExponent());
if (CurrencyUtil.isCryptoCurrency(getCurrencyCode())) {
if (direction.equals(OfferDirection.SELL))
data.add(0, new XYChart.Data<>(priceAsDouble, accumulatedAmount));
else
data.add(new XYChart.Data<>(priceAsDouble, accumulatedAmount));
} else {
if (direction.equals(OfferDirection.BUY))
data.add(0, new XYChart.Data<>(priceAsDouble, accumulatedAmount));
else
data.add(new XYChart.Data<>(priceAsDouble, accumulatedAmount));
}
if (direction.equals(OfferDirection.BUY))
data.add(0, new XYChart.Data<>(priceAsDouble, accumulatedAmount));
else
data.add(new XYChart.Data<>(priceAsDouble, accumulatedAmount));
}
}
offerTableList.setAll(offerTableListTemp);

View file

@ -260,23 +260,27 @@ public abstract class OfferView extends ActivatableView<TabPane, Void> {
btcOfferBookTab.setContent(btcOfferBookView.getRoot());
btcOfferBookView.setOfferActionHandler(offerActionHandler);
btcOfferBookView.setDirection(direction);
tabPane.getSelectionModel().select(btcOfferBookTab);
btcOfferBookView.onTabSelected(true);
} else if (viewClass == BsqOfferBookView.class) {
bsqOfferBookView = (OfferBookView) viewLoader.load(BsqOfferBookView.class);
bsqOfferBookView.setOfferActionHandler(offerActionHandler);
bsqOfferBookView.setDirection(direction);
tabPane.getSelectionModel().select(bsqOfferBookTab);
bsqOfferBookTab.setContent(bsqOfferBookView.getRoot());
bsqOfferBookView.onTabSelected(true);
} else if (viewClass == TopAltcoinOfferBookView.class) {
topAltcoinOfferBookView = (OfferBookView) viewLoader.load(TopAltcoinOfferBookView.class);
topAltcoinOfferBookView.setOfferActionHandler(offerActionHandler);
topAltcoinOfferBookView.setDirection(direction);
tabPane.getSelectionModel().select(topAltcoinOfferBookTab);
topAltcoinOfferBookTab.setContent(topAltcoinOfferBookView.getRoot());
topAltcoinOfferBookView.onTabSelected(true);
} else if (viewClass == OtherOfferBookView.class) {
otherOfferBookView = (OfferBookView) viewLoader.load(OtherOfferBookView.class);
otherOfferBookView.setOfferActionHandler(offerActionHandler);
otherOfferBookView.setDirection(direction);
tabPane.getSelectionModel().select(otherOfferBookTab);
otherOfferBookTab.setContent(otherOfferBookView.getRoot());
otherOfferBookView.onTabSelected(true);
}