diff --git a/build.gradle b/build.gradle index 9ae88630..5116e731 100644 --- a/build.gradle +++ b/build.gradle @@ -52,7 +52,9 @@ dependencies { exclude group: 'org.slf4j' } implementation('com.sparrowwallet:hummingbird:1.2') - implementation('com.nativelibs4java:bridj:0.7-20140918-3') + implementation('com.nativelibs4java:bridj:0.7-20140918-3') { + exclude group: 'com.google.android.tools', module: 'dx' + } implementation('com.github.sarxos:webcam-capture:0.3.13-SNAPSHOT') { exclude group: 'com.nativelibs4java', module: 'bridj' } diff --git a/drongo b/drongo index 661e8844..8b07336d 160000 --- a/drongo +++ b/drongo @@ -1 +1 @@ -Subproject commit 661e88447f232e44f96f69ee795f151233099ed6 +Subproject commit 8b07336d71f32094acb8eb8c162ebd8621ffc4aa diff --git a/src/main/java/com/sparrowwallet/sparrow/control/TransactionDiagram.java b/src/main/java/com/sparrowwallet/sparrow/control/TransactionDiagram.java index 07eab1a2..c7d1c63e 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/TransactionDiagram.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/TransactionDiagram.java @@ -2,6 +2,7 @@ package com.sparrowwallet.sparrow.control; import com.sparrowwallet.drongo.protocol.Sha256Hash; import com.sparrowwallet.drongo.wallet.BlockTransactionHashIndex; +import com.sparrowwallet.drongo.wallet.Payment; import com.sparrowwallet.drongo.wallet.WalletNode; import com.sparrowwallet.drongo.wallet.WalletTransaction; import com.sparrowwallet.sparrow.EventManager; @@ -26,6 +27,7 @@ import java.util.*; public class TransactionDiagram extends GridPane { private static final int MAX_UTXOS = 8; + private static final int MAX_PAYMENTS = 6; private static final double DIAGRAM_HEIGHT = 230.0; private static final int TOOLTIP_SHOW_DELAY = 50; @@ -55,10 +57,12 @@ public class TransactionDiagram extends GridPane { Pane txPane = getTransactionPane(); GridPane.setConstraints(txPane, 3, 0); - Pane outputsLinesPane = getOutputsLines(); + List displayedPayments = getDisplayedPayments(); + + Pane outputsLinesPane = getOutputsLines(displayedPayments); GridPane.setConstraints(outputsLinesPane, 4, 0); - Pane outputsPane = getOutputsLabels(); + Pane outputsPane = getOutputsLabels(displayedPayments); GridPane.setConstraints(outputsPane, 5, 0); getChildren().clear(); @@ -241,7 +245,28 @@ public class TransactionDiagram extends GridPane { return value * (1.0 - scaleFactor) + additional; } - private Pane getOutputsLines() { + private List getDisplayedPayments() { + List payments = walletTx.getPayments(); + + if(payments.size() > MAX_PAYMENTS) { + List displayedPayments = new ArrayList<>(); + List additional = new ArrayList<>(); + for(Payment payment : payments) { + if(displayedPayments.size() < MAX_PAYMENTS) { + displayedPayments.add(payment); + } else { + additional.add(payment); + } + } + + displayedPayments.add(new AdditionalPayment(additional)); + return displayedPayments; + } else { + return payments; + } + } + + private Pane getOutputsLines(List displayedPayments) { VBox pane = new VBox(); Group group = new Group(); VBox.setVgrow(group, Priority.ALWAYS); @@ -255,7 +280,7 @@ public class TransactionDiagram extends GridPane { group.getChildren().add(yaxisLine); double width = 140.0; - int numOutputs = (walletTx.getChangeNode() == null ? 2 : 3); + int numOutputs = displayedPayments.size() + (walletTx.getChangeNode() == null ? 1 : 2); for(int i = 1; i <= numOutputs; i++) { CubicCurve curve = new CubicCurve(); curve.getStyleClass().add("output-line"); @@ -280,23 +305,25 @@ public class TransactionDiagram extends GridPane { return pane; } - private Pane getOutputsLabels() { + private Pane getOutputsLabels(List displayedPayments) { VBox outputsBox = new VBox(); outputsBox.setMaxWidth(150); outputsBox.setPadding(new Insets(0, 20, 0, 10)); outputsBox.setAlignment(Pos.CENTER_LEFT); outputsBox.getChildren().add(createSpacer()); - boolean isConsolidation = walletTx.isConsolidationSend(); - String recipientDesc = walletTx.getRecipientAddress().toString().substring(0, 8) + "..."; - Label recipientLabel = new Label(recipientDesc, isConsolidation ? getConsolidationGlyph() : getPaymentGlyph()); - recipientLabel.getStyleClass().addAll("output-label", "recipient-label"); - Tooltip recipientTooltip = new Tooltip((isConsolidation ? "Consolidate " : "Pay ") + getSatsValue(walletTx.getRecipientAmount()) + " sats to\n" + walletTx.getRecipientAddress().toString()); - recipientTooltip.getStyleClass().add("recipient-label"); - recipientTooltip.setShowDelay(new Duration(TOOLTIP_SHOW_DELAY)); - recipientLabel.setTooltip(recipientTooltip); - outputsBox.getChildren().add(recipientLabel); - outputsBox.getChildren().add(createSpacer()); + for(Payment payment : displayedPayments) { + boolean isConsolidation = walletTx.isConsolidationSend(payment); + String recipientDesc = payment instanceof AdditionalPayment ? payment.getLabel() : payment.getAddress().toString().substring(0, 8) + "..."; + Label recipientLabel = new Label(recipientDesc, isConsolidation ? getConsolidationGlyph() : getPaymentGlyph()); + recipientLabel.getStyleClass().addAll("output-label", "recipient-label"); + Tooltip recipientTooltip = new Tooltip((isConsolidation ? "Consolidate " : "Pay ") + getSatsValue(payment.getAmount()) + " sats to\n" + payment.getAddress().toString()); + recipientTooltip.getStyleClass().add("recipient-label"); + recipientTooltip.setShowDelay(new Duration(TOOLTIP_SHOW_DELAY)); + recipientLabel.setTooltip(recipientTooltip); + outputsBox.getChildren().add(recipientLabel); + outputsBox.getChildren().add(createSpacer()); + } if(walletTx.getChangeNode() != null) { String changeDesc = walletTx.getChangeAddress().toString().substring(0, 8) + "..."; @@ -412,4 +439,10 @@ public class TransactionDiagram extends GridPane { return additionalInputs; } } + + private static class AdditionalPayment extends Payment { + public AdditionalPayment(List additionalPayments) { + super(null, additionalPayments.size() + " more...", additionalPayments.stream().map(Payment::getAmount).mapToLong(v -> v).sum(), false); + } + } } diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/SendController.java b/src/main/java/com/sparrowwallet/sparrow/wallet/SendController.java index 1d89f464..58a9bb0c 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/SendController.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/SendController.java @@ -275,9 +275,9 @@ public class SendController extends WalletFormController implements Initializabl walletTransactionProperty.addListener((observable, oldValue, walletTransaction) -> { if(walletTransaction != null) { - if(getRecipientValueSats() == null || walletTransaction.getRecipientAmount() != getRecipientValueSats()) { - setRecipientValueSats(walletTransaction.getRecipientAmount()); - setFiatAmount(AppController.getFiatCurrencyExchangeRate(), walletTransaction.getRecipientAmount()); + if(getRecipientValueSats() == null || walletTransaction.getPayments().get(0).getAmount() != getRecipientValueSats()) { + setRecipientValueSats(walletTransaction.getPayments().get(0).getAmount()); + setFiatAmount(AppController.getFiatCurrencyExchangeRate(), walletTransaction.getPayments().get(0).getAmount()); } double feeRate = walletTransaction.getFeeRate(); @@ -329,11 +329,12 @@ public class SendController extends WalletFormController implements Initializabl Long recipientAmount = sendAll ? Long.valueOf(recipientDustThreshold + 1) : getRecipientValueSats(); if(recipientAmount != null && recipientAmount > recipientDustThreshold && (!userFeeSet.get() || (getFeeValueSats() != null && getFeeValueSats() > 0))) { Wallet wallet = getWalletForm().getWallet(); + List payments = List.of(new Payment(recipientAddress, label.getText(), recipientAmount, sendAll)); Long userFee = userFeeSet.get() ? getFeeValueSats() : null; Integer currentBlockHeight = AppController.getCurrentBlockHeight(); boolean groupByAddress = Config.get().isGroupByAddress(); boolean includeMempoolChange = Config.get().isIncludeMempoolChange(); - WalletTransaction walletTransaction = wallet.createWalletTransaction(getUtxoSelectors(), getUtxoFilters(), recipientAddress, recipientAmount, getFeeRate(), getMinimumFeeRate(), userFee, currentBlockHeight, sendAll, groupByAddress, includeMempoolChange); + WalletTransaction walletTransaction = wallet.createWalletTransaction(getUtxoSelectors(), getUtxoFilters(), payments, getFeeRate(), getMinimumFeeRate(), userFee, currentBlockHeight, groupByAddress, includeMempoolChange); walletTransactionProperty.setValue(walletTransaction); insufficientInputsProperty.set(false); @@ -611,10 +612,8 @@ public class SendController extends WalletFormController implements Initializabl WalletTransaction walletTransaction = walletTransactionProperty.get(); Set nodes = new LinkedHashSet<>(walletTransaction.getSelectedUtxos().values()); nodes.add(walletTransaction.getChangeNode()); - WalletNode consolidationNode = walletTransaction.getConsolidationSendNode(); - if(consolidationNode != null) { - nodes.add(consolidationNode); - } + List consolidationNodes = walletTransaction.getConsolidationSendNodes(); + nodes.addAll(consolidationNodes); //All wallet nodes applicable to this transaction are stored so when the subscription status for one is updated, the history for all can be fetched in one atomic update walletForm.addWalletTransactionNodes(nodes);