diff --git a/src/main/java/com/sparrowwallet/sparrow/AppController.java b/src/main/java/com/sparrowwallet/sparrow/AppController.java index 3b2d3a99..e26fad2c 100644 --- a/src/main/java/com/sparrowwallet/sparrow/AppController.java +++ b/src/main/java/com/sparrowwallet/sparrow/AppController.java @@ -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); diff --git a/src/main/java/com/sparrowwallet/sparrow/control/CoinLabel.java b/src/main/java/com/sparrowwallet/sparrow/control/CoinLabel.java index 8ce5dad4..acae46a1 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/CoinLabel.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/CoinLabel.java @@ -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(); diff --git a/src/main/java/com/sparrowwallet/sparrow/control/CopyableCoinLabel.java b/src/main/java/com/sparrowwallet/sparrow/control/CopyableCoinLabel.java new file mode 100644 index 00000000..a75d6075 --- /dev/null +++ b/src/main/java/com/sparrowwallet/sparrow/control/CopyableCoinLabel.java @@ -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); + } + } +} diff --git a/src/main/java/com/sparrowwallet/sparrow/control/TextUtils.java b/src/main/java/com/sparrowwallet/sparrow/control/TextUtils.java index b9828259..b7d84728 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/TextUtils.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/TextUtils.java @@ -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; + } } diff --git a/src/main/java/com/sparrowwallet/sparrow/control/TransactionDiagram.java b/src/main/java/com/sparrowwallet/sparrow/control/TransactionDiagram.java index edc2a4ea..7a68e5bc 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/TransactionDiagram.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/TransactionDiagram.java @@ -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 optimizationStrategyProperty = new SimpleObjectProperty<>(OptimizationStrategy.EFFICIENCY); + private boolean expanded; + private TransactionDiagram expandedDiagram; + + private final EventHandler 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> 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> displayedUtxoSets = getDisplayedUtxoSets(); @@ -287,17 +367,19 @@ public class TransactionDiagram extends GridPane { private Pane getInputsLabels(List> 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 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 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 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); diff --git a/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java b/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java index 972ac6d0..95bdf9bb 100644 --- a/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java +++ b/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java @@ -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; diff --git a/src/main/java/com/sparrowwallet/sparrow/transaction/InputController.java b/src/main/java/com/sparrowwallet/sparrow/transaction/InputController.java index 4a15584f..be69d705 100644 --- a/src/main/java/com/sparrowwallet/sparrow/transaction/InputController.java +++ b/src/main/java/com/sparrowwallet/sparrow/transaction/InputController.java @@ -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; diff --git a/src/main/java/com/sparrowwallet/sparrow/transaction/InputsController.java b/src/main/java/com/sparrowwallet/sparrow/transaction/InputsController.java index b6ce6f2a..4703bab3 100644 --- a/src/main/java/com/sparrowwallet/sparrow/transaction/InputsController.java +++ b/src/main/java/com/sparrowwallet/sparrow/transaction/InputsController.java @@ -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; diff --git a/src/main/java/com/sparrowwallet/sparrow/transaction/OutputController.java b/src/main/java/com/sparrowwallet/sparrow/transaction/OutputController.java index 7c97e67c..155fa0c6 100644 --- a/src/main/java/com/sparrowwallet/sparrow/transaction/OutputController.java +++ b/src/main/java/com/sparrowwallet/sparrow/transaction/OutputController.java @@ -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; diff --git a/src/main/java/com/sparrowwallet/sparrow/transaction/OutputsController.java b/src/main/java/com/sparrowwallet/sparrow/transaction/OutputsController.java index 6ee637c0..3e7fb28b 100644 --- a/src/main/java/com/sparrowwallet/sparrow/transaction/OutputsController.java +++ b/src/main/java/com/sparrowwallet/sparrow/transaction/OutputsController.java @@ -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; diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/TransactionsController.java b/src/main/java/com/sparrowwallet/sparrow/wallet/TransactionsController.java index 1baac343..a4a5b360 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/TransactionsController.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/TransactionsController.java @@ -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) { diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/UtxosController.java b/src/main/java/com/sparrowwallet/sparrow/wallet/UtxosController.java index 6ea14d28..011a69de 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/UtxosController.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/UtxosController.java @@ -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; diff --git a/src/main/java/com/sparrowwallet/sparrow/whirlpool/WhirlpoolController.java b/src/main/java/com/sparrowwallet/sparrow/whirlpool/WhirlpoolController.java index 05a32be3..75aefecc 100644 --- a/src/main/java/com/sparrowwallet/sparrow/whirlpool/WhirlpoolController.java +++ b/src/main/java/com/sparrowwallet/sparrow/whirlpool/WhirlpoolController.java @@ -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) + "."); } }); diff --git a/src/main/resources/com/sparrowwallet/sparrow/about.fxml b/src/main/resources/com/sparrowwallet/sparrow/about.fxml index 6bc59be6..1e834ba7 100644 --- a/src/main/resources/com/sparrowwallet/sparrow/about.fxml +++ b/src/main/resources/com/sparrowwallet/sparrow/about.fxml @@ -26,7 +26,7 @@ -