mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-24 12:46:45 +00:00
receive and address pane improvements
This commit is contained in:
parent
3db7fc1e99
commit
c115f6e729
13 changed files with 189 additions and 31 deletions
2
drongo
2
drongo
|
@ -1 +1 @@
|
|||
Subproject commit 7871413573e67ed7539cf03d6deadd1a2c4abafa
|
||||
Subproject commit 11978e1f48851cd964f1c5f52a29a8e2ea432432
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,3 +6,8 @@
|
|||
-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.8), 10, 0, 0, 0);
|
||||
-fx-padding: 20;
|
||||
}
|
||||
|
||||
.receive-form .form .fieldset:horizontal .label-container {
|
||||
-fx-pref-width: 90px;
|
||||
-fx-pref-height: 25px;
|
||||
}
|
|
@ -20,13 +20,13 @@
|
|||
<BorderPane stylesheets="@receive.css, @wallet.css, @../script.css, @../general.css" styleClass="wallet-pane" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.sparrowwallet.sparrow.wallet.ReceiveController">
|
||||
<center>
|
||||
|
||||
<GridPane hgap="10.0" vgap="10.0">
|
||||
<GridPane styleClass="receive-form" hgap="10.0" vgap="10.0">
|
||||
<padding>
|
||||
<Insets left="25.0" right="25.0" top="25.0" />
|
||||
</padding>
|
||||
<columnConstraints>
|
||||
<ColumnConstraints percentWidth="70" />
|
||||
<ColumnConstraints percentWidth="30" />
|
||||
<ColumnConstraints percentWidth="80" />
|
||||
<ColumnConstraints percentWidth="20" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints />
|
||||
|
@ -34,7 +34,7 @@
|
|||
<Form GridPane.columnIndex="0" GridPane.rowIndex="0">
|
||||
<Fieldset inputGrow="SOMETIMES" text="Receive">
|
||||
<Field text="Address:">
|
||||
<CopyableTextField fx:id="address" styleClass="address-text-field" editable="false" prefWidth="350"/>
|
||||
<CopyableTextField fx:id="address" styleClass="address-text-field" editable="false"/>
|
||||
</Field>
|
||||
<Field text="Label:">
|
||||
<TextField fx:id="label" />
|
||||
|
@ -56,7 +56,7 @@
|
|||
|
||||
<Form GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.rowIndex="2">
|
||||
<Fieldset inputGrow="SOMETIMES" text="Required Script">
|
||||
<Field text="ScriptPubKey:">
|
||||
<Field text="ScriptPubKey">
|
||||
<VirtualizedScrollPane>
|
||||
<content>
|
||||
<CodeArea fx:id="scriptPubKeyArea" editable="false" wrapText="true" prefHeight="42" maxHeight="42" styleClass="uneditable-codearea" />
|
||||
|
@ -66,6 +66,18 @@
|
|||
</Fieldset>
|
||||
</Form>
|
||||
|
||||
<Form GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.rowIndex="3">
|
||||
<Fieldset inputGrow="SOMETIMES" text="Output Descriptor">
|
||||
<Field text="Descriptor:">
|
||||
<VirtualizedScrollPane>
|
||||
<content>
|
||||
<CodeArea fx:id="outputDescriptor" editable="false" wrapText="true" prefHeight="42" maxHeight="42" styleClass="uneditable-codearea" />
|
||||
</content>
|
||||
</VirtualizedScrollPane>
|
||||
</Field>
|
||||
</Fieldset>
|
||||
</Form>
|
||||
|
||||
</GridPane>
|
||||
</center>
|
||||
<bottom>
|
||||
|
|
Loading…
Reference in a new issue