add unit format menu selection for alternative grouping and decimal separators

This commit is contained in:
Craig Raw 2022-09-21 11:36:13 +02:00
parent 8270eb71db
commit 8fb6de85f1
33 changed files with 408 additions and 165 deletions

View file

@ -132,6 +132,9 @@ public class AppController implements Initializable {
@FXML @FXML
private ToggleGroup bitcoinUnit; private ToggleGroup bitcoinUnit;
@FXML
private ToggleGroup unitFormat;
@FXML @FXML
private ToggleGroup theme; private ToggleGroup theme;
@ -325,6 +328,15 @@ public class AppController implements Initializable {
Optional<Toggle> selectedUnitToggle = bitcoinUnit.getToggles().stream().filter(toggle -> selectedUnit.equals(toggle.getUserData())).findFirst(); Optional<Toggle> selectedUnitToggle = bitcoinUnit.getToggles().stream().filter(toggle -> selectedUnit.equals(toggle.getUserData())).findFirst();
selectedUnitToggle.ifPresent(toggle -> bitcoinUnit.selectToggle(toggle)); selectedUnitToggle.ifPresent(toggle -> bitcoinUnit.selectToggle(toggle));
UnitFormat format = Config.get().getUnitFormat();
if(format == null) {
format = UnitFormat.DOT;
Config.get().setUnitFormat(format);
}
final UnitFormat selectedFormat = format;
Optional<Toggle> selectedFormatToggle = unitFormat.getToggles().stream().filter(toggle -> selectedFormat.equals(toggle.getUserData())).findFirst();
selectedFormatToggle.ifPresent(toggle -> unitFormat.selectToggle(toggle));
Theme configTheme = Config.get().getTheme(); Theme configTheme = Config.get().getTheme();
if(configTheme == null) { if(configTheme == null) {
configTheme = Theme.LIGHT; configTheme = Theme.LIGHT;
@ -858,6 +870,13 @@ public class AppController implements Initializable {
EventManager.get().post(new BitcoinUnitChangedEvent(unit)); EventManager.get().post(new BitcoinUnitChangedEvent(unit));
} }
public void setUnitFormat(ActionEvent event) {
MenuItem item = (MenuItem)event.getSource();
UnitFormat format = (UnitFormat)item.getUserData();
Config.get().setUnitFormat(format);
EventManager.get().post(new UnitFormatChangedEvent(format));
}
public void preventSleep(ActionEvent event) { public void preventSleep(ActionEvent event) {
CheckMenuItem item = (CheckMenuItem)event.getSource(); CheckMenuItem item = (CheckMenuItem)event.getSource();
Config.get().setPreventSleep(item.isSelected()); Config.get().setPreventSleep(item.isSelected());
@ -2698,6 +2717,12 @@ public class AppController implements Initializable {
selectedToggle.ifPresent(toggle -> bitcoinUnit.selectToggle(toggle)); selectedToggle.ifPresent(toggle -> bitcoinUnit.selectToggle(toggle));
} }
@Subscribe
public void unitFormatChanged(UnitFormatChangedEvent event) {
Optional<Toggle> selectedToggle = unitFormat.getToggles().stream().filter(toggle -> event.getUnitFormat().equals(toggle.getUserData())).findFirst();
selectedToggle.ifPresent(toggle -> unitFormat.selectToggle(toggle));
}
@Subscribe @Subscribe
public void openWalletsInNewWindowsStatusChanged(OpenWalletsNewWindowsStatusEvent event) { public void openWalletsInNewWindowsStatusChanged(OpenWalletsNewWindowsStatusEvent event) {
openWalletsInNewWindows.setSelected(event.isOpenWalletsInNewWindows()); openWalletsInNewWindows.setSelected(event.isOpenWalletsInNewWindows());

View file

@ -0,0 +1,86 @@
package com.sparrowwallet.sparrow;
import com.sparrowwallet.drongo.protocol.Transaction;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
public enum UnitFormat {
DOT {
private final DecimalFormat btcFormat = new DecimalFormat("0", DecimalFormatSymbols.getInstance(getLocale()));
private final DecimalFormat tableBtcFormat = new DecimalFormat("0.00000000", DecimalFormatSymbols.getInstance(getLocale()));
private final DecimalFormat currencyFormat = new DecimalFormat("#,##0.00", DecimalFormatSymbols.getInstance(getLocale()));
public DecimalFormat getBtcFormat() {
btcFormat.setMaximumFractionDigits(8);
return btcFormat;
}
public DecimalFormat getTableBtcFormat() {
return tableBtcFormat;
}
public DecimalFormat getCurrencyFormat() {
return currencyFormat;
}
public Locale getLocale() {
return Locale.ENGLISH;
}
},
COMMA {
private final DecimalFormat btcFormat = new DecimalFormat("0", DecimalFormatSymbols.getInstance(getLocale()));
private final DecimalFormat tableBtcFormat = new DecimalFormat("0.00000000", DecimalFormatSymbols.getInstance(getLocale()));
private final DecimalFormat currencyFormat = new DecimalFormat("#,##0.00", DecimalFormatSymbols.getInstance(getLocale()));
public DecimalFormat getBtcFormat() {
btcFormat.setMaximumFractionDigits(8);
return btcFormat;
}
public DecimalFormat getTableBtcFormat() {
return tableBtcFormat;
}
public DecimalFormat getCurrencyFormat() {
return currencyFormat;
}
public Locale getLocale() {
return Locale.GERMAN;
}
};
public abstract Locale getLocale();
public abstract DecimalFormat getBtcFormat();
public abstract DecimalFormat getTableBtcFormat();
public abstract DecimalFormat getCurrencyFormat();
public String formatBtcValue(Long amount) {
return getBtcFormat().format(amount.doubleValue() / Transaction.SATOSHIS_PER_BITCOIN);
}
public String formatSatsValue(Long amount) {
return String.format(getLocale(), "%,d", amount);
}
public String formatCurrencyValue(double amount) {
return getCurrencyFormat().format(amount);
}
public DecimalFormatSymbols getDecimalFormatSymbols() {
return DecimalFormatSymbols.getInstance(getLocale());
}
public String getGroupingSeparator() {
return Character.toString(getDecimalFormatSymbols().getGroupingSeparator());
}
public String getDecimalSeparator() {
return Character.toString(getDecimalFormatSymbols().getDecimalSeparator());
}
}

View file

@ -20,7 +20,7 @@ import java.util.*;
public class AddressTreeTable extends CoinTreeTable { public class AddressTreeTable extends CoinTreeTable {
public void initialize(NodeEntry rootEntry) { public void initialize(NodeEntry rootEntry) {
getStyleClass().add("address-treetable"); getStyleClass().add("address-treetable");
setBitcoinUnit(rootEntry.getWallet()); setUnitFormat(rootEntry.getWallet());
String address = rootEntry.getAddress().toString(); String address = rootEntry.getAddress().toString();
updateAll(rootEntry); updateAll(rootEntry);
@ -114,7 +114,7 @@ public class AddressTreeTable extends CoinTreeTable {
} }
public void updateAll(NodeEntry rootEntry) { public void updateAll(NodeEntry rootEntry) {
setBitcoinUnit(rootEntry.getWallet()); setUnitFormat(rootEntry.getWallet());
RecursiveTreeItem<Entry> rootItem = new RecursiveTreeItem<>(rootEntry, Entry::getChildren); RecursiveTreeItem<Entry> rootItem = new RecursiveTreeItem<>(rootEntry, Entry::getChildren);
setRoot(rootItem); setRoot(rootItem);

View file

@ -3,6 +3,7 @@ package com.sparrowwallet.sparrow.control;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.sparrowwallet.drongo.BitcoinUnit; import com.sparrowwallet.drongo.BitcoinUnit;
import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.UnitFormat;
import com.sparrowwallet.sparrow.io.Config; import com.sparrowwallet.sparrow.io.Config;
import com.sparrowwallet.sparrow.wallet.Entry; import com.sparrowwallet.sparrow.wallet.Entry;
import com.sparrowwallet.sparrow.wallet.TransactionEntry; import com.sparrowwallet.sparrow.wallet.TransactionEntry;
@ -35,8 +36,7 @@ public class BalanceChart extends LineChart<Number, Number> {
getData().add(balanceSeries); getData().add(balanceSeries);
update(walletTransactionsEntry); update(walletTransactionsEntry);
BitcoinUnit unit = Config.get().getBitcoinUnit(); setUnitFormat(walletTransactionsEntry.getWallet(), Config.get().getUnitFormat(), Config.get().getBitcoinUnit());
setBitcoinUnit(walletTransactionsEntry.getWallet(), unit);
} }
public void update(WalletTransactionsEntry walletTransactionsEntry) { public void update(WalletTransactionsEntry walletTransactionsEntry) {
@ -116,12 +116,16 @@ public class BalanceChart extends LineChart<Number, Number> {
} }
} }
public void setBitcoinUnit(Wallet wallet, BitcoinUnit unit) { public void setUnitFormat(Wallet wallet, UnitFormat format, BitcoinUnit unit) {
if(format == null) {
format = UnitFormat.DOT;
}
if(unit == null || unit.equals(BitcoinUnit.AUTO)) { if(unit == null || unit.equals(BitcoinUnit.AUTO)) {
unit = wallet.getAutoUnit(); unit = wallet.getAutoUnit();
} }
NumberAxis yaxis = (NumberAxis)getYAxis(); NumberAxis yaxis = (NumberAxis)getYAxis();
yaxis.setTickLabelFormatter(new CoinAxisFormatter(yaxis, unit)); yaxis.setTickLabelFormatter(new CoinAxisFormatter(yaxis, format, unit));
} }
} }

View file

@ -1,28 +1,31 @@
package com.sparrowwallet.sparrow.control; package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.drongo.BitcoinUnit; import com.sparrowwallet.drongo.BitcoinUnit;
import com.sparrowwallet.sparrow.UnitFormat;
import javafx.scene.chart.NumberAxis; import javafx.scene.chart.NumberAxis;
import javafx.util.StringConverter; import javafx.util.StringConverter;
import java.text.ParseException; import java.text.ParseException;
final class CoinAxisFormatter extends StringConverter<Number> { final class CoinAxisFormatter extends StringConverter<Number> {
private final UnitFormat unitFormat;
private final BitcoinUnit bitcoinUnit; private final BitcoinUnit bitcoinUnit;
public CoinAxisFormatter(NumberAxis axis, BitcoinUnit unit) { public CoinAxisFormatter(NumberAxis axis, UnitFormat format, BitcoinUnit unit) {
this.unitFormat = format;
this.bitcoinUnit = unit; this.bitcoinUnit = unit;
} }
@Override @Override
public String toString(Number object) { public String toString(Number object) {
Double value = bitcoinUnit.getValue(object.longValue()); Double value = bitcoinUnit.getValue(object.longValue());
return CoinTextFormatter.COIN_FORMAT.format(value); return new CoinTextFormatter(unitFormat).getCoinFormat().format(value);
} }
@Override @Override
public Number fromString(String string) { public Number fromString(String string) {
try { try {
Number number = CoinTextFormatter.COIN_FORMAT.parse(string); Number number = new CoinTextFormatter(unitFormat).getCoinFormat().parse(string);
return bitcoinUnit.getSatsValue(number.doubleValue()); return bitcoinUnit.getSatsValue(number.doubleValue());
} catch (ParseException e) { } catch (ParseException e) {
throw new RuntimeException(e); throw new RuntimeException(e);

View file

@ -2,6 +2,7 @@ package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.drongo.BitcoinUnit; import com.sparrowwallet.drongo.BitcoinUnit;
import com.sparrowwallet.drongo.protocol.Transaction; import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.sparrow.UnitFormat;
import com.sparrowwallet.sparrow.wallet.Entry; import com.sparrowwallet.sparrow.wallet.Entry;
import com.sparrowwallet.sparrow.wallet.HashIndexEntry; import com.sparrowwallet.sparrow.wallet.HashIndexEntry;
import com.sparrowwallet.sparrow.wallet.TransactionEntry; import com.sparrowwallet.sparrow.wallet.TransactionEntry;
@ -14,12 +15,8 @@ import javafx.util.Duration;
import org.controlsfx.tools.Platform; import org.controlsfx.tools.Platform;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
class CoinCell extends TreeTableCell<Entry, Number> { class CoinCell extends TreeTableCell<Entry, Number> {
public static final DecimalFormat TABLE_BTC_FORMAT = new DecimalFormat("0.00000000", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
private final Tooltip tooltip; private final Tooltip tooltip;
public CoinCell() { public CoinCell() {
@ -45,10 +42,11 @@ class CoinCell extends TreeTableCell<Entry, Number> {
EntryCell.applyRowStyles(this, entry); EntryCell.applyRowStyles(this, entry);
CoinTreeTable coinTreeTable = (CoinTreeTable)getTreeTableView(); CoinTreeTable coinTreeTable = (CoinTreeTable)getTreeTableView();
UnitFormat format = coinTreeTable.getUnitFormat();
BitcoinUnit unit = coinTreeTable.getBitcoinUnit(); BitcoinUnit unit = coinTreeTable.getBitcoinUnit();
String satsValue = String.format(Locale.ENGLISH, "%,d", amount.longValue()); String satsValue = format.formatSatsValue(amount.longValue());
DecimalFormat decimalFormat = (amount.longValue() == 0L ? CoinLabel.getBTCFormat() : TABLE_BTC_FORMAT); DecimalFormat decimalFormat = (amount.longValue() == 0L ? format.getBtcFormat() : format.getTableBtcFormat());
final String btcValue = decimalFormat.format(amount.doubleValue() / Transaction.SATOSHIS_PER_BITCOIN); final String btcValue = decimalFormat.format(amount.doubleValue() / Transaction.SATOSHIS_PER_BITCOIN);
if(unit.equals(BitcoinUnit.BTC)) { if(unit.equals(BitcoinUnit.BTC)) {
@ -61,8 +59,7 @@ class CoinCell extends TreeTableCell<Entry, Number> {
setTooltip(tooltip); setTooltip(tooltip);
String tooltipValue = tooltip.getText(); String tooltipValue = tooltip.getText();
if(entry instanceof TransactionEntry) { if(entry instanceof TransactionEntry transactionEntry) {
TransactionEntry transactionEntry = (TransactionEntry)entry;
tooltip.setText(tooltipValue + " (" + transactionEntry.getConfirmationsDescription() + ")"); tooltip.setText(tooltipValue + " (" + transactionEntry.getConfirmationsDescription() + ")");
transactionEntry.confirmationsProperty().addListener((observable, oldValue, newValue) -> { transactionEntry.confirmationsProperty().addListener((observable, oldValue, newValue) -> {

View file

@ -1,7 +1,7 @@
package com.sparrowwallet.sparrow.control; package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.drongo.BitcoinUnit; import com.sparrowwallet.drongo.BitcoinUnit;
import com.sparrowwallet.drongo.protocol.Transaction; import com.sparrowwallet.sparrow.UnitFormat;
import com.sparrowwallet.sparrow.io.Config; import com.sparrowwallet.sparrow.io.Config;
import javafx.beans.property.LongProperty; import javafx.beans.property.LongProperty;
import javafx.beans.property.SimpleLongProperty; import javafx.beans.property.SimpleLongProperty;
@ -12,13 +12,7 @@ import javafx.scene.control.Tooltip;
import javafx.scene.input.Clipboard; import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent; import javafx.scene.input.ClipboardContent;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
public class CoinLabel extends Label { public class CoinLabel extends Label {
public static final DecimalFormat BTC_FORMAT = new DecimalFormat("0", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
private final LongProperty valueProperty = new SimpleLongProperty(-1); private final LongProperty valueProperty = new SimpleLongProperty(-1);
private final Tooltip tooltip; private final Tooltip tooltip;
private final CoinContextMenu contextMenu; private final CoinContextMenu contextMenu;
@ -58,8 +52,9 @@ public class CoinLabel extends Label {
setTooltip(tooltip); setTooltip(tooltip);
setContextMenu(contextMenu); setContextMenu(contextMenu);
String satsValue = String.format(Locale.ENGLISH, "%,d", value) + " sats"; UnitFormat format = Config.get().getUnitFormat() == null ? UnitFormat.DOT : Config.get().getUnitFormat();
String btcValue = BTC_FORMAT.format(value.doubleValue() / Transaction.SATOSHIS_PER_BITCOIN) + " BTC"; String satsValue = format.formatSatsValue(value) + " sats";
String btcValue = format.formatBtcValue(value) + " BTC";
BitcoinUnit unit = bitcoinUnit; BitcoinUnit unit = bitcoinUnit;
if(unit == null || unit.equals(BitcoinUnit.AUTO)) { if(unit == null || unit.equals(BitcoinUnit.AUTO)) {
@ -89,16 +84,12 @@ public class CoinLabel extends Label {
copyBtcValue.setOnAction(AE -> { copyBtcValue.setOnAction(AE -> {
hide(); hide();
ClipboardContent content = new ClipboardContent(); ClipboardContent content = new ClipboardContent();
content.putString(BTC_FORMAT.format((double)getValue() / Transaction.SATOSHIS_PER_BITCOIN)); UnitFormat format = Config.get().getUnitFormat() == null ? UnitFormat.DOT : Config.get().getUnitFormat();
content.putString(format.formatBtcValue(getValue()));
Clipboard.getSystemClipboard().setContent(content); Clipboard.getSystemClipboard().setContent(content);
}); });
getItems().addAll(copySatsValue, copyBtcValue); getItems().addAll(copySatsValue, copyBtcValue);
} }
} }
public static DecimalFormat getBTCFormat() {
BTC_FORMAT.setMaximumFractionDigits(8);
return BTC_FORMAT;
}
} }

View file

@ -1,24 +1,39 @@
package com.sparrowwallet.sparrow.control; package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.sparrow.UnitFormat;
import javafx.scene.control.TextFormatter; import javafx.scene.control.TextFormatter;
import javafx.scene.control.TextInputControl; import javafx.scene.control.TextInputControl;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols; import java.text.DecimalFormatSymbols;
import java.text.ParseException; import java.text.ParseException;
import java.util.Locale;
import java.util.function.UnaryOperator; import java.util.function.UnaryOperator;
import java.util.regex.Pattern; import java.util.regex.Pattern;
public class CoinTextFormatter extends TextFormatter<String> { public class CoinTextFormatter extends TextFormatter<String> {
private static final Pattern COIN_VALIDATION = Pattern.compile("[\\d,]*(\\.\\d{0,8})?"); public CoinTextFormatter(UnitFormat unitFormat) {
public static final DecimalFormat COIN_FORMAT = new DecimalFormat("###,###.########", DecimalFormatSymbols.getInstance(Locale.ENGLISH)); super(new CoinFilter(unitFormat));
}
public CoinTextFormatter() { public UnitFormat getUnitFormat() {
super(new CoinFilter()); return ((CoinFilter)getFilter()).unitFormat;
}
public DecimalFormat getCoinFormat() {
return ((CoinFilter)getFilter()).coinFormat;
} }
private static class CoinFilter implements UnaryOperator<Change> { private static class CoinFilter implements UnaryOperator<Change> {
private final UnitFormat unitFormat;
private final DecimalFormat coinFormat;
private final Pattern coinValidation;
public CoinFilter(UnitFormat unitFormat) {
this.unitFormat = unitFormat == null ? UnitFormat.DOT : unitFormat;
this.coinFormat = new DecimalFormat("###,###.########", DecimalFormatSymbols.getInstance(unitFormat.getLocale()));
this.coinValidation = Pattern.compile("[\\d" + Pattern.quote(unitFormat.getGroupingSeparator()) + "]*(" + Pattern.quote(unitFormat.getDecimalSeparator()) + "\\d{0,8})?");
}
@Override @Override
public Change apply(Change change) { public Change apply(Change change) {
String oldText = change.getControlText(); String oldText = change.getControlText();
@ -30,17 +45,17 @@ public class CoinTextFormatter extends TextFormatter<String> {
String noFractionCommaText = newText; String noFractionCommaText = newText;
int commasRemoved = 0; int commasRemoved = 0;
int dotIndex = newText.indexOf("."); int dotIndex = newText.indexOf(unitFormat.getDecimalSeparator());
if(dotIndex > -1) { if(dotIndex > -1) {
noFractionCommaText = newText.substring(0, dotIndex) + newText.substring(dotIndex).replaceAll(",", ""); noFractionCommaText = newText.substring(0, dotIndex) + newText.substring(dotIndex).replaceAll(Pattern.quote(unitFormat.getGroupingSeparator()), "");
commasRemoved = newText.length() - noFractionCommaText.length(); commasRemoved = newText.length() - noFractionCommaText.length();
} }
if(!COIN_VALIDATION.matcher(noFractionCommaText).matches()) { if(!coinValidation.matcher(noFractionCommaText).matches()) {
return null; return null;
} }
if(",".equals(change.getText())) { if(unitFormat.getGroupingSeparator().equals(change.getText())) {
return null; return null;
} }
@ -48,20 +63,20 @@ public class CoinTextFormatter extends TextFormatter<String> {
return change; return change;
} }
if(change.isDeleted() && ",".equals(deleted) && change.getRangeStart() > 0) { if(change.isDeleted() && unitFormat.getGroupingSeparator().equals(deleted) && change.getRangeStart() > 0) {
noFractionCommaText = noFractionCommaText.substring(0, change.getRangeStart() - 1) + noFractionCommaText.substring(change.getRangeEnd() - 1); noFractionCommaText = noFractionCommaText.substring(0, change.getRangeStart() - 1) + noFractionCommaText.substring(change.getRangeEnd() - 1);
} }
try { try {
Number value = COIN_FORMAT.parse(noFractionCommaText); Number value = coinFormat.parse(noFractionCommaText);
String correct = COIN_FORMAT.format(value.doubleValue()); String correct = coinFormat.format(value.doubleValue());
String compare = newText; String compare = newText;
if(compare.contains(".") && compare.endsWith("0")) { if(compare.contains(unitFormat.getDecimalSeparator()) && compare.endsWith("0")) {
compare = compare.replaceAll("0*$", ""); compare = compare.replaceAll("0*$", "");
} }
if(compare.endsWith(".")) { if(compare.endsWith(unitFormat.getDecimalSeparator())) {
compare = compare.substring(0, compare.length() - 1); compare = compare.substring(0, compare.length() - 1);
} }
@ -79,11 +94,11 @@ public class CoinTextFormatter extends TextFormatter<String> {
if(correct.length() != newText.length()) { if(correct.length() != newText.length()) {
String postCorrect = correct.substring(Math.min(change.getCaretPosition(), correct.length())); String postCorrect = correct.substring(Math.min(change.getCaretPosition(), correct.length()));
int commasAfter = postCorrect.length() - postCorrect.replace(",", "").length(); int commasAfter = postCorrect.length() - postCorrect.replace(unitFormat.getGroupingSeparator(), "").length();
int caretShift = change.isDeleted() && ".".equals(deleted) ? commasAfter : 0; int caretShift = change.isDeleted() && unitFormat.getDecimalSeparator().equals(deleted) ? commasAfter : 0;
int caret = change.getCaretPosition() + (correct.length() - newText.length() - caretShift) + commasRemoved; int caret = change.getCaretPosition() + (correct.length() - newText.length() - caretShift) + commasRemoved;
if(caret >= 0) { if(caret >= 0 && caret <= change.getControlNewText().length()) {
change.setCaretPosition(caret); change.setCaretPosition(caret);
change.setAnchor(caret); change.setAnchor(caret);
} }

View file

@ -2,6 +2,7 @@ package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.drongo.BitcoinUnit; import com.sparrowwallet.drongo.BitcoinUnit;
import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.UnitFormat;
import com.sparrowwallet.sparrow.AppServices; import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.EventManager; import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.event.WalletAddressesChangedEvent; import com.sparrowwallet.sparrow.event.WalletAddressesChangedEvent;
@ -26,25 +27,36 @@ import java.util.Optional;
public class CoinTreeTable extends TreeTableView<Entry> { public class CoinTreeTable extends TreeTableView<Entry> {
private BitcoinUnit bitcoinUnit; private BitcoinUnit bitcoinUnit;
private UnitFormat unitFormat;
public BitcoinUnit getBitcoinUnit() { public BitcoinUnit getBitcoinUnit() {
return bitcoinUnit; return bitcoinUnit;
} }
public void setBitcoinUnit(BitcoinUnit bitcoinUnit) { public UnitFormat getUnitFormat() {
this.bitcoinUnit = bitcoinUnit; return unitFormat;
} }
public void setBitcoinUnit(Wallet wallet) { public void setUnitFormat(Wallet wallet) {
setBitcoinUnit(wallet, Config.get().getBitcoinUnit()); setUnitFormat(wallet, Config.get().getUnitFormat(), Config.get().getBitcoinUnit());
}
public void setUnitFormat(Wallet wallet, UnitFormat format) {
setUnitFormat(wallet, format, Config.get().getBitcoinUnit());
}
public void setUnitFormat(Wallet wallet, UnitFormat format, BitcoinUnit unit) {
if(format == null) {
format = UnitFormat.DOT;
} }
public void setBitcoinUnit(Wallet wallet, BitcoinUnit unit) {
if(unit == null || unit.equals(BitcoinUnit.AUTO)) { if(unit == null || unit.equals(BitcoinUnit.AUTO)) {
unit = wallet.getAutoUnit(); unit = wallet.getAutoUnit();
} }
boolean changed = (bitcoinUnit != unit); boolean changed = (unitFormat != format);
changed |= (bitcoinUnit != unit);
this.unitFormat = format;
this.bitcoinUnit = unit; this.bitcoinUnit = unit;
if(changed && !getChildren().isEmpty()) { if(changed && !getChildren().isEmpty()) {

View file

@ -1,7 +1,7 @@
package com.sparrowwallet.sparrow.control; package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.drongo.BitcoinUnit; import com.sparrowwallet.drongo.BitcoinUnit;
import com.sparrowwallet.drongo.protocol.Transaction; import com.sparrowwallet.sparrow.UnitFormat;
import com.sparrowwallet.sparrow.io.Config; import com.sparrowwallet.sparrow.io.Config;
import javafx.beans.property.LongProperty; import javafx.beans.property.LongProperty;
import javafx.beans.property.SimpleLongProperty; import javafx.beans.property.SimpleLongProperty;
@ -11,8 +11,6 @@ import javafx.scene.control.Tooltip;
import javafx.scene.input.Clipboard; import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent; import javafx.scene.input.ClipboardContent;
import java.util.Locale;
public class CopyableCoinLabel extends CopyableLabel { public class CopyableCoinLabel extends CopyableLabel {
private final LongProperty valueProperty = new SimpleLongProperty(-1); private final LongProperty valueProperty = new SimpleLongProperty(-1);
private final Tooltip tooltip; private final Tooltip tooltip;
@ -24,7 +22,7 @@ public class CopyableCoinLabel extends CopyableLabel {
public CopyableCoinLabel(String text) { public CopyableCoinLabel(String text) {
super(text); super(text);
valueProperty().addListener((observable, oldValue, newValue) -> setValueAsText((Long)newValue, Config.get().getBitcoinUnit())); valueProperty().addListener((observable, oldValue, newValue) -> setValueAsText((Long)newValue, Config.get().getUnitFormat(), Config.get().getBitcoinUnit()));
tooltip = new Tooltip(); tooltip = new Tooltip();
contextMenu = new CoinContextMenu(); contextMenu = new CoinContextMenu();
} }
@ -42,19 +40,23 @@ public class CopyableCoinLabel extends CopyableLabel {
} }
public void refresh() { public void refresh() {
refresh(Config.get().getBitcoinUnit()); refresh(Config.get().getUnitFormat(), Config.get().getBitcoinUnit());
} }
public void refresh(BitcoinUnit bitcoinUnit) { public void refresh(UnitFormat unitFormat, BitcoinUnit bitcoinUnit) {
setValueAsText(getValue(), bitcoinUnit); setValueAsText(getValue(), unitFormat, bitcoinUnit);
} }
private void setValueAsText(Long value, BitcoinUnit bitcoinUnit) { private void setValueAsText(Long value, UnitFormat unitFormat, BitcoinUnit bitcoinUnit) {
setTooltip(tooltip); setTooltip(tooltip);
setContextMenu(contextMenu); setContextMenu(contextMenu);
String satsValue = String.format(Locale.ENGLISH, "%,d", value) + " sats"; if(unitFormat == null) {
String btcValue = CoinLabel.getBTCFormat().format(value.doubleValue() / Transaction.SATOSHIS_PER_BITCOIN) + " BTC"; unitFormat = UnitFormat.DOT;
}
String satsValue = unitFormat.formatSatsValue(value) + " sats";
String btcValue = unitFormat.formatBtcValue(value) + " BTC";
BitcoinUnit unit = bitcoinUnit; BitcoinUnit unit = bitcoinUnit;
if(unit == null || unit.equals(BitcoinUnit.AUTO)) { if(unit == null || unit.equals(BitcoinUnit.AUTO)) {
@ -84,7 +86,8 @@ public class CopyableCoinLabel extends CopyableLabel {
copyBtcValue.setOnAction(AE -> { copyBtcValue.setOnAction(AE -> {
hide(); hide();
ClipboardContent content = new ClipboardContent(); ClipboardContent content = new ClipboardContent();
content.putString(CoinLabel.getBTCFormat().format((double)getValue() / Transaction.SATOSHIS_PER_BITCOIN)); UnitFormat format = Config.get().getUnitFormat() == null ? UnitFormat.DOT : Config.get().getUnitFormat();
content.putString(format.formatBtcValue(getValue()));
Clipboard.getSystemClipboard().setContent(content); Clipboard.getSystemClipboard().setContent(content);
}); });

View file

@ -1,7 +1,9 @@
package com.sparrowwallet.sparrow.control; package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.drongo.protocol.Transaction; import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.sparrow.UnitFormat;
import com.sparrowwallet.sparrow.CurrencyRate; import com.sparrowwallet.sparrow.CurrencyRate;
import com.sparrowwallet.sparrow.io.Config;
import javafx.beans.property.*; import javafx.beans.property.*;
import javafx.scene.control.ContextMenu; import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem; import javafx.scene.control.MenuItem;
@ -10,14 +12,9 @@ import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent; import javafx.scene.input.ClipboardContent;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Currency; import java.util.Currency;
import java.util.Locale;
public class FiatLabel extends CopyableLabel { public class FiatLabel extends CopyableLabel {
private static final DecimalFormat CURRENCY_FORMAT = new DecimalFormat("#,##0.00", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
private final LongProperty valueProperty = new SimpleLongProperty(-1); private final LongProperty valueProperty = new SimpleLongProperty(-1);
private final DoubleProperty btcRateProperty = new SimpleDoubleProperty(0.0); private final DoubleProperty btcRateProperty = new SimpleDoubleProperty(0.0);
private final ObjectProperty<Currency> currencyProperty = new SimpleObjectProperty<>(null); private final ObjectProperty<Currency> currencyProperty = new SimpleObjectProperty<>(null);
@ -30,9 +27,9 @@ public class FiatLabel extends CopyableLabel {
public FiatLabel(String text) { public FiatLabel(String text) {
super(text); super(text);
valueProperty().addListener((observable, oldValue, newValue) -> setValueAsText((Long)newValue)); valueProperty().addListener((observable, oldValue, newValue) -> setValueAsText((Long)newValue, Config.get().getUnitFormat()));
btcRateProperty().addListener((observable, oldValue, newValue) -> setValueAsText(getValue())); btcRateProperty().addListener((observable, oldValue, newValue) -> setValueAsText(getValue(), Config.get().getUnitFormat()));
currencyProperty().addListener((observable, oldValue, newValue) -> setValueAsText(getValue())); currencyProperty().addListener((observable, oldValue, newValue) -> setValueAsText(getValue(), Config.get().getUnitFormat()));
tooltip = new Tooltip(); tooltip = new Tooltip();
contextMenu = new FiatContextMenu(); contextMenu = new FiatContextMenu();
} }
@ -83,14 +80,22 @@ public class FiatLabel extends CopyableLabel {
setCurrency(currency); setCurrency(currency);
} }
private void setValueAsText(long balance) { public void refresh() {
refresh(Config.get().getUnitFormat());
}
public void refresh(UnitFormat unitFormat) {
setValueAsText(getValue(), unitFormat);
}
private void setValueAsText(long balance, UnitFormat unitFormat) {
if(getCurrency() != null && getBtcRate() > 0.0) { if(getCurrency() != null && getBtcRate() > 0.0) {
BigDecimal satsBalance = BigDecimal.valueOf(balance); BigDecimal satsBalance = BigDecimal.valueOf(balance);
BigDecimal btcBalance = satsBalance.divide(BigDecimal.valueOf(Transaction.SATOSHIS_PER_BITCOIN)); BigDecimal btcBalance = satsBalance.divide(BigDecimal.valueOf(Transaction.SATOSHIS_PER_BITCOIN));
BigDecimal fiatBalance = btcBalance.multiply(BigDecimal.valueOf(getBtcRate())); BigDecimal fiatBalance = btcBalance.multiply(BigDecimal.valueOf(getBtcRate()));
String label = getCurrency().getSymbol() + " " + CURRENCY_FORMAT.format(fiatBalance.doubleValue()); String label = getCurrency().getSymbol() + " " + unitFormat.formatCurrencyValue(fiatBalance.doubleValue());
tooltip.setText("1 BTC = " + getCurrency().getSymbol() + " " + CURRENCY_FORMAT.format(getBtcRate())); tooltip.setText("1 BTC = " + getCurrency().getSymbol() + " " + unitFormat.formatCurrencyValue(getBtcRate()));
setText(label); setText(label);
setTooltip(tooltip); setTooltip(tooltip);

View file

@ -74,7 +74,7 @@ public class SearchWalletDialog extends Dialog<Entry> {
results = new CoinTreeTable(); results = new CoinTreeTable();
results.setShowRoot(false); results.setShowRoot(false);
results.setPrefWidth(showWallet ? 950 : 850); results.setPrefWidth(showWallet ? 950 : 850);
results.setBitcoinUnit(walletForms.iterator().next().getWallet()); results.setUnitFormat(walletForms.iterator().next().getWallet());
results.setColumnResizePolicy(TreeTableView.CONSTRAINED_RESIZE_POLICY); results.setColumnResizePolicy(TreeTableView.CONSTRAINED_RESIZE_POLICY);
results.setPlaceholder(new Label("No results")); results.setPlaceholder(new Label("No results"));

View file

@ -3,10 +3,10 @@ package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.drongo.KeyPurpose; import com.sparrowwallet.drongo.KeyPurpose;
import com.sparrowwallet.drongo.address.Address; import com.sparrowwallet.drongo.address.Address;
import com.sparrowwallet.drongo.protocol.Sha256Hash; import com.sparrowwallet.drongo.protocol.Sha256Hash;
import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.drongo.protocol.TransactionOutput; import com.sparrowwallet.drongo.protocol.TransactionOutput;
import com.sparrowwallet.drongo.uri.BitcoinURI; import com.sparrowwallet.drongo.uri.BitcoinURI;
import com.sparrowwallet.drongo.wallet.*; import com.sparrowwallet.drongo.wallet.*;
import com.sparrowwallet.sparrow.UnitFormat;
import com.sparrowwallet.sparrow.AppServices; import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.EventManager; import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.Theme; import com.sparrowwallet.sparrow.Theme;
@ -56,8 +56,6 @@ import java.util.*;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static com.sparrowwallet.sparrow.control.CoinLabel.BTC_FORMAT;
public class TransactionDiagram extends GridPane { public class TransactionDiagram extends GridPane {
private static final int MAX_UTXOS = 8; private static final int MAX_UTXOS = 8;
private static final int REDUCED_MAX_UTXOS = MAX_UTXOS - 2; private static final int REDUCED_MAX_UTXOS = MAX_UTXOS - 2;
@ -1334,7 +1332,8 @@ public class TransactionDiagram extends GridPane {
copyBtcValue.setOnAction(event -> { copyBtcValue.setOnAction(event -> {
hide(); hide();
ClipboardContent content = new ClipboardContent(); ClipboardContent content = new ClipboardContent();
content.putString(BTC_FORMAT.format((double)value / Transaction.SATOSHIS_PER_BITCOIN)); UnitFormat format = Config.get().getUnitFormat() == null ? UnitFormat.DOT : Config.get().getUnitFormat();
content.putString(format.formatBtcValue(value));
Clipboard.getSystemClipboard().setContent(content); Clipboard.getSystemClipboard().setContent(content);
}); });
getItems().addAll(copySatsValue, copyBtcValue); getItems().addAll(copySatsValue, copyBtcValue);

View file

@ -1,6 +1,5 @@
package com.sparrowwallet.sparrow.control; package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.drongo.wallet.WalletNode;
import com.sparrowwallet.sparrow.wallet.Entry; import com.sparrowwallet.sparrow.wallet.Entry;
import com.sparrowwallet.sparrow.wallet.TransactionEntry; import com.sparrowwallet.sparrow.wallet.TransactionEntry;
import com.sparrowwallet.sparrow.wallet.WalletTransactionsEntry; import com.sparrowwallet.sparrow.wallet.WalletTransactionsEntry;
@ -8,12 +7,10 @@ import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.scene.control.TreeTableColumn; import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView; import javafx.scene.control.TreeTableView;
import java.util.List;
public class TransactionsTreeTable extends CoinTreeTable { public class TransactionsTreeTable extends CoinTreeTable {
public void initialize(WalletTransactionsEntry rootEntry) { public void initialize(WalletTransactionsEntry rootEntry) {
getStyleClass().add("transactions-treetable"); getStyleClass().add("transactions-treetable");
setBitcoinUnit(rootEntry.getWallet()); setUnitFormat(rootEntry.getWallet());
updateAll(rootEntry); updateAll(rootEntry);
setShowRoot(false); setShowRoot(false);
@ -58,7 +55,7 @@ public class TransactionsTreeTable extends CoinTreeTable {
} }
public void updateAll(WalletTransactionsEntry rootEntry) { public void updateAll(WalletTransactionsEntry rootEntry) {
setBitcoinUnit(rootEntry.getWallet()); setUnitFormat(rootEntry.getWallet());
RecursiveTreeItem<Entry> rootItem = new RecursiveTreeItem<>(rootEntry, Entry::getChildren); RecursiveTreeItem<Entry> rootItem = new RecursiveTreeItem<>(rootEntry, Entry::getChildren);
setRoot(rootItem); setRoot(rootItem);

View file

@ -2,6 +2,7 @@ package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.drongo.BitcoinUnit; import com.sparrowwallet.drongo.BitcoinUnit;
import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.UnitFormat;
import com.sparrowwallet.sparrow.io.Config; import com.sparrowwallet.sparrow.io.Config;
import com.sparrowwallet.sparrow.wallet.Entry; import com.sparrowwallet.sparrow.wallet.Entry;
import com.sparrowwallet.sparrow.wallet.UtxoEntry; import com.sparrowwallet.sparrow.wallet.UtxoEntry;
@ -36,8 +37,7 @@ public class UtxosChart extends BarChart<String, Number> {
getData().add(utxoSeries); getData().add(utxoSeries);
update(walletUtxosEntry); update(walletUtxosEntry);
BitcoinUnit unit = Config.get().getBitcoinUnit(); setUnitFormat(walletUtxosEntry.getWallet(), Config.get().getUnitFormat(), Config.get().getBitcoinUnit());
setBitcoinUnit(walletUtxosEntry.getWallet(), unit);
} }
public void update(WalletUtxosEntry walletUtxosEntry) { public void update(WalletUtxosEntry walletUtxosEntry) {
@ -117,12 +117,16 @@ public class UtxosChart extends BarChart<String, Number> {
this.selectedEntries = entries; this.selectedEntries = entries;
} }
public void setBitcoinUnit(Wallet wallet, BitcoinUnit unit) { public void setUnitFormat(Wallet wallet, UnitFormat format, BitcoinUnit unit) {
if(format == null) {
format = UnitFormat.DOT;
}
if(unit == null || unit.equals(BitcoinUnit.AUTO)) { if(unit == null || unit.equals(BitcoinUnit.AUTO)) {
unit = wallet.getAutoUnit(); unit = wallet.getAutoUnit();
} }
NumberAxis yaxis = (NumberAxis)getYAxis(); NumberAxis yaxis = (NumberAxis)getYAxis();
yaxis.setTickLabelFormatter(new CoinAxisFormatter(yaxis, unit)); yaxis.setTickLabelFormatter(new CoinAxisFormatter(yaxis, format, unit));
} }
} }

View file

@ -1,20 +1,17 @@
package com.sparrowwallet.sparrow.control; package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.drongo.wallet.WalletNode;
import com.sparrowwallet.sparrow.wallet.*; import com.sparrowwallet.sparrow.wallet.*;
import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.scene.control.SelectionMode; import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumnBase;
import javafx.scene.control.TreeTableColumn; import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView; import javafx.scene.control.TreeTableView;
import java.util.Comparator; import java.util.Comparator;
import java.util.List;
public class UtxosTreeTable extends CoinTreeTable { public class UtxosTreeTable extends CoinTreeTable {
public void initialize(WalletUtxosEntry rootEntry) { public void initialize(WalletUtxosEntry rootEntry) {
getStyleClass().add("utxos-treetable"); getStyleClass().add("utxos-treetable");
setBitcoinUnit(rootEntry.getWallet()); setUnitFormat(rootEntry.getWallet());
updateAll(rootEntry); updateAll(rootEntry);
setShowRoot(false); setShowRoot(false);
@ -93,7 +90,7 @@ public class UtxosTreeTable extends CoinTreeTable {
} }
public void updateAll(WalletUtxosEntry rootEntry) { public void updateAll(WalletUtxosEntry rootEntry) {
setBitcoinUnit(rootEntry.getWallet()); setUnitFormat(rootEntry.getWallet());
RecursiveTreeItem<Entry> rootItem = new RecursiveTreeItem<>(rootEntry, Entry::getChildren); RecursiveTreeItem<Entry> rootItem = new RecursiveTreeItem<>(rootEntry, Entry::getChildren);
setRoot(rootItem); setRoot(rootItem);

View file

@ -1,11 +1,19 @@
package com.sparrowwallet.sparrow.event; package com.sparrowwallet.sparrow.event;
import com.sparrowwallet.drongo.BitcoinUnit; import com.sparrowwallet.drongo.BitcoinUnit;
import com.sparrowwallet.sparrow.UnitFormat;
import com.sparrowwallet.sparrow.io.Config;
public class BitcoinUnitChangedEvent { public class BitcoinUnitChangedEvent extends UnitFormatChangedEvent {
private final BitcoinUnit bitcoinUnit; private final BitcoinUnit bitcoinUnit;
public BitcoinUnitChangedEvent(BitcoinUnit bitcoinUnit) { public BitcoinUnitChangedEvent(BitcoinUnit bitcoinUnit) {
super(Config.get().getUnitFormat() == null ? UnitFormat.DOT : Config.get().getUnitFormat());
this.bitcoinUnit = bitcoinUnit;
}
public BitcoinUnitChangedEvent(UnitFormat unitFormat, BitcoinUnit bitcoinUnit) {
super(unitFormat);
this.bitcoinUnit = bitcoinUnit; this.bitcoinUnit = bitcoinUnit;
} }

View file

@ -1,10 +1,9 @@
package com.sparrowwallet.sparrow.event; package com.sparrowwallet.sparrow.event;
import com.sparrowwallet.drongo.BitcoinUnit; import com.sparrowwallet.drongo.BitcoinUnit;
import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.drongo.wallet.BlockTransaction; import com.sparrowwallet.drongo.wallet.BlockTransaction;
import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.control.CoinLabel; import com.sparrowwallet.sparrow.UnitFormat;
import com.sparrowwallet.sparrow.io.Config; import com.sparrowwallet.sparrow.io.Config;
import com.sparrowwallet.sparrow.wallet.Entry; import com.sparrowwallet.sparrow.wallet.Entry;
import com.sparrowwallet.sparrow.wallet.HashIndexEntry; import com.sparrowwallet.sparrow.wallet.HashIndexEntry;
@ -13,7 +12,6 @@ import com.sparrowwallet.sparrow.wallet.TransactionHashIndexEntry;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class NewWalletTransactionsEvent { public class NewWalletTransactionsEvent {
@ -50,16 +48,21 @@ public class NewWalletTransactionsEvent {
} }
public String getValueAsText(long value) { public String getValueAsText(long value) {
UnitFormat format = Config.get().getUnitFormat();
if(format == null) {
format = UnitFormat.DOT;
}
BitcoinUnit unit = Config.get().getBitcoinUnit(); BitcoinUnit unit = Config.get().getBitcoinUnit();
if(unit == null || unit.equals(BitcoinUnit.AUTO)) { if(unit == null || unit.equals(BitcoinUnit.AUTO)) {
unit = (value >= BitcoinUnit.getAutoThreshold() ? BitcoinUnit.BTC : BitcoinUnit.SATOSHIS); unit = (value >= BitcoinUnit.getAutoThreshold() ? BitcoinUnit.BTC : BitcoinUnit.SATOSHIS);
} }
if(unit == BitcoinUnit.BTC) { if(unit == BitcoinUnit.BTC) {
return CoinLabel.getBTCFormat().format((double) value / Transaction.SATOSHIS_PER_BITCOIN) + " BTC"; return format.formatBtcValue(value) + " BTC";
} }
return String.format(Locale.ENGLISH, "%,d", value) + " sats"; return format.formatSatsValue(value) + " sats";
} }
public List<BlockTransaction> getUnspentConfirmingWhirlpoolMixTransactions() { public List<BlockTransaction> getUnspentConfirmingWhirlpoolMixTransactions() {

View file

@ -0,0 +1,21 @@
package com.sparrowwallet.sparrow.event;
import com.sparrowwallet.drongo.BitcoinUnit;
import com.sparrowwallet.sparrow.UnitFormat;
import com.sparrowwallet.sparrow.io.Config;
public class UnitFormatChangedEvent {
private final UnitFormat unitFormat;
public UnitFormatChangedEvent(UnitFormat unitFormat) {
this.unitFormat = unitFormat;
}
public UnitFormat getUnitFormat() {
return unitFormat;
}
public BitcoinUnit getBitcoinUnit() {
return Config.get().getBitcoinUnit();
}
}

View file

@ -2,6 +2,7 @@ package com.sparrowwallet.sparrow.io;
import com.google.gson.*; import com.google.gson.*;
import com.sparrowwallet.drongo.BitcoinUnit; import com.sparrowwallet.drongo.BitcoinUnit;
import com.sparrowwallet.sparrow.UnitFormat;
import com.sparrowwallet.sparrow.Mode; import com.sparrowwallet.sparrow.Mode;
import com.sparrowwallet.sparrow.Theme; import com.sparrowwallet.sparrow.Theme;
import com.sparrowwallet.sparrow.net.*; import com.sparrowwallet.sparrow.net.*;
@ -27,6 +28,7 @@ public class Config {
private Mode mode; private Mode mode;
private BitcoinUnit bitcoinUnit; private BitcoinUnit bitcoinUnit;
private UnitFormat unitFormat;
private FeeRatesSource feeRatesSource; private FeeRatesSource feeRatesSource;
private FeeRatesSelection feeRatesSelection; private FeeRatesSelection feeRatesSelection;
private OptimizationStrategy sendOptimizationStrategy; private OptimizationStrategy sendOptimizationStrategy;
@ -133,6 +135,15 @@ public class Config {
flush(); flush();
} }
public UnitFormat getUnitFormat() {
return unitFormat;
}
public void setUnitFormat(UnitFormat unitFormat) {
this.unitFormat = unitFormat;
flush();
}
public FeeRatesSource getFeeRatesSource() { public FeeRatesSource getFeeRatesSource() {
return feeRatesSource; return feeRatesSource;
} }

View file

@ -1270,8 +1270,8 @@ public class HeadersController extends TransactionFormController implements Init
} }
@Subscribe @Subscribe
public void bitcoinUnitChanged(BitcoinUnitChangedEvent event) { public void unitFormatChanged(UnitFormatChangedEvent event) {
fee.refresh(event.getBitcoinUnit()); fee.refresh(event.getUnitFormat(), event.getBitcoinUnit());
} }
@Subscribe @Subscribe

View file

@ -529,8 +529,8 @@ public class InputController extends TransactionFormController implements Initia
} }
@Subscribe @Subscribe
public void bitcoinUnitChanged(BitcoinUnitChangedEvent event) { public void unitFormatChanged(UnitFormatChangedEvent event) {
spends.refresh(event.getBitcoinUnit()); spends.refresh(event.getUnitFormat(), event.getBitcoinUnit());
} }
@Subscribe @Subscribe

View file

@ -9,10 +9,7 @@ import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.sparrow.EventManager; import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.CopyableCoinLabel; import com.sparrowwallet.sparrow.control.CopyableCoinLabel;
import com.sparrowwallet.sparrow.control.CopyableLabel; import com.sparrowwallet.sparrow.control.CopyableLabel;
import com.sparrowwallet.sparrow.event.BitcoinUnitChangedEvent; import com.sparrowwallet.sparrow.event.*;
import com.sparrowwallet.sparrow.event.BlockTransactionFetchedEvent;
import com.sparrowwallet.sparrow.event.PSBTCombinedEvent;
import com.sparrowwallet.sparrow.event.PSBTFinalizedEvent;
import javafx.collections.MapChangeListener; import javafx.collections.MapChangeListener;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
@ -170,8 +167,8 @@ public class InputsController extends TransactionFormController implements Initi
} }
@Subscribe @Subscribe
public void bitcoinUnitChanged(BitcoinUnitChangedEvent event) { public void unitFormatChanged(UnitFormatChangedEvent event) {
total.refresh(event.getBitcoinUnit()); total.refresh(event.getUnitFormat(), event.getBitcoinUnit());
} }
@Subscribe @Subscribe

View file

@ -9,7 +9,7 @@ import com.sparrowwallet.drongo.wallet.BlockTransaction;
import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.EventManager; import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.*; import com.sparrowwallet.sparrow.control.*;
import com.sparrowwallet.sparrow.event.BitcoinUnitChangedEvent; import com.sparrowwallet.sparrow.event.UnitFormatChangedEvent;
import com.sparrowwallet.sparrow.event.BlockTransactionOutputsFetchedEvent; import com.sparrowwallet.sparrow.event.BlockTransactionOutputsFetchedEvent;
import com.sparrowwallet.sparrow.event.ViewTransactionEvent; import com.sparrowwallet.sparrow.event.ViewTransactionEvent;
import com.sparrowwallet.sparrow.net.ElectrumServer; import com.sparrowwallet.sparrow.net.ElectrumServer;
@ -175,7 +175,7 @@ public class OutputController extends TransactionFormController implements Initi
} }
@Subscribe @Subscribe
public void bitcoinUnitChanged(BitcoinUnitChangedEvent event) { public void unitFormatChanged(UnitFormatChangedEvent event) {
value.refresh(event.getBitcoinUnit()); value.refresh(event.getUnitFormat(), event.getBitcoinUnit());
} }
} }

View file

@ -6,7 +6,7 @@ import com.sparrowwallet.drongo.protocol.TransactionOutput;
import com.sparrowwallet.sparrow.EventManager; import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.CopyableCoinLabel; import com.sparrowwallet.sparrow.control.CopyableCoinLabel;
import com.sparrowwallet.sparrow.control.CopyableLabel; import com.sparrowwallet.sparrow.control.CopyableLabel;
import com.sparrowwallet.sparrow.event.BitcoinUnitChangedEvent; import com.sparrowwallet.sparrow.event.UnitFormatChangedEvent;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
import javafx.scene.chart.PieChart; import javafx.scene.chart.PieChart;
@ -57,7 +57,7 @@ public class OutputsController extends TransactionFormController implements Init
} }
@Subscribe @Subscribe
public void bitcoinUnitChanged(BitcoinUnitChangedEvent event) { public void unitFormatChanged(UnitFormatChangedEvent event) {
total.refresh(event.getBitcoinUnit()); total.refresh(event.getUnitFormat(), event.getBitcoinUnit());
} }
} }

View file

@ -4,12 +4,11 @@ import com.google.common.eventbus.Subscribe;
import com.sparrowwallet.drongo.BitcoinUnit; import com.sparrowwallet.drongo.BitcoinUnit;
import com.sparrowwallet.drongo.address.Address; import com.sparrowwallet.drongo.address.Address;
import com.sparrowwallet.drongo.protocol.NonStandardScriptException; import com.sparrowwallet.drongo.protocol.NonStandardScriptException;
import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.drongo.protocol.TransactionOutput; import com.sparrowwallet.drongo.protocol.TransactionOutput;
import com.sparrowwallet.sparrow.UnitFormat;
import com.sparrowwallet.sparrow.BaseController; import com.sparrowwallet.sparrow.BaseController;
import com.sparrowwallet.sparrow.EventManager; import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.TransactionTabData; import com.sparrowwallet.sparrow.TransactionTabData;
import com.sparrowwallet.sparrow.control.CoinLabel;
import com.sparrowwallet.sparrow.event.TransactionTabsClosedEvent; import com.sparrowwallet.sparrow.event.TransactionTabsClosedEvent;
import com.sparrowwallet.sparrow.io.Config; import com.sparrowwallet.sparrow.io.Config;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
@ -22,7 +21,6 @@ import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent; import javafx.scene.input.ClipboardContent;
import java.util.List; import java.util.List;
import java.util.Locale;
public abstract class TransactionFormController extends BaseController { public abstract class TransactionFormController extends BaseController {
private static final int MAX_PIE_SEGMENTS = 200; private static final int MAX_PIE_SEGMENTS = 200;
@ -64,13 +62,14 @@ public abstract class TransactionFormController extends BaseController {
return; return;
} }
UnitFormat format = Config.get().getUnitFormat() == null ? UnitFormat.DOT : Config.get().getUnitFormat();
pie.setData(outputsPieData); pie.setData(outputsPieData);
final double totalSum = outputsPieData.stream().map(PieChart.Data::getPieValue).mapToDouble(Double::doubleValue).sum(); final double totalSum = outputsPieData.stream().map(PieChart.Data::getPieValue).mapToDouble(Double::doubleValue).sum();
pie.getData().forEach(data -> { pie.getData().forEach(data -> {
Tooltip tooltip = new Tooltip(); Tooltip tooltip = new Tooltip();
double percent = 100.0 * (data.getPieValue() / totalSum); double percent = 100.0 * (data.getPieValue() / totalSum);
String satsValue = String.format(Locale.ENGLISH, "%,d", (long)data.getPieValue()) + " sats"; String satsValue = format.formatSatsValue((long)data.getPieValue()) + " sats";
String btcValue = CoinLabel.BTC_FORMAT.format(data.getPieValue() / Transaction.SATOSHIS_PER_BITCOIN) + " BTC"; String btcValue = format.formatBtcValue((long)data.getPieValue()) + " BTC";
tooltip.setText(data.getName() + "\n" + (Config.get().getBitcoinUnit() == BitcoinUnit.BTC ? btcValue : satsValue) + " (" + String.format("%.1f", percent) + "%)"); tooltip.setText(data.getName() + "\n" + (Config.get().getBitcoinUnit() == BitcoinUnit.BTC ? btcValue : satsValue) + " (" + String.format("%.1f", percent) + "%)");
Tooltip.install(data.getNode(), tooltip); Tooltip.install(data.getNode(), tooltip);
data.pieValueProperty().addListener((observable, oldValue, newValue) -> tooltip.setText(newValue + "%")); data.pieValueProperty().addListener((observable, oldValue, newValue) -> tooltip.setText(newValue + "%"));

View file

@ -88,9 +88,9 @@ public class AddressesController extends WalletFormController implements Initial
} }
@Subscribe @Subscribe
public void bitcoinUnitChanged(BitcoinUnitChangedEvent event) { public void unitFormatChanged(UnitFormatChangedEvent event) {
receiveTable.setBitcoinUnit(getWalletForm().getWallet(), event.getBitcoinUnit()); receiveTable.setUnitFormat(getWalletForm().getWallet(), event.getUnitFormat(), event.getBitcoinUnit());
changeTable.setBitcoinUnit(getWalletForm().getWallet(), event.getBitcoinUnit()); changeTable.setUnitFormat(getWalletForm().getWallet(), event.getUnitFormat(), event.getBitcoinUnit());
} }
@Subscribe @Subscribe

View file

@ -14,6 +14,7 @@ import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.drongo.protocol.TransactionOutput; import com.sparrowwallet.drongo.protocol.TransactionOutput;
import com.sparrowwallet.drongo.uri.BitcoinURI; import com.sparrowwallet.drongo.uri.BitcoinURI;
import com.sparrowwallet.drongo.wallet.*; import com.sparrowwallet.drongo.wallet.*;
import com.sparrowwallet.sparrow.UnitFormat;
import com.sparrowwallet.sparrow.AppServices; import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.CurrencyRate; import com.sparrowwallet.sparrow.CurrencyRate;
import com.sparrowwallet.sparrow.EventManager; import com.sparrowwallet.sparrow.EventManager;
@ -50,6 +51,7 @@ import java.net.URL;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols; import java.text.DecimalFormatSymbols;
import java.util.*; import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static com.sparrowwallet.sparrow.AppServices.showErrorDialog; import static com.sparrowwallet.sparrow.AppServices.showErrorDialog;
@ -240,7 +242,7 @@ public class PaymentController extends WalletFormController implements Initializ
sendController.updateTransaction(); sendController.updateTransaction();
}); });
amount.setTextFormatter(new CoinTextFormatter()); amount.setTextFormatter(new CoinTextFormatter(Config.get().getUnitFormat()));
amount.textProperty().addListener(amountListener); amount.textProperty().addListener(amountListener);
amountUnit.getSelectionModel().select(BitcoinUnit.BTC.equals(sendController.getBitcoinUnit(Config.get().getBitcoinUnit())) ? 0 : 1); amountUnit.getSelectionModel().select(BitcoinUnit.BTC.equals(sendController.getBitcoinUnit(Config.get().getBitcoinUnit())) ? 0 : 1);
@ -390,8 +392,13 @@ public class PaymentController extends WalletFormController implements Initializ
} }
private Long getRecipientValueSats(BitcoinUnit bitcoinUnit) { private Long getRecipientValueSats(BitcoinUnit bitcoinUnit) {
return getRecipientValueSats(Config.get().getUnitFormat(), bitcoinUnit);
}
private Long getRecipientValueSats(UnitFormat unitFormat, BitcoinUnit bitcoinUnit) {
if(amount.getText() != null && !amount.getText().isEmpty()) { if(amount.getText() != null && !amount.getText().isEmpty()) {
double fieldValue = Double.parseDouble(amount.getText().replaceAll(",", "")); UnitFormat format = unitFormat == null ? UnitFormat.DOT : unitFormat;
double fieldValue = Double.parseDouble(amount.getText().replaceAll(Pattern.quote(format.getGroupingSeparator()), "").replaceAll(",", "."));
return bitcoinUnit.getSatsValue(fieldValue); return bitcoinUnit.getSatsValue(fieldValue);
} }
@ -400,7 +407,8 @@ public class PaymentController extends WalletFormController implements Initializ
private void setRecipientValueSats(long recipientValue) { private void setRecipientValueSats(long recipientValue) {
amount.textProperty().removeListener(amountListener); amount.textProperty().removeListener(amountListener);
DecimalFormat df = new DecimalFormat("#.#", DecimalFormatSymbols.getInstance(Locale.ENGLISH)); UnitFormat unitFormat = Config.get().getUnitFormat() == null ? UnitFormat.DOT : Config.get().getUnitFormat();
DecimalFormat df = new DecimalFormat("#.#", unitFormat.getDecimalFormatSymbols());
df.setMaximumFractionDigits(8); df.setMaximumFractionDigits(8);
amount.setText(df.format(amountUnit.getValue().getValue(recipientValue))); amount.setText(df.format(amountUnit.getValue().getValue(recipientValue)));
amount.textProperty().addListener(amountListener); amount.textProperty().addListener(amountListener);
@ -621,6 +629,19 @@ public class PaymentController extends WalletFormController implements Initializ
amountUnit.getSelectionModel().select(BitcoinUnit.BTC.equals(unit) ? 0 : 1); amountUnit.getSelectionModel().select(BitcoinUnit.BTC.equals(unit) ? 0 : 1);
} }
@Subscribe
public void unitFormatChanged(UnitFormatChangedEvent event) {
if(amount.getTextFormatter() instanceof CoinTextFormatter coinTextFormatter && coinTextFormatter.getUnitFormat() != event.getUnitFormat()) {
Long value = getRecipientValueSats(coinTextFormatter.getUnitFormat(), event.getBitcoinUnit());
amount.setTextFormatter(new CoinTextFormatter(event.getUnitFormat()));
if(value != null) {
setRecipientValueSats(value);
}
}
fiatAmount.refresh(event.getUnitFormat());
}
@Subscribe @Subscribe
public void fiatCurrencySelected(FiatCurrencySelectedEvent event) { public void fiatCurrencySelected(FiatCurrencySelectedEvent event) {
if(event.getExchangeSource() == ExchangeSource.NONE) { if(event.getExchangeSource() == ExchangeSource.NONE) {

View file

@ -13,6 +13,7 @@ import com.sparrowwallet.drongo.crypto.ECKey;
import com.sparrowwallet.drongo.protocol.*; import com.sparrowwallet.drongo.protocol.*;
import com.sparrowwallet.drongo.psbt.PSBT; import com.sparrowwallet.drongo.psbt.PSBT;
import com.sparrowwallet.drongo.wallet.*; import com.sparrowwallet.drongo.wallet.*;
import com.sparrowwallet.sparrow.UnitFormat;
import com.sparrowwallet.sparrow.AppServices; import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.CurrencyRate; import com.sparrowwallet.sparrow.CurrencyRate;
import com.sparrowwallet.sparrow.EventManager; import com.sparrowwallet.sparrow.EventManager;
@ -61,8 +62,8 @@ import tornadofx.control.Field;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.*; import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static com.sparrowwallet.sparrow.AppServices.*; import static com.sparrowwallet.sparrow.AppServices.*;
@ -354,7 +355,7 @@ public class SendController extends WalletFormController implements Initializabl
}; };
}); });
fee.setTextFormatter(new CoinTextFormatter()); fee.setTextFormatter(new CoinTextFormatter(Config.get().getUnitFormat()));
fee.textProperty().addListener(feeListener); fee.textProperty().addListener(feeListener);
BitcoinUnit unit = getBitcoinUnit(Config.get().getBitcoinUnit()); BitcoinUnit unit = getBitcoinUnit(Config.get().getBitcoinUnit());
@ -737,8 +738,13 @@ public class SendController extends WalletFormController implements Initializabl
} }
private Long getFeeValueSats(BitcoinUnit bitcoinUnit) { private Long getFeeValueSats(BitcoinUnit bitcoinUnit) {
return getFeeValueSats(Config.get().getUnitFormat(), bitcoinUnit);
}
private Long getFeeValueSats(UnitFormat unitFormat, BitcoinUnit bitcoinUnit) {
if(fee.getText() != null && !fee.getText().isEmpty()) { if(fee.getText() != null && !fee.getText().isEmpty()) {
double fieldValue = Double.parseDouble(fee.getText().replaceAll(",", "")); UnitFormat format = unitFormat == null ? UnitFormat.DOT : unitFormat;
double fieldValue = Double.parseDouble(fee.getText().replaceAll(Pattern.quote(format.getGroupingSeparator()), "").replaceAll(",", "."));
return bitcoinUnit.getSatsValue(fieldValue); return bitcoinUnit.getSatsValue(fieldValue);
} }
@ -747,7 +753,8 @@ public class SendController extends WalletFormController implements Initializabl
private void setFeeValueSats(long feeValue) { private void setFeeValueSats(long feeValue) {
fee.textProperty().removeListener(feeListener); fee.textProperty().removeListener(feeListener);
DecimalFormat df = new DecimalFormat("#.#", DecimalFormatSymbols.getInstance(Locale.ENGLISH)); UnitFormat unitFormat = Config.get().getUnitFormat() == null ? UnitFormat.DOT : Config.get().getUnitFormat();
DecimalFormat df = new DecimalFormat("#.#", unitFormat.getDecimalFormatSymbols());
df.setMaximumFractionDigits(8); df.setMaximumFractionDigits(8);
fee.setText(df.format(feeAmountUnit.getValue().getValue(feeValue))); fee.setText(df.format(feeAmountUnit.getValue().getValue(feeValue)));
fee.textProperty().addListener(feeListener); fee.textProperty().addListener(feeListener);
@ -1533,6 +1540,19 @@ public class SendController extends WalletFormController implements Initializabl
feeAmountUnit.getSelectionModel().select(BitcoinUnit.BTC.equals(unit) ? 0 : 1); feeAmountUnit.getSelectionModel().select(BitcoinUnit.BTC.equals(unit) ? 0 : 1);
} }
@Subscribe
public void unitFormatChanged(UnitFormatChangedEvent event) {
if(fee.getTextFormatter() instanceof CoinTextFormatter coinTextFormatter && coinTextFormatter.getUnitFormat() != event.getUnitFormat()) {
Long value = getFeeValueSats(coinTextFormatter.getUnitFormat(), event.getBitcoinUnit());
fee.setTextFormatter(new CoinTextFormatter(event.getUnitFormat()));
if(value != null) {
setFeeValueSats(value);
}
}
fiatFeeAmount.refresh(event.getUnitFormat());
}
@Subscribe @Subscribe
public void fiatCurrencySelected(FiatCurrencySelectedEvent event) { public void fiatCurrencySelected(FiatCurrencySelectedEvent event) {
if(event.getExchangeSource() == ExchangeSource.NONE) { if(event.getExchangeSource() == ExchangeSource.NONE) {

View file

@ -3,7 +3,7 @@ package com.sparrowwallet.sparrow.wallet;
import com.csvreader.CsvWriter; import com.csvreader.CsvWriter;
import com.google.common.eventbus.Subscribe; import com.google.common.eventbus.Subscribe;
import com.sparrowwallet.drongo.BitcoinUnit; import com.sparrowwallet.drongo.BitcoinUnit;
import com.sparrowwallet.drongo.protocol.Transaction; import com.sparrowwallet.sparrow.UnitFormat;
import com.sparrowwallet.sparrow.AppServices; import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.EventManager; import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.*; import com.sparrowwallet.sparrow.control.*;
@ -141,9 +141,8 @@ public class TransactionsController extends WalletFormController implements Init
} }
private String getCoinValue(Long value) { private String getCoinValue(Long value) {
return BitcoinUnit.BTC.equals(transactionsTable.getBitcoinUnit()) ? UnitFormat format = Config.get().getUnitFormat() == null ? UnitFormat.DOT : Config.get().getUnitFormat();
CoinLabel.getBTCFormat().format(value.doubleValue() / Transaction.SATOSHIS_PER_BITCOIN) : return BitcoinUnit.BTC.equals(transactionsTable.getBitcoinUnit()) ? format.formatBtcValue(value) : String.format(Locale.ENGLISH, "%d", value);
String.format(Locale.ENGLISH, "%d", value);
} }
private void logMessage(String logMessage) { private void logMessage(String logMessage) {
@ -201,11 +200,13 @@ public class TransactionsController extends WalletFormController implements Init
} }
@Subscribe @Subscribe
public void bitcoinUnitChanged(BitcoinUnitChangedEvent event) { public void unitFormatChanged(UnitFormatChangedEvent event) {
transactionsTable.setBitcoinUnit(getWalletForm().getWallet(), event.getBitcoinUnit()); transactionsTable.setUnitFormat(getWalletForm().getWallet(), event.getUnitFormat(), event.getBitcoinUnit());
balanceChart.setBitcoinUnit(getWalletForm().getWallet(), event.getBitcoinUnit()); balanceChart.setUnitFormat(getWalletForm().getWallet(), event.getUnitFormat(), event.getBitcoinUnit());
balance.refresh(event.getBitcoinUnit()); balance.refresh(event.getUnitFormat(), event.getBitcoinUnit());
mempoolBalance.refresh(event.getBitcoinUnit()); mempoolBalance.refresh(event.getUnitFormat(), event.getBitcoinUnit());
fiatBalance.refresh(event.getUnitFormat());
fiatMempoolBalance.refresh(event.getUnitFormat());
} }
@Subscribe @Subscribe

View file

@ -9,8 +9,8 @@ import com.sparrowwallet.drongo.SecureString;
import com.sparrowwallet.drongo.address.Address; import com.sparrowwallet.drongo.address.Address;
import com.sparrowwallet.drongo.address.InvalidAddressException; import com.sparrowwallet.drongo.address.InvalidAddressException;
import com.sparrowwallet.drongo.crypto.*; import com.sparrowwallet.drongo.crypto.*;
import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.drongo.wallet.*; import com.sparrowwallet.drongo.wallet.*;
import com.sparrowwallet.sparrow.UnitFormat;
import com.sparrowwallet.sparrow.AppServices; import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.EventManager; import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.*; import com.sparrowwallet.sparrow.control.*;
@ -189,7 +189,7 @@ public class UtxosController extends WalletFormController implements Initializab
utxosTable.getSelectionModel().getSelectedIndices().addListener((ListChangeListener<Integer>) c -> { utxosTable.getSelectionModel().getSelectedIndices().addListener((ListChangeListener<Integer>) c -> {
List<Entry> selectedEntries = utxosTable.getSelectionModel().getSelectedCells().stream().filter(tp -> tp.getTreeItem() != null).map(tp -> tp.getTreeItem().getValue()).collect(Collectors.toList()); List<Entry> selectedEntries = utxosTable.getSelectionModel().getSelectedCells().stream().filter(tp -> tp.getTreeItem() != null).map(tp -> tp.getTreeItem().getValue()).collect(Collectors.toList());
utxosChart.select(selectedEntries); utxosChart.select(selectedEntries);
updateButtons(Config.get().getBitcoinUnit()); updateButtons(Config.get().getUnitFormat(), Config.get().getBitcoinUnit());
updateUtxoCount(getWalletForm().getWalletUtxosEntry()); updateUtxoCount(getWalletForm().getWalletUtxosEntry());
}); });
} }
@ -210,7 +210,7 @@ public class UtxosController extends WalletFormController implements Initializab
return WhirlpoolServices.canWalletMix(getWalletForm().getWallet()); return WhirlpoolServices.canWalletMix(getWalletForm().getWallet());
} }
private void updateButtons(BitcoinUnit unit) { private void updateButtons(UnitFormat format, BitcoinUnit unit) {
List<Entry> selectedEntries = getSelectedEntries(); List<Entry> selectedEntries = getSelectedEntries();
selectAll.setDisable(utxosTable.getRoot().getChildren().size() == utxosTable.getSelectionModel().getSelectedCells().size()); selectAll.setDisable(utxosTable.getRoot().getChildren().size() == utxosTable.getSelectionModel().getSelectedCells().size());
@ -220,16 +220,20 @@ public class UtxosController extends WalletFormController implements Initializab
long selectedTotal = selectedEntries.stream().mapToLong(Entry::getValue).sum(); long selectedTotal = selectedEntries.stream().mapToLong(Entry::getValue).sum();
if(selectedTotal > 0) { if(selectedTotal > 0) {
if(format == null) {
format = UnitFormat.DOT;
}
if(unit == null || unit.equals(BitcoinUnit.AUTO)) { if(unit == null || unit.equals(BitcoinUnit.AUTO)) {
unit = (selectedTotal >= BitcoinUnit.getAutoThreshold() ? BitcoinUnit.BTC : BitcoinUnit.SATOSHIS); unit = (selectedTotal >= BitcoinUnit.getAutoThreshold() ? BitcoinUnit.BTC : BitcoinUnit.SATOSHIS);
} }
if(unit.equals(BitcoinUnit.BTC)) { if(unit.equals(BitcoinUnit.BTC)) {
sendSelected.setText("Send Selected (" + CoinLabel.getBTCFormat().format((double)selectedTotal / Transaction.SATOSHIS_PER_BITCOIN) + " BTC)"); sendSelected.setText("Send Selected (" + format.formatBtcValue(selectedTotal) + " BTC)");
mixSelected.setText("Mix Selected (" + CoinLabel.getBTCFormat().format((double)selectedTotal / Transaction.SATOSHIS_PER_BITCOIN) + " BTC)"); mixSelected.setText("Mix Selected (" + format.formatBtcValue(selectedTotal) + " BTC)");
} else { } else {
sendSelected.setText("Send Selected (" + String.format(Locale.ENGLISH, "%,d", selectedTotal) + " sats)"); sendSelected.setText("Send Selected (" + format.formatSatsValue(selectedTotal) + " sats)");
mixSelected.setText("Mix Selected (" + String.format(Locale.ENGLISH, "%,d", selectedTotal) + " sats)"); mixSelected.setText("Mix Selected (" + format.formatSatsValue(selectedTotal) + " sats)");
} }
} else { } else {
sendSelected.setText("Send Selected"); sendSelected.setText("Send Selected");
@ -486,9 +490,8 @@ public class UtxosController extends WalletFormController implements Initializab
} }
private String getCoinValue(Long value) { private String getCoinValue(Long value) {
return BitcoinUnit.BTC.equals(utxosTable.getBitcoinUnit()) ? UnitFormat format = Config.get().getUnitFormat() == null ? UnitFormat.DOT : Config.get().getUnitFormat();
CoinLabel.getBTCFormat().format(value.doubleValue() / Transaction.SATOSHIS_PER_BITCOIN) : return BitcoinUnit.BTC.equals(utxosTable.getBitcoinUnit()) ? format.formatBtcValue(value) : String.format(Locale.ENGLISH, "%d", value);
String.format(Locale.ENGLISH, "%d", value);
} }
private static Glyph getExternalGlyph() { private static Glyph getExternalGlyph() {
@ -546,12 +549,14 @@ public class UtxosController extends WalletFormController implements Initializab
} }
@Subscribe @Subscribe
public void bitcoinUnitChanged(BitcoinUnitChangedEvent event) { public void unitFormatChanged(UnitFormatChangedEvent event) {
utxosTable.setBitcoinUnit(getWalletForm().getWallet(), event.getBitcoinUnit()); utxosTable.setUnitFormat(getWalletForm().getWallet(), event.getUnitFormat(), event.getBitcoinUnit());
utxosChart.setBitcoinUnit(getWalletForm().getWallet(), event.getBitcoinUnit()); utxosChart.setUnitFormat(getWalletForm().getWallet(), event.getUnitFormat(), event.getBitcoinUnit());
balance.refresh(event.getBitcoinUnit()); balance.refresh(event.getUnitFormat(), event.getBitcoinUnit());
mempoolBalance.refresh(event.getBitcoinUnit()); mempoolBalance.refresh(event.getUnitFormat(), event.getBitcoinUnit());
updateButtons(event.getBitcoinUnit()); updateButtons(event.getUnitFormat(), event.getBitcoinUnit());
fiatBalance.refresh(event.getUnitFormat());
fiatMempoolBalance.refresh(event.getUnitFormat());
} }
@Subscribe @Subscribe
@ -588,7 +593,7 @@ public class UtxosController extends WalletFormController implements Initializab
public void walletUtxoStatusChanged(WalletUtxoStatusChangedEvent event) { public void walletUtxoStatusChanged(WalletUtxoStatusChangedEvent event) {
if(event.fromThisOrNested(getWalletForm().getWallet())) { if(event.fromThisOrNested(getWalletForm().getWallet())) {
utxosTable.refresh(); utxosTable.refresh();
updateButtons(Config.get().getBitcoinUnit()); updateButtons(Config.get().getUnitFormat(), Config.get().getBitcoinUnit());
} }
} }

View file

@ -5,12 +5,11 @@ import com.samourai.whirlpool.client.tx0.Tx0Previews;
import com.samourai.whirlpool.client.wallet.beans.Tx0FeeTarget; import com.samourai.whirlpool.client.wallet.beans.Tx0FeeTarget;
import com.samourai.whirlpool.client.whirlpool.beans.Pool; import com.samourai.whirlpool.client.whirlpool.beans.Pool;
import com.sparrowwallet.drongo.BitcoinUnit; import com.sparrowwallet.drongo.BitcoinUnit;
import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.drongo.wallet.MixConfig; import com.sparrowwallet.drongo.wallet.MixConfig;
import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.UnitFormat;
import com.sparrowwallet.sparrow.AppServices; import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.EventManager; import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.CoinLabel;
import com.sparrowwallet.sparrow.control.CopyableCoinLabel; import com.sparrowwallet.sparrow.control.CopyableCoinLabel;
import com.sparrowwallet.sparrow.control.CopyableLabel; import com.sparrowwallet.sparrow.control.CopyableLabel;
import com.sparrowwallet.sparrow.event.WalletMasterMixConfigChangedEvent; import com.sparrowwallet.sparrow.event.WalletMasterMixConfigChangedEvent;
@ -157,9 +156,10 @@ public class WhirlpoolController {
return "Fetching pools..."; return "Fetching pools...";
} }
UnitFormat format = Config.get().getUnitFormat() == null ? UnitFormat.DOT : Config.get().getUnitFormat();
BitcoinUnit bitcoinUnit = wallet.getAutoUnit(); BitcoinUnit bitcoinUnit = wallet.getAutoUnit();
String satsValue = String.format(Locale.ENGLISH, "%,d", selectedPool.getDenomination()) + " sats"; String satsValue = format.formatSatsValue(selectedPool.getDenomination()) + " sats";
String btcValue = CoinLabel.BTC_FORMAT.format((double)selectedPool.getDenomination() / Transaction.SATOSHIS_PER_BITCOIN) + " BTC"; String btcValue = format.formatBtcValue(selectedPool.getDenomination()) + " BTC";
pool.setTooltip(bitcoinUnit == BitcoinUnit.BTC ? new Tooltip(satsValue) : new Tooltip(btcValue)); pool.setTooltip(bitcoinUnit == BitcoinUnit.BTC ? new Tooltip(satsValue) : new Tooltip(btcValue));
return bitcoinUnit == BitcoinUnit.BTC ? btcValue : satsValue; return bitcoinUnit == BitcoinUnit.BTC ? btcValue : satsValue;
@ -273,8 +273,9 @@ public class WhirlpoolController {
allPoolsService.setOnSucceeded(poolsStateEvent -> { allPoolsService.setOnSucceeded(poolsStateEvent -> {
OptionalLong optMinValue = allPoolsService.getValue().stream().mapToLong(pool1 -> pool1.getPremixValueMin() + pool1.getFeeValue()).min(); OptionalLong optMinValue = allPoolsService.getValue().stream().mapToLong(pool1 -> pool1.getPremixValueMin() + pool1.getFeeValue()).min();
if(optMinValue.isPresent() && totalUtxoValue < optMinValue.getAsLong()) { if(optMinValue.isPresent() && totalUtxoValue < optMinValue.getAsLong()) {
String satsValue = String.format(Locale.ENGLISH, "%,d", optMinValue.getAsLong()) + " sats"; UnitFormat format = Config.get().getUnitFormat() == null ? UnitFormat.DOT : Config.get().getUnitFormat();
String btcValue = CoinLabel.getBTCFormat().format((double)optMinValue.getAsLong() / Transaction.SATOSHIS_PER_BITCOIN) + " BTC"; String satsValue = format.formatSatsValue(optMinValue.getAsLong()) + " sats";
String btcValue = format.formatBtcValue(optMinValue.getAsLong()) + " BTC";
poolInsufficient.setText("No available pools. Select a value over " + (Config.get().getBitcoinUnit() == BitcoinUnit.BTC ? btcValue : satsValue) + "."); poolInsufficient.setText("No available pools. Select a value over " + (Config.get().getBitcoinUnit() == BitcoinUnit.BTC ? btcValue : satsValue) + ".");
} }
}); });

View file

@ -7,6 +7,7 @@
<?import javafx.scene.shape.Rectangle?> <?import javafx.scene.shape.Rectangle?>
<?import com.sparrowwallet.sparrow.control.UnlabeledToggleSwitch?> <?import com.sparrowwallet.sparrow.control.UnlabeledToggleSwitch?>
<?import com.sparrowwallet.drongo.BitcoinUnit?> <?import com.sparrowwallet.drongo.BitcoinUnit?>
<?import com.sparrowwallet.sparrow.UnitFormat?>
<?import com.sparrowwallet.sparrow.Theme?> <?import com.sparrowwallet.sparrow.Theme?>
<?import impl.org.controlsfx.skin.DecorationPane?> <?import impl.org.controlsfx.skin.DecorationPane?>
@ -56,6 +57,9 @@
<fx:define> <fx:define>
<ToggleGroup fx:id="bitcoinUnit"/> <ToggleGroup fx:id="bitcoinUnit"/>
</fx:define> </fx:define>
<fx:define>
<ToggleGroup fx:id="unitFormat"/>
</fx:define>
<fx:define> <fx:define>
<ToggleGroup fx:id="theme"/> <ToggleGroup fx:id="theme"/>
</fx:define> </fx:define>
@ -80,6 +84,20 @@
</RadioMenuItem> </RadioMenuItem>
</items> </items>
</Menu> </Menu>
<Menu mnemonicParsing="false" text="Unit Format">
<items>
<RadioMenuItem mnemonicParsing="false" text="1,234.56" toggleGroup="$unitFormat" onAction="#setUnitFormat">
<userData>
<UnitFormat fx:constant="DOT" />
</userData>
</RadioMenuItem>
<RadioMenuItem mnemonicParsing="false" text="1.234,56" toggleGroup="$unitFormat" onAction="#setUnitFormat">
<userData>
<UnitFormat fx:constant="COMMA" />
</userData>
</RadioMenuItem>
</items>
</Menu>
<Menu mnemonicParsing="false" text="Theme"> <Menu mnemonicParsing="false" text="Theme">
<items> <items>
<RadioMenuItem mnemonicParsing="false" text="Light" toggleGroup="$theme" onAction="#setTheme"> <RadioMenuItem mnemonicParsing="false" text="Light" toggleGroup="$theme" onAction="#setTheme">