mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-11-02 20:36:44 +00:00
improve input and output labels on transaction tree and detail panels
This commit is contained in:
parent
540424a2e3
commit
57dba5d6ae
14 changed files with 367 additions and 266 deletions
2
drongo
2
drongo
|
@ -1 +1 @@
|
|||
Subproject commit 78944a7114f5e22d0622dd07ca426e04acdce5b7
|
||||
Subproject commit 42f279e5e7cfdcf0de80f60f65857d26db8580ad
|
|
@ -14,6 +14,7 @@ import com.sparrowwallet.sparrow.event.ExcludeUtxoEvent;
|
|||
import com.sparrowwallet.sparrow.event.ReplaceChangeAddressEvent;
|
||||
import com.sparrowwallet.sparrow.event.SorobanInitiatedEvent;
|
||||
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
||||
import com.sparrowwallet.sparrow.glyphfont.GlyphUtils;
|
||||
import com.sparrowwallet.sparrow.io.Config;
|
||||
import com.sparrowwallet.sparrow.soroban.SorobanServices;
|
||||
import com.sparrowwallet.sparrow.wallet.OptimizationStrategy;
|
||||
|
@ -44,7 +45,6 @@ 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;
|
||||
import org.controlsfx.tools.Platform;
|
||||
|
||||
|
@ -56,6 +56,8 @@ import java.util.*;
|
|||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.sparrowwallet.sparrow.glyphfont.GlyphUtils.*;
|
||||
|
||||
public class TransactionDiagram extends GridPane {
|
||||
private static final int MAX_UTXOS = 8;
|
||||
private static final int REDUCED_MAX_UTXOS = MAX_UTXOS - 2;
|
||||
|
@ -686,19 +688,18 @@ public class TransactionDiagram extends GridPane {
|
|||
|
||||
List<OutputNode> outputNodes = new ArrayList<>();
|
||||
for(Payment payment : displayedPayments) {
|
||||
Glyph outputGlyph = getOutputGlyph(payment);
|
||||
Glyph outputGlyph = GlyphUtils.getOutputGlyph(walletTx, payment);
|
||||
boolean labelledPayment = outputGlyph.getStyleClass().stream().anyMatch(style -> List.of("premix-icon", "badbank-icon", "whirlpoolfee-icon").contains(style)) || payment instanceof AdditionalPayment;
|
||||
payment.setLabel(getOutputLabel(payment));
|
||||
Label recipientLabel = new Label(payment.getLabel() == null || payment.getType() == Payment.Type.FAKE_MIX || payment.getType() == Payment.Type.MIX ? payment.getAddress().toString().substring(0, 8) + "..." : payment.getLabel(), outputGlyph);
|
||||
recipientLabel.getStyleClass().add("output-label");
|
||||
recipientLabel.getStyleClass().add(labelledPayment ? "payment-label" : "recipient-label");
|
||||
Wallet toWallet = getToWallet(payment);
|
||||
Wallet toWallet = walletTx.getToWallet(AppServices.get().getOpenWallets().keySet(), payment);
|
||||
WalletNode toNode = walletTx.getWallet() != null && !walletTx.getWallet().isBip47() ? walletTx.getAddressNodeMap().get(payment.getAddress()) : null;
|
||||
Wallet toBip47Wallet = getBip47SendWallet(payment);
|
||||
Tooltip recipientTooltip = new Tooltip((toWallet == null ? (toNode != null ? "Consolidate " : "Pay ") : "Receive ")
|
||||
+ getSatsValue(payment.getAmount()) + " sats to "
|
||||
+ (payment instanceof AdditionalPayment ? (isExpanded() ? "\n" : "(click to expand)\n") + payment : (toWallet == null ? (payment.getLabel() == null ? (toNode != null ? toNode : (toBip47Wallet == null ? "external address" : toBip47Wallet.getDisplayName())) : payment.getLabel()) : toWallet.getFullDisplayName()) + "\n" + payment.getAddress().toString())
|
||||
+ (isDuplicateAddress(payment) ? " (Duplicate)" : ""));
|
||||
+ (walletTx.isDuplicateAddress(payment) ? " (Duplicate)" : ""));
|
||||
recipientTooltip.getStyleClass().add("recipient-label");
|
||||
recipientTooltip.setShowDelay(new Duration(TOOLTIP_SHOW_DELAY));
|
||||
recipientTooltip.setShowDuration(Duration.INDEFINITE);
|
||||
|
@ -928,42 +929,12 @@ public class TransactionDiagram extends GridPane {
|
|||
return spacer;
|
||||
}
|
||||
|
||||
private String getOutputLabel(Payment payment) {
|
||||
if(payment.getLabel() != null) {
|
||||
return payment.getLabel();
|
||||
}
|
||||
|
||||
if(payment.getType() == Payment.Type.WHIRLPOOL_FEE) {
|
||||
return "Whirlpool fee";
|
||||
} else if(walletTx.isPremixSend(payment)) {
|
||||
int premixIndex = getOutputIndex(payment.getAddress(), payment.getAmount(), Collections.emptySet()) - 1;
|
||||
return "Premix #" + premixIndex;
|
||||
} else if(walletTx.isBadbankSend(payment)) {
|
||||
return "Badbank change";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private int getOutputIndex(Address address, long amount, Collection<Integer> seenIndexes) {
|
||||
List<TransactionOutput> addressOutputs = walletTx.getTransaction().getOutputs().stream().filter(txOutput -> txOutput.getScript().getToAddress() != null).collect(Collectors.toList());
|
||||
TransactionOutput output = addressOutputs.stream().filter(txOutput -> address.equals(txOutput.getScript().getToAddress()) && txOutput.getValue() == amount && !seenIndexes.contains(txOutput.getIndex())).findFirst().orElseThrow();
|
||||
return addressOutputs.indexOf(output);
|
||||
}
|
||||
|
||||
Wallet getToWallet(Payment payment) {
|
||||
for(Wallet openWallet : AppServices.get().getOpenWallets().keySet()) {
|
||||
if(openWallet != walletTx.getWallet() && openWallet.isValid()) {
|
||||
WalletNode addressNode = openWallet.getWalletAddresses().get(payment.getAddress());
|
||||
if(addressNode != null) {
|
||||
return addressNode.getWallet();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Wallet getBip47SendWallet(Payment payment) {
|
||||
if(walletTx.getWallet() != null) {
|
||||
for(Wallet childWallet : walletTx.getWallet().getChildWallets()) {
|
||||
|
@ -981,164 +952,6 @@ public class TransactionDiagram extends GridPane {
|
|||
return null;
|
||||
}
|
||||
|
||||
public Glyph getOutputGlyph(Payment payment) {
|
||||
if(payment.getType().equals(Payment.Type.MIX)) {
|
||||
return getMixGlyph();
|
||||
} else if(payment.getType().equals(Payment.Type.FAKE_MIX)) {
|
||||
return getFakeMixGlyph();
|
||||
} else if(walletTx.isConsolidationSend(payment)) {
|
||||
return getConsolidationGlyph();
|
||||
} else if(walletTx.isPremixSend(payment)) {
|
||||
return getPremixGlyph();
|
||||
} else if(walletTx.isBadbankSend(payment)) {
|
||||
return getBadbankGlyph();
|
||||
} else if(payment.getType().equals(Payment.Type.WHIRLPOOL_FEE)) {
|
||||
return getWhirlpoolFeeGlyph();
|
||||
} else if(payment instanceof AdditionalPayment) {
|
||||
return ((AdditionalPayment)payment).getOutputGlyph(this);
|
||||
} else if(getToWallet(payment) != null) {
|
||||
return getDepositGlyph();
|
||||
} else if(isDuplicateAddress(payment)) {
|
||||
return getPaymentWarningGlyph();
|
||||
}
|
||||
|
||||
return getPaymentGlyph();
|
||||
}
|
||||
|
||||
private boolean isDuplicateAddress(Payment payment) {
|
||||
return walletTx.getPayments().stream().filter(p -> payment != p).anyMatch(p -> payment.getAddress() != null && payment.getAddress().equals(p.getAddress()));
|
||||
}
|
||||
|
||||
public static Glyph getExcludeGlyph() {
|
||||
Glyph excludeGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.TIMES_CIRCLE);
|
||||
excludeGlyph.getStyleClass().add("exclude-utxo");
|
||||
excludeGlyph.setFontSize(12);
|
||||
return excludeGlyph;
|
||||
}
|
||||
|
||||
public static Glyph getPaymentGlyph() {
|
||||
Glyph paymentGlyph = new Glyph("FontAwesome", FontAwesome.Glyph.SEND);
|
||||
paymentGlyph.getStyleClass().add("payment-icon");
|
||||
paymentGlyph.setFontSize(12);
|
||||
return paymentGlyph;
|
||||
}
|
||||
|
||||
public static Glyph getPaymentWarningGlyph() {
|
||||
Glyph paymentWarningGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.EXCLAMATION_TRIANGLE);
|
||||
paymentWarningGlyph.getStyleClass().add("payment-warning-icon");
|
||||
paymentWarningGlyph.setFontSize(12);
|
||||
return paymentWarningGlyph;
|
||||
}
|
||||
|
||||
public static Glyph getConsolidationGlyph() {
|
||||
Glyph consolidationGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.REPLY_ALL);
|
||||
consolidationGlyph.getStyleClass().add("consolidation-icon");
|
||||
consolidationGlyph.setFontSize(12);
|
||||
return consolidationGlyph;
|
||||
}
|
||||
|
||||
public static Glyph getDepositGlyph() {
|
||||
Glyph depositGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.ARROW_DOWN);
|
||||
depositGlyph.getStyleClass().add("deposit-icon");
|
||||
depositGlyph.setFontSize(12);
|
||||
return depositGlyph;
|
||||
}
|
||||
|
||||
public static Glyph getPremixGlyph() {
|
||||
Glyph premixGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.RANDOM);
|
||||
premixGlyph.getStyleClass().add("premix-icon");
|
||||
premixGlyph.setFontSize(12);
|
||||
return premixGlyph;
|
||||
}
|
||||
|
||||
public static Glyph getBadbankGlyph() {
|
||||
Glyph badbankGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.BIOHAZARD);
|
||||
badbankGlyph.getStyleClass().add("badbank-icon");
|
||||
badbankGlyph.setFontSize(12);
|
||||
return badbankGlyph;
|
||||
}
|
||||
|
||||
public static Glyph getWhirlpoolFeeGlyph() {
|
||||
Glyph whirlpoolFeeGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.HAND_HOLDING_WATER);
|
||||
whirlpoolFeeGlyph.getStyleClass().add("whirlpoolfee-icon");
|
||||
whirlpoolFeeGlyph.setFontSize(12);
|
||||
return whirlpoolFeeGlyph;
|
||||
}
|
||||
|
||||
public static Glyph getFakeMixGlyph() {
|
||||
Glyph fakeMixGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.THEATER_MASKS);
|
||||
fakeMixGlyph.getStyleClass().add("fakemix-icon");
|
||||
fakeMixGlyph.setFontSize(12);
|
||||
return fakeMixGlyph;
|
||||
}
|
||||
|
||||
public static Glyph getTxoGlyph() {
|
||||
return getChangeGlyph();
|
||||
}
|
||||
|
||||
public static Glyph getMixGlyph() {
|
||||
Glyph payjoinGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.RANDOM);
|
||||
payjoinGlyph.getStyleClass().add("mix-icon");
|
||||
payjoinGlyph.setFontSize(12);
|
||||
return payjoinGlyph;
|
||||
}
|
||||
|
||||
public static Glyph getChangeGlyph() {
|
||||
Glyph changeGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.COINS);
|
||||
changeGlyph.getStyleClass().add("change-icon");
|
||||
changeGlyph.setFontSize(12);
|
||||
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;
|
||||
}
|
||||
|
||||
public Glyph getFeeGlyph() {
|
||||
Glyph feeGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.HAND_HOLDING);
|
||||
feeGlyph.getStyleClass().add("fee-icon");
|
||||
feeGlyph.setFontSize(12);
|
||||
return feeGlyph;
|
||||
}
|
||||
|
||||
private Glyph getWarningGlyph() {
|
||||
Glyph feeWarningGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.EXCLAMATION_CIRCLE);
|
||||
feeWarningGlyph.getStyleClass().add("fee-warning-icon");
|
||||
feeWarningGlyph.setFontSize(12);
|
||||
return feeWarningGlyph;
|
||||
}
|
||||
|
||||
private Glyph getQuestionGlyph() {
|
||||
Glyph feeWarningGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.QUESTION_CIRCLE);
|
||||
feeWarningGlyph.getStyleClass().add("question-icon");
|
||||
feeWarningGlyph.setFontSize(12);
|
||||
return feeWarningGlyph;
|
||||
}
|
||||
|
||||
private Glyph getLockGlyph() {
|
||||
Glyph lockGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.LOCK);
|
||||
lockGlyph.getStyleClass().add("lock-icon");
|
||||
lockGlyph.setFontSize(12);
|
||||
return lockGlyph;
|
||||
}
|
||||
|
||||
private Glyph getUserGlyph() {
|
||||
Glyph userGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.USER);
|
||||
userGlyph.getStyleClass().add("user-icon");
|
||||
userGlyph.setFontSize(12);
|
||||
return userGlyph;
|
||||
}
|
||||
|
||||
private Glyph getUserAddGlyph() {
|
||||
Glyph userAddGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.USER_PLUS);
|
||||
userAddGlyph.getStyleClass().add("useradd-icon");
|
||||
|
@ -1295,7 +1108,7 @@ public class TransactionDiagram extends GridPane {
|
|||
}
|
||||
}
|
||||
|
||||
private static class AdditionalPayment extends Payment {
|
||||
public static class AdditionalPayment extends Payment {
|
||||
private final List<Payment> additionalPayments;
|
||||
|
||||
public AdditionalPayment(List<Payment> additionalPayments) {
|
||||
|
@ -1303,10 +1116,10 @@ public class TransactionDiagram extends GridPane {
|
|||
this.additionalPayments = additionalPayments;
|
||||
}
|
||||
|
||||
public Glyph getOutputGlyph(TransactionDiagram transactionDiagram) {
|
||||
public Glyph getOutputGlyph(WalletTransaction walletTx) {
|
||||
Glyph glyph = null;
|
||||
for(Payment payment : additionalPayments) {
|
||||
Glyph paymentGlyph = transactionDiagram.getOutputGlyph(payment);
|
||||
Glyph paymentGlyph = GlyphUtils.getOutputGlyph(walletTx, payment);
|
||||
if(glyph != null && !paymentGlyph.getStyleClass().equals(glyph.getStyleClass())) {
|
||||
return getPaymentGlyph();
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package com.sparrowwallet.sparrow.control;
|
||||
|
||||
import com.sparrowwallet.drongo.wallet.*;
|
||||
import com.sparrowwallet.sparrow.AppServices;
|
||||
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
||||
import com.sparrowwallet.sparrow.glyphfont.GlyphUtils;
|
||||
import javafx.beans.property.IntegerProperty;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.geometry.Pos;
|
||||
|
@ -81,13 +83,13 @@ public class TransactionDiagramLabel extends HBox {
|
|||
List<Payment> badbankOutputs = walletTx.getPayments().stream().filter(walletTx::isBadbankSend).collect(Collectors.toList());
|
||||
List<OutputLabel> badbankOutputLabels = badbankOutputs.stream().map(payment -> getBadbankOutputLabel(transactionDiagram, payment)).collect(Collectors.toList());
|
||||
outputLabels.addAll(badbankOutputLabels);
|
||||
} else if(walletTx.getPayments().size() >= 5 && walletTx.getPayments().stream().mapToLong(Payment::getAmount).distinct().count() <= 1
|
||||
} else if(walletTx.getPayments().size() >= 5 && walletTx.getPayments().stream().mapToLong(Payment::getAmount).distinct().count() <= 1 && walletTx.getWallet() != null
|
||||
&& walletTx.getWallet().getStandardAccountType() == StandardAccount.WHIRLPOOL_PREMIX && walletTx.getPayments().stream().anyMatch(walletTx::isPostmixSend)) {
|
||||
OutputLabel mixOutputLabel = getMixOutputLabel(transactionDiagram, walletTx.getPayments());
|
||||
if(mixOutputLabel != null) {
|
||||
outputLabels.add(mixOutputLabel);
|
||||
}
|
||||
} else if(walletTx.getPayments().size() >= 5 && walletTx.getPayments().stream().mapToLong(Payment::getAmount).distinct().count() <= 1
|
||||
} else if(walletTx.getPayments().size() >= 5 && walletTx.getPayments().stream().mapToLong(Payment::getAmount).distinct().count() <= 1 && walletTx.getWallet() != null
|
||||
&& walletTx.getWallet().getStandardAccountType() == StandardAccount.WHIRLPOOL_POSTMIX && walletTx.getPayments().stream().anyMatch(walletTx::isConsolidationSend)) {
|
||||
OutputLabel remixOutputLabel = getRemixOutputLabel(transactionDiagram, walletTx.getPayments());
|
||||
if(remixOutputLabel != null) {
|
||||
|
@ -142,7 +144,7 @@ public class TransactionDiagramLabel extends HBox {
|
|||
|
||||
Payment premixOutput = premixOutputs.get(0);
|
||||
long total = premixOutputs.stream().mapToLong(Payment::getAmount).sum();
|
||||
Glyph glyph = transactionDiagram.getOutputGlyph(premixOutput);
|
||||
Glyph glyph = GlyphUtils.getOutputGlyph(transactionDiagram.getWalletTransaction(), premixOutput);
|
||||
String text;
|
||||
if(premixOutputs.size() == 1) {
|
||||
text = "Premix transaction with 1 output of " + transactionDiagram.getSatsValue(premixOutput.getAmount()) + " sats";
|
||||
|
@ -155,7 +157,7 @@ public class TransactionDiagramLabel extends HBox {
|
|||
}
|
||||
|
||||
private OutputLabel getBadbankOutputLabel(TransactionDiagram transactionDiagram, Payment payment) {
|
||||
Glyph glyph = transactionDiagram.getOutputGlyph(payment);
|
||||
Glyph glyph = GlyphUtils.getOutputGlyph(transactionDiagram.getWalletTransaction(), payment);
|
||||
String text = "Badbank change of " + transactionDiagram.getSatsValue(payment.getAmount()) + " sats to " + payment.getAddress().toString();
|
||||
|
||||
return getOutputLabel(glyph, text);
|
||||
|
@ -164,7 +166,7 @@ public class TransactionDiagramLabel extends HBox {
|
|||
private OutputLabel getWhirlpoolFeeOutputLabel(TransactionDiagram transactionDiagram, Payment whirlpoolFee, List<Payment> premixOutputs) {
|
||||
long total = premixOutputs.stream().mapToLong(Payment::getAmount).sum();
|
||||
double feePercentage = (double)whirlpoolFee.getAmount() / (total - whirlpoolFee.getAmount());
|
||||
Glyph glyph = transactionDiagram.getOutputGlyph(whirlpoolFee);
|
||||
Glyph glyph = GlyphUtils.getOutputGlyph(transactionDiagram.getWalletTransaction(), whirlpoolFee);
|
||||
String text = "Whirlpool fee of " + transactionDiagram.getSatsValue(whirlpoolFee.getAmount()) + " sats (" + String.format("%.2f", feePercentage * 100.0) + "% of total premix value)";
|
||||
|
||||
return getOutputLabel(glyph, text);
|
||||
|
@ -177,7 +179,7 @@ public class TransactionDiagramLabel extends HBox {
|
|||
|
||||
Payment remixOutput = mixOutputs.get(0);
|
||||
long total = mixOutputs.stream().mapToLong(Payment::getAmount).sum();
|
||||
Glyph glyph = TransactionDiagram.getPremixGlyph();
|
||||
Glyph glyph = GlyphUtils.getPremixGlyph();
|
||||
String text = "Mix transaction with " + mixOutputs.size() + " outputs of " + transactionDiagram.getSatsValue(remixOutput.getAmount()) + " sats each ("
|
||||
+ transactionDiagram.getSatsValue(total) + " sats)";
|
||||
|
||||
|
@ -191,7 +193,7 @@ public class TransactionDiagramLabel extends HBox {
|
|||
|
||||
Payment remixOutput = remixOutputs.get(0);
|
||||
long total = remixOutputs.stream().mapToLong(Payment::getAmount).sum();
|
||||
Glyph glyph = TransactionDiagram.getPremixGlyph();
|
||||
Glyph glyph = GlyphUtils.getPremixGlyph();
|
||||
String text = "Remix transaction with " + remixOutputs.size() + " outputs of " + transactionDiagram.getSatsValue(remixOutput.getAmount()) + " sats each ("
|
||||
+ transactionDiagram.getSatsValue(total) + " sats)";
|
||||
|
||||
|
@ -200,10 +202,10 @@ public class TransactionDiagramLabel extends HBox {
|
|||
|
||||
private OutputLabel getOutputLabel(TransactionDiagram transactionDiagram, Payment payment) {
|
||||
WalletTransaction walletTx = transactionDiagram.getWalletTransaction();
|
||||
Wallet toWallet = transactionDiagram.getToWallet(payment);
|
||||
Wallet toWallet = walletTx.getToWallet(AppServices.get().getOpenWallets().keySet(), payment);
|
||||
WalletNode toNode = walletTx.getWallet() != null && !walletTx.getWallet().isBip47() ? walletTx.getAddressNodeMap().get(payment.getAddress()) : null;
|
||||
|
||||
Glyph glyph = transactionDiagram.getOutputGlyph(payment);
|
||||
Glyph glyph = GlyphUtils.getOutputGlyph(transactionDiagram.getWalletTransaction(), payment);
|
||||
String text = (toWallet == null ? (toNode != null ? "Consolidate " : "Pay ") : "Receive ") + transactionDiagram.getSatsValue(payment.getAmount()) + " sats to " + payment.getAddress().toString();
|
||||
|
||||
return getOutputLabel(glyph, text);
|
||||
|
@ -212,7 +214,7 @@ public class TransactionDiagramLabel extends HBox {
|
|||
private OutputLabel getOutputLabel(TransactionDiagram transactionDiagram, Map.Entry<WalletNode, Long> changeEntry) {
|
||||
WalletTransaction walletTx = transactionDiagram.getWalletTransaction();
|
||||
|
||||
Glyph glyph = TransactionDiagram.getChangeGlyph();
|
||||
Glyph glyph = GlyphUtils.getChangeGlyph();
|
||||
String text = "Change of " + transactionDiagram.getSatsValue(changeEntry.getValue()) + " sats to " + walletTx.getChangeAddress(changeEntry.getKey()).toString();
|
||||
|
||||
return getOutputLabel(glyph, text);
|
||||
|
@ -224,7 +226,7 @@ public class TransactionDiagramLabel extends HBox {
|
|||
return null;
|
||||
}
|
||||
|
||||
Glyph glyph = transactionDiagram.getFeeGlyph();
|
||||
Glyph glyph = GlyphUtils.getFeeGlyph();
|
||||
String text = "Fee of " + transactionDiagram.getSatsValue(walletTx.getFee()) + " sats (" + String.format("%.2f", walletTx.getFeePercentage() * 100.0) + "%)";
|
||||
|
||||
return getOutputLabel(glyph, text);
|
||||
|
|
|
@ -51,8 +51,10 @@ public class FontAwesome5 extends GlyphFont {
|
|||
LINK('\uf0c1'),
|
||||
LOCK('\uf023'),
|
||||
LOCK_OPEN('\uf3c1'),
|
||||
LONG_ARROW_ALT_RIGHT('\uf30b'),
|
||||
MAGNIFYING_GLASS_PLUS('\uf00e'),
|
||||
MAGNIFYING_GLASS_MINUS('\uf010'),
|
||||
MICROCHIP('\uf2db'),
|
||||
MINUS_CIRCLE('\uf056'),
|
||||
PEN_FANCY('\uf5ac'),
|
||||
PLUS('\uf067'),
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
package com.sparrowwallet.sparrow.glyphfont;
|
||||
|
||||
import com.sparrowwallet.drongo.wallet.Payment;
|
||||
import com.sparrowwallet.drongo.wallet.WalletTransaction;
|
||||
import com.sparrowwallet.sparrow.AppServices;
|
||||
import com.sparrowwallet.sparrow.control.TransactionDiagram;
|
||||
import org.controlsfx.glyphfont.FontAwesome;
|
||||
import org.controlsfx.glyphfont.Glyph;
|
||||
|
||||
public class GlyphUtils {
|
||||
public static Glyph getOutputGlyph(WalletTransaction walletTx, Payment payment) {
|
||||
if(payment.getType().equals(Payment.Type.MIX)) {
|
||||
return getMixGlyph();
|
||||
} else if(payment.getType().equals(Payment.Type.FAKE_MIX)) {
|
||||
return getFakeMixGlyph();
|
||||
} else if(walletTx.isConsolidationSend(payment)) {
|
||||
return getConsolidationGlyph();
|
||||
} else if(walletTx.isPremixSend(payment)) {
|
||||
return getPremixGlyph();
|
||||
} else if(walletTx.isBadbankSend(payment)) {
|
||||
return getBadbankGlyph();
|
||||
} else if(payment.getType().equals(Payment.Type.WHIRLPOOL_FEE)) {
|
||||
return getWhirlpoolFeeGlyph();
|
||||
} else if(payment instanceof TransactionDiagram.AdditionalPayment) {
|
||||
return ((TransactionDiagram.AdditionalPayment)payment).getOutputGlyph(walletTx);
|
||||
} else if(walletTx.getToWallet(AppServices.get().getOpenWallets().keySet(), payment) != null) {
|
||||
return getDepositGlyph();
|
||||
} else if(walletTx.isDuplicateAddress(payment)) {
|
||||
return getPaymentWarningGlyph();
|
||||
}
|
||||
|
||||
return getPaymentGlyph();
|
||||
}
|
||||
|
||||
public static Glyph getPaymentGlyph() {
|
||||
Glyph paymentGlyph = new Glyph("FontAwesome", FontAwesome.Glyph.SEND);
|
||||
paymentGlyph.getStyleClass().add("payment-icon");
|
||||
paymentGlyph.setFontSize(12);
|
||||
return paymentGlyph;
|
||||
}
|
||||
|
||||
public static Glyph getPaymentWarningGlyph() {
|
||||
Glyph paymentWarningGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.EXCLAMATION_TRIANGLE);
|
||||
paymentWarningGlyph.getStyleClass().add("payment-warning-icon");
|
||||
paymentWarningGlyph.setFontSize(12);
|
||||
return paymentWarningGlyph;
|
||||
}
|
||||
|
||||
public static Glyph getConsolidationGlyph() {
|
||||
Glyph consolidationGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.REPLY_ALL);
|
||||
consolidationGlyph.getStyleClass().add("consolidation-icon");
|
||||
consolidationGlyph.setFontSize(12);
|
||||
return consolidationGlyph;
|
||||
}
|
||||
|
||||
public static Glyph getDepositGlyph() {
|
||||
Glyph depositGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.ARROW_DOWN);
|
||||
depositGlyph.getStyleClass().add("deposit-icon");
|
||||
depositGlyph.setFontSize(12);
|
||||
return depositGlyph;
|
||||
}
|
||||
|
||||
public static Glyph getPremixGlyph() {
|
||||
Glyph premixGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.RANDOM);
|
||||
premixGlyph.getStyleClass().add("premix-icon");
|
||||
premixGlyph.setFontSize(12);
|
||||
return premixGlyph;
|
||||
}
|
||||
|
||||
public static Glyph getBadbankGlyph() {
|
||||
Glyph badbankGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.BIOHAZARD);
|
||||
badbankGlyph.getStyleClass().add("badbank-icon");
|
||||
badbankGlyph.setFontSize(12);
|
||||
return badbankGlyph;
|
||||
}
|
||||
|
||||
public static Glyph getWhirlpoolFeeGlyph() {
|
||||
Glyph whirlpoolFeeGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.HAND_HOLDING_WATER);
|
||||
whirlpoolFeeGlyph.getStyleClass().add("whirlpoolfee-icon");
|
||||
whirlpoolFeeGlyph.setFontSize(12);
|
||||
return whirlpoolFeeGlyph;
|
||||
}
|
||||
|
||||
public static Glyph getFakeMixGlyph() {
|
||||
Glyph fakeMixGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.THEATER_MASKS);
|
||||
fakeMixGlyph.getStyleClass().add("fakemix-icon");
|
||||
fakeMixGlyph.setFontSize(12);
|
||||
return fakeMixGlyph;
|
||||
}
|
||||
|
||||
public static Glyph getTxoGlyph() {
|
||||
return getChangeGlyph();
|
||||
}
|
||||
|
||||
public static Glyph getMixGlyph() {
|
||||
Glyph payjoinGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.RANDOM);
|
||||
payjoinGlyph.getStyleClass().add("mix-icon");
|
||||
payjoinGlyph.setFontSize(12);
|
||||
return payjoinGlyph;
|
||||
}
|
||||
|
||||
public static Glyph getExternalInputGlyph() {
|
||||
Glyph externalGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.LONG_ARROW_ALT_RIGHT);
|
||||
externalGlyph.getStyleClass().add("external-input-icon");
|
||||
externalGlyph.setFontSize(12);
|
||||
return externalGlyph;
|
||||
}
|
||||
|
||||
public static Glyph getExcludeGlyph() {
|
||||
Glyph excludeGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.TIMES_CIRCLE);
|
||||
excludeGlyph.getStyleClass().add("exclude-utxo");
|
||||
excludeGlyph.setFontSize(12);
|
||||
return excludeGlyph;
|
||||
}
|
||||
|
||||
public static Glyph getChangeGlyph() {
|
||||
Glyph changeGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.COINS);
|
||||
changeGlyph.getStyleClass().add("change-icon");
|
||||
changeGlyph.setFontSize(12);
|
||||
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;
|
||||
}
|
||||
|
||||
public static Glyph getFeeGlyph() {
|
||||
Glyph feeGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.HAND_HOLDING);
|
||||
feeGlyph.getStyleClass().add("fee-icon");
|
||||
feeGlyph.setFontSize(12);
|
||||
return feeGlyph;
|
||||
}
|
||||
|
||||
public static Glyph getWarningGlyph() {
|
||||
Glyph feeWarningGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.EXCLAMATION_CIRCLE);
|
||||
feeWarningGlyph.getStyleClass().add("fee-warning-icon");
|
||||
feeWarningGlyph.setFontSize(12);
|
||||
return feeWarningGlyph;
|
||||
}
|
||||
|
||||
public static Glyph getQuestionGlyph() {
|
||||
Glyph feeWarningGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.QUESTION_CIRCLE);
|
||||
feeWarningGlyph.getStyleClass().add("question-icon");
|
||||
feeWarningGlyph.setFontSize(12);
|
||||
return feeWarningGlyph;
|
||||
}
|
||||
|
||||
public static Glyph getLockGlyph() {
|
||||
Glyph lockGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.LOCK);
|
||||
lockGlyph.getStyleClass().add("lock-icon");
|
||||
lockGlyph.setFontSize(12);
|
||||
return lockGlyph;
|
||||
}
|
||||
|
||||
public static Glyph getUserGlyph() {
|
||||
Glyph userGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.USER);
|
||||
userGlyph.getStyleClass().add("user-icon");
|
||||
userGlyph.setFontSize(12);
|
||||
return userGlyph;
|
||||
}
|
||||
|
||||
public static Glyph getOpcodeGlyph() {
|
||||
Glyph userGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.MICROCHIP);
|
||||
userGlyph.getStyleClass().add("opcode-icon");
|
||||
userGlyph.setFontSize(12);
|
||||
return userGlyph;
|
||||
}
|
||||
}
|
|
@ -437,8 +437,11 @@ public class HeadersController extends TransactionFormController implements Init
|
|||
updateFee(feeAmt);
|
||||
}
|
||||
|
||||
headersForm.walletTransactionProperty().addListener((observable, oldValue, walletTransaction) -> {
|
||||
transactionDiagram.update(walletTransaction);
|
||||
});
|
||||
transactionDiagram.labelProperty().set(transactionDiagramLabel);
|
||||
transactionDiagram.update(getWalletTransaction(headersForm.getInputTransactions()));
|
||||
headersForm.setWalletTransaction(getWalletTransaction(headersForm.getInputTransactions()));
|
||||
|
||||
blockchainForm.managedProperty().bind(blockchainForm.visibleProperty());
|
||||
|
||||
|
@ -1334,7 +1337,7 @@ public class HeadersController extends TransactionFormController implements Init
|
|||
if(headersForm.getInputTransactions() != null) {
|
||||
allFetchedInputTransactions.putAll(headersForm.getInputTransactions());
|
||||
}
|
||||
transactionDiagram.update(getWalletTransaction(allFetchedInputTransactions));
|
||||
headersForm.setWalletTransaction(getWalletTransaction(allFetchedInputTransactions));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1500,7 +1503,7 @@ public class HeadersController extends TransactionFormController implements Init
|
|||
updateType();
|
||||
updateSize();
|
||||
updateFee(headersForm.getPsbt().getFee());
|
||||
transactionDiagram.update(getWalletTransaction(headersForm.getInputTransactions()));
|
||||
headersForm.setWalletTransaction(getWalletTransaction(headersForm.getInputTransactions()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1597,7 +1600,7 @@ public class HeadersController extends TransactionFormController implements Init
|
|||
public void psbtReordered(PSBTReorderedEvent event) {
|
||||
if(event.getPsbt().equals(headersForm.getPsbt())) {
|
||||
updateTxId();
|
||||
transactionDiagram.update(getWalletTransaction(headersForm.getInputTransactions()));
|
||||
headersForm.setWalletTransaction(getWalletTransaction(headersForm.getInputTransactions()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import com.sparrowwallet.drongo.wallet.Wallet;
|
|||
import com.sparrowwallet.sparrow.EventManager;
|
||||
import com.sparrowwallet.sparrow.control.*;
|
||||
import com.sparrowwallet.sparrow.event.*;
|
||||
import com.sparrowwallet.sparrow.glyphfont.GlyphUtils;
|
||||
import javafx.collections.MapChangeListener;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
|
@ -124,7 +125,7 @@ public class InputController extends TransactionFormController implements Initia
|
|||
inputForm.signingWalletProperty().addListener((observable, oldValue, signingWallet) -> {
|
||||
updateInputLegendFromWallet(txInput, signingWallet);
|
||||
});
|
||||
updateInputLegendFromWallet(txInput, inputForm.getSigningWallet());
|
||||
updateInputLegendFromWallet(txInput, inputForm.getWallet());
|
||||
|
||||
initializeInputFields(txInput, psbtInput);
|
||||
initializeScriptFields(txInput, psbtInput);
|
||||
|
@ -142,19 +143,19 @@ public class InputController extends TransactionFormController implements Initia
|
|||
return "Input #" + txInput.getIndex();
|
||||
}
|
||||
|
||||
private void updateInputLegendFromWallet(TransactionInput txInput, Wallet signingWallet) {
|
||||
private void updateInputLegendFromWallet(TransactionInput txInput, Wallet wallet) {
|
||||
String baseText = getLegendText(txInput);
|
||||
if(signingWallet != null) {
|
||||
if(wallet != null) {
|
||||
if(inputForm.isWalletTxo()) {
|
||||
inputFieldset.setText(baseText + " from " + signingWallet.getFullDisplayName());
|
||||
inputFieldset.setIcon(TransactionDiagram.getTxoGlyph());
|
||||
inputFieldset.setText(baseText + " from " + wallet.getFullDisplayName());
|
||||
inputFieldset.setIcon(GlyphUtils.getTxoGlyph());
|
||||
} else {
|
||||
inputFieldset.setText(baseText + " - External");
|
||||
inputFieldset.setIcon(TransactionDiagram.getMixGlyph());
|
||||
inputFieldset.setText(baseText + (txInput.isCoinBase() ? " - Coinbase" : " - External"));
|
||||
inputFieldset.setIcon(GlyphUtils.getMixGlyph());
|
||||
}
|
||||
} else {
|
||||
inputFieldset.setText(baseText);
|
||||
inputFieldset.setIcon(null);
|
||||
inputFieldset.setText(baseText + (txInput.isCoinBase() ? " - Coinbase" : " - External"));
|
||||
inputFieldset.setIcon(GlyphUtils.getExternalInputGlyph());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,20 @@
|
|||
package com.sparrowwallet.sparrow.transaction;
|
||||
|
||||
import com.sparrowwallet.drongo.protocol.TransactionInput;
|
||||
import com.sparrowwallet.drongo.protocol.TransactionOutPoint;
|
||||
import com.sparrowwallet.drongo.protocol.TransactionOutput;
|
||||
import com.sparrowwallet.drongo.psbt.PSBTInput;
|
||||
import com.sparrowwallet.drongo.wallet.BlockTransaction;
|
||||
import com.sparrowwallet.drongo.wallet.BlockTransactionHashIndex;
|
||||
import com.sparrowwallet.sparrow.glyphfont.GlyphUtils;
|
||||
import com.sparrowwallet.sparrow.net.ElectrumServer;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Label;
|
||||
import org.controlsfx.glyphfont.Glyph;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
|
||||
public class InputForm extends IndexedTransactionForm {
|
||||
public InputForm(TransactionData txdata, PSBTInput psbtInput) {
|
||||
|
@ -48,7 +54,7 @@ public class InputForm extends IndexedTransactionForm {
|
|||
|
||||
public boolean isWalletTxo() {
|
||||
TransactionInput txInput = getTransactionInput();
|
||||
return getSigningWallet() != null && getSigningWallet().isWalletTxo(txInput);
|
||||
return getWallet() != null && getWallet().isWalletTxo(txInput);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -67,6 +73,24 @@ public class InputForm extends IndexedTransactionForm {
|
|||
}
|
||||
|
||||
public String toString() {
|
||||
return "Input #" + getIndex();
|
||||
TransactionOutPoint outPoint = getTransactionInput().getOutpoint();
|
||||
return outPoint.getHash().toString().substring(0, 8) + "..:" + outPoint.getIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Label getLabel() {
|
||||
if(getWalletTransaction() != null) {
|
||||
TransactionOutPoint outPoint = getTransactionInput().getOutpoint();
|
||||
Optional<BlockTransactionHashIndex> optRef = getWalletTransaction().getSelectedUtxos().keySet().stream()
|
||||
.filter(txo -> txo.getHash().equals(outPoint.getHash()) && txo.getIndex() == outPoint.getIndex()).findFirst();
|
||||
Glyph inputGlyph = isWalletTxo() ? GlyphUtils.getTxoGlyph() : (getWallet() != null ? GlyphUtils.getMixGlyph() : GlyphUtils.getExternalInputGlyph());
|
||||
if(optRef.isPresent() && optRef.get().getLabel() != null) {
|
||||
return new Label(optRef.get().getLabel(), inputGlyph);
|
||||
} else {
|
||||
return new Label(toString(), inputGlyph);
|
||||
}
|
||||
}
|
||||
|
||||
return super.getLabel();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@ import com.sparrowwallet.drongo.address.Address;
|
|||
import com.sparrowwallet.drongo.protocol.NonStandardScriptException;
|
||||
import com.sparrowwallet.drongo.protocol.TransactionInput;
|
||||
import com.sparrowwallet.drongo.protocol.TransactionOutput;
|
||||
import com.sparrowwallet.drongo.wallet.BlockTransaction;
|
||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||
import com.sparrowwallet.drongo.wallet.*;
|
||||
import com.sparrowwallet.sparrow.AppServices;
|
||||
import com.sparrowwallet.sparrow.EventManager;
|
||||
import com.sparrowwallet.sparrow.control.*;
|
||||
import com.sparrowwallet.sparrow.event.PSBTReorderedEvent;
|
||||
|
@ -66,7 +66,10 @@ public class OutputController extends TransactionFormController implements Initi
|
|||
outputForm.signingWalletProperty().addListener((observable, oldValue, signingWallet) -> {
|
||||
updateOutputLegendFromWallet(txOutput, signingWallet);
|
||||
});
|
||||
updateOutputLegendFromWallet(txOutput, outputForm.getSigningWallet());
|
||||
outputForm.walletTransactionProperty().addListener((observable, oldValue, walletTransaction) -> {
|
||||
updateOutputLegendFromWallet(txOutput, walletTransaction != null ? walletTransaction.getWallet() : null);
|
||||
});
|
||||
updateOutputLegendFromWallet(txOutput, outputForm.getWallet());
|
||||
|
||||
value.setValue(txOutput.getValue());
|
||||
to.setVisible(false);
|
||||
|
@ -103,23 +106,40 @@ public class OutputController extends TransactionFormController implements Initi
|
|||
return "Output #" + txOutput.getIndex();
|
||||
}
|
||||
|
||||
private void updateOutputLegendFromWallet(TransactionOutput txOutput, Wallet signingWallet) {
|
||||
private void updateOutputLegendFromWallet(TransactionOutput txOutput, Wallet wallet) {
|
||||
String baseText = getLegendText(txOutput);
|
||||
if(signingWallet != null) {
|
||||
if(outputForm.isWalletChange()) {
|
||||
outputFieldset.setText(baseText + " - Change");
|
||||
outputFieldset.setIcon(TransactionDiagram.getChangeGlyph());
|
||||
} else if(outputForm.isWalletConsolidation()) {
|
||||
outputFieldset.setText(baseText + " - Consolidation");
|
||||
outputFieldset.setIcon(TransactionDiagram.getConsolidationGlyph());
|
||||
WalletTransaction walletTx = outputForm.getWalletTransaction();
|
||||
if(walletTx != null) {
|
||||
List<WalletTransaction.Output> outputs = walletTx.getOutputs();
|
||||
if(outputForm.getIndex() < outputs.size()) {
|
||||
WalletTransaction.Output output = outputs.get(outputForm.getIndex());
|
||||
if(output instanceof WalletTransaction.NonAddressOutput) {
|
||||
outputFieldset.setText(baseText);
|
||||
} else if(output instanceof WalletTransaction.PaymentOutput paymentOutput) {
|
||||
Payment payment = paymentOutput.getPayment();
|
||||
Wallet toWallet = walletTx.getToWallet(AppServices.get().getOpenWallets().keySet(), payment);
|
||||
WalletNode toNode = walletTx.getWallet() != null && !walletTx.getWallet().isBip47() ? walletTx.getAddressNodeMap().get(payment.getAddress()) : null;
|
||||
outputFieldset.setText(baseText + (toWallet == null ? (toNode != null ? " - Consolidation" : " - Payment") : " - Received to " + toWallet.getFullDisplayName()));
|
||||
} else if(output instanceof WalletTransaction.ChangeOutput changeOutput) {
|
||||
outputFieldset.setText(baseText + " - Change to " + changeOutput.getWalletNode().toString());
|
||||
} else {
|
||||
outputFieldset.setText(baseText + " - Payment");
|
||||
outputFieldset.setIcon(TransactionDiagram.getPaymentGlyph());
|
||||
outputFieldset.setText(baseText);
|
||||
}
|
||||
} else {
|
||||
outputFieldset.setText(baseText);
|
||||
outputFieldset.setIcon(null);
|
||||
}
|
||||
} else if(wallet != null) {
|
||||
if(outputForm.isWalletChange()) {
|
||||
outputFieldset.setText(baseText + " - Change");
|
||||
} else if(outputForm.isWalletConsolidation()) {
|
||||
outputFieldset.setText(baseText + " - Consolidation");
|
||||
} else {
|
||||
outputFieldset.setText(baseText + " - Payment");
|
||||
}
|
||||
} else {
|
||||
outputFieldset.setText(baseText);
|
||||
}
|
||||
outputFieldset.setIcon(outputForm.getLabel().getGraphic());
|
||||
}
|
||||
|
||||
private void updateSpent(List<BlockTransaction> outputTransactions) {
|
||||
|
|
|
@ -1,12 +1,20 @@
|
|||
package com.sparrowwallet.sparrow.transaction;
|
||||
|
||||
import com.sparrowwallet.drongo.KeyPurpose;
|
||||
import com.sparrowwallet.drongo.address.Address;
|
||||
import com.sparrowwallet.drongo.protocol.ScriptChunk;
|
||||
import com.sparrowwallet.drongo.protocol.ScriptOpCodes;
|
||||
import com.sparrowwallet.drongo.protocol.TransactionOutput;
|
||||
import com.sparrowwallet.drongo.psbt.PSBTOutput;
|
||||
import com.sparrowwallet.drongo.wallet.Payment;
|
||||
import com.sparrowwallet.drongo.wallet.WalletTransaction;
|
||||
import com.sparrowwallet.sparrow.glyphfont.GlyphUtils;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Label;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
public class OutputForm extends IndexedTransactionForm {
|
||||
public OutputForm(TransactionData txdata, PSBTOutput psbtOutput) {
|
||||
|
@ -26,15 +34,15 @@ public class OutputForm extends IndexedTransactionForm {
|
|||
}
|
||||
|
||||
public boolean isWalletConsolidation() {
|
||||
return (getSigningWallet() != null && getSigningWallet().getWalletOutputScripts(KeyPurpose.RECEIVE).containsKey(getTransactionOutput().getScript()));
|
||||
return (getWallet() != null && getWallet().getWalletOutputScripts(KeyPurpose.RECEIVE).containsKey(getTransactionOutput().getScript()));
|
||||
}
|
||||
|
||||
public boolean isWalletChange() {
|
||||
return (getSigningWallet() != null && getSigningWallet().getWalletOutputScripts(getSigningWallet().getChangeKeyPurpose()).containsKey(getTransactionOutput().getScript()));
|
||||
return (getWallet() != null && getWallet().getWalletOutputScripts(getWallet().getChangeKeyPurpose()).containsKey(getTransactionOutput().getScript()));
|
||||
}
|
||||
|
||||
public boolean isWalletPayment() {
|
||||
return getSigningWallet() != null;
|
||||
return getWallet() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -53,6 +61,33 @@ public class OutputForm extends IndexedTransactionForm {
|
|||
}
|
||||
|
||||
public String toString() {
|
||||
return "Output #" + getIndex();
|
||||
Address address = getTransactionOutput().getScript().getToAddress();
|
||||
return address != null ? address.toString() : "Output #" + getIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Label getLabel() {
|
||||
if(getWalletTransaction() != null) {
|
||||
List<WalletTransaction.Output> outputs = getWalletTransaction().getOutputs();
|
||||
if(getIndex() < outputs.size()) {
|
||||
WalletTransaction.Output output = outputs.get(getIndex());
|
||||
if(output instanceof WalletTransaction.NonAddressOutput) {
|
||||
List<ScriptChunk> chunks = output.getTransactionOutput().getScript().getChunks();
|
||||
if(!chunks.isEmpty() && chunks.get(0).isOpCode() && chunks.get(0).getOpcode() == ScriptOpCodes.OP_RETURN) {
|
||||
return new Label(chunks.get(0).toString(), GlyphUtils.getOpcodeGlyph());
|
||||
} else {
|
||||
return new Label("Output #" + getIndex(), GlyphUtils.getOpcodeGlyph());
|
||||
}
|
||||
} else if(output instanceof WalletTransaction.PaymentOutput paymentOutput) {
|
||||
Payment payment = paymentOutput.getPayment();
|
||||
return new Label(payment.getLabel() != null && payment.getType() != Payment.Type.FAKE_MIX && payment.getType() != Payment.Type.MIX ? payment.getLabel() : payment.getAddress().toString(),
|
||||
GlyphUtils.getOutputGlyph(getWalletTransaction(), payment));
|
||||
} else if(output instanceof WalletTransaction.ChangeOutput changeOutput) {
|
||||
return new Label(changeOutput.getWalletNode().getAddress().toString(), GlyphUtils.getChangeGlyph());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.getLabel();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import com.sparrowwallet.drongo.wallet.Wallet;
|
|||
import com.sparrowwallet.sparrow.AppServices;
|
||||
import com.sparrowwallet.sparrow.EventManager;
|
||||
import com.sparrowwallet.sparrow.TransactionTabData;
|
||||
import com.sparrowwallet.sparrow.control.TransactionDiagram;
|
||||
import com.sparrowwallet.sparrow.control.TransactionHexArea;
|
||||
import com.sparrowwallet.sparrow.event.*;
|
||||
import com.sparrowwallet.sparrow.io.Config;
|
||||
|
@ -20,6 +19,7 @@ import javafx.fxml.FXML;
|
|||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TreeCell;
|
||||
import javafx.scene.control.TreeItem;
|
||||
import javafx.scene.control.TreeView;
|
||||
|
@ -158,28 +158,11 @@ public class TransactionController implements Initializable {
|
|||
setContextMenu(null);
|
||||
|
||||
if(form != null) {
|
||||
setText(form.toString());
|
||||
Label label = form.getLabel();
|
||||
label.setMaxWidth(100);
|
||||
setGraphic(label);
|
||||
|
||||
if(form.getSigningWallet() != null) {
|
||||
if(form instanceof InputForm) {
|
||||
InputForm inputForm = (InputForm)form;
|
||||
if(inputForm.isWalletTxo()) {
|
||||
setGraphic(TransactionDiagram.getTxoGlyph());
|
||||
} else {
|
||||
setGraphic(TransactionDiagram.getMixGlyph());
|
||||
}
|
||||
}
|
||||
if(form instanceof OutputForm) {
|
||||
OutputForm outputForm = (OutputForm)form;
|
||||
if(outputForm.isWalletChange()) {
|
||||
setGraphic(TransactionDiagram.getChangeGlyph());
|
||||
} else if(outputForm.isWalletConsolidation()) {
|
||||
setGraphic(TransactionDiagram.getConsolidationGlyph());
|
||||
} else {
|
||||
setGraphic(TransactionDiagram.getPaymentGlyph());
|
||||
}
|
||||
}
|
||||
|
||||
setOnDragDetected(null);
|
||||
setOnDragOver(null);
|
||||
setOnDragDropped(null);
|
||||
|
@ -196,6 +179,10 @@ public class TransactionController implements Initializable {
|
|||
txtree.refresh();
|
||||
});
|
||||
|
||||
txdata.walletTransactionProperty().addListener((observable, oldValue, newValue) -> {
|
||||
txtree.refresh();
|
||||
});
|
||||
|
||||
txtree.getSelectionModel().selectedItemProperty().addListener((observable, old_val, selectedItem) -> {
|
||||
TransactionForm transactionForm = selectedItem.getValue();
|
||||
if(transactionForm instanceof PageForm) {
|
||||
|
|
|
@ -3,10 +3,7 @@ package com.sparrowwallet.sparrow.transaction;
|
|||
import com.sparrowwallet.drongo.KeyPurpose;
|
||||
import com.sparrowwallet.drongo.protocol.*;
|
||||
import com.sparrowwallet.drongo.psbt.PSBT;
|
||||
import com.sparrowwallet.drongo.wallet.BlockTransaction;
|
||||
import com.sparrowwallet.drongo.wallet.Keystore;
|
||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||
import com.sparrowwallet.drongo.wallet.WalletNode;
|
||||
import com.sparrowwallet.drongo.wallet.*;
|
||||
import com.sparrowwallet.sparrow.io.Storage;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.collections.FXCollections;
|
||||
|
@ -30,6 +27,7 @@ public class TransactionData {
|
|||
private final ObservableMap<Wallet, Storage> availableWallets = FXCollections.observableHashMap();
|
||||
private final SimpleObjectProperty<Wallet> signingWallet = new SimpleObjectProperty<>(this, "signingWallet", null);
|
||||
private final ObservableMap<TransactionSignature, Keystore> signatureKeystoreMap = FXCollections.observableMap(new LinkedHashMap<>());
|
||||
private final SimpleObjectProperty<WalletTransaction> walletTransaction = new SimpleObjectProperty<>(this, "walletTransaction", null);
|
||||
|
||||
public TransactionData(String name, PSBT psbt) {
|
||||
this(name, psbt.getTransaction());
|
||||
|
@ -179,4 +177,20 @@ public class TransactionData {
|
|||
|
||||
return signingWalletNodes;
|
||||
}
|
||||
|
||||
public WalletTransaction getWalletTransaction() {
|
||||
return walletTransaction.get();
|
||||
}
|
||||
|
||||
public SimpleObjectProperty<WalletTransaction> walletTransactionProperty() {
|
||||
return walletTransaction;
|
||||
}
|
||||
|
||||
public void setWalletTransaction(WalletTransaction walletTransaction) {
|
||||
this.walletTransaction.set(walletTransaction);
|
||||
}
|
||||
|
||||
public Wallet getWallet() {
|
||||
return getSigningWallet() != null ? getSigningWallet() : (getWalletTransaction() != null ? getWalletTransaction().getWallet() : null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,14 +4,12 @@ import com.sparrowwallet.drongo.protocol.Sha256Hash;
|
|||
import com.sparrowwallet.drongo.protocol.Transaction;
|
||||
import com.sparrowwallet.drongo.protocol.TransactionSignature;
|
||||
import com.sparrowwallet.drongo.psbt.PSBT;
|
||||
import com.sparrowwallet.drongo.wallet.BlockTransaction;
|
||||
import com.sparrowwallet.drongo.wallet.Keystore;
|
||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||
import com.sparrowwallet.drongo.wallet.WalletNode;
|
||||
import com.sparrowwallet.drongo.wallet.*;
|
||||
import com.sparrowwallet.sparrow.io.Storage;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.collections.ObservableMap;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Label;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
@ -98,6 +96,22 @@ public abstract class TransactionForm {
|
|||
return txdata.getSigningWalletNodes();
|
||||
}
|
||||
|
||||
public WalletTransaction getWalletTransaction() {
|
||||
return txdata.getWalletTransaction();
|
||||
}
|
||||
|
||||
public SimpleObjectProperty<WalletTransaction> walletTransactionProperty() {
|
||||
return txdata.walletTransactionProperty();
|
||||
}
|
||||
|
||||
public void setWalletTransaction(WalletTransaction walletTransaction) {
|
||||
txdata.setWalletTransaction(walletTransaction);
|
||||
}
|
||||
|
||||
public Wallet getWallet() {
|
||||
return txdata.getWallet();
|
||||
}
|
||||
|
||||
public boolean isEditable() {
|
||||
if(getBlockTransaction() != null) {
|
||||
return false;
|
||||
|
@ -120,4 +134,8 @@ public abstract class TransactionForm {
|
|||
public abstract Node getContents() throws IOException;
|
||||
|
||||
public abstract TransactionView getView();
|
||||
|
||||
public Label getLabel() {
|
||||
return new Label(toString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,3 +31,7 @@
|
|||
.color-8 { -fx-fill: #000000 }
|
||||
|
||||
.color-grey { -fx-fill: #e5e5e6 }
|
||||
|
||||
.change-warning-icon, .payment-warning-icon {
|
||||
-fx-text-fill: rgb(238, 210, 2);
|
||||
}
|
Loading…
Reference in a new issue