mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-24 12:46:45 +00:00
wallet tx and addresses updating
This commit is contained in:
parent
d4d61b8d41
commit
150f65e7bd
11 changed files with 139 additions and 50 deletions
|
@ -176,6 +176,7 @@ public class AppController implements Initializable {
|
|||
openTransactionIdItem.disableProperty().bind(onlineProperty.not());
|
||||
|
||||
openWalletFile(new File("/Users/scy/.sparrow/wallets/sparta.json"));
|
||||
openWalletFile(new File("/Users/scy/.sparrow/wallets/sparta-test.json"));
|
||||
}
|
||||
|
||||
private ElectrumServer.ConnectionService createConnectionService() {
|
||||
|
|
|
@ -43,8 +43,8 @@ public class AddressTreeTable extends TreeTableView<Entry> {
|
|||
labelCol.setSortable(false);
|
||||
getColumns().add(labelCol);
|
||||
|
||||
TreeTableColumn<Entry, Long> amountCol = new TreeTableColumn<>("Value");
|
||||
amountCol.setCellValueFactory((TreeTableColumn.CellDataFeatures<Entry, Long> param) -> {
|
||||
TreeTableColumn<Entry, Number> amountCol = new TreeTableColumn<>("Value");
|
||||
amountCol.setCellValueFactory((TreeTableColumn.CellDataFeatures<Entry, Number> param) -> {
|
||||
return new ReadOnlyObjectWrapper<>(param.getValue().getValue().getValue());
|
||||
});
|
||||
amountCol.setCellFactory(p -> new AmountCell());
|
||||
|
@ -54,6 +54,9 @@ public class AddressTreeTable extends TreeTableView<Entry> {
|
|||
setEditable(true);
|
||||
setColumnResizePolicy(TreeTableView.CONSTRAINED_RESIZE_POLICY);
|
||||
|
||||
addressCol.setSortType(TreeTableColumn.SortType.ASCENDING);
|
||||
getSortOrder().add(addressCol);
|
||||
|
||||
Integer highestUsedIndex = rootEntry.getNode().getHighestUsedIndex();
|
||||
if(highestUsedIndex != null) {
|
||||
scrollTo(highestUsedIndex);
|
||||
|
@ -80,18 +83,29 @@ public class AddressTreeTable extends TreeTableView<Entry> {
|
|||
RecursiveTreeItem<Entry> rootItem = new RecursiveTreeItem<>(rootEntry, Entry::getChildren);
|
||||
setRoot(rootItem);
|
||||
rootItem.setExpanded(true);
|
||||
|
||||
if(getColumns().size() > 0 && getSortOrder().isEmpty()) {
|
||||
TreeTableColumn<Entry, ?> addressCol = getColumns().get(0);
|
||||
getSortOrder().add(addressCol);
|
||||
addressCol.setSortType(TreeTableColumn.SortType.ASCENDING);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateHistory(List<WalletNode> updatedNodes) {
|
||||
NodeEntry rootEntry = (NodeEntry)getRoot().getValue();
|
||||
|
||||
for(WalletNode updatedNode : updatedNodes) {
|
||||
NodeEntry nodeEntry = new NodeEntry(rootEntry.getWallet(), updatedNode);
|
||||
|
||||
Optional<Entry> optEntry = rootEntry.getChildren().stream().filter(childEntry -> ((NodeEntry)childEntry).getNode().equals(updatedNode)).findFirst();
|
||||
if(optEntry.isPresent()) {
|
||||
int index = rootEntry.getChildren().indexOf(optEntry.get());
|
||||
NodeEntry nodeEntry = new NodeEntry(rootEntry.getWallet(), updatedNode);
|
||||
rootEntry.getChildren().set(index, nodeEntry);
|
||||
} else {
|
||||
rootEntry.getChildren().add(nodeEntry);
|
||||
}
|
||||
}
|
||||
|
||||
sort();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,14 +11,14 @@ import javafx.scene.layout.Region;
|
|||
|
||||
import java.util.Locale;
|
||||
|
||||
class AmountCell extends TreeTableCell<Entry, Long> {
|
||||
class AmountCell extends TreeTableCell<Entry, Number> {
|
||||
public AmountCell() {
|
||||
super();
|
||||
getStyleClass().add("amount-cell");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateItem(Long amount, boolean empty) {
|
||||
protected void updateItem(Number amount, boolean empty) {
|
||||
super.updateItem(amount, empty);
|
||||
|
||||
if(empty || amount == null) {
|
||||
|
@ -28,7 +28,7 @@ class AmountCell extends TreeTableCell<Entry, Long> {
|
|||
Entry entry = getTreeTableView().getTreeItem(getIndex()).getValue();
|
||||
EntryCell.applyRowStyles(this, entry);
|
||||
|
||||
String satsValue = String.format(Locale.ENGLISH, "%,d", amount);
|
||||
String satsValue = String.format(Locale.ENGLISH, "%,d", amount.longValue());
|
||||
final String btcValue = CoinLabel.getBTCFormat().format(amount.doubleValue() / Transaction.SATOSHIS_PER_BITCOIN) + " BTC";
|
||||
|
||||
if(entry instanceof TransactionEntry) {
|
||||
|
@ -71,7 +71,6 @@ class AmountCell extends TreeTableCell<Entry, Long> {
|
|||
}
|
||||
|
||||
setText(satsValue);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,11 @@ public class RecursiveTreeItem<T> extends TreeItem<T> {
|
|||
while(change.next()){
|
||||
|
||||
if(change.wasAdded()){
|
||||
change.getAddedSubList().forEach(t-> RecursiveTreeItem.this.getChildren().add(change.getFrom(), new RecursiveTreeItem<>(t, this.graphicsFactory, childrenFactory)));
|
||||
if(change.getFrom() >= RecursiveTreeItem.this.getChildren().size()) {
|
||||
change.getAddedSubList().forEach(t-> RecursiveTreeItem.this.getChildren().add(new RecursiveTreeItem<>(t, this.graphicsFactory, childrenFactory)));
|
||||
} else {
|
||||
change.getAddedSubList().forEach(t-> RecursiveTreeItem.this.getChildren().add(change.getFrom(), new RecursiveTreeItem<>(t, this.graphicsFactory, childrenFactory)));
|
||||
}
|
||||
}
|
||||
|
||||
if(change.wasRemoved()){
|
||||
|
|
|
@ -34,17 +34,17 @@ public class TransactionsTreeTable extends TreeTableView<Entry> {
|
|||
labelCol.setSortable(true);
|
||||
getColumns().add(labelCol);
|
||||
|
||||
TreeTableColumn<Entry, Long> amountCol = new TreeTableColumn<>("Value");
|
||||
amountCol.setCellValueFactory((TreeTableColumn.CellDataFeatures<Entry, Long> param) -> {
|
||||
TreeTableColumn<Entry, Number> amountCol = new TreeTableColumn<>("Value");
|
||||
amountCol.setCellValueFactory((TreeTableColumn.CellDataFeatures<Entry, Number> param) -> {
|
||||
return new ReadOnlyObjectWrapper<>(param.getValue().getValue().getValue());
|
||||
});
|
||||
amountCol.setCellFactory(p -> new AmountCell());
|
||||
amountCol.setSortable(true);
|
||||
getColumns().add(amountCol);
|
||||
|
||||
TreeTableColumn<Entry, Long> balanceCol = new TreeTableColumn<>("Balance");
|
||||
balanceCol.setCellValueFactory((TreeTableColumn.CellDataFeatures<Entry, Long> param) -> {
|
||||
return new ReadOnlyObjectWrapper<>(param.getValue().getValue() instanceof TransactionEntry ? ((TransactionEntry)param.getValue().getValue()).getBalance() : null);
|
||||
TreeTableColumn<Entry, Number> balanceCol = new TreeTableColumn<>("Balance");
|
||||
balanceCol.setCellValueFactory((TreeTableColumn.CellDataFeatures<Entry, Number> param) -> {
|
||||
return param.getValue().getValue() instanceof TransactionEntry ? ((TransactionEntry)param.getValue().getValue()).balanceProperty() : new ReadOnlyObjectWrapper<>(null);
|
||||
});
|
||||
balanceCol.setCellFactory(p -> new AmountCell());
|
||||
balanceCol.setSortable(true);
|
||||
|
@ -62,7 +62,7 @@ public class TransactionsTreeTable extends TreeTableView<Entry> {
|
|||
setRoot(rootItem);
|
||||
rootItem.setExpanded(true);
|
||||
|
||||
if(getColumns().size() > 0) {
|
||||
if(getColumns().size() > 0 && getSortOrder().isEmpty()) {
|
||||
TreeTableColumn<Entry, ?> dateCol = getColumns().get(0);
|
||||
getSortOrder().add(dateCol);
|
||||
dateCol.setSortType(TreeTableColumn.SortType.DESCENDING);
|
||||
|
@ -72,5 +72,6 @@ public class TransactionsTreeTable extends TreeTableView<Entry> {
|
|||
public void updateHistory(List<WalletNode> updatedNodes) {
|
||||
WalletTransactionsEntry rootEntry = (WalletTransactionsEntry)getRoot().getValue();
|
||||
rootEntry.updateTransactions();
|
||||
sort();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -366,7 +366,10 @@ public class Storage {
|
|||
@Override
|
||||
public WalletNode deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
WalletNode node = getGson(false).fromJson(json, typeOfT);
|
||||
node.parseDerivation();
|
||||
|
||||
for(WalletNode childNode : node.getChildren()) {
|
||||
childNode.parseDerivation();
|
||||
if(childNode.getChildren() == null) {
|
||||
childNode.setChildren(new TreeSet<>());
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ public abstract class Entry {
|
|||
private final ObservableList<Entry> children;
|
||||
|
||||
public Entry(String label, List<Entry> entries) {
|
||||
this.labelProperty = new SimpleStringProperty(label);
|
||||
this.labelProperty = new SimpleStringProperty(this, "label", label);
|
||||
this.children = FXCollections.observableList(entries);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import com.sparrowwallet.sparrow.event.WalletEntryLabelChangedEvent;
|
|||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class NodeEntry extends Entry {
|
||||
public class NodeEntry extends Entry implements Comparable<NodeEntry> {
|
||||
private final Wallet wallet;
|
||||
private final WalletNode node;
|
||||
|
||||
|
@ -56,4 +56,9 @@ public class NodeEntry extends Entry {
|
|||
|
||||
return node.getUnspentValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(NodeEntry other) {
|
||||
return node.compareTo(other.node);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ import com.sparrowwallet.sparrow.event.WalletBlockHeightChangedEvent;
|
|||
import com.sparrowwallet.sparrow.event.WalletEntryLabelChangedEvent;
|
||||
import javafx.beans.property.IntegerProperty;
|
||||
import javafx.beans.property.IntegerPropertyBase;
|
||||
import javafx.beans.property.LongProperty;
|
||||
import javafx.beans.property.LongPropertyBase;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -20,7 +22,6 @@ public class TransactionEntry extends Entry implements Comparable<TransactionEnt
|
|||
|
||||
private final Wallet wallet;
|
||||
private final BlockTransaction blockTransaction;
|
||||
private WalletTransactionsEntry parent;
|
||||
|
||||
public TransactionEntry(Wallet wallet, BlockTransaction blockTransaction, Map<BlockTransactionHashIndex, KeyPurpose> inputs, Map<BlockTransactionHashIndex, KeyPurpose> outputs) {
|
||||
super(blockTransaction.getLabel(), createChildEntries(wallet, inputs, outputs));
|
||||
|
@ -42,10 +43,6 @@ public class TransactionEntry extends Entry implements Comparable<TransactionEnt
|
|||
return wallet;
|
||||
}
|
||||
|
||||
void setParent(WalletTransactionsEntry walletTransactionsEntry) {
|
||||
this.parent = walletTransactionsEntry;
|
||||
}
|
||||
|
||||
public BlockTransaction getBlockTransaction() {
|
||||
return blockTransaction;
|
||||
}
|
||||
|
@ -65,10 +62,6 @@ public class TransactionEntry extends Entry implements Comparable<TransactionEnt
|
|||
return value;
|
||||
}
|
||||
|
||||
public Long getBalance() {
|
||||
return parent.getBalance(this);
|
||||
}
|
||||
|
||||
public boolean isConfirming() {
|
||||
return getConfirmations() < BLOCKS_TO_CONFIRM;
|
||||
}
|
||||
|
@ -128,13 +121,12 @@ public class TransactionEntry extends Entry implements Comparable<TransactionEnt
|
|||
if (o == null || getClass() != o.getClass()) return false;
|
||||
TransactionEntry that = (TransactionEntry) o;
|
||||
return wallet.equals(that.wallet) &&
|
||||
blockTransaction.equals(that.blockTransaction) &&
|
||||
parent.equals(that.parent);
|
||||
blockTransaction.equals(that.blockTransaction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(wallet, blockTransaction, parent);
|
||||
return Objects.hash(wallet, blockTransaction);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -175,6 +167,39 @@ public class TransactionEntry extends Entry implements Comparable<TransactionEnt
|
|||
return confirmations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the wallet balance at the historical point of this transaction, as defined by BlockTransaction's compareTo method.
|
||||
*/
|
||||
private LongProperty balance;
|
||||
|
||||
public final void setBalance(long value) {
|
||||
if(balance != null || value != 0) {
|
||||
balanceProperty().set(value);
|
||||
}
|
||||
}
|
||||
|
||||
public final long getBalance() {
|
||||
return balance == null ? 0L : balance.get();
|
||||
}
|
||||
|
||||
public final LongProperty balanceProperty() {
|
||||
if(balance == null) {
|
||||
balance = new LongPropertyBase(0L) {
|
||||
|
||||
@Override
|
||||
public Object getBean() {
|
||||
return TransactionEntry.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "balance";
|
||||
}
|
||||
};
|
||||
}
|
||||
return balance;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void blockHeightChanged(WalletBlockHeightChangedEvent event) {
|
||||
if(getWallet().equals(event.getWallet())) {
|
||||
|
|
|
@ -90,6 +90,8 @@ public class WalletForm {
|
|||
if(!currentNode.getTransactionOutputs().equals(previousNode.getTransactionOutputs())) {
|
||||
changedNodes.add(currentNode);
|
||||
}
|
||||
} else {
|
||||
changedNodes.add(currentNode);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ import com.sparrowwallet.drongo.wallet.BlockTransaction;
|
|||
import com.sparrowwallet.drongo.wallet.BlockTransactionHashIndex;
|
||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||
import com.sparrowwallet.drongo.wallet.WalletNode;
|
||||
import javafx.beans.property.LongProperty;
|
||||
import javafx.beans.property.LongPropertyBase;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -15,40 +17,42 @@ public class WalletTransactionsEntry extends Entry {
|
|||
public WalletTransactionsEntry(Wallet wallet) {
|
||||
super(wallet.getName(), getWalletTransactions(wallet).stream().map(WalletTransaction::getTransactionEntry).collect(Collectors.toList()));
|
||||
this.wallet = wallet;
|
||||
getChildren().forEach(entry -> ((TransactionEntry)entry).setParent(this));
|
||||
calculateBalances();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getValue() {
|
||||
return getBalance(null);
|
||||
return getBalance();
|
||||
}
|
||||
|
||||
protected Long getBalance(TransactionEntry transactionEntry) {
|
||||
protected void calculateBalances() {
|
||||
long balance = 0L;
|
||||
for(Entry entry : getChildren()) {
|
||||
balance += entry.getValue();
|
||||
|
||||
if(entry == transactionEntry) {
|
||||
return balance;
|
||||
}
|
||||
//Note transaction entries must be in ascending order. This sorting is ultimately done according to BlockTransactions' comparator
|
||||
getChildren().sort(Comparator.comparing(TransactionEntry.class::cast));
|
||||
|
||||
for(Entry entry : getChildren()) {
|
||||
TransactionEntry transactionEntry = (TransactionEntry)entry;
|
||||
balance += entry.getValue();
|
||||
transactionEntry.setBalance(balance);
|
||||
}
|
||||
|
||||
return balance;
|
||||
setBalance(balance);
|
||||
}
|
||||
|
||||
public void updateTransactions() {
|
||||
List<Entry> current = getWalletTransactions(wallet).stream().map(WalletTransaction::getTransactionEntry).peek(entry -> entry.setParent(this)).collect(Collectors.toList());
|
||||
List<Entry> current = getWalletTransactions(wallet).stream().map(WalletTransaction::getTransactionEntry).collect(Collectors.toList());
|
||||
List<Entry> previous = new ArrayList<>(getChildren());
|
||||
for(Entry currentEntry : current) {
|
||||
int index = previous.indexOf(currentEntry);
|
||||
if (index > -1) {
|
||||
getChildren().set(index, currentEntry);
|
||||
} else {
|
||||
getChildren().add(currentEntry);
|
||||
}
|
||||
}
|
||||
|
||||
getChildren().sort(Comparator.comparing(TransactionEntry.class::cast));
|
||||
List<Entry> entriesAdded = new ArrayList<>(current);
|
||||
entriesAdded.removeAll(previous);
|
||||
getChildren().addAll(entriesAdded);
|
||||
|
||||
List<Entry> entriesRemoved = new ArrayList<>(previous);
|
||||
entriesRemoved.removeAll(current);
|
||||
getChildren().removeAll(entriesRemoved);
|
||||
|
||||
calculateBalances();
|
||||
}
|
||||
|
||||
private static Collection<WalletTransaction> getWalletTransactions(Wallet wallet) {
|
||||
|
@ -57,9 +61,7 @@ public class WalletTransactionsEntry extends Entry {
|
|||
getWalletTransactions(wallet, walletTransactionMap, wallet.getNode(KeyPurpose.RECEIVE));
|
||||
getWalletTransactions(wallet, walletTransactionMap, wallet.getNode(KeyPurpose.CHANGE));
|
||||
|
||||
List<WalletTransaction> walletTxList = new ArrayList<>(walletTransactionMap.values());
|
||||
Collections.reverse(walletTxList);
|
||||
return walletTxList;
|
||||
return new ArrayList<>(walletTransactionMap.values());
|
||||
}
|
||||
|
||||
private static void getWalletTransactions(Wallet wallet, Map<BlockTransaction, WalletTransaction> walletTransactionMap, WalletNode purposeNode) {
|
||||
|
@ -87,6 +89,39 @@ public class WalletTransactionsEntry extends Entry {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the wallet balance in total.
|
||||
*/
|
||||
private LongProperty balance;
|
||||
|
||||
public final void setBalance(long value) {
|
||||
if(balance != null || value != 0) {
|
||||
balanceProperty().set(value);
|
||||
}
|
||||
}
|
||||
|
||||
public final long getBalance() {
|
||||
return balance == null ? 0L : balance.get();
|
||||
}
|
||||
|
||||
public final LongProperty balanceProperty() {
|
||||
if(balance == null) {
|
||||
balance = new LongPropertyBase(0L) {
|
||||
|
||||
@Override
|
||||
public Object getBean() {
|
||||
return WalletTransactionsEntry.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "balance";
|
||||
}
|
||||
};
|
||||
}
|
||||
return balance;
|
||||
}
|
||||
|
||||
private static class WalletTransaction {
|
||||
private final Wallet wallet;
|
||||
private final BlockTransaction blockTransaction;
|
||||
|
|
Loading…
Reference in a new issue