receive and address pane improvements

This commit is contained in:
Craig Raw
2020-05-28 11:42:42 +02:00
parent 3db7fc1e99
commit c115f6e729
13 changed files with 189 additions and 31 deletions
@@ -5,8 +5,10 @@ import com.sparrowwallet.drongo.address.Address;
import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.event.ReceiveActionEvent;
import com.sparrowwallet.sparrow.event.ReceiveToEvent;
import com.sparrowwallet.sparrow.wallet.Entry;
import com.sparrowwallet.sparrow.wallet.NodeEntry;
import javafx.application.Platform;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.event.Event;
import javafx.geometry.Pos;
@@ -27,16 +29,11 @@ public class AddressTreeTable extends TreeTableView<Entry> {
public void initialize(NodeEntry rootEntry) {
getStyleClass().add("address-treetable");
String address = null;
TreeItem<Entry> rootItem = new TreeItem<>(rootEntry);
for(Entry childEntry : rootEntry.getChildren()) {
TreeItem<Entry> childItem = new TreeItem<>(childEntry);
rootItem.getChildren().add(childItem);
address = rootEntry.getNode().getAddress().toString();
}
String address = rootEntry.getNode().getAddress().toString();
RecursiveTreeItem<Entry> rootItem = new RecursiveTreeItem<>(rootEntry, Entry::getChildren);
setRoot(rootItem);
rootItem.setExpanded(true);
setRoot(rootItem);
setShowRoot(false);
TreeTableColumn<Entry, Entry> addressCol = new TreeTableColumn<>("Address / Outpoints");
@@ -249,6 +246,7 @@ public class AddressTreeTable extends TreeTableView<Entry> {
receiveButton.setOnAction(event -> {
NodeEntry nodeEntry = (NodeEntry)getTreeTableView().getTreeItem(getIndex()).getValue();
EventManager.get().post(new ReceiveActionEvent(nodeEntry));
Platform.runLater(() -> EventManager.get().post(new ReceiveToEvent(nodeEntry)));
});
}
@@ -0,0 +1,72 @@
package com.sparrowwallet.sparrow.control;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.Node;
import javafx.scene.control.TreeItem;
import javafx.util.Callback;
import java.util.List;
import java.util.stream.Collectors;
public class RecursiveTreeItem<T> extends TreeItem<T> {
private final Callback<T, ObservableList<T>> childrenFactory;
private final Callback<T, Node> graphicsFactory;
public RecursiveTreeItem(Callback<T, ObservableList<T>> childrenFactory){
this(null, childrenFactory);
}
public RecursiveTreeItem(final T value, Callback<T, ObservableList<T>> childrenFactory){
this(value, (item) -> null, childrenFactory);
}
public RecursiveTreeItem(final T value, Callback<T, Node> graphicsFactory, Callback<T, ObservableList<T>> childrenFactory){
super(value, graphicsFactory.call(value));
this.graphicsFactory = graphicsFactory;
this.childrenFactory = childrenFactory;
if(value != null) {
addChildrenListener(value);
}
valueProperty().addListener((obs, oldValue, newValue)->{
if(newValue != null){
addChildrenListener(newValue);
}
});
this.setExpanded(true);
}
private void addChildrenListener(T value){
final ObservableList<T> children = childrenFactory.call(value);
children.forEach(child -> RecursiveTreeItem.this.getChildren().add(
new RecursiveTreeItem<>(child, this.graphicsFactory, childrenFactory)));
children.addListener((ListChangeListener<T>) change -> {
while(change.next()){
if(change.wasAdded()){
change.getAddedSubList().forEach(t-> RecursiveTreeItem.this.getChildren().add(
new RecursiveTreeItem<>(t, this.graphicsFactory, childrenFactory)));
}
if(change.wasRemoved()){
change.getRemoved().forEach(t->{
final List<TreeItem<T>> itemsToRemove = RecursiveTreeItem.this
.getChildren()
.stream()
.filter(treeItem -> treeItem.getValue().equals(t))
.collect(Collectors.toList());
RecursiveTreeItem.this.getChildren().removeAll(itemsToRemove);
});
}
}
});
}
}
@@ -3,7 +3,7 @@ package com.sparrowwallet.sparrow.event;
import com.sparrowwallet.sparrow.wallet.NodeEntry;
public class ReceiveActionEvent {
private NodeEntry receiveEntry;
private final NodeEntry receiveEntry;
public ReceiveActionEvent(NodeEntry receiveEntry) {
this.receiveEntry = receiveEntry;
@@ -0,0 +1,15 @@
package com.sparrowwallet.sparrow.event;
import com.sparrowwallet.sparrow.wallet.NodeEntry;
public class ReceiveToEvent {
private final NodeEntry receiveEntry;
public ReceiveToEvent(NodeEntry receiveEntry) {
this.receiveEntry = receiveEntry;
}
public NodeEntry getReceiveEntry() {
return receiveEntry;
}
}
@@ -18,6 +18,8 @@ import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Base64;
import java.util.Iterator;
import java.util.TreeSet;
import java.util.zip.*;
import static com.sparrowwallet.drongo.crypto.Argon2KeyDeriver.SPRW1_PARAMETERS;
@@ -49,14 +51,16 @@ public class Storage {
return getGson(true);
}
private static Gson getGson(boolean includeKeystoreSerializer) {
private static Gson getGson(boolean includeWalletSerializers) {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(ExtendedKey.class, new ExtendedPublicKeySerializer());
gsonBuilder.registerTypeAdapter(ExtendedKey.class, new ExtendedPublicKeyDeserializer());
gsonBuilder.registerTypeAdapter(byte[].class, new ByteArraySerializer());
gsonBuilder.registerTypeAdapter(byte[].class, new ByteArrayDeserializer());
if(includeKeystoreSerializer) {
if(includeWalletSerializers) {
gsonBuilder.registerTypeAdapter(Keystore.class, new KeystoreSerializer());
gsonBuilder.registerTypeAdapter(Wallet.Node.class, new NodeSerializer());
gsonBuilder.registerTypeAdapter(Wallet.Node.class, new NodeDeserializer());
}
return gsonBuilder.setPrettyPrinting().disableHtmlEscaping().create();
@@ -266,7 +270,6 @@ public class Storage {
private static class KeystoreSerializer implements JsonSerializer<Keystore> {
@Override
public JsonElement serialize(Keystore keystore, Type typeOfSrc, JsonSerializationContext context) {
JsonObject jsonObject = (JsonObject)getGson(false).toJsonTree(keystore);
if(keystore.hasSeed()) {
jsonObject.remove("extendedPublicKey");
@@ -277,6 +280,42 @@ public class Storage {
}
}
private static class NodeSerializer implements JsonSerializer<Wallet.Node> {
@Override
public JsonElement serialize(Wallet.Node node, Type typeOfSrc, JsonSerializationContext context) {
JsonObject jsonObject = (JsonObject)getGson(false).toJsonTree(node);
JsonArray children = jsonObject.getAsJsonArray("children");
Iterator<JsonElement> iter = children.iterator();
while(iter.hasNext()) {
JsonObject childObject = (JsonObject)iter.next();
if(childObject.get("label") == null) {
iter.remove();
}
if(childObject.get("children") != null && childObject.getAsJsonArray("children").size() == 0) {
childObject.remove("children");
}
}
return jsonObject;
}
}
private static class NodeDeserializer implements JsonDeserializer<Wallet.Node> {
@Override
public Wallet.Node deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
Wallet.Node node = getGson(false).fromJson(json, typeOfT);
for(Wallet.Node childNode : node.getChildren()) {
if(childNode.getChildren() == null) {
childNode.setChildren(new TreeSet<>());
}
}
return node;
}
}
public static class WalletAndKey {
public final Wallet wallet;
public final Key key;
@@ -1,20 +1,23 @@
package com.sparrowwallet.sparrow.wallet;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import java.util.ArrayList;
import java.util.List;
public abstract class Entry {
private final SimpleStringProperty labelProperty;
private final List<Entry> children = new ArrayList<>();
private final ObservableList<Entry> children;
public Entry(String label) {
public Entry(String label, List<Entry> entries) {
this.labelProperty = new SimpleStringProperty(label);
this.children = FXCollections.observableList(entries);
}
public Entry(SimpleStringProperty labelProperty) {
public Entry(SimpleStringProperty labelProperty, ObservableList<Entry> children) {
this.labelProperty = labelProperty;
this.children = children;
}
public String getLabel() {
@@ -25,7 +28,7 @@ public abstract class Entry {
return labelProperty;
}
public List<Entry> getChildren() {
public ObservableList<Entry> getChildren() {
return children;
}
@@ -2,11 +2,13 @@ package com.sparrowwallet.sparrow.wallet;
import com.sparrowwallet.drongo.wallet.Wallet;
import java.util.stream.Collectors;
public class NodeEntry extends Entry {
private final Wallet.Node node;
public NodeEntry(Wallet.Node node) {
super(node.getLabel());
super(node.getLabel(), node.getChildren().stream().map(NodeEntry::new).collect(Collectors.toList()));
this.node = node;
labelProperty().addListener((observable, oldValue, newValue) -> node.setLabel(newValue));
@@ -1,5 +1,6 @@
package com.sparrowwallet.sparrow.wallet;
import com.google.common.eventbus.Subscribe;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.client.j2se.MatrixToImageConfig;
import com.google.zxing.client.j2se.MatrixToImageWriter;
@@ -9,8 +10,7 @@ import com.sparrowwallet.drongo.KeyPurpose;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.CopyableLabel;
import com.sparrowwallet.sparrow.control.CopyableTextField;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import com.sparrowwallet.sparrow.event.ReceiveToEvent;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
@@ -43,6 +43,9 @@ public class ReceiveController extends WalletFormController implements Initializ
@FXML
private CodeArea scriptPubKeyArea;
@FXML
private CodeArea outputDescriptor;
private NodeEntry currentEntry;
@Override
@@ -78,6 +81,9 @@ public class ReceiveController extends WalletFormController implements Initializ
scriptPubKeyArea.clear();
appendScript(scriptPubKeyArea, nodeEntry.getNode().getOutputScript(), null, null);
outputDescriptor.clear();
outputDescriptor.appendText(nodeEntry.getNode().getOutputDescriptor());
}
private Image getQrCode(String address) {
@@ -101,4 +107,9 @@ public class ReceiveController extends WalletFormController implements Initializ
NodeEntry freshEntry = getWalletForm().getFreshNodeEntry(KeyPurpose.RECEIVE, currentEntry);
setNodeEntry(freshEntry);
}
@Subscribe
public void receiveTo(ReceiveToEvent event) {
setNodeEntry(event.getReceiveEntry());
}
}
@@ -3,6 +3,7 @@ package com.sparrowwallet.sparrow.wallet;
import com.google.common.eventbus.Subscribe;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.event.ReceiveActionEvent;
import com.sparrowwallet.sparrow.event.WalletChangedEvent;
import javafx.application.Platform;
import javafx.fxml.FXML;
@@ -97,4 +98,9 @@ public class WalletController extends WalletFormController implements Initializa
public void walletChanged(WalletChangedEvent event) {
configure(walletForm.getWallet().isValid());
}
@Subscribe
public void receiveAction(ReceiveActionEvent event) {
selectFunction(Function.RECEIVE);
}
}
@@ -52,11 +52,6 @@ public class WalletForm {
} else {
Wallet.Node purposeNode = getWallet().getNode(keyPurpose);
purposeEntry = new NodeEntry(purposeNode);
for(Wallet.Node childNode : purposeNode.getChildren()) {
NodeEntry childEntry = new NodeEntry(childNode);
purposeEntry.getChildren().add(childEntry);
}
accountEntries.add(purposeEntry);
}