expand transaction diagram in popup on click

This commit is contained in:
Craig Raw 2022-02-02 16:03:08 +02:00
parent 9bf53ab0cd
commit ca928fc136
22 changed files with 329 additions and 47 deletions

View file

@ -424,7 +424,9 @@ public class AppController implements Initializable {
Stage stage = new Stage();
stage.setTitle("About " + MainApp.APP_NAME);
stage.initStyle(org.controlsfx.tools.Platform.getCurrent() == org.controlsfx.tools.Platform.OSX ? StageStyle.UNDECORATED : StageStyle.DECORATED);
stage.initStyle(StageStyle.UNDECORATED);
stage.initOwner(tabs.getScene().getWindow());
stage.initModality(Modality.WINDOW_MODAL);
stage.setResizable(false);
Scene scene = new Scene(root);
AppServices.onEscapePressed(scene, stage::close);

View file

@ -6,6 +6,7 @@ import com.sparrowwallet.sparrow.io.Config;
import javafx.beans.property.LongProperty;
import javafx.beans.property.SimpleLongProperty;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.Tooltip;
import javafx.scene.input.Clipboard;
@ -15,7 +16,7 @@ import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
public class CoinLabel extends CopyableLabel {
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);
@ -28,7 +29,6 @@ public class CoinLabel extends CopyableLabel {
public CoinLabel(String text) {
super(text);
BTC_FORMAT.setMaximumFractionDigits(8);
valueProperty().addListener((observable, oldValue, newValue) -> setValueAsText((Long)newValue, Config.get().getBitcoinUnit()));
tooltip = new Tooltip();
contextMenu = new CoinContextMenu();
@ -77,7 +77,7 @@ public class CoinLabel extends CopyableLabel {
private class CoinContextMenu extends ContextMenu {
public CoinContextMenu() {
MenuItem copySatsValue = new MenuItem("Copy Value in Satoshis");
MenuItem copySatsValue = new MenuItem("Copy Value in sats");
copySatsValue.setOnAction(AE -> {
hide();
ClipboardContent content = new ClipboardContent();

View file

@ -0,0 +1,94 @@
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;
import javafx.scene.control.MenuItem;
import javafx.scene.control.Tooltip;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import java.util.Locale;
public class CopyableCoinLabel extends CopyableLabel {
private final LongProperty valueProperty = new SimpleLongProperty(-1);
private final Tooltip tooltip;
private final CoinContextMenu contextMenu;
public CopyableCoinLabel() {
this("Unknown");
}
public CopyableCoinLabel(String text) {
super(text);
valueProperty().addListener((observable, oldValue, newValue) -> setValueAsText((Long)newValue, Config.get().getBitcoinUnit()));
tooltip = new Tooltip();
contextMenu = new CoinContextMenu();
}
public final LongProperty valueProperty() {
return valueProperty;
}
public final long getValue() {
return valueProperty.get();
}
public final void setValue(long value) {
this.valueProperty.set(value);
}
public void refresh() {
refresh(Config.get().getBitcoinUnit());
}
public void refresh(BitcoinUnit bitcoinUnit) {
setValueAsText(getValue(), bitcoinUnit);
}
private void setValueAsText(Long value, BitcoinUnit bitcoinUnit) {
setTooltip(tooltip);
setContextMenu(contextMenu);
String satsValue = String.format(Locale.ENGLISH, "%,d", value) + " sats";
String btcValue = CoinLabel.getBTCFormat().format(value.doubleValue() / Transaction.SATOSHIS_PER_BITCOIN) + " BTC";
BitcoinUnit unit = bitcoinUnit;
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 {
tooltip.setText(btcValue);
setText(satsValue);
}
}
private class CoinContextMenu extends ContextMenu {
public CoinContextMenu() {
MenuItem copySatsValue = new MenuItem("Copy Value in sats");
copySatsValue.setOnAction(AE -> {
hide();
ClipboardContent content = new ClipboardContent();
content.putString(Long.toString(getValue()));
Clipboard.getSystemClipboard().setContent(content);
});
MenuItem copyBtcValue = new MenuItem("Copy Value in BTC");
copyBtcValue.setOnAction(AE -> {
hide();
ClipboardContent content = new ClipboardContent();
content.putString(CoinLabel.getBTCFormat().format((double)getValue() / Transaction.SATOSHIS_PER_BITCOIN));
Clipboard.getSystemClipboard().setContent(content);
});
getItems().addAll(copySatsValue, copyBtcValue);
}
}
}

View file

@ -34,4 +34,18 @@ public class TextUtils {
helper.setText(DEFAULT_TEXT);
return d;
}
public static double computeTextHeight(Font font, String text) {
helper.setText(text);
helper.setFont(font);
helper.setWrappingWidth(0.0D);
helper.setLineSpacing(0.0D);
double d = Math.ceil(helper.getLayoutBounds().getHeight());
helper.setWrappingWidth(DEFAULT_WRAPPING_WIDTH);
helper.setLineSpacing(DEFAULT_LINE_SPACING);
helper.setText(DEFAULT_TEXT);
return d;
}
}

View file

@ -18,18 +18,24 @@ import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.control.Tooltip;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.*;
import javafx.scene.shape.Circle;
import javafx.scene.shape.CubicCurve;
import javafx.scene.shape.Line;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration;
import org.controlsfx.glyphfont.FontAwesome;
import org.controlsfx.glyphfont.Glyph;
@ -40,16 +46,68 @@ import java.util.stream.Collectors;
public class TransactionDiagram extends GridPane {
private static final int MAX_UTXOS = 8;
private static final int REDUCED_MAX_UTXOS = MAX_UTXOS - 2;
private static final int EXPANDED_MAX_UTXOS = 20;
private static final int MAX_PAYMENTS = 6;
private static final int REDUCED_MAX_PAYMENTS = MAX_PAYMENTS - 2;
private static final int EXPANDED_MAX_PAYMENTS = 18;
private static final double DIAGRAM_HEIGHT = 210.0;
private static final double REDUCED_DIAGRAM_HEIGHT = DIAGRAM_HEIGHT - 60;
private static final double EXPANDED_DIAGRAM_HEIGHT = 500;
private static final int TOOLTIP_SHOW_DELAY = 50;
private static final int RELATIVE_SIZE_MAX_RADIUS = 7;
private static final int ROW_HEIGHT = 27;
private WalletTransaction walletTx;
private final BooleanProperty finalProperty = new SimpleBooleanProperty(false);
private final ObjectProperty<OptimizationStrategy> optimizationStrategyProperty = new SimpleObjectProperty<>(OptimizationStrategy.EFFICIENCY);
private boolean expanded;
private TransactionDiagram expandedDiagram;
private final EventHandler<MouseEvent> expandedDiagramHandler = new EventHandler<>() {
@Override
public void handle(MouseEvent event) {
if(!event.isConsumed()) {
Stage stage = new Stage();
stage.setTitle(walletTx.getPayments().iterator().next().getLabel());
stage.initStyle(StageStyle.UNDECORATED);
stage.initOwner(TransactionDiagram.this.getScene().getWindow());
stage.initModality(Modality.WINDOW_MODAL);
stage.setResizable(false);
VBox vBox = new VBox(20);
vBox.getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm());
vBox.getStylesheets().add(AppServices.class.getResource("wallet/wallet.css").toExternalForm());
vBox.getStylesheets().add(AppServices.class.getResource("wallet/send.css").toExternalForm());
vBox.setPadding(new Insets(20, 40, 20, 50));
expandedDiagram = new TransactionDiagram();
expandedDiagram.setId("transactionDiagram");
expandedDiagram.setExpanded(true);
updateExpandedDiagram();
HBox buttonBox = new HBox();
buttonBox.setAlignment(Pos.CENTER_RIGHT);
Button button = new Button("Close");
button.setOnAction(e -> {
stage.close();
});
buttonBox.getChildren().add(button);
vBox.getChildren().addAll(expandedDiagram, buttonBox);
Scene scene = new Scene(vBox);
AppServices.onEscapePressed(scene, stage::close);
AppServices.setStageIcon(stage);
stage.setScene(scene);
stage.setOnShowing(e -> {
AppServices.moveToActiveWindowScreen(stage, 600, 460);
});
stage.setOnHidden(e -> {
expandedDiagram = null;
});
stage.show();
}
}
};
public void update(WalletTransaction walletTx) {
setMinHeight(getDiagramHeight());
@ -60,6 +118,10 @@ public class TransactionDiagram extends GridPane {
} else {
this.walletTx = walletTx;
update();
setOnMouseClicked(expandedDiagramHandler);
if(expandedDiagram != null) {
updateExpandedDiagram();
}
}
}
@ -87,6 +149,24 @@ public class TransactionDiagram extends GridPane {
getChildren().clear();
}
private void updateExpandedDiagram() {
expandedDiagram.setFinal(isFinal());
expandedDiagram.setOptimizationStrategy(getOptimizationStrategy());
expandedDiagram.walletTx = walletTx;
List<Map<BlockTransactionHashIndex, WalletNode>> utxoSets = expandedDiagram.getDisplayedUtxoSets();
int maxSetSize = utxoSets.stream().mapToInt(Map::size).max().orElse(0);
int maxRows = Math.max(maxSetSize * utxoSets.size(), walletTx.getPayments().size() + 2);
double diagramHeight = Math.max(DIAGRAM_HEIGHT, Math.min(EXPANDED_DIAGRAM_HEIGHT, maxRows * ROW_HEIGHT));
expandedDiagram.setMinHeight(diagramHeight);
expandedDiagram.setMaxHeight(diagramHeight);
expandedDiagram.update();
if(expandedDiagram.getScene() != null && expandedDiagram.getScene().getWindow() instanceof Stage stage) {
stage.sizeToScene();
}
}
public void update() {
List<Map<BlockTransactionHashIndex, WalletNode>> displayedUtxoSets = getDisplayedUtxoSets();
@ -287,17 +367,19 @@ public class TransactionDiagram extends GridPane {
private Pane getInputsLabels(List<Map<BlockTransactionHashIndex, WalletNode>> displayedUtxoSets) {
VBox inputsBox = new VBox();
inputsBox.setMaxWidth(150);
inputsBox.setPrefWidth(150);
inputsBox.setMaxWidth(isExpanded() ? 300 : 150);
inputsBox.setPrefWidth(isExpanded() ? 230 : 150);
inputsBox.setPadding(new Insets(0, 10, 0, 10));
inputsBox.minHeightProperty().bind(minHeightProperty());
inputsBox.setAlignment(Pos.CENTER_RIGHT);
inputsBox.getChildren().add(createSpacer());
double labelHeight = TextUtils.computeTextHeight(AppServices.getMonospaceFont(), "0") + 1;
for(Map<BlockTransactionHashIndex, WalletNode> displayedUtxos : displayedUtxoSets) {
for(BlockTransactionHashIndex input : displayedUtxos.keySet()) {
WalletNode walletNode = displayedUtxos.get(input);
String desc = getInputDescription(input);
Label label = new Label(desc);
label.setPrefHeight(labelHeight);
label.getStyleClass().add("utxo-label");
Button excludeUtxoButton = new Button("");
@ -307,8 +389,10 @@ public class TransactionDiagram extends GridPane {
});
Tooltip tooltip = new Tooltip();
Long inputValue = null;
if(walletNode != null) {
tooltip.setText("Spending " + getSatsValue(input.getValue()) + " sats from " + (isFinal() ? walletTx.getWallet().getFullDisplayName() : "") + " " + walletNode + "\n" + input.getHashAsString() + ":" + input.getIndex() + "\n" + walletTx.getWallet().getAddress(walletNode));
inputValue = input.getValue();
tooltip.setText("Spending " + getSatsValue(inputValue) + " sats from " + (isFinal() ? walletTx.getWallet().getFullDisplayName() : "") + " " + walletNode + "\n" + input.getHashAsString() + ":" + input.getIndex() + "\n" + walletTx.getWallet().getAddress(walletNode));
tooltip.getStyleClass().add("input-label");
if(input.getLabel() == null || input.getLabel().isEmpty()) {
@ -335,13 +419,16 @@ public class TransactionDiagram extends GridPane {
label.setGraphic(walletTx.isTwoPersonCoinjoin() ? getQuestionGlyph() : getWarningGlyph());
label.setOnMouseClicked(event -> {
EventManager.get().post(new SorobanInitiatedEvent(walletTx.getWallet()));
closeExpanded();
event.consume();
});
} else {
if(walletTx.getInputTransactions() != null && walletTx.getInputTransactions().get(input.getHash()) != null) {
BlockTransaction blockTransaction = walletTx.getInputTransactions().get(input.getHash());
TransactionOutput txOutput = blockTransaction.getTransaction().getOutputs().get((int) input.getIndex());
Address fromAddress = txOutput.getScript().getToAddress();
tooltip.setText("Input of " + getSatsValue(txOutput.getValue()) + " sats\n" + input.getHashAsString() + ":" + input.getIndex() + (fromAddress != null ? "\n" + fromAddress : ""));
inputValue = txOutput.getValue();
tooltip.setText("Input of " + getSatsValue(inputValue) + " sats\n" + input.getHashAsString() + ":" + input.getIndex() + (fromAddress != null ? "\n" + fromAddress : ""));
} else {
tooltip.setText(input.getHashAsString() + ":" + input.getIndex());
}
@ -355,7 +442,21 @@ public class TransactionDiagram extends GridPane {
label.setTooltip(tooltip);
}
inputsBox.getChildren().add(label);
HBox inputBox = new HBox();
inputBox.setAlignment(Pos.CENTER_RIGHT);
inputBox.getChildren().add(label);
if(isExpanded() && inputValue != null) {
label.setMinWidth(120);
Region region = new Region();
HBox.setHgrow(region, Priority.ALWAYS);
CoinLabel amountLabel = new CoinLabel();
amountLabel.setValue(inputValue);
amountLabel.setMinWidth(TextUtils.computeTextWidth(amountLabel.getFont(), amountLabel.getText(), 0.0D) + 2);
inputBox.getChildren().addAll(region, amountLabel);
}
inputsBox.getChildren().add(inputBox);
inputsBox.getChildren().add(createSpacer());
}
}
@ -505,7 +606,8 @@ public class TransactionDiagram extends GridPane {
private Pane getOutputsLabels(List<Payment> displayedPayments) {
VBox outputsBox = new VBox();
outputsBox.setMaxWidth(150);
outputsBox.setMaxWidth(isExpanded() ? 350 : 150);
outputsBox.setPrefWidth(isExpanded() ? 230 : 150);
outputsBox.setPadding(new Insets(0, 20, 0, 10));
outputsBox.setAlignment(Pos.CENTER_LEFT);
outputsBox.getChildren().add(createSpacer());
@ -527,7 +629,20 @@ public class TransactionDiagram extends GridPane {
recipientTooltip.setShowDelay(new Duration(TOOLTIP_SHOW_DELAY));
recipientTooltip.setShowDuration(Duration.INDEFINITE);
recipientLabel.setTooltip(recipientTooltip);
outputNodes.add(new OutputNode(recipientLabel, payment.getAddress(), payment.getAmount()));
HBox paymentBox = new HBox();
paymentBox.setAlignment(Pos.CENTER_LEFT);
paymentBox.getChildren().add(recipientLabel);
if(isExpanded()) {
Region region = new Region();
region.setMinWidth(20);
HBox.setHgrow(region, Priority.ALWAYS);
CoinLabel amountLabel = new CoinLabel();
amountLabel.setValue(payment.getAmount());
amountLabel.setMinWidth(TextUtils.computeTextWidth(amountLabel.getFont(), amountLabel.getText(), 0.0D) + 2);
paymentBox.getChildren().addAll(region, amountLabel);
}
outputNodes.add(new OutputNode(paymentBox, payment.getAddress(), payment.getAmount()));
}
for(Map.Entry<WalletNode, Long> changeEntry : walletTx.getChangeMap().entrySet()) {
@ -536,6 +651,7 @@ public class TransactionDiagram extends GridPane {
boolean overGapLimit = (changeNode.getIndex() - defaultChangeNode.getIndex()) > walletTx.getWallet().getGapLimit();
HBox actionBox = new HBox();
actionBox.setAlignment(Pos.CENTER_LEFT);
Address changeAddress = walletTx.getChangeAddress(changeNode);
String changeDesc = changeAddress.toString().substring(0, 8) + "...";
Label changeLabel = new Label(changeDesc, overGapLimit ? getChangeWarningGlyph() : getChangeGlyph());
@ -563,6 +679,17 @@ public class TransactionDiagram extends GridPane {
actionBox.getChildren().add(replaceChangeLabel);
}
if(isExpanded()) {
changeLabel.setMinWidth(120);
Region region = new Region();
region.setMinWidth(20);
HBox.setHgrow(region, Priority.ALWAYS);
CoinLabel amountLabel = new CoinLabel();
amountLabel.setValue(changeEntry.getValue());
amountLabel.setMinWidth(TextUtils.computeTextWidth(amountLabel.getFont(), amountLabel.getText(), 0.0D) + 2);
actionBox.getChildren().addAll(region, amountLabel);
}
outputNodes.add(new OutputNode(actionBox, changeAddress, changeEntry.getValue()));
}
@ -584,7 +711,21 @@ public class TransactionDiagram extends GridPane {
feeTooltip.setShowDelay(new Duration(TOOLTIP_SHOW_DELAY));
feeTooltip.setShowDuration(Duration.INDEFINITE);
feeLabel.setTooltip(feeTooltip);
outputsBox.getChildren().add(feeLabel);
HBox feeBox = new HBox();
feeBox.setAlignment(Pos.CENTER_LEFT);
feeBox.getChildren().add(feeLabel);
if(isExpanded()) {
Region region = new Region();
region.setMinWidth(20);
HBox.setHgrow(region, Priority.ALWAYS);
CoinLabel amountLabel = new CoinLabel();
amountLabel.setValue(walletTx.getFee());
amountLabel.setMinWidth(TextUtils.computeTextWidth(amountLabel.getFont(), amountLabel.getText(), 0.0D) + 2);
feeBox.getChildren().addAll(region, amountLabel);
}
outputsBox.getChildren().add(feeBox);
outputsBox.getChildren().add(createSpacer());
return outputsBox;
@ -613,6 +754,10 @@ public class TransactionDiagram extends GridPane {
}
public double getDiagramHeight() {
if(isExpanded()) {
return getMaxHeight();
}
if(isReducedHeight()) {
return REDUCED_DIAGRAM_HEIGHT;
}
@ -621,6 +766,10 @@ public class TransactionDiagram extends GridPane {
}
private int getMaxUtxos() {
if(isExpanded()) {
return EXPANDED_MAX_UTXOS;
}
if(isReducedHeight()) {
return REDUCED_MAX_UTXOS;
}
@ -629,6 +778,10 @@ public class TransactionDiagram extends GridPane {
}
private int getMaxPayments() {
if(isExpanded()) {
return EXPANDED_MAX_PAYMENTS;
}
if(isReducedHeight()) {
return REDUCED_MAX_PAYMENTS;
}
@ -834,6 +987,8 @@ public class TransactionDiagram extends GridPane {
});
userAddGlyph.setOnMouseClicked(event -> {
EventManager.get().post(new SorobanInitiatedEvent(walletTx.getWallet()));
closeExpanded();
event.consume();
});
return userAddGlyph;
}
@ -853,6 +1008,8 @@ public class TransactionDiagram extends GridPane {
});
coinsGlyph.setOnMouseClicked(event -> {
EventManager.get().post(new SorobanInitiatedEvent(walletTx.getWallet()));
closeExpanded();
event.consume();
});
} else {
coinsGlyph.getStyleClass().add("coins-icon");
@ -861,6 +1018,12 @@ public class TransactionDiagram extends GridPane {
return coinsGlyph;
}
private void closeExpanded() {
if(isExpanded() && this.getScene() != null && this.getScene().getWindow() instanceof Stage stage) {
stage.close();
}
}
public boolean isFinal() {
return finalProperty.get();
}
@ -885,6 +1048,14 @@ public class TransactionDiagram extends GridPane {
this.optimizationStrategyProperty.set(optimizationStrategy);
}
public boolean isExpanded() {
return expanded;
}
public void setExpanded(boolean expanded) {
this.expanded = expanded;
}
private static class PayjoinBlockTransactionHashIndex extends BlockTransactionHashIndex {
public PayjoinBlockTransactionHashIndex() {
super(Sha256Hash.ZERO_HASH, 0, new Date(), 0L, 0, 0);

View file

@ -132,7 +132,7 @@ public class HeadersController extends TransactionFormController implements Init
private CopyableLabel virtualSize;
@FXML
private CoinLabel fee;
private CopyableCoinLabel fee;
@FXML
private CopyableLabel feeRate;

View file

@ -44,7 +44,7 @@ public class InputController extends TransactionFormController implements Initia
private Hyperlink linkedOutpoint;
@FXML
private CoinLabel spends;
private CopyableCoinLabel spends;
@FXML
private CopyableLabel from;

View file

@ -7,7 +7,7 @@ import com.sparrowwallet.drongo.psbt.PSBTInput;
import com.sparrowwallet.drongo.wallet.BlockTransaction;
import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.CoinLabel;
import com.sparrowwallet.sparrow.control.CopyableCoinLabel;
import com.sparrowwallet.sparrow.control.CopyableLabel;
import com.sparrowwallet.sparrow.event.BitcoinUnitChangedEvent;
import com.sparrowwallet.sparrow.event.BlockTransactionFetchedEvent;
@ -31,7 +31,7 @@ public class InputsController extends TransactionFormController implements Initi
private CopyableLabel count;
@FXML
private CoinLabel total;
private CopyableCoinLabel total;
@FXML
private CopyableLabel signatures;

View file

@ -31,7 +31,7 @@ public class OutputController extends TransactionFormController implements Initi
private Fieldset outputFieldset;
@FXML
private CoinLabel value;
private CopyableCoinLabel value;
@FXML
private CopyableLabel to;

View file

@ -4,7 +4,7 @@ import com.google.common.eventbus.Subscribe;
import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.drongo.protocol.TransactionOutput;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.CoinLabel;
import com.sparrowwallet.sparrow.control.CopyableCoinLabel;
import com.sparrowwallet.sparrow.control.CopyableLabel;
import com.sparrowwallet.sparrow.event.BitcoinUnitChangedEvent;
import javafx.fxml.FXML;
@ -21,7 +21,7 @@ public class OutputsController extends TransactionFormController implements Init
private CopyableLabel count;
@FXML
private CoinLabel total;
private CopyableCoinLabel total;
@FXML
private PieChart outputsPie;

View file

@ -42,13 +42,13 @@ public class TransactionsController extends WalletFormController implements Init
private static final DateFormat LOG_DATE_FORMAT = new SimpleDateFormat("[MMM dd HH:mm:ss]");
@FXML
private CoinLabel balance;
private CopyableCoinLabel balance;
@FXML
private FiatLabel fiatBalance;
@FXML
private CoinLabel mempoolBalance;
private CopyableCoinLabel mempoolBalance;
@FXML
private FiatLabel fiatMempoolBalance;
@ -228,7 +228,7 @@ public class TransactionsController extends WalletFormController implements Init
public void walletHistoryStatus(WalletHistoryStatusEvent event) {
transactionsTable.updateHistoryStatus(event);
if(event.getWallet() != null && getWalletForm().getWallet() == event.getWallet()) {
if(event.getWallet() != null && getWalletForm() != null && getWalletForm().getWallet() == event.getWallet()) {
String logMessage = event.getStatusMessage();
if(logMessage == null) {
if(event instanceof WalletHistoryFinishedEvent) {

View file

@ -53,13 +53,13 @@ public class UtxosController extends WalletFormController implements Initializab
private static final Logger log = LoggerFactory.getLogger(UtxosController.class);
@FXML
private CoinLabel balance;
private CopyableCoinLabel balance;
@FXML
private FiatLabel fiatBalance;
@FXML
private CoinLabel mempoolBalance;
private CopyableCoinLabel mempoolBalance;
@FXML
private FiatLabel fiatMempoolBalance;

View file

@ -11,6 +11,7 @@ import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.CoinLabel;
import com.sparrowwallet.sparrow.control.CopyableCoinLabel;
import com.sparrowwallet.sparrow.control.CopyableLabel;
import com.sparrowwallet.sparrow.event.WalletMasterMixConfigChangedEvent;
import com.sparrowwallet.sparrow.io.Config;
@ -62,7 +63,7 @@ public class WhirlpoolController {
private VBox selectedPool;
@FXML
private CoinLabel poolFee;
private CopyableCoinLabel poolFee;
@FXML
private Label poolInsufficient;
@ -83,7 +84,7 @@ public class WhirlpoolController {
private Label nbOutputs;
@FXML
private CoinLabel discountFee;
private CopyableCoinLabel discountFee;
private String walletId;
private Wallet wallet;
@ -273,7 +274,7 @@ public class WhirlpoolController {
OptionalLong optMinValue = allPoolsService.getValue().stream().mapToLong(pool1 -> pool1.getPremixValueMin() + pool1.getFeeValue()).min();
if(optMinValue.isPresent() && totalUtxoValue < optMinValue.getAsLong()) {
String satsValue = String.format(Locale.ENGLISH, "%,d", optMinValue.getAsLong()) + " sats";
String btcValue = CoinLabel.BTC_FORMAT.format((double)optMinValue.getAsLong() / Transaction.SATOSHIS_PER_BITCOIN) + " BTC";
String btcValue = CoinLabel.getBTCFormat().format((double)optMinValue.getAsLong() / Transaction.SATOSHIS_PER_BITCOIN) + " BTC";
poolInsufficient.setText("No available pools. Select a value over " + (Config.get().getBitcoinUnit() == BitcoinUnit.BTC ? btcValue : satsValue) + ".");
}
});

View file

@ -26,7 +26,7 @@
<HBox><Label text="If you find Sparrow useful, consider donating at "/><Hyperlink text="https://sparrowwallet.com/donate" onAction="#openDonate"/></HBox>
</VBox>
<HBox styleClass="button-area" alignment="BOTTOM_RIGHT" VBox.vgrow="SOMETIMES">
<Button text="Done" onAction="#close" />
<Button text="Close" onAction="#close" />
</HBox>
</VBox>
</StackPane>

View file

@ -13,7 +13,7 @@
<?import org.controlsfx.control.SegmentedButton?>
<?import com.sparrowwallet.sparrow.control.CopyableLabel?>
<?import com.sparrowwallet.sparrow.control.IdLabel?>
<?import com.sparrowwallet.sparrow.control.CoinLabel?>
<?import com.sparrowwallet.sparrow.control.CopyableCoinLabel?>
<?import javafx.scene.control.Button?>
<?import org.controlsfx.glyphfont.Glyph?>
<?import javafx.scene.control.ComboBox?>
@ -143,7 +143,7 @@
<Form GridPane.columnIndex="1" GridPane.rowIndex="2" styleClass="details-lower">
<Fieldset text="Fee" inputGrow="SOMETIMES">
<Field text="Amount:">
<CoinLabel fx:id="fee" />
<CopyableCoinLabel fx:id="fee" />
</Field>
<Field text="Rate:">
<CopyableLabel fx:id="feeRate" />

View file

@ -13,7 +13,7 @@
<?import com.sparrowwallet.sparrow.control.RelativeTimelockSpinner?>
<?import com.sparrowwallet.sparrow.control.CopyableLabel?>
<?import com.sparrowwallet.sparrow.control.IdLabel?>
<?import com.sparrowwallet.sparrow.control.CoinLabel?>
<?import com.sparrowwallet.sparrow.control.CopyableCoinLabel?>
<?import com.sparrowwallet.sparrow.control.AddressLabel?>
<?import com.sparrowwallet.sparrow.control.UnlabeledToggleSwitch?>
<?import com.sparrowwallet.sparrow.control.ScriptArea?>
@ -37,7 +37,7 @@
<Hyperlink fx:id="linkedOutpoint" styleClass="id" visible="false" />
</Field>
<Field text="Spends:">
<CoinLabel fx:id="spends" />
<CopyableCoinLabel fx:id="spends" />
<CopyableLabel fx:id="from" text="from" />
<AddressLabel fx:id="address" />
</Field>

View file

@ -6,7 +6,7 @@
<?import tornadofx.control.*?>
<?import javafx.scene.chart.PieChart?>
<?import com.sparrowwallet.sparrow.control.CopyableLabel?>
<?import com.sparrowwallet.sparrow.control.CoinLabel?>
<?import com.sparrowwallet.sparrow.control.CopyableCoinLabel?>
<GridPane hgap="10.0" vgap="10.0" styleClass="tx-pane" stylesheets="@inputs.css, @transaction.css, @../general.css" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.sparrowwallet.sparrow.transaction.InputsController">
<padding>
@ -25,7 +25,7 @@
<CopyableLabel fx:id="count" />
</Field>
<Field text="Total:">
<CoinLabel fx:id="total" />
<CopyableCoinLabel fx:id="total" />
</Field>
</Fieldset>
</Form>

View file

@ -12,7 +12,7 @@
<?import tornadofx.control.Form?>
<?import javafx.geometry.Insets?>
<?import com.sparrowwallet.sparrow.control.CopyableLabel?>
<?import com.sparrowwallet.sparrow.control.CoinLabel?>
<?import com.sparrowwallet.sparrow.control.CopyableCoinLabel?>
<?import com.sparrowwallet.sparrow.control.AddressLabel?>
<?import com.sparrowwallet.sparrow.control.ScriptArea?>
@ -31,7 +31,7 @@
<Form GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.rowIndex="0">
<Fieldset fx:id="outputFieldset" inputGrow="SOMETIMES" text="Output">
<Field text="Sends:">
<CoinLabel fx:id="value"/>
<CopyableCoinLabel fx:id="value"/>
<CopyableLabel fx:id="to" text="to" />
<AddressLabel fx:id="address" />
</Field>

View file

@ -6,7 +6,7 @@
<?import tornadofx.control.*?>
<?import javafx.scene.chart.PieChart?>
<?import com.sparrowwallet.sparrow.control.CopyableLabel?>
<?import com.sparrowwallet.sparrow.control.CoinLabel?>
<?import com.sparrowwallet.sparrow.control.CopyableCoinLabel?>
<GridPane hgap="10.0" vgap="10.0" styleClass="tx-pane" stylesheets="@outputs.css, @transaction.css, @../general.css" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.sparrowwallet.sparrow.transaction.OutputsController">
<padding>
@ -25,7 +25,7 @@
<CopyableLabel fx:id="count" />
</Field>
<Field text="Total:">
<CoinLabel fx:id="total" />
<CopyableCoinLabel fx:id="total" />
</Field>
</Fieldset>
</Form>

View file

@ -12,7 +12,7 @@
<?import tornadofx.control.Form?>
<?import tornadofx.control.Fieldset?>
<?import tornadofx.control.Field?>
<?import com.sparrowwallet.sparrow.control.CoinLabel?>
<?import com.sparrowwallet.sparrow.control.CopyableCoinLabel?>
<?import com.sparrowwallet.sparrow.control.FiatLabel?>
<?import com.sparrowwallet.sparrow.control.CopyableLabel?>
<?import org.controlsfx.glyphfont.Glyph?>
@ -35,10 +35,10 @@
<Form GridPane.columnIndex="0" GridPane.rowIndex="0">
<Fieldset inputGrow="SOMETIMES" text="Transactions" styleClass="header">
<Field text="Balance:">
<CoinLabel fx:id="balance"/><Region HBox.hgrow="ALWAYS"/><FiatLabel fx:id="fiatBalance" minWidth="110" />
<CopyableCoinLabel fx:id="balance"/><Region HBox.hgrow="ALWAYS"/><FiatLabel fx:id="fiatBalance" minWidth="110" />
</Field>
<Field text="Mempool:">
<CoinLabel fx:id="mempoolBalance" /><Region HBox.hgrow="ALWAYS"/><FiatLabel fx:id="fiatMempoolBalance" minWidth="110" />
<CopyableCoinLabel fx:id="mempoolBalance" /><Region HBox.hgrow="ALWAYS"/><FiatLabel fx:id="fiatMempoolBalance" minWidth="110" />
</Field>
<Field text="Transactions:">
<CopyableLabel fx:id="transactionCount" />

View file

@ -14,7 +14,7 @@
<?import tornadofx.control.Form?>
<?import tornadofx.control.Fieldset?>
<?import tornadofx.control.Field?>
<?import com.sparrowwallet.sparrow.control.CoinLabel?>
<?import com.sparrowwallet.sparrow.control.CopyableCoinLabel?>
<?import com.sparrowwallet.sparrow.control.FiatLabel?>
<?import com.sparrowwallet.sparrow.control.CopyableLabel?>
@ -35,10 +35,10 @@
<Form GridPane.columnIndex="0" GridPane.rowIndex="0">
<Fieldset inputGrow="SOMETIMES" text="Unspent Transaction Outputs" styleClass="header">
<Field text="Balance:">
<CoinLabel fx:id="balance"/><Region HBox.hgrow="ALWAYS"/><FiatLabel fx:id="fiatBalance" minWidth="110" />
<CopyableCoinLabel fx:id="balance"/><Region HBox.hgrow="ALWAYS"/><FiatLabel fx:id="fiatBalance" minWidth="110" />
</Field>
<Field text="Mempool:">
<CoinLabel fx:id="mempoolBalance" /><Region HBox.hgrow="ALWAYS"/><FiatLabel fx:id="fiatMempoolBalance" minWidth="110" />
<CopyableCoinLabel fx:id="mempoolBalance" /><Region HBox.hgrow="ALWAYS"/><FiatLabel fx:id="fiatMempoolBalance" minWidth="110" />
</Field>
<Field text="UTXOs:">
<CopyableLabel fx:id="utxoCount" />

View file

@ -10,7 +10,7 @@
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.image.Image?>
<?import javafx.geometry.Insets?>
<?import com.sparrowwallet.sparrow.control.CoinLabel?>
<?import com.sparrowwallet.sparrow.control.CopyableCoinLabel?>
<?import com.sparrowwallet.sparrow.control.CopyableLabel?>
<StackPane prefHeight="460.0" prefWidth="600.0" stylesheets="@whirlpool.css, @../general.css" styleClass="whirlpool-pane" fx:controller="com.sparrowwallet.sparrow.whirlpool.WhirlpoolController" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml">
<VBox spacing="20">
@ -131,10 +131,10 @@
</HBox>
<HBox styleClass="field-box">
<Label text="Pool Fee:" styleClass="field-label" />
<CoinLabel fx:id="poolFee" />
<CopyableCoinLabel fx:id="poolFee" />
<HBox fx:id="discountFeeBox" alignment="CENTER_LEFT">
<Label text=" (discounted to " />
<CoinLabel fx:id="discountFee" />
<CopyableCoinLabel fx:id="discountFee" />
<Label text=")" />
</HBox>
</HBox>