request new change address in the transaction diagram

This commit is contained in:
Craig Raw 2021-05-17 13:21:56 +02:00
parent c9cdf6e77d
commit b17c15f702
6 changed files with 77 additions and 9 deletions

2
drongo

@ -1 +1 @@
Subproject commit 7dca0d0c39404bd89a5a4589a79ffe0f688e8181
Subproject commit 567294a4b055cc062650de45fccbbc89db714f39

View file

@ -1,5 +1,6 @@
package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.drongo.KeyPurpose;
import com.sparrowwallet.drongo.address.Address;
import com.sparrowwallet.drongo.protocol.Sha256Hash;
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.EventManager;
import com.sparrowwallet.sparrow.event.ExcludeUtxoEvent;
import com.sparrowwallet.sparrow.event.ReplaceChangeAddressEvent;
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
@ -200,6 +202,7 @@ public class TransactionDiagram extends GridPane {
private Pane getInputsLabels(Map<BlockTransactionHashIndex, WalletNode> displayedUtxos) {
VBox inputsBox = new VBox();
inputsBox.setMaxWidth(150);
inputsBox.setPrefWidth(150);
inputsBox.setPadding(new Insets(0, 10, 0, 10));
inputsBox.minHeightProperty().bind(minHeightProperty());
inputsBox.setAlignment(Pos.CENTER_RIGHT);
@ -388,14 +391,33 @@ public class TransactionDiagram extends GridPane {
}
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) + "...";
Label changeLabel = new Label(changeDesc, getChangeGlyph());
Label changeLabel = new Label(changeDesc, overGapLimit ? getChangeWarningGlyph() : getChangeGlyph());
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.setShowDelay(new Duration(TOOLTIP_SHOW_DELAY));
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());
}
@ -484,6 +506,20 @@ public class TransactionDiagram extends GridPane {
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() {
Glyph feeGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.HAND_HOLDING);
feeGlyph.getStyleClass().add("fee-icon");

View file

@ -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;
}
}

View file

@ -134,6 +134,8 @@ public class SendController extends WalletFormController implements Initializabl
private final BooleanProperty includeSpentMempoolOutputsProperty = new SimpleBooleanProperty(false);
private final List<WalletNode> excludedChangeNodes = new ArrayList<>();
private final ChangeListener<String> feeListener = new ChangeListener<>() {
@Override
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 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 -> {
if(!walletTransactionService.isIgnoreResult()) {
walletTransactionProperty.setValue(walletTransactionService.getValue());
@ -545,6 +547,7 @@ public class SendController extends WalletFormController implements Initializabl
private final List<UtxoSelector> utxoSelectors;
private final List<UtxoFilter> utxoFilters;
private final List<Payment> payments;
private final List<WalletNode> excludedChangeNodes;
private final double feeRate;
private final double longTermFeeRate;
private final Long fee;
@ -554,11 +557,12 @@ public class SendController extends WalletFormController implements Initializabl
private final boolean includeSpentMempoolOutputs;
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.utxoSelectors = utxoSelectors;
this.utxoFilters = utxoFilters;
this.payments = payments;
this.excludedChangeNodes = excludedChangeNodes;
this.feeRate = feeRate;
this.longTermFeeRate = longTermFeeRate;
this.fee = fee;
@ -572,7 +576,7 @@ public class SendController extends WalletFormController implements Initializabl
protected Task<WalletTransaction> createTask() {
return new Task<>() {
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);
utxoFilterProperty.setValue(null);
includeSpentMempoolOutputsProperty.set(false);
excludedChangeNodes.clear();
walletTransactionProperty.setValue(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
public void walletUtxoStatusChanged(WalletUtxoStatusChangedEvent event) {
if(event.getWallet().equals(getWalletForm().getWallet())) {

View file

@ -157,7 +157,7 @@ public class TransactionsController extends WalletFormController implements Init
private void logMessage(String logMessage) {
if(logMessage != null) {
logMessage = logMessage.replace("m/", "/");
logMessage = logMessage.replace("m/", "../");
String date = LOG_DATE_FORMAT.format(new Date());
String logLine = "\n" + date + " " + logMessage;
Platform.runLater(() -> {

View file

@ -89,7 +89,7 @@
-fx-stroke-dash-array: 5px 5px;
}
#transactionDiagram .utxo-label .button {
#transactionDiagram .utxo-label .button, #transactionDiagram .replace-change-label .button {
-fx-padding: 0;
-fx-pref-height: 18;
-fx-pref-width: 18;
@ -105,6 +105,10 @@
-fx-fill: -fx-text-base-color;
}
#transactionDiagram .change-warning-icon {
-fx-text-fill: rgb(238, 210, 2);
}
#targetBlocks .track {
-fx-background-color: -fx-shadow-highlight-color,
linear-gradient(to bottom, derive(-fx-text-box-border, -10%), -fx-text-box-border),