user set bitcoin unit support

This commit is contained in:
Craig Raw 2020-07-09 14:35:34 +02:00
parent fc5bff9788
commit d8c19ac0f8
19 changed files with 283 additions and 41 deletions

2
drongo

@ -1 +1 @@
Subproject commit 4e7f0611c4bd15ae983bd06feeb80ad69eedb853
Subproject commit 49a4b548b4b93aa9b765b0b6f9520d0314b1395f

View file

@ -3,6 +3,7 @@ package com.sparrowwallet.sparrow;
import com.google.common.base.Charsets;
import com.google.common.eventbus.Subscribe;
import com.google.common.io.ByteSource;
import com.sparrowwallet.drongo.BitcoinUnit;
import com.sparrowwallet.drongo.SecureString;
import com.sparrowwallet.drongo.Utils;
import com.sparrowwallet.drongo.crypto.InvalidPasswordException;
@ -64,6 +65,9 @@ public class AppController implements Initializable {
@FXML
private MenuItem openTransactionIdItem;
@FXML
private ToggleGroup bitcoinUnit;
@FXML
private CheckMenuItem showTxHex;
@ -146,6 +150,15 @@ public class AppController implements Initializable {
}
});
BitcoinUnit unit = Config.get().getBitcoinUnit();
if(unit == null) {
unit = BitcoinUnit.AUTO;
Config.get().setBitcoinUnit(unit);
}
final BitcoinUnit selectedUnit = unit;
Optional<Toggle> selectedToggle = bitcoinUnit.getToggles().stream().filter(toggle -> selectedUnit.equals(toggle.getUserData())).findFirst();
selectedToggle.ifPresent(toggle -> bitcoinUnit.selectToggle(toggle));
showTxHex.setSelected(true);
showTxHexProperty = true;
exportWallet.setDisable(true);
@ -374,6 +387,13 @@ public class AppController implements Initializable {
showTxHexProperty = item.isSelected();
}
public void setBitcoinUnit(ActionEvent event) {
MenuItem item = (MenuItem)event.getSource();
BitcoinUnit unit = (BitcoinUnit)item.getUserData();
Config.get().setBitcoinUnit(unit);
EventManager.get().post(new BitcoinUnitChangedEvent(unit));
}
public void newWallet(ActionEvent event) {
WalletNameDialog dlg = new WalletNameDialog();
Optional<String> walletName = dlg.showAndWait();

View file

@ -15,9 +15,10 @@ import javafx.scene.text.Font;
import java.util.List;
import java.util.Optional;
public class AddressTreeTable extends TreeTableView<Entry> {
public class AddressTreeTable extends CoinTreeTable {
public void initialize(NodeEntry rootEntry) {
getStyleClass().add("address-treetable");
setBitcoinUnit(rootEntry.getWallet());
String address = rootEntry.getAddress().toString();
updateAll(rootEntry);
@ -80,6 +81,8 @@ public class AddressTreeTable extends TreeTableView<Entry> {
}
public void updateAll(NodeEntry rootEntry) {
setBitcoinUnit(rootEntry.getWallet());
RecursiveTreeItem<Entry> rootItem = new RecursiveTreeItem<>(rootEntry, Entry::getChildren);
setRoot(rootItem);
rootItem.setExpanded(true);

View file

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

View file

@ -1,5 +1,6 @@
package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.drongo.BitcoinUnit;
import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.sparrow.wallet.Entry;
import com.sparrowwallet.sparrow.wallet.HashIndexEntry;
@ -13,8 +14,11 @@ import javafx.scene.layout.Region;
import java.util.Locale;
class CoinCell extends TreeTableCell<Entry, Number> {
private final Tooltip tooltip;
public CoinCell() {
super();
tooltip = new Tooltip();
getStyleClass().add("coin-cell");
}
@ -25,23 +29,33 @@ class CoinCell extends TreeTableCell<Entry, Number> {
if(empty || amount == null) {
setText(null);
setGraphic(null);
setTooltip(null);
} else {
Entry entry = getTreeTableView().getTreeItem(getIndex()).getValue();
EntryCell.applyRowStyles(this, entry);
CoinTreeTable coinTreeTable = (CoinTreeTable)getTreeTableView();
BitcoinUnit unit = coinTreeTable.getBitcoinUnit();
String satsValue = String.format(Locale.ENGLISH, "%,d", amount.longValue());
final String btcValue = CoinLabel.getBTCFormat().format(amount.doubleValue() / Transaction.SATOSHIS_PER_BITCOIN) + " BTC";
final String btcValue = CoinLabel.getBTCFormat().format(amount.doubleValue() / Transaction.SATOSHIS_PER_BITCOIN);
if(unit.equals(BitcoinUnit.BTC)) {
tooltip.setText(satsValue + " " + BitcoinUnit.SATOSHIS.getLabel());
setText(btcValue);
} else {
tooltip.setText(btcValue + " " + BitcoinUnit.BTC.getLabel());
setText(satsValue);
}
setTooltip(tooltip);
String tooltipValue = tooltip.getText();
if(entry instanceof TransactionEntry) {
TransactionEntry transactionEntry = (TransactionEntry)entry;
Tooltip tooltip = new Tooltip();
tooltip.setText(btcValue + " (" + transactionEntry.getConfirmationsDescription() + ")");
setTooltip(tooltip);
tooltip.setText(tooltipValue + " (" + transactionEntry.getConfirmationsDescription() + ")");
transactionEntry.confirmationsProperty().addListener((observable, oldValue, newValue) -> {
Tooltip newTooltip = new Tooltip();
newTooltip.setText(btcValue + " (" + transactionEntry.getConfirmationsDescription() + ")");
setTooltip(newTooltip);
tooltip.setText(tooltipValue + " (" + transactionEntry.getConfirmationsDescription() + ")");
});
if(transactionEntry.isConfirming()) {
@ -66,14 +80,6 @@ class CoinCell extends TreeTableCell<Entry, Number> {
} else {
setGraphic(null);
}
if(getTooltip() == null) {
Tooltip tooltip = new Tooltip();
tooltip.setText(btcValue);
setTooltip(tooltip);
}
setText(satsValue);
}
}
}

View file

@ -1,6 +1,8 @@
package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.drongo.BitcoinUnit;
import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.sparrow.io.Config;
import javafx.beans.property.LongProperty;
import javafx.beans.property.SimpleLongProperty;
import javafx.scene.control.ContextMenu;
@ -14,8 +16,6 @@ import java.text.DecimalFormatSymbols;
import java.util.Locale;
public class CoinLabel extends CopyableLabel {
public static final int MAX_SATS_SHOWN = 1000000;
public static final DecimalFormat BTC_FORMAT = new DecimalFormat("0", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
private final LongProperty value = new SimpleLongProperty(-1);
@ -52,7 +52,13 @@ public class CoinLabel extends CopyableLabel {
String satsValue = String.format(Locale.ENGLISH, "%,d",value) + " sats";
String btcValue = BTC_FORMAT.format(value.doubleValue() / Transaction.SATOSHIS_PER_BITCOIN) + " BTC";
if(value > MAX_SATS_SHOWN) {
BitcoinUnit unit = Config.get().getBitcoinUnit();
if(unit == null || unit.equals(BitcoinUnit.AUTO)) {
unit = (value >= BitcoinUnit.getAutoThreshold() ? BitcoinUnit.BTC : BitcoinUnit.SATOSHIS);
}
if(unit.equals(BitcoinUnit.BTC)) {
tooltip.setText(satsValue);
setText(btcValue);
} else {

View file

@ -8,11 +8,11 @@ import java.text.ParseException;
import java.util.function.UnaryOperator;
import java.util.regex.Pattern;
public class CoinFormatter extends TextFormatter<String> {
public class CoinTextFormatter extends TextFormatter<String> {
private static final Pattern COIN_VALIDATION = Pattern.compile("[\\d,]*(\\.\\d{0,8})?");
private static final DecimalFormat COIN_FORMAT = new DecimalFormat("###,###.########");
public static final DecimalFormat COIN_FORMAT = new DecimalFormat("###,###.########");
public CoinFormatter() {
public CoinTextFormatter() {
super(new CoinFilter());
}

View file

@ -0,0 +1,36 @@
package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.drongo.BitcoinUnit;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.io.Config;
import com.sparrowwallet.sparrow.wallet.Entry;
import javafx.scene.control.TreeTableView;
public class CoinTreeTable extends TreeTableView<Entry> {
private BitcoinUnit bitcoinUnit;
public BitcoinUnit getBitcoinUnit() {
return bitcoinUnit;
}
public void setBitcoinUnit(BitcoinUnit bitcoinUnit) {
this.bitcoinUnit = bitcoinUnit;
}
public void setBitcoinUnit(Wallet wallet) {
setBitcoinUnit(wallet, Config.get().getBitcoinUnit());
}
public void setBitcoinUnit(Wallet wallet, BitcoinUnit unit) {
if(unit == null || unit.equals(BitcoinUnit.AUTO)) {
unit = wallet.getAutoUnit();
}
boolean changed = (bitcoinUnit != unit);
this.bitcoinUnit = unit;
if(changed && !getChildren().isEmpty()) {
refresh();
}
}
}

View file

@ -11,9 +11,10 @@ import javafx.scene.control.TreeTableView;
import java.util.List;
public class TransactionsTreeTable extends TreeTableView<Entry> {
public class TransactionsTreeTable extends CoinTreeTable {
public void initialize(WalletTransactionsEntry rootEntry) {
getStyleClass().add("transactions-treetable");
setBitcoinUnit(rootEntry.getWallet());
updateAll(rootEntry);
setShowRoot(false);
@ -58,6 +59,8 @@ public class TransactionsTreeTable extends TreeTableView<Entry> {
}
public void updateAll(WalletTransactionsEntry rootEntry) {
setBitcoinUnit(rootEntry.getWallet());
RecursiveTreeItem<Entry> rootItem = new RecursiveTreeItem<>(rootEntry, Entry::getChildren);
setRoot(rootItem);
rootItem.setExpanded(true);

View file

@ -1,13 +1,14 @@
package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.drongo.BitcoinUnit;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.io.Config;
import com.sparrowwallet.sparrow.wallet.Entry;
import com.sparrowwallet.sparrow.wallet.UtxoEntry;
import com.sparrowwallet.sparrow.wallet.WalletUtxosEntry;
import javafx.beans.NamedArg;
import javafx.scene.Node;
import javafx.scene.chart.Axis;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.*;
import java.util.List;
import java.util.Set;
@ -30,11 +31,14 @@ public class UtxosChart extends BarChart<String, Number> {
utxoSeries = new XYChart.Series<>();
getData().add(utxoSeries);
update(walletUtxosEntry);
BitcoinUnit unit = Config.get().getBitcoinUnit();
setBitcoinUnit(walletUtxosEntry.getWallet(), unit);
}
public void update(WalletUtxosEntry walletUtxosEntry) {
List<Data<String, Number>> utxoDataList = walletUtxosEntry.getChildren().stream()
.map(entry -> new XYChart.Data<>(entry.getLabel() != null && !entry.getLabel().isEmpty() ? entry.getLabel() : ((UtxoEntry)entry).getDescription(), (Number)entry.getValue(), entry))
.map(entry -> new XYChart.Data<>(getCategoryName(entry), (Number)entry.getValue(), entry))
.sorted((o1, o2) -> (int) (o2.getYValue().longValue() - o1.getYValue().longValue()))
.collect(Collectors.toList());
@ -66,6 +70,14 @@ public class UtxosChart extends BarChart<String, Number> {
}
}
private String getCategoryName(Entry entry) {
if(entry.getLabel() != null && !entry.getLabel().isEmpty()) {
return entry.getLabel().length() > 15 ? entry.getLabel().substring(0, 15) + "..." : entry.getLabel();
}
return ((UtxoEntry)entry).getDescription();
}
public void select(List<Entry> entries) {
Set<Node> selectedBars = lookupAll(".chart-bar.selected");
for(Node selectedBar : selectedBars) {
@ -86,4 +98,13 @@ public class UtxosChart extends BarChart<String, Number> {
this.selectedEntries = entries;
}
public void setBitcoinUnit(Wallet wallet, BitcoinUnit unit) {
if(unit == null || unit.equals(BitcoinUnit.AUTO)) {
unit = wallet.getAutoUnit();
}
NumberAxis yaxis = (NumberAxis)getYAxis();
yaxis.setTickLabelFormatter(new CoinAxisFormatter(yaxis, unit));
}
}

View file

@ -10,9 +10,10 @@ import javafx.scene.control.TreeTableView;
import java.util.List;
public class UtxosTreeTable extends TreeTableView<Entry> {
public class UtxosTreeTable extends CoinTreeTable {
public void initialize(WalletUtxosEntry rootEntry) {
getStyleClass().add("utxos-treetable");
setBitcoinUnit(rootEntry.getWallet());
updateAll(rootEntry);
setShowRoot(false);
@ -78,6 +79,8 @@ public class UtxosTreeTable extends TreeTableView<Entry> {
}
public void updateAll(WalletUtxosEntry rootEntry) {
setBitcoinUnit(rootEntry.getWallet());
RecursiveTreeItem<Entry> rootItem = new RecursiveTreeItem<>(rootEntry, Entry::getChildren);
setRoot(rootItem);
rootItem.setExpanded(true);

View file

@ -0,0 +1,15 @@
package com.sparrowwallet.sparrow.event;
import com.sparrowwallet.drongo.BitcoinUnit;
public class BitcoinUnitChangedEvent {
private final BitcoinUnit bitcoinUnit;
public BitcoinUnitChangedEvent(BitcoinUnit bitcoinUnit) {
this.bitcoinUnit = bitcoinUnit;
}
public BitcoinUnit getBitcoinUnit() {
return bitcoinUnit;
}
}

View file

@ -1,6 +1,7 @@
package com.sparrowwallet.sparrow.io;
import com.google.gson.*;
import com.sparrowwallet.drongo.BitcoinUnit;
import com.sparrowwallet.sparrow.Mode;
import java.io.*;
@ -10,6 +11,7 @@ public class Config {
public static final String CONFIG_FILENAME = ".config";
private Mode mode;
private BitcoinUnit bitcoinUnit;
private Integer keyDerivationPeriod;
private File hwi;
private String electrumServer;
@ -67,6 +69,15 @@ public class Config {
flush();
}
public BitcoinUnit getBitcoinUnit() {
return bitcoinUnit;
}
public void setBitcoinUnit(BitcoinUnit bitcoinUnit) {
this.bitcoinUnit = bitcoinUnit;
flush();
}
public Integer getKeyDerivationPeriod() {
return keyDerivationPeriod;
}

View file

@ -5,6 +5,7 @@ import com.sparrowwallet.drongo.KeyPurpose;
import com.sparrowwallet.drongo.wallet.WalletNode;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.AddressTreeTable;
import com.sparrowwallet.sparrow.event.BitcoinUnitChangedEvent;
import com.sparrowwallet.sparrow.event.WalletEntryLabelChangedEvent;
import com.sparrowwallet.sparrow.event.WalletHistoryChangedEvent;
import com.sparrowwallet.sparrow.event.WalletNodesChangedEvent;
@ -63,4 +64,10 @@ public class AddressesController extends WalletFormController implements Initial
changeTable.updateLabel(event.getEntry());
}
}
@Subscribe
public void bitcoinUnitChanged(BitcoinUnitChangedEvent event) {
receiveTable.setBitcoinUnit(getWalletForm().getWallet(), event.getBitcoinUnit());
changeTable.setBitcoinUnit(getWalletForm().getWallet(), event.getBitcoinUnit());
}
}

View file

@ -8,8 +8,8 @@ import com.sparrowwallet.drongo.wallet.*;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.*;
import com.sparrowwallet.sparrow.event.FeeRatesUpdatedEvent;
import com.sparrowwallet.sparrow.event.SpendUtxoEvent;
import com.sparrowwallet.sparrow.event.*;
import com.sparrowwallet.sparrow.io.Config;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
@ -29,6 +29,7 @@ import org.controlsfx.validation.decoration.StyleClassValidationDecoration;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
@ -141,10 +142,15 @@ public class SendController extends WalletFormController implements Initializabl
updateTransaction();
});
amount.setTextFormatter(new CoinFormatter());
amount.setTextFormatter(new CoinTextFormatter());
amount.textProperty().addListener(amountListener);
amountUnit.getSelectionModel().select(1);
BitcoinUnit unit = Config.get().getBitcoinUnit();
if(unit == null || unit.equals(BitcoinUnit.AUTO)) {
unit = getWalletForm().getWallet().getAutoUnit();
}
amountUnit.getSelectionModel().select(BitcoinUnit.BTC.equals(unit) ? 0 : 1);
amountUnit.valueProperty().addListener((observable, oldValue, newValue) -> {
Long value = getRecipientValueSats(oldValue);
if(value != null) {
@ -197,10 +203,10 @@ public class SendController extends WalletFormController implements Initializabl
setTargetBlocks(5);
fee.setTextFormatter(new CoinFormatter());
fee.setTextFormatter(new CoinTextFormatter());
fee.textProperty().addListener(feeListener);
feeAmountUnit.getSelectionModel().select(1);
feeAmountUnit.getSelectionModel().select(BitcoinUnit.BTC.equals(unit) ? 0 : 1);
feeAmountUnit.valueProperty().addListener((observable, oldValue, newValue) -> {
Long value = getFeeValueSats(oldValue);
if(value != null) {
@ -305,7 +311,12 @@ public class SendController extends WalletFormController implements Initializabl
return List.of(utxoSelectorProperty.get());
}
UtxoSelector priorityUtxoSelector = new PriorityUtxoSelector(AppController.getCurrentBlockHeight());
Integer blockHeight = AppController.getCurrentBlockHeight();
if(blockHeight == null) {
blockHeight = getWalletForm().getWallet().getStoredBlockHeight();
}
UtxoSelector priorityUtxoSelector = new PriorityUtxoSelector(blockHeight);
return List.of(priorityUtxoSelector);
}
@ -395,7 +406,9 @@ public class SendController extends WalletFormController implements Initializabl
private Map<Integer, Double> getTargetBlocksFeeRates() {
Map<Integer, Double> retrievedFeeRates = AppController.getTargetBlockFeeRates();
if(retrievedFeeRates == null) {
retrievedFeeRates = TARGET_BLOCKS_RANGE.stream().collect(Collectors.toMap(java.util.function.Function.identity(), v -> FALLBACK_FEE_RATE));
retrievedFeeRates = TARGET_BLOCKS_RANGE.stream().collect(Collectors.toMap(java.util.function.Function.identity(), v -> FALLBACK_FEE_RATE,
(u, v) -> { throw new IllegalStateException("Duplicate target blocks"); },
LinkedHashMap::new));
}
return retrievedFeeRates;
@ -449,6 +462,27 @@ public class SendController extends WalletFormController implements Initializabl
}
@Subscribe
public void walletNodesChanged(WalletNodesChangedEvent event) {
if(event.getWallet().equals(walletForm.getWallet())) {
clear(null);
}
}
@Subscribe
public void walletHistoryChanged(WalletHistoryChangedEvent event) {
if(event.getWallet().equals(walletForm.getWallet())) {
updateTransaction();
}
}
@Subscribe
public void walletEntryLabelChanged(WalletEntryLabelChangedEvent event) {
if(event.getWallet().equals(walletForm.getWallet())) {
updateTransaction();
}
}
@Subscribe
public void feeRatesUpdated(FeeRatesUpdatedEvent event) {
feeRatesChart.update(event.getTargetBlockFeeRates());
@ -464,4 +498,14 @@ public class SendController extends WalletFormController implements Initializabl
updateTransaction(true);
}
}
@Subscribe
public void bitcoinUnitChanged(BitcoinUnitChangedEvent event) {
BitcoinUnit unit = event.getBitcoinUnit();
if(unit == null || unit.equals(BitcoinUnit.AUTO)) {
unit = getWalletForm().getWallet().getAutoUnit();
}
amountUnit.getSelectionModel().select(BitcoinUnit.BTC.equals(unit) ? 0 : 1);
feeAmountUnit.getSelectionModel().select(BitcoinUnit.BTC.equals(unit) ? 0 : 1);
}
}

View file

@ -3,10 +3,7 @@ package com.sparrowwallet.sparrow.wallet;
import com.google.common.eventbus.Subscribe;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.TransactionsTreeTable;
import com.sparrowwallet.sparrow.event.WalletBlockHeightChangedEvent;
import com.sparrowwallet.sparrow.event.WalletEntryLabelChangedEvent;
import com.sparrowwallet.sparrow.event.WalletHistoryChangedEvent;
import com.sparrowwallet.sparrow.event.WalletNodesChangedEvent;
import com.sparrowwallet.sparrow.event.*;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.input.MouseEvent;
@ -50,6 +47,11 @@ public class TransactionsController extends WalletFormController implements Init
}
}
@Subscribe
public void bitcoinUnitChanged(BitcoinUnitChangedEvent event) {
transactionsTable.setBitcoinUnit(getWalletForm().getWallet(), event.getBitcoinUnit());
}
//TODO: Remove
public void advanceBlock(MouseEvent event) {
Integer currentBlock = getWalletForm().getWallet().getStoredBlockHeight();

View file

@ -4,6 +4,7 @@ import com.google.common.eventbus.Subscribe;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.UtxosChart;
import com.sparrowwallet.sparrow.control.UtxosTreeTable;
import com.sparrowwallet.sparrow.event.BitcoinUnitChangedEvent;
import com.sparrowwallet.sparrow.event.WalletEntryLabelChangedEvent;
import com.sparrowwallet.sparrow.event.WalletHistoryChangedEvent;
import com.sparrowwallet.sparrow.event.WalletNodesChangedEvent;
@ -63,4 +64,10 @@ public class UtxosController extends WalletFormController implements Initializab
utxosChart.update(getWalletForm().getWalletUtxosEntry());
}
}
@Subscribe
public void bitcoinUnitChanged(BitcoinUnitChangedEvent event) {
utxosTable.setBitcoinUnit(getWalletForm().getWallet(), event.getBitcoinUnit());
utxosChart.setBitcoinUnit(getWalletForm().getWallet(), event.getBitcoinUnit());
}
}

View file

@ -20,6 +20,10 @@ public class WalletTransactionsEntry extends Entry {
calculateBalances();
}
public Wallet getWallet() {
return wallet;
}
@Override
public Long getValue() {
return getBalance();

View file

@ -6,6 +6,7 @@
<?import javafx.scene.text.Text?>
<?import javafx.scene.shape.Rectangle?>
<?import com.sparrowwallet.sparrow.control.UnlabeledToggleSwitch?>
<?import com.sparrowwallet.drongo.BitcoinUnit?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="200" minWidth="350" prefHeight="750.0" prefWidth="1000.0" fx:controller="com.sparrowwallet.sparrow.AppController" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1">
<children>
@ -34,8 +35,30 @@
<MenuItem styleClass="macHide" mnemonicParsing="false" text="Quit" onAction="#quit"/>
</items>
</Menu>
<fx:define>
<ToggleGroup fx:id="bitcoinUnit"/>
</fx:define>
<Menu mnemonicParsing="false" text="View">
<items>
<Menu mnemonicParsing="false" text="Bitcoin Unit">
<items>
<RadioMenuItem mnemonicParsing="false" text="Auto" toggleGroup="$bitcoinUnit" onAction="#setBitcoinUnit">
<userData>
<BitcoinUnit fx:constant="AUTO" />
</userData>
</RadioMenuItem>
<RadioMenuItem mnemonicParsing="false" text="BTC" toggleGroup="$bitcoinUnit" onAction="#setBitcoinUnit">
<userData>
<BitcoinUnit fx:constant="BTC" />
</userData>
</RadioMenuItem>
<RadioMenuItem mnemonicParsing="false" text="sats" toggleGroup="$bitcoinUnit" onAction="#setBitcoinUnit">
<userData>
<BitcoinUnit fx:constant="SATOSHIS" />
</userData>
</RadioMenuItem>
</items>
</Menu>
<CheckMenuItem fx:id="showTxHex" mnemonicParsing="false" text="Show Transaction Hex" onAction="#showTxHex"/>
</items>
</Menu>