Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move volume formatting from DisplayUtils to VolumeUtil #5740

Merged
merged 2 commits into from
Oct 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions core/src/main/java/bisq/core/util/VolumeUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,28 @@

package bisq.core.util;

import bisq.core.locale.Res;
import bisq.core.monetary.Altcoin;
import bisq.core.monetary.AltcoinExchangeRate;
import bisq.core.monetary.Price;
import bisq.core.monetary.Volume;
import bisq.core.offer.Offer;

import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Monetary;
import org.bitcoinj.utils.ExchangeRate;
import org.bitcoinj.utils.Fiat;
import org.bitcoinj.utils.MonetaryFormat;

import java.text.DecimalFormat;
import java.text.NumberFormat;

import java.util.Locale;

public class VolumeUtil {

private static final MonetaryFormat FIAT_VOLUME_FORMAT = new MonetaryFormat().shift(0).minDecimals(0).repeatOptionalDecimals(0, 0);

public static Volume getRoundedFiatVolume(Volume volumeByAmount) {
// We want to get rounded to 1 unit of the fiat currency, e.g. 1 EUR.
return getAdjustedFiatVolume(volumeByAmount, 1);
Expand Down Expand Up @@ -62,4 +73,76 @@ public static Volume getVolume(Coin amount, Price price) {
return new Volume(new ExchangeRate((Fiat) price.getMonetary()).coinToFiat(amount));
}
}


public static String formatVolume(Offer offer, Boolean decimalAligned, int maxNumberOfDigits) {
return formatVolume(offer, decimalAligned, maxNumberOfDigits, true);
}

public static String formatVolume(Offer offer, Boolean decimalAligned, int maxNumberOfDigits, boolean showRange) {
String formattedVolume = offer.isRange() && showRange
? formatVolume(offer.getMinVolume()) + FormattingUtils.RANGE_SEPARATOR + formatVolume(offer.getVolume())
: formatVolume(offer.getVolume());

if (decimalAligned) {
formattedVolume = FormattingUtils.fillUpPlacesWithEmptyStrings(formattedVolume, maxNumberOfDigits);
}
return formattedVolume;
}

public static String formatLargeFiat(double value, String currency) {
if (value <= 0) {
return "0";
}
NumberFormat numberFormat = DecimalFormat.getInstance(Locale.US);
numberFormat.setGroupingUsed(true);
return numberFormat.format(value) + " " + currency;
}

public static String formatLargeFiatWithUnitPostFix(double value, String currency) {
if (value <= 0) {
return "0";
}
String[] units = new String[]{"", "K", "M", "B"};
int digitGroups = (int) (Math.log10(value) / Math.log10(1000));
return new DecimalFormat("#,##0.###")
.format(value / Math.pow(1000, digitGroups)) + units[digitGroups] + " " + currency;
}

public static String formatVolume(Volume volume) {
return formatVolume(volume, FIAT_VOLUME_FORMAT, false);
}

private static String formatVolume(Volume volume, MonetaryFormat fiatVolumeFormat, boolean appendCurrencyCode) {
if (volume != null) {
Monetary monetary = volume.getMonetary();
if (monetary instanceof Fiat)
return FormattingUtils.formatFiat((Fiat) monetary, fiatVolumeFormat, appendCurrencyCode);
else
return FormattingUtils.formatAltcoinVolume((Altcoin) monetary, appendCurrencyCode);
} else {
return "";
}
}

public static String formatVolumeWithCode(Volume volume) {
return formatVolume(volume, true);
}

public static String formatVolume(Volume volume, boolean appendCode) {
return formatVolume(volume, FIAT_VOLUME_FORMAT, appendCode);
}

public static String formatAverageVolumeWithCode(Volume volume) {
return formatVolume(volume, FIAT_VOLUME_FORMAT.minDecimals(2), true);
}

public static String formatVolumeLabel(String currencyCode) {
return formatVolumeLabel(currencyCode, "");
}

public static String formatVolumeLabel(String currencyCode, String postFix) {
return Res.get("formatter.formatVolumeLabel",
currencyCode, postFix);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import bisq.desktop.main.overlays.windows.TxDetailsBsq;
import bisq.desktop.main.overlays.windows.TxInputSelectionWindow;
import bisq.desktop.main.overlays.windows.WalletPasswordWindow;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.FormBuilder;
import bisq.desktop.util.GUIUtil;
import bisq.desktop.util.Layout;
Expand All @@ -54,6 +53,7 @@
import bisq.core.user.Preferences;
import bisq.core.util.FormattingUtils;
import bisq.core.util.ParsingUtils;
import bisq.core.util.VolumeUtil;
import bisq.core.util.coin.BsqFormatter;
import bisq.core.util.coin.CoinFormatter;
import bisq.core.util.coin.CoinUtil;
Expand Down Expand Up @@ -256,7 +256,7 @@ public void onUpdateBalances(Coin availableConfirmedBalance,
}

public void fillFromTradeData(Tuple2<Volume, String> tuple) {
amountInputTextField.setText(DisplayUtils.formatVolume(tuple.first));
amountInputTextField.setText(VolumeUtil.formatVolume(tuple.first));
receiversAddressInputTextField.setText(tuple.second);
}

Expand Down Expand Up @@ -528,7 +528,7 @@ public void onFailure(TxBroadcastException exception) {
private void doWithdraw(Transaction txWithBtcFee, TxType txType, TxBroadcaster.Callback callback) {
if (btcWalletService.isEncrypted()) {
UserThread.runAfter(() -> walletPasswordWindow.onAesKey(aesKey ->
sendFunds(txWithBtcFee, txType, callback))
sendFunds(txWithBtcFee, txType, callback))
.show(), 300, TimeUnit.MILLISECONDS);
} else {
sendFunds(txWithBtcFee, txType, callback);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import bisq.core.trade.statistics.TradeStatistics3;
import bisq.core.trade.statistics.TradeStatistics3StorageService;
import bisq.core.util.FormattingUtils;
import bisq.core.util.VolumeUtil;
import bisq.core.util.coin.CoinFormatter;

import bisq.common.util.Utilities;
Expand Down Expand Up @@ -198,7 +199,7 @@ private String getAllTradesWithReferralId() {
.append("Market: ").append(CurrencyUtil.getCurrencyPair(tradeStatistics3.getCurrency())).append("\n")
.append("Price: ").append(FormattingUtils.formatPrice(tradeStatistics3.getTradePrice())).append("\n")
.append("Amount: ").append(formatter.formatCoin(tradeStatistics3.getTradeAmount())).append("\n")
.append("Volume: ").append(DisplayUtils.formatVolume(tradeStatistics3.getTradeVolume())).append("\n")
.append("Volume: ").append(VolumeUtil.formatVolume(tradeStatistics3.getTradeVolume())).append("\n")
.append("Payment method: ").append(Res.get(tradeStatistics3.getPaymentMethod())).append("\n")
.append("ReferralID: ").append(tradeStatistics3.getExtraDataMap().get(OfferPayload.REFERRAL_ID));
return sb.toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import bisq.core.offer.Offer;
import bisq.core.offer.OfferPayload;
import bisq.core.util.FormattingUtils;
import bisq.core.util.VolumeUtil;
import bisq.core.util.coin.CoinFormatter;

import bisq.network.p2p.NodeAddress;
Expand Down Expand Up @@ -88,11 +89,11 @@
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;

import java.text.DecimalFormat;

import javafx.util.Callback;
import javafx.util.StringConverter;

import java.text.DecimalFormat;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
Expand Down Expand Up @@ -140,7 +141,9 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
///////////////////////////////////////////////////////////////////////////////////////////

@Inject
public OfferBookChartView(OfferBookChartViewModel model, Navigation navigation, @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter,
public OfferBookChartView(OfferBookChartViewModel model,
Navigation navigation,
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter,
@Named(Config.USE_DEV_PRIVILEGE_KEYS) boolean useDevPrivilegeKeys) {
super(model);
this.navigation = navigation;
Expand Down Expand Up @@ -230,7 +233,7 @@ 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.substring(0, 3).equals("0.0")) {
return FormattingUtils.formatRoundedDoubleWithPrecision(doubleValue, 8).replaceFirst("0+$", "");
} else {
return withCryptoPrecision.replaceFirst("0+$", "");
Expand Down Expand Up @@ -398,7 +401,7 @@ private void updateChartData() {
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
mnmx.get(1).doubleValue() == Double.MIN_VALUE) { // no filtering
return buy;
}
// apply filtering
Expand All @@ -408,7 +411,7 @@ List<XYChart.Data<Number, Number>> filterOutliersBuy(List<XYChart.Data<Number, N
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
mnmx.get(1).doubleValue() == Double.MIN_VALUE) { // no filtering
return sell;
}
// apply filtering
Expand All @@ -417,43 +420,43 @@ List<XYChart.Data<Number, Number>> filterOutliersSell(List<XYChart.Data<Number,

private List<Double> minMaxFilterLeft(List<XYChart.Data<Number, Number>> data) {
double maxValue = data.stream()
.mapToDouble(o -> o.getXValue().doubleValue())
.max()
.orElse(Double.MIN_VALUE);
.mapToDouble(o -> o.getXValue().doubleValue())
.max()
.orElse(Double.MIN_VALUE);
// Hide offers less than a div-factor of dataLimitFactor lower than the highest offer.
double minValue = data.stream()
.mapToDouble(o -> o.getXValue().doubleValue())
.filter(o -> o > maxValue / dataLimitFactor)
.min()
.orElse(Double.MAX_VALUE);
.mapToDouble(o -> o.getXValue().doubleValue())
.filter(o -> o > maxValue / dataLimitFactor)
.min()
.orElse(Double.MAX_VALUE);
return List.of(minValue, maxValue);
}

private List<Double> minMaxFilterRight(List<XYChart.Data<Number, Number>> data) {
double minValue = data.stream()
.mapToDouble(o -> o.getXValue().doubleValue())
.min()
.orElse(Double.MAX_VALUE);
.mapToDouble(o -> o.getXValue().doubleValue())
.min()
.orElse(Double.MAX_VALUE);

// Hide offers a dataLimitFactor factor higher than the lowest offer
double maxValue = data.stream()
.mapToDouble(o -> o.getXValue().doubleValue())
.filter(o -> o < minValue * dataLimitFactor)
.max()
.orElse(Double.MIN_VALUE);
.mapToDouble(o -> o.getXValue().doubleValue())
.filter(o -> o < minValue * dataLimitFactor)
.max()
.orElse(Double.MIN_VALUE);
return List.of(minValue, maxValue);
}

private List<XYChart.Data<Number, Number>> filterLeft(List<XYChart.Data<Number, Number>> data, double maxValue) {
return data.stream()
.filter(o -> o.getXValue().doubleValue() > maxValue / dataLimitFactor)
.collect(Collectors.toList());
.filter(o -> o.getXValue().doubleValue() > maxValue / dataLimitFactor)
.collect(Collectors.toList());
}

private List<XYChart.Data<Number, Number>> filterRight(List<XYChart.Data<Number, Number>> data, double minValue) {
return data.stream()
.filter(o -> o.getXValue().doubleValue() < minValue * dataLimitFactor)
.collect(Collectors.toList());
.filter(o -> o.getXValue().doubleValue() < minValue * dataLimitFactor)
.collect(Collectors.toList());
}

private Tuple4<TableView<OfferListItem>, VBox, Button, Label> getOfferTable(OfferPayload.Direction direction) {
Expand All @@ -479,7 +482,9 @@ public TableCell<OfferListItem, OfferListItem> call(TableColumn<OfferListItem, O
private Offer offer;
final ChangeListener<Number> listener = new ChangeListener<>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
public void changed(ObservableValue<? extends Number> observable,
Number oldValue,
Number newValue) {
if (offer != null && offer.getPrice() != null) {
setText("");
setGraphic(new ColoredDecimalPlacesWithZerosText(model.getPrice(offer),
Expand Down Expand Up @@ -529,7 +534,9 @@ public TableCell<OfferListItem, OfferListItem> call(TableColumn<OfferListItem, O
private Offer offer;
final ChangeListener<Number> listener = new ChangeListener<>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
public void changed(ObservableValue<? extends Number> observable,
Number oldValue,
Number newValue) {
if (offer != null && offer.getPrice() != null) {
renderCellContentRange();
model.priceFeedService.updateCounterProperty().removeListener(listener);
Expand Down Expand Up @@ -562,7 +569,7 @@ public void updateItem(final OfferListItem offerListItem, boolean empty) {
* Should not be called for empty cells
*/
private void renderCellContentRange() {
String volumeRange = DisplayUtils.formatVolume(offer, true, 2);
String volumeRange = VolumeUtil.formatVolume(offer, true, 2);

setText("");
setGraphic(new ColoredDecimalPlacesWithZerosText(volumeRange,
Expand Down Expand Up @@ -711,8 +718,8 @@ private void layout() {
if (buyOfferTableView.getHeight() != newTableViewHeight) {
buyOfferTableView.setMinHeight(newTableViewHeight);
sellOfferTableView.setMinHeight(newTableViewHeight);
}
}
}
}, 100, TimeUnit.MILLISECONDS);
}
}, 100, TimeUnit.MILLISECONDS);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import bisq.core.offer.OfferPayload;
import bisq.core.provider.price.PriceFeedService;
import bisq.core.user.Preferences;
import bisq.core.util.VolumeUtil;

import com.google.inject.Inject;

Expand Down Expand Up @@ -232,31 +233,41 @@ public ObservableList<CurrencyListItem> getCurrencyListItems() {
}

public Optional<CurrencyListItem> getSelectedCurrencyListItem() {
return currencyListItems.getObservableList().stream().filter(e -> e.tradeCurrency.equals(selectedTradeCurrencyProperty.get())).findAny();
return currencyListItems.getObservableList().stream()
.filter(e -> e.tradeCurrency.equals(selectedTradeCurrencyProperty.get())).findAny();
}

public int getMaxNumberOfPriceZeroDecimalsToColorize(Offer offer) {
return CurrencyUtil.isFiatCurrency(offer.getCurrencyCode()) ? GUIUtil.FIAT_DECIMALS_WITH_ZEROS : GUIUtil.ALTCOINS_DECIMALS_WITH_ZEROS;
return CurrencyUtil.isFiatCurrency(offer.getCurrencyCode())
? GUIUtil.FIAT_DECIMALS_WITH_ZEROS
: GUIUtil.ALTCOINS_DECIMALS_WITH_ZEROS;
}

public int getZeroDecimalsForPrice(Offer offer) {
return CurrencyUtil.isFiatCurrency(offer.getCurrencyCode()) ? GUIUtil.FIAT_PRICE_DECIMALS_WITH_ZEROS : GUIUtil.ALTCOINS_DECIMALS_WITH_ZEROS;
return CurrencyUtil.isFiatCurrency(offer.getCurrencyCode())
? GUIUtil.FIAT_PRICE_DECIMALS_WITH_ZEROS
: GUIUtil.ALTCOINS_DECIMALS_WITH_ZEROS;
}

public String getPrice(Offer offer) {
return formatPrice(offer, true);
}

private String formatPrice(Offer offer, boolean decimalAligned) {
return DisplayUtils.formatPrice(offer.getPrice(), decimalAligned, offer.isBuyOffer() ? maxPlacesForBuyPrice.get() : maxPlacesForSellPrice.get());
return DisplayUtils.formatPrice(offer.getPrice(), decimalAligned, offer.isBuyOffer()
? maxPlacesForBuyPrice.get()
: maxPlacesForSellPrice.get());
}

public String getVolume(Offer offer) {
return formatVolume(offer, true);
}

private String formatVolume(Offer offer, boolean decimalAligned) {
return DisplayUtils.formatVolume(offer, decimalAligned, offer.isBuyOffer() ? maxPlacesForBuyVolume.get() : maxPlacesForSellVolume.get(), false);
return VolumeUtil.formatVolume(offer,
decimalAligned,
offer.isBuyOffer() ? maxPlacesForBuyVolume.get() : maxPlacesForSellVolume.get(),
false);
}

///////////////////////////////////////////////////////////////////////////////////////////
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import bisq.core.locale.Res;
import bisq.core.trade.statistics.TradeStatistics3;
import bisq.core.util.FormattingUtils;
import bisq.core.util.VolumeUtil;
import bisq.core.util.coin.CoinFormatter;

import lombok.experimental.Delegate;
Expand Down Expand Up @@ -73,8 +74,8 @@ public String getPriceString() {
public String getVolumeString() {
if (volumeString == null) {
volumeString = tradeStatistics3 != null ? showAllTradeCurrencies ?
DisplayUtils.formatVolumeWithCode(tradeStatistics3.getTradeVolume()) :
DisplayUtils.formatVolume(tradeStatistics3.getTradeVolume())
VolumeUtil.formatVolumeWithCode(tradeStatistics3.getTradeVolume()) :
VolumeUtil.formatVolume(tradeStatistics3.getTradeVolume())
: "";
}
return volumeString;
Expand Down
Loading