mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-24 12:46:45 +00:00
request new change address in the transaction diagram
This commit is contained in:
parent
c9cdf6e77d
commit
b17c15f702
6 changed files with 77 additions and 9 deletions
2
drongo
2
drongo
|
@ -1 +1 @@
|
||||||
Subproject commit 7dca0d0c39404bd89a5a4589a79ffe0f688e8181
|
Subproject commit 567294a4b055cc062650de45fccbbc89db714f39
|
|
@ -1,5 +1,6 @@
|
||||||
package com.sparrowwallet.sparrow.control;
|
package com.sparrowwallet.sparrow.control;
|
||||||
|
|
||||||
|
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.uri.BitcoinURI;
|
import com.sparrowwallet.drongo.uri.BitcoinURI;
|
||||||
|
@ -10,6 +11,7 @@ import com.sparrowwallet.drongo.wallet.WalletTransaction;
|
||||||
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.ExcludeUtxoEvent;
|
import com.sparrowwallet.sparrow.event.ExcludeUtxoEvent;
|
||||||
|
import com.sparrowwallet.sparrow.event.ReplaceChangeAddressEvent;
|
||||||
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
|
@ -200,6 +202,7 @@ public class TransactionDiagram extends GridPane {
|
||||||
private Pane getInputsLabels(Map<BlockTransactionHashIndex, WalletNode> displayedUtxos) {
|
private Pane getInputsLabels(Map<BlockTransactionHashIndex, WalletNode> displayedUtxos) {
|
||||||
VBox inputsBox = new VBox();
|
VBox inputsBox = new VBox();
|
||||||
inputsBox.setMaxWidth(150);
|
inputsBox.setMaxWidth(150);
|
||||||
|
inputsBox.setPrefWidth(150);
|
||||||
inputsBox.setPadding(new Insets(0, 10, 0, 10));
|
inputsBox.setPadding(new Insets(0, 10, 0, 10));
|
||||||
inputsBox.minHeightProperty().bind(minHeightProperty());
|
inputsBox.minHeightProperty().bind(minHeightProperty());
|
||||||
inputsBox.setAlignment(Pos.CENTER_RIGHT);
|
inputsBox.setAlignment(Pos.CENTER_RIGHT);
|
||||||
|
@ -388,14 +391,33 @@ public class TransactionDiagram extends GridPane {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(walletTx.getChangeNode() != null) {
|
if(walletTx.getChangeNode() != null) {
|
||||||
|
WalletNode defaultChangeNode = walletTx.getWallet().getFreshNode(KeyPurpose.CHANGE);
|
||||||
|
boolean overGapLimit = (walletTx.getChangeNode().getIndex() - defaultChangeNode.getIndex()) > walletTx.getWallet().getGapLimit();
|
||||||
|
|
||||||
|
HBox actionBox = new HBox();
|
||||||
String changeDesc = walletTx.getChangeAddress().toString().substring(0, 8) + "...";
|
String changeDesc = walletTx.getChangeAddress().toString().substring(0, 8) + "...";
|
||||||
Label changeLabel = new Label(changeDesc, getChangeGlyph());
|
Label changeLabel = new Label(changeDesc, overGapLimit ? getChangeWarningGlyph() : getChangeGlyph());
|
||||||
changeLabel.getStyleClass().addAll("output-label", "change-label");
|
changeLabel.getStyleClass().addAll("output-label", "change-label");
|
||||||
Tooltip changeTooltip = new Tooltip("Change of " + getSatsValue(walletTx.getChangeAmount()) + " sats to " + walletTx.getChangeNode().getDerivationPath().replace("m", "..") + "\n" + walletTx.getChangeAddress().toString());
|
Tooltip changeTooltip = new Tooltip("Change of " + getSatsValue(walletTx.getChangeAmount()) + " sats to " + walletTx.getChangeNode().getDerivationPath().replace("m", "..") + "\n" + walletTx.getChangeAddress().toString() + (overGapLimit ? "\nAddress is beyond the gap limit!" : ""));
|
||||||
changeTooltip.getStyleClass().add("change-label");
|
changeTooltip.getStyleClass().add("change-label");
|
||||||
changeTooltip.setShowDelay(new Duration(TOOLTIP_SHOW_DELAY));
|
changeTooltip.setShowDelay(new Duration(TOOLTIP_SHOW_DELAY));
|
||||||
changeLabel.setTooltip(changeTooltip);
|
changeLabel.setTooltip(changeTooltip);
|
||||||
outputsBox.getChildren().add(changeLabel);
|
|
||||||
|
Button nextChangeAddressButton = new Button("");
|
||||||
|
nextChangeAddressButton.setGraphic(getChangeReplaceGlyph());
|
||||||
|
nextChangeAddressButton.setOnAction(event -> {
|
||||||
|
EventManager.get().post(new ReplaceChangeAddressEvent(walletTx));
|
||||||
|
});
|
||||||
|
Tooltip replaceChangeTooltip = new Tooltip("Use next change address");
|
||||||
|
nextChangeAddressButton.setTooltip(replaceChangeTooltip);
|
||||||
|
Label replaceChangeLabel = new Label("", nextChangeAddressButton);
|
||||||
|
replaceChangeLabel.getStyleClass().add("replace-change-label");
|
||||||
|
replaceChangeLabel.setVisible(false);
|
||||||
|
actionBox.setOnMouseEntered(event -> replaceChangeLabel.setVisible(true));
|
||||||
|
actionBox.setOnMouseExited(event -> replaceChangeLabel.setVisible(false));
|
||||||
|
|
||||||
|
actionBox.getChildren().addAll(changeLabel, replaceChangeLabel);
|
||||||
|
outputsBox.getChildren().add(actionBox);
|
||||||
outputsBox.getChildren().add(createSpacer());
|
outputsBox.getChildren().add(createSpacer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -484,6 +506,20 @@ public class TransactionDiagram extends GridPane {
|
||||||
return changeGlyph;
|
return changeGlyph;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Glyph getChangeWarningGlyph() {
|
||||||
|
Glyph changeWarningGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.EXCLAMATION_TRIANGLE);
|
||||||
|
changeWarningGlyph.getStyleClass().add("change-warning-icon");
|
||||||
|
changeWarningGlyph.setFontSize(12);
|
||||||
|
return changeWarningGlyph;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Glyph getChangeReplaceGlyph() {
|
||||||
|
Glyph changeReplaceGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.ARROW_DOWN);
|
||||||
|
changeReplaceGlyph.getStyleClass().add("change-replace-icon");
|
||||||
|
changeReplaceGlyph.setFontSize(12);
|
||||||
|
return changeReplaceGlyph;
|
||||||
|
}
|
||||||
|
|
||||||
private Glyph getFeeGlyph() {
|
private Glyph getFeeGlyph() {
|
||||||
Glyph feeGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.HAND_HOLDING);
|
Glyph feeGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.HAND_HOLDING);
|
||||||
feeGlyph.getStyleClass().add("fee-icon");
|
feeGlyph.getStyleClass().add("fee-icon");
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.sparrowwallet.sparrow.event;
|
||||||
|
|
||||||
|
import com.sparrowwallet.drongo.wallet.WalletTransaction;
|
||||||
|
|
||||||
|
public class ReplaceChangeAddressEvent {
|
||||||
|
private final WalletTransaction walletTransaction;
|
||||||
|
|
||||||
|
public ReplaceChangeAddressEvent(WalletTransaction walletTx) {
|
||||||
|
this.walletTransaction = walletTx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WalletTransaction getWalletTransaction() {
|
||||||
|
return walletTransaction;
|
||||||
|
}
|
||||||
|
}
|
|
@ -134,6 +134,8 @@ public class SendController extends WalletFormController implements Initializabl
|
||||||
|
|
||||||
private final BooleanProperty includeSpentMempoolOutputsProperty = new SimpleBooleanProperty(false);
|
private final BooleanProperty includeSpentMempoolOutputsProperty = new SimpleBooleanProperty(false);
|
||||||
|
|
||||||
|
private final List<WalletNode> excludedChangeNodes = new ArrayList<>();
|
||||||
|
|
||||||
private final ChangeListener<String> feeListener = new ChangeListener<>() {
|
private final ChangeListener<String> feeListener = new ChangeListener<>() {
|
||||||
@Override
|
@Override
|
||||||
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
|
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
|
||||||
|
@ -494,7 +496,7 @@ public class SendController extends WalletFormController implements Initializabl
|
||||||
boolean includeMempoolOutputs = Config.get().isIncludeMempoolOutputs();
|
boolean includeMempoolOutputs = Config.get().isIncludeMempoolOutputs();
|
||||||
boolean includeSpentMempoolOutputs = includeSpentMempoolOutputsProperty.get();
|
boolean includeSpentMempoolOutputs = includeSpentMempoolOutputsProperty.get();
|
||||||
|
|
||||||
walletTransactionService = new WalletTransactionService(wallet, getUtxoSelectors(), getUtxoFilters(), payments, feeRate, getMinimumFeeRate(), userFee, currentBlockHeight, groupByAddress, includeMempoolOutputs, includeSpentMempoolOutputs);
|
walletTransactionService = new WalletTransactionService(wallet, getUtxoSelectors(), getUtxoFilters(), payments, excludedChangeNodes, feeRate, getMinimumFeeRate(), userFee, currentBlockHeight, groupByAddress, includeMempoolOutputs, includeSpentMempoolOutputs);
|
||||||
walletTransactionService.setOnSucceeded(event -> {
|
walletTransactionService.setOnSucceeded(event -> {
|
||||||
if(!walletTransactionService.isIgnoreResult()) {
|
if(!walletTransactionService.isIgnoreResult()) {
|
||||||
walletTransactionProperty.setValue(walletTransactionService.getValue());
|
walletTransactionProperty.setValue(walletTransactionService.getValue());
|
||||||
|
@ -545,6 +547,7 @@ public class SendController extends WalletFormController implements Initializabl
|
||||||
private final List<UtxoSelector> utxoSelectors;
|
private final List<UtxoSelector> utxoSelectors;
|
||||||
private final List<UtxoFilter> utxoFilters;
|
private final List<UtxoFilter> utxoFilters;
|
||||||
private final List<Payment> payments;
|
private final List<Payment> payments;
|
||||||
|
private final List<WalletNode> excludedChangeNodes;
|
||||||
private final double feeRate;
|
private final double feeRate;
|
||||||
private final double longTermFeeRate;
|
private final double longTermFeeRate;
|
||||||
private final Long fee;
|
private final Long fee;
|
||||||
|
@ -554,11 +557,12 @@ public class SendController extends WalletFormController implements Initializabl
|
||||||
private final boolean includeSpentMempoolOutputs;
|
private final boolean includeSpentMempoolOutputs;
|
||||||
private boolean ignoreResult;
|
private boolean ignoreResult;
|
||||||
|
|
||||||
public WalletTransactionService(Wallet wallet, List<UtxoSelector> utxoSelectors, List<UtxoFilter> utxoFilters, List<Payment> payments, double feeRate, double longTermFeeRate, Long fee, Integer currentBlockHeight, boolean groupByAddress, boolean includeMempoolOutputs, boolean includeSpentMempoolOutputs) {
|
public WalletTransactionService(Wallet wallet, List<UtxoSelector> utxoSelectors, List<UtxoFilter> utxoFilters, List<Payment> payments, List<WalletNode> excludedChangeNodes, double feeRate, double longTermFeeRate, Long fee, Integer currentBlockHeight, boolean groupByAddress, boolean includeMempoolOutputs, boolean includeSpentMempoolOutputs) {
|
||||||
this.wallet = wallet;
|
this.wallet = wallet;
|
||||||
this.utxoSelectors = utxoSelectors;
|
this.utxoSelectors = utxoSelectors;
|
||||||
this.utxoFilters = utxoFilters;
|
this.utxoFilters = utxoFilters;
|
||||||
this.payments = payments;
|
this.payments = payments;
|
||||||
|
this.excludedChangeNodes = excludedChangeNodes;
|
||||||
this.feeRate = feeRate;
|
this.feeRate = feeRate;
|
||||||
this.longTermFeeRate = longTermFeeRate;
|
this.longTermFeeRate = longTermFeeRate;
|
||||||
this.fee = fee;
|
this.fee = fee;
|
||||||
|
@ -572,7 +576,7 @@ public class SendController extends WalletFormController implements Initializabl
|
||||||
protected Task<WalletTransaction> createTask() {
|
protected Task<WalletTransaction> createTask() {
|
||||||
return new Task<>() {
|
return new Task<>() {
|
||||||
protected WalletTransaction call() throws InsufficientFundsException {
|
protected WalletTransaction call() throws InsufficientFundsException {
|
||||||
return wallet.createWalletTransaction(utxoSelectors, utxoFilters, payments, feeRate, longTermFeeRate, fee, currentBlockHeight, groupByAddress, includeMempoolOutputs, includeSpentMempoolOutputs);
|
return wallet.createWalletTransaction(utxoSelectors, utxoFilters, payments, excludedChangeNodes, feeRate, longTermFeeRate, fee, currentBlockHeight, groupByAddress, includeMempoolOutputs, includeSpentMempoolOutputs);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -898,6 +902,7 @@ public class SendController extends WalletFormController implements Initializabl
|
||||||
utxoSelectorProperty.setValue(null);
|
utxoSelectorProperty.setValue(null);
|
||||||
utxoFilterProperty.setValue(null);
|
utxoFilterProperty.setValue(null);
|
||||||
includeSpentMempoolOutputsProperty.set(false);
|
includeSpentMempoolOutputsProperty.set(false);
|
||||||
|
excludedChangeNodes.clear();
|
||||||
walletTransactionProperty.setValue(null);
|
walletTransactionProperty.setValue(null);
|
||||||
createdWalletTransactionProperty.set(null);
|
createdWalletTransactionProperty.set(null);
|
||||||
|
|
||||||
|
@ -1137,6 +1142,14 @@ public class SendController extends WalletFormController implements Initializabl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void replaceChangeAddress(ReplaceChangeAddressEvent event) {
|
||||||
|
if(event.getWalletTransaction() == walletTransactionProperty.get()) {
|
||||||
|
excludedChangeNodes.add(event.getWalletTransaction().getChangeNode());
|
||||||
|
updateTransaction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void walletUtxoStatusChanged(WalletUtxoStatusChangedEvent event) {
|
public void walletUtxoStatusChanged(WalletUtxoStatusChangedEvent event) {
|
||||||
if(event.getWallet().equals(getWalletForm().getWallet())) {
|
if(event.getWallet().equals(getWalletForm().getWallet())) {
|
||||||
|
|
|
@ -157,7 +157,7 @@ public class TransactionsController extends WalletFormController implements Init
|
||||||
|
|
||||||
private void logMessage(String logMessage) {
|
private void logMessage(String logMessage) {
|
||||||
if(logMessage != null) {
|
if(logMessage != null) {
|
||||||
logMessage = logMessage.replace("m/", "/");
|
logMessage = logMessage.replace("m/", "../");
|
||||||
String date = LOG_DATE_FORMAT.format(new Date());
|
String date = LOG_DATE_FORMAT.format(new Date());
|
||||||
String logLine = "\n" + date + " " + logMessage;
|
String logLine = "\n" + date + " " + logMessage;
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
|
|
|
@ -89,7 +89,7 @@
|
||||||
-fx-stroke-dash-array: 5px 5px;
|
-fx-stroke-dash-array: 5px 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#transactionDiagram .utxo-label .button {
|
#transactionDiagram .utxo-label .button, #transactionDiagram .replace-change-label .button {
|
||||||
-fx-padding: 0;
|
-fx-padding: 0;
|
||||||
-fx-pref-height: 18;
|
-fx-pref-height: 18;
|
||||||
-fx-pref-width: 18;
|
-fx-pref-width: 18;
|
||||||
|
@ -105,6 +105,10 @@
|
||||||
-fx-fill: -fx-text-base-color;
|
-fx-fill: -fx-text-base-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#transactionDiagram .change-warning-icon {
|
||||||
|
-fx-text-fill: rgb(238, 210, 2);
|
||||||
|
}
|
||||||
|
|
||||||
#targetBlocks .track {
|
#targetBlocks .track {
|
||||||
-fx-background-color: -fx-shadow-highlight-color,
|
-fx-background-color: -fx-shadow-highlight-color,
|
||||||
linear-gradient(to bottom, derive(-fx-text-box-border, -10%), -fx-text-box-border),
|
linear-gradient(to bottom, derive(-fx-text-box-border, -10%), -fx-text-box-border),
|
||||||
|
|
Loading…
Reference in a new issue