show relative sizes of amounts in transaction diagram

This commit is contained in:
Craig Raw 2021-12-15 14:14:08 +02:00
parent 5d0025b4a7
commit aff872eea0
3 changed files with 60 additions and 22 deletions

2
drongo

@ -1 +1 @@
Subproject commit 6ac593f161f7d17bf1f99658a92d7d65d25997be Subproject commit d59da365065fffe07fbaf6bae45b457752114e79

View file

@ -27,6 +27,7 @@ import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.Tooltip; import javafx.scene.control.Tooltip;
import javafx.scene.layout.*; import javafx.scene.layout.*;
import javafx.scene.shape.Circle;
import javafx.scene.shape.CubicCurve; import javafx.scene.shape.CubicCurve;
import javafx.scene.shape.Line; import javafx.scene.shape.Line;
import javafx.util.Duration; import javafx.util.Duration;
@ -44,6 +45,7 @@ public class TransactionDiagram extends GridPane {
private static final double DIAGRAM_HEIGHT = 210.0; private static final double DIAGRAM_HEIGHT = 210.0;
private static final double REDUCED_DIAGRAM_HEIGHT = DIAGRAM_HEIGHT - 60; private static final double REDUCED_DIAGRAM_HEIGHT = DIAGRAM_HEIGHT - 60;
private static final int TOOLTIP_SHOW_DELAY = 50; private static final int TOOLTIP_SHOW_DELAY = 50;
private static final int RELATIVE_SIZE_MAX_RADIUS = 7;
private WalletTransaction walletTx; private WalletTransaction walletTx;
private final BooleanProperty finalProperty = new SimpleBooleanProperty(false); private final BooleanProperty finalProperty = new SimpleBooleanProperty(false);
@ -387,6 +389,7 @@ public class TransactionDiagram extends GridPane {
double width = 140.0; double width = 140.0;
List<BlockTransactionHashIndex> inputs = new ArrayList<>(displayedUtxos.keySet()); List<BlockTransactionHashIndex> inputs = new ArrayList<>(displayedUtxos.keySet());
long sum = walletTx.getTotal();
int numUtxos = displayedUtxos.size(); int numUtxos = displayedUtxos.size();
for(int i = 1; i <= numUtxos; i++) { for(int i = 1; i <= numUtxos; i++) {
CubicCurve curve = new CubicCurve(); CubicCurve curve = new CubicCurve();
@ -398,7 +401,7 @@ public class TransactionDiagram extends GridPane {
continue; continue;
} }
curve.setStartX(0); curve.setStartX(RELATIVE_SIZE_MAX_RADIUS);
double scaleFactor = (double)i / (numUtxos + 1); double scaleFactor = (double)i / (numUtxos + 1);
int nodeHeight = 17; int nodeHeight = 17;
double additional = (0.5 - scaleFactor) * ((double)nodeHeight); double additional = (0.5 - scaleFactor) * ((double)nodeHeight);
@ -406,12 +409,18 @@ public class TransactionDiagram extends GridPane {
curve.setEndX(width); curve.setEndX(width);
curve.setEndY(scale(getDiagramHeight(), 0.5, 0)); curve.setEndY(scale(getDiagramHeight(), 0.5, 0));
curve.setControlX1(scale(width, 0.2, 0)); curve.setControlX1(scale(width - RELATIVE_SIZE_MAX_RADIUS, 0.2, 0));
curve.setControlY1(curve.getStartY()); curve.setControlY1(curve.getStartY());
curve.setControlX2(scale(width, 0.8, 0)); curve.setControlX2(scale(width - RELATIVE_SIZE_MAX_RADIUS, 0.8, 0));
curve.setControlY2(curve.getEndY()); curve.setControlY2(curve.getEndY());
group.getChildren().add(curve); group.getChildren().add(curve);
if(sum > 0 && !curve.getStyleClass().contains("input-dashed-line")) {
long radius = Math.round((double)inputs.get(numUtxos-i).getValue() * (RELATIVE_SIZE_MAX_RADIUS - 1) / sum) + 1;
Circle circle = new Circle(curve.getStartX(), curve.getStartY(), radius);
group.getChildren().add(circle);
}
} }
pane.getChildren().add(group); pane.getChildren().add(group);
@ -458,6 +467,9 @@ public class TransactionDiagram extends GridPane {
group.getChildren().add(yaxisLine); group.getChildren().add(yaxisLine);
double width = 140.0; double width = 140.0;
long sum = walletTx.getTotal();
List<Long> values = walletTx.getTransaction().getOutputs().stream().map(TransactionOutput::getValue).collect(Collectors.toList());
values.add(walletTx.getFee());
int numOutputs = displayedPayments.size() + walletTx.getChangeMap().size() + 1; int numOutputs = displayedPayments.size() + walletTx.getChangeMap().size() + 1;
for(int i = 1; i <= numOutputs; i++) { for(int i = 1; i <= numOutputs; i++) {
CubicCurve curve = new CubicCurve(); CubicCurve curve = new CubicCurve();
@ -465,18 +477,24 @@ public class TransactionDiagram extends GridPane {
curve.setStartX(0); curve.setStartX(0);
curve.setStartY(scale(getDiagramHeight(), 0.5, 0)); curve.setStartY(scale(getDiagramHeight(), 0.5, 0));
curve.setEndX(width); curve.setEndX(width - RELATIVE_SIZE_MAX_RADIUS);
double scaleFactor = (double)i / (numOutputs + 1); double scaleFactor = (double)i / (numOutputs + 1);
int nodeHeight = 20; int nodeHeight = 20;
double additional = (0.5 - scaleFactor) * ((double)nodeHeight); double additional = (0.5 - scaleFactor) * ((double)nodeHeight);
curve.setEndY(scale(getDiagramHeight(), scaleFactor, additional)); curve.setEndY(scale(getDiagramHeight(), scaleFactor, additional));
curve.setControlX1(scale(width, 0.2, 0)); curve.setControlX1(scale(width - RELATIVE_SIZE_MAX_RADIUS, 0.2, 0));
curve.controlY1Property().bind(curve.startYProperty()); curve.controlY1Property().bind(curve.startYProperty());
curve.setControlX2(scale(width, 0.8, 0)); curve.setControlX2(scale(width - RELATIVE_SIZE_MAX_RADIUS, 0.8, 0));
curve.controlY2Property().bind(curve.endYProperty()); curve.controlY2Property().bind(curve.endYProperty());
group.getChildren().add(curve); group.getChildren().add(curve);
if(sum > 0) {
long radius = Math.min(RELATIVE_SIZE_MAX_RADIUS, Math.round((double)values.get(numOutputs-i) * (RELATIVE_SIZE_MAX_RADIUS - 1) / sum) + 1);
Circle circle = new Circle(curve.getEndX(), curve.getEndY(), radius);
group.getChildren().add(circle);
}
} }
pane.getChildren().add(group); pane.getChildren().add(group);
@ -880,7 +898,7 @@ public class TransactionDiagram extends GridPane {
private final List<BlockTransactionHashIndex> additionalInputs; private final List<BlockTransactionHashIndex> additionalInputs;
public AdditionalBlockTransactionHashIndex(List<BlockTransactionHashIndex> additionalInputs) { public AdditionalBlockTransactionHashIndex(List<BlockTransactionHashIndex> additionalInputs) {
super(Sha256Hash.ZERO_HASH, 0, new Date(), 0L, 0, 0); super(Sha256Hash.ZERO_HASH, 0, new Date(), 0L, 0, additionalInputs.stream().mapToLong(BlockTransactionHashIndex::getValue).sum());
this.additionalInputs = additionalInputs; this.additionalInputs = additionalInputs;
} }

View file

@ -403,6 +403,11 @@ public class HeadersController extends TransactionFormController implements Init
feeAmt = 0L; feeAmt = 0L;
} else if(headersForm.getInputTransactions() != null) { } else if(headersForm.getInputTransactions() != null) {
feeAmt = calculateFee(headersForm.getInputTransactions()); feeAmt = calculateFee(headersForm.getInputTransactions());
} else {
Wallet wallet = getWalletFromTransactionInputs();
if(wallet != null) {
feeAmt = calculateFee(wallet.getTransactions());
}
} }
if(feeAmt != null) { if(feeAmt != null) {
@ -523,7 +528,7 @@ public class HeadersController extends TransactionFormController implements Init
} }
BlockTransaction inputTx = inputTransactions.get(input.getOutpoint().getHash()); BlockTransaction inputTx = inputTransactions.get(input.getOutpoint().getHash());
if(inputTx == null) { if(inputTx == null && headersForm.getInputTransactions() != null) {
inputTx = headersForm.getInputTransactions().get(input.getOutpoint().getHash()); inputTx = headersForm.getInputTransactions().get(input.getOutpoint().getHash());
} }
@ -557,11 +562,18 @@ public class HeadersController extends TransactionFormController implements Init
Wallet wallet = getWalletFromTransactionInputs(); Wallet wallet = getWalletFromTransactionInputs();
if(wallet != null) { if(wallet != null) {
Map<Sha256Hash, BlockTransaction> walletInputTransactions = inputTransactions;
if(walletInputTransactions == null) {
Set<Sha256Hash> refs = headersForm.getTransaction().getInputs().stream().map(txInput -> txInput.getOutpoint().getHash()).collect(Collectors.toSet());
walletInputTransactions = new HashMap<>(wallet.getTransactions());
walletInputTransactions.keySet().retainAll(refs);
}
Map<BlockTransactionHashIndex, WalletNode> selectedTxos = new LinkedHashMap<>(); Map<BlockTransactionHashIndex, WalletNode> selectedTxos = new LinkedHashMap<>();
Map<BlockTransactionHashIndex, WalletNode> walletTxos = wallet.getWalletTxos(); Map<BlockTransactionHashIndex, WalletNode> walletTxos = wallet.getWalletTxos();
for(TransactionInput txInput : headersForm.getTransaction().getInputs()) { for(TransactionInput txInput : headersForm.getTransaction().getInputs()) {
BlockTransactionHashIndex selectedTxo = walletTxos.keySet().stream().filter(txo -> txInput.getOutpoint().getHash().equals(txo.getHash()) && txInput.getOutpoint().getIndex() == txo.getIndex()) BlockTransactionHashIndex selectedTxo = walletTxos.keySet().stream().filter(txo -> txInput.getOutpoint().getHash().equals(txo.getHash()) && txInput.getOutpoint().getIndex() == txo.getIndex())
.findFirst().orElse(new BlockTransactionHashIndex(txInput.getOutpoint().getHash(), 0, null, null, txInput.getOutpoint().getIndex(), 0)); .findFirst().orElse(getBlockTransactionInput(walletInputTransactions, txInput));
selectedTxos.put(selectedTxo, walletTxos.get(selectedTxo)); selectedTxos.put(selectedTxo, walletTxos.get(selectedTxo));
} }
@ -607,19 +619,10 @@ public class HeadersController extends TransactionFormController implements Init
} }
} }
return new WalletTransaction(wallet, headersForm.getTransaction(), Collections.emptyList(), List.of(selectedTxos), payments, changeMap, fee.getValue(), inputTransactions); return new WalletTransaction(wallet, headersForm.getTransaction(), Collections.emptyList(), List.of(selectedTxos), payments, changeMap, fee.getValue(), walletInputTransactions);
} else { } else {
Map<BlockTransactionHashIndex, WalletNode> selectedTxos = headersForm.getTransaction().getInputs().stream() Map<BlockTransactionHashIndex, WalletNode> selectedTxos = headersForm.getTransaction().getInputs().stream()
.collect(Collectors.toMap(txInput -> { .collect(Collectors.toMap(txInput -> getBlockTransactionInput(inputTransactions, txInput),
if(inputTransactions != null) {
BlockTransaction blockTransaction = inputTransactions.get(txInput.getOutpoint().getHash());
if(blockTransaction != null) {
TransactionOutput txOutput = blockTransaction.getTransaction().getOutputs().get((int)txInput.getOutpoint().getIndex());
return new BlockTransactionHashIndex(blockTransaction.getHash(), blockTransaction.getHeight(), blockTransaction.getDate(), blockTransaction.getFee(), txInput.getOutpoint().getIndex(), txOutput.getValue());
}
}
return new BlockTransactionHashIndex(txInput.getOutpoint().getHash(), 0, null, null, txInput.getOutpoint().getIndex(), 0);
},
txInput -> new WalletNode("m/0"), txInput -> new WalletNode("m/0"),
(u, v) -> { throw new IllegalStateException("Duplicate TXOs"); }, (u, v) -> { throw new IllegalStateException("Duplicate TXOs"); },
LinkedHashMap::new)); LinkedHashMap::new));
@ -638,6 +641,18 @@ public class HeadersController extends TransactionFormController implements Init
} }
} }
private BlockTransactionHashIndex getBlockTransactionInput(Map<Sha256Hash, BlockTransaction> inputTransactions, TransactionInput txInput) {
if(inputTransactions != null) {
BlockTransaction blockTransaction = inputTransactions.get(txInput.getOutpoint().getHash());
if(blockTransaction != null) {
TransactionOutput txOutput = blockTransaction.getTransaction().getOutputs().get((int) txInput.getOutpoint().getIndex());
return new BlockTransactionHashIndex(blockTransaction.getHash(), blockTransaction.getHeight(), blockTransaction.getDate(), blockTransaction.getFee(), txInput.getOutpoint().getIndex(), txOutput.getValue());
}
}
return new BlockTransactionHashIndex(txInput.getOutpoint().getHash(), 0, null, null, txInput.getOutpoint().getIndex(), 0);
}
private Wallet getWalletFromTransactionInputs() { private Wallet getWalletFromTransactionInputs() {
for(TransactionInput txInput : headersForm.getTransaction().getInputs()) { for(TransactionInput txInput : headersForm.getTransaction().getInputs()) {
for(Wallet openWallet : AppServices.get().getOpenWallets().keySet()) { for(Wallet openWallet : AppServices.get().getOpenWallets().keySet()) {
@ -1147,7 +1162,12 @@ public class HeadersController extends TransactionFormController implements Init
if(feeAmt != null) { if(feeAmt != null) {
updateFee(feeAmt); updateFee(feeAmt);
} }
transactionDiagram.update(getWalletTransaction(event.getInputTransactions()));
Map<Sha256Hash, BlockTransaction> allFetchedInputTransactions = new HashMap<>(event.getInputTransactions());
if(headersForm.getInputTransactions() != null) {
allFetchedInputTransactions.putAll(headersForm.getInputTransactions());
}
transactionDiagram.update(getWalletTransaction(allFetchedInputTransactions));
} }
} }