diff --git a/core/src/main/java/haveno/core/util/VolumeUtil.java b/core/src/main/java/haveno/core/util/VolumeUtil.java index b74a70f226..050b7b1a4d 100644 --- a/core/src/main/java/haveno/core/util/VolumeUtil.java +++ b/core/src/main/java/haveno/core/util/VolumeUtil.java @@ -51,6 +51,7 @@ import org.bitcoinj.utils.MonetaryFormat; import java.math.BigInteger; import java.text.DecimalFormat; import java.text.NumberFormat; +import java.util.Collection; import java.util.Locale; public class VolumeUtil { @@ -187,4 +188,35 @@ public class VolumeUtil { private static MonetaryFormat getMonetaryFormat(String currencyCode) { return CurrencyUtil.isVolumeRoundedToNearestUnit(currencyCode) ? VOLUME_FORMAT_UNIT : VOLUME_FORMAT_PRECISE; } + + public static Volume sum(Collection volumes) { + if (volumes == null || volumes.isEmpty()) { + return null; + } + Volume sum = null; + for (Volume volume : volumes) { + if (sum == null) { + sum = volume; + } else { + if (!sum.getCurrencyCode().equals(volume.getCurrencyCode())) { + throw new IllegalArgumentException("Cannot sum volumes with different currencies"); + } + sum = add(sum, volume); + } + } + return sum; + } + + public static Volume add(Volume volume1, Volume volume2) { + if (volume1 == null) return volume2; + if (volume2 == null) return volume1; + if (!volume1.getCurrencyCode().equals(volume2.getCurrencyCode())) { + throw new IllegalArgumentException("Cannot add volumes with different currencies"); + } + if (volume1.getMonetary() instanceof CryptoMoney) { + return new Volume(((CryptoMoney) volume1.getMonetary()).add((CryptoMoney) volume2.getMonetary())); + } else { + return new Volume(((TraditionalMoney) volume1.getMonetary()).add((TraditionalMoney) volume2.getMonetary())); + } + } } diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index b6306bf75b..10aac01898 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -407,8 +407,10 @@ shared.notSigned.noNeedAlts=Cryptocurrency accounts do not feature signing or ag offerbook.nrOffers=No. of offers: {0} offerbook.volume={0} (min - max) +offerbook.volumeTotal={0} ({1}) offerbook.deposit=Deposit XMR (%) offerbook.deposit.help=Deposit paid by each trader to guarantee the trade. Will be returned when the trade is completed. +offerbook.XMRTotal=XMR ({0}) offerbook.createNewOffer=Create offer to {0} {1} offerbook.createOfferDisabled.tooltip=You can only create one offer at a time diff --git a/desktop/src/main/java/haveno/desktop/main/market/offerbook/OfferBookChartView.java b/desktop/src/main/java/haveno/desktop/main/market/offerbook/OfferBookChartView.java index 608f714301..17210a52b3 100644 --- a/desktop/src/main/java/haveno/desktop/main/market/offerbook/OfferBookChartView.java +++ b/desktop/src/main/java/haveno/desktop/main/market/offerbook/OfferBookChartView.java @@ -95,7 +95,10 @@ public class OfferBookChartView extends ActivatableViewAndModel currencyComboBox; private Subscription tradeCurrencySubscriber; - private final StringProperty volumeColumnLabel = new SimpleStringProperty(); + private final StringProperty volumeSellColumnLabel = new SimpleStringProperty(); + private final StringProperty volumeBuyColumnLabel = new SimpleStringProperty(); + private final StringProperty amountSellColumnLabel = new SimpleStringProperty(); + private final StringProperty amountBuyColumnLabel = new SimpleStringProperty(); private final StringProperty priceColumnLabel = new SimpleStringProperty(); private AutoTooltipButton sellButton; private AutoTooltipButton buyButton; @@ -201,7 +204,6 @@ public class OfferBookChartView extends ActivatableViewAndModel { String code = tradeCurrency.getCode(); - volumeColumnLabel.set(Res.get("offerbook.volume", code)); xAxis.setTickLabelFormatter(new StringConverter<>() { final int cryptoPrecision = 3; final DecimalFormat df = new DecimalFormat(",###"); @@ -351,6 +353,11 @@ public class OfferBookChartView extends ActivatableViewAndModel volumeColumn = new TableColumn<>(); volumeColumn.setMinWidth(115); volumeColumn.setSortable(false); - volumeColumn.textProperty().bind(volumeColumnLabel); + volumeColumn.textProperty().bind(isSellTable ? volumeSellColumnLabel : volumeBuyColumnLabel); volumeColumn.getStyleClass().addAll("number-column"); volumeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue())); volumeColumn.setCellFactory( @@ -553,7 +562,8 @@ public class OfferBookChartView extends ActivatableViewAndModel amountColumn = new AutoTooltipTableColumn<>(Res.get("shared.XMRMinMax")); + TableColumn amountColumn = new TableColumn<>(); + amountColumn.textProperty().bind(isSellTable ? amountSellColumnLabel : amountBuyColumnLabel); amountColumn.setMinWidth(115); amountColumn.setSortable(false); amountColumn.getStyleClass().add("number-column"); @@ -577,10 +587,8 @@ public class OfferBookChartView extends ActivatableViewAndModel avatarColumn = new AutoTooltipTableColumn<>(isSellOffer ? + TableColumn avatarColumn = new AutoTooltipTableColumn<>(isSellTable ? Res.get("shared.sellerUpperCase") : Res.get("shared.buyerUpperCase")) { { setMinWidth(80); @@ -645,7 +653,7 @@ public class OfferBookChartView extends ActivatableViewAndModel model.goToOfferView(direction)); diff --git a/desktop/src/main/java/haveno/desktop/main/market/offerbook/OfferBookChartViewModel.java b/desktop/src/main/java/haveno/desktop/main/market/offerbook/OfferBookChartViewModel.java index 91b962af95..0c14239f60 100644 --- a/desktop/src/main/java/haveno/desktop/main/market/offerbook/OfferBookChartViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/market/offerbook/OfferBookChartViewModel.java @@ -26,6 +26,7 @@ import haveno.core.locale.CurrencyUtil; import haveno.core.locale.GlobalSettings; import haveno.core.locale.TradeCurrency; import haveno.core.monetary.Price; +import haveno.core.monetary.Volume; import haveno.core.offer.Offer; import haveno.core.offer.OfferDirection; import haveno.core.offer.OpenOfferManager; @@ -215,6 +216,29 @@ class OfferBookChartViewModel extends ActivatableViewModel { return direction == OfferDirection.SELL; } + public double getTotalAmount(OfferDirection direction) { + synchronized (offerBookListItems) { + return offerBookListItems.stream() + .map(OfferBookListItem::getOffer) + .filter(e -> e.getCurrencyCode().equals(selectedTradeCurrencyProperty.get().getCode()) + && e.getDirection().equals(direction)) + .mapToDouble(item -> HavenoUtils.atomicUnitsToXmr(item.getAmount())) + .sum(); + } + } + + public Volume getTotalVolume(OfferDirection direction) { + synchronized (offerBookListItems) { + List volumes = offerBookListItems.stream() + .map(OfferBookListItem::getOffer) + .filter(e -> e.getCurrencyCode().equals(selectedTradeCurrencyProperty.get().getCode()) + && e.getDirection().equals(direction)) + .map(Offer::getVolume) + .collect(Collectors.toList()); + return VolumeUtil.sum(volumes); + } + } + public boolean isMyOffer(Offer offer) { return openOfferManager.isMyOffer(offer); }