wallet and settings initial work

This commit is contained in:
Craig Raw 2020-04-17 10:03:50 +02:00
parent 950ae07df5
commit 17b03a6750
18 changed files with 417 additions and 9 deletions

View file

@ -16,7 +16,7 @@ repositories {
javafx { javafx {
version = "14" version = "14"
modules = [ 'javafx.controls', 'javafx.fxml' ] modules = [ 'javafx.controls', 'javafx.fxml', 'javafx.swing' ]
} }
java { java {
@ -46,7 +46,7 @@ dependencies {
mainClassName = 'com.sparrowwallet.sparrow/com.sparrowwallet.sparrow.MainApp' mainClassName = 'com.sparrowwallet.sparrow/com.sparrowwallet.sparrow.MainApp'
run { run {
applicationDefaultJvmArgs = ["-Xdock:name=Sparrow", "-Xdock:icon=/Users/scy/git/sparrow/src/main/resources/sparrow.png", "--add-opens=javafx.graphics/com.sun.javafx.css=org.controlsfx.controls", "--add-opens=javafx.graphics/javafx.scene=org.controlsfx.controls"] applicationDefaultJvmArgs = ["-Xdock:name=Sparrow", "-Xdock:icon=/Users/scy/git/sparrow/src/main/resources/sparrow.png", "--add-opens=javafx.graphics/com.sun.javafx.css=org.controlsfx.controls", "--add-opens=javafx.graphics/javafx.scene=org.controlsfx.controls", "--add-opens=javafx.controls/com.sun.javafx.scene.control.behavior=org.controlsfx.controls", "--add-opens=javafx.controls/com.sun.javafx.scene.control.inputmap=org.controlsfx.controls", "--add-opens=javafx.graphics/com.sun.javafx.scene.traversal=org.controlsfx.controls"]
} }
jlink { jlink {
@ -61,7 +61,7 @@ jlink {
options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages', '--ignore-signing-information', '--exclude-files', '**.png'] options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages', '--ignore-signing-information', '--exclude-files', '**.png']
launcher { launcher {
name = 'sparrow' name = 'sparrow'
jvmArgs = ["--add-opens=javafx.graphics/com.sun.javafx.css=org.controlsfx.controls", "--add-opens=javafx.graphics/javafx.scene=org.controlsfx.controls"] jvmArgs = ["--add-opens=javafx.graphics/com.sun.javafx.css=org.controlsfx.controls", "--add-opens=javafx.graphics/javafx.scene=org.controlsfx.controls", "--add-opens=javafx.controls/com.sun.javafx.scene.control.behavior=org.controlsfx.controls", "--add-opens=javafx.controls/com.sun.javafx.scene.control.inputmap=org.controlsfx.controls", "--add-opens=javafx.graphics/com.sun.javafx.scene.traversal=org.controlsfx.controls"]
} }
addExtraDependencies("javafx") addExtraDependencies("javafx")
jpackage { jpackage {

2
drongo

@ -1 +1 @@
Subproject commit 0cebee3d22740d0ab38657b1deaba67fe282f920 Subproject commit 08e8df0807a01b2716ac80e9d6d9e2c113025848

View file

@ -7,11 +7,14 @@ import com.sparrowwallet.drongo.Utils;
import com.sparrowwallet.drongo.protocol.Transaction; import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.drongo.psbt.PSBT; import com.sparrowwallet.drongo.psbt.PSBT;
import com.sparrowwallet.drongo.psbt.PSBTParseException; import com.sparrowwallet.drongo.psbt.PSBTParseException;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.control.TextAreaDialog; import com.sparrowwallet.sparrow.control.TextAreaDialog;
import com.sparrowwallet.sparrow.event.TabEvent; import com.sparrowwallet.sparrow.event.TabEvent;
import com.sparrowwallet.sparrow.event.TransactionTabChangedEvent; import com.sparrowwallet.sparrow.event.TransactionTabChangedEvent;
import com.sparrowwallet.sparrow.event.TransactionTabSelectedEvent; import com.sparrowwallet.sparrow.event.TransactionTabSelectedEvent;
import com.sparrowwallet.sparrow.transaction.TransactionController; import com.sparrowwallet.sparrow.transaction.TransactionController;
import com.sparrowwallet.sparrow.wallet.WalletController;
import com.sparrowwallet.sparrow.wallet.WalletForm;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
@ -88,6 +91,8 @@ public class AppController implements Initializable {
showTxHex.setSelected(true); showTxHex.setSelected(true);
showTxHexProperty = true; showTxHexProperty = true;
addWalletTab(null, new Wallet());
} }
public void openFromFile(ActionEvent event) { public void openFromFile(ActionEvent event) {
@ -192,6 +197,36 @@ public class AppController implements Initializable {
showTxHexProperty = item.isSelected(); showTxHexProperty = item.isSelected();
} }
public void newWallet(ActionEvent event) {
Tab tab = addWalletTab(null, new Wallet());
tabs.getSelectionModel().select(tab);
}
public Tab addWalletTab(String name, Wallet wallet) {
try {
String tabName = name;
if(tabName == null || tabName.isEmpty()) {
tabName = "New wallet";
}
Tab tab = new Tab(tabName);
TabData tabData = new TabData(TabData.TabType.WALLET);
tab.setUserData(tabData);
tab.setContextMenu(getTabContextMenu(tab));
tab.setClosable(true);
FXMLLoader walletLoader = new FXMLLoader(getClass().getResource("wallet/wallet.fxml"));
tab.setContent(walletLoader.load());
WalletController controller = walletLoader.getController();
WalletForm walletForm = new WalletForm(wallet);
controller.setWalletForm(walletForm);
tabs.getTabs().add(tab);
return tab;
} catch(IOException e) {
throw new RuntimeException(e);
}
}
public void openExamples(ActionEvent event) { public void openExamples(ActionEvent event) {
try { try {
addTransactionTab("p2pkh", "01000000019c2e0f24a03e72002a96acedb12a632e72b6b74c05dc3ceab1fe78237f886c48010000006a47304402203da9d487be5302a6d69e02a861acff1da472885e43d7528ed9b1b537a8e2cac9022002d1bca03a1e9715a99971bafe3b1852b7a4f0168281cbd27a220380a01b3307012102c9950c622494c2e9ff5a003e33b690fe4832477d32c2d256c67eab8bf613b34effffffff02b6f50500000000001976a914bdf63990d6dc33d705b756e13dd135466c06b3b588ac845e0201000000001976a9145fb0e9755a3424efd2ba0587d20b1e98ee29814a88ac06241559"); addTransactionTab("p2pkh", "01000000019c2e0f24a03e72002a96acedb12a632e72b6b74c05dc3ceab1fe78237f886c48010000006a47304402203da9d487be5302a6d69e02a861acff1da472885e43d7528ed9b1b537a8e2cac9022002d1bca03a1e9715a99971bafe3b1852b7a4f0168281cbd27a220380a01b3307012102c9950c622494c2e9ff5a003e33b690fe4832477d32c2d256c67eab8bf613b34effffffff02b6f50500000000001976a914bdf63990d6dc33d705b756e13dd135466c06b3b588ac845e0201000000001976a9145fb0e9755a3424efd2ba0587d20b1e98ee29814a88ac06241559");

View file

@ -32,6 +32,6 @@ public class TabData {
} }
public enum TabType { public enum TabType {
TRANSACTION WALLET, TRANSACTION
} }
} }

View file

@ -0,0 +1,14 @@
package com.sparrowwallet.sparrow.control;
import javafx.beans.NamedArg;
import javafx.scene.control.ChoiceBox;
public class EnumChoiceBox<E extends Enum<E>> extends ChoiceBox<E> {
public EnumChoiceBox(@NamedArg("enumType") String enumType) throws Exception {
Class<E> enumClass = (Class<E>) Class.forName(enumType);
getItems().setAll(enumClass.getEnumConstants());
}
}

View file

@ -17,6 +17,7 @@ import java.time.Duration;
import java.util.List; import java.util.List;
import static org.fxmisc.richtext.model.TwoDimensional.Bias.Backward; import static org.fxmisc.richtext.model.TwoDimensional.Bias.Backward;
import static com.sparrowwallet.drongo.protocol.ScriptType.*;
public abstract class TransactionFormController { public abstract class TransactionFormController {
protected void addPieData(PieChart pie, List<TransactionOutput> outputs) { protected void addPieData(PieChart pie, List<TransactionOutput> outputs) {
@ -57,7 +58,7 @@ public abstract class TransactionFormController {
} }
protected void appendScript(CodeArea codeArea, Script script, Script redeemScript, Script witnessScript) { protected void appendScript(CodeArea codeArea, Script script, Script redeemScript, Script witnessScript) {
if(ScriptPattern.isP2PKH(script)) { if(P2PKH.isScriptType(script)) {
codeArea.append(script.getChunks().get(0).toString(), "script-opcode"); codeArea.append(script.getChunks().get(0).toString(), "script-opcode");
codeArea.append(" ", ""); codeArea.append(" ", "");
codeArea.append(script.getChunks().get(1).toString(), "script-opcode"); codeArea.append(script.getChunks().get(1).toString(), "script-opcode");
@ -67,17 +68,17 @@ public abstract class TransactionFormController {
codeArea.append(script.getChunks().get(3).toString(), "script-opcode"); codeArea.append(script.getChunks().get(3).toString(), "script-opcode");
codeArea.append(" ", ""); codeArea.append(" ", "");
codeArea.append(script.getChunks().get(4).toString(), "script-opcode"); codeArea.append(script.getChunks().get(4).toString(), "script-opcode");
} else if(ScriptPattern.isP2SH(script)) { } else if(P2SH.isScriptType(script)) {
codeArea.append(script.getChunks().get(0).toString(), "script-opcode"); codeArea.append(script.getChunks().get(0).toString(), "script-opcode");
codeArea.append(" ", ""); codeArea.append(" ", "");
codeArea.append("<sh>", "script-hash"); codeArea.append("<sh>", "script-hash");
codeArea.append(" ", ""); codeArea.append(" ", "");
codeArea.append(script.getChunks().get(2).toString(), "script-opcode"); codeArea.append(script.getChunks().get(2).toString(), "script-opcode");
} else if(ScriptPattern.isP2WPKH(script)) { } else if(P2WPKH.isScriptType(script)) {
codeArea.append(script.getChunks().get(0).toString(), "script-opcode"); codeArea.append(script.getChunks().get(0).toString(), "script-opcode");
codeArea.append(" ", ""); codeArea.append(" ", "");
codeArea.append("<wpkh>", "script-hash"); codeArea.append("<wpkh>", "script-hash");
} else if(ScriptPattern.isP2WSH(script)) { } else if(P2WSH.isScriptType(script)) {
codeArea.append(script.getChunks().get(0).toString(), "script-opcode"); codeArea.append(script.getChunks().get(0).toString(), "script-opcode");
codeArea.append(" ", ""); codeArea.append(" ", "");
codeArea.append("<wsh>", "script-hash"); codeArea.append("<wsh>", "script-hash");

View file

@ -0,0 +1,5 @@
package com.sparrowwallet.sparrow.wallet;
public enum Function {
TRANSACTIONS, SEND, RECEIVE, ADDRESSES, POLICIES, SETTINGS;
}

View file

@ -0,0 +1,69 @@
package com.sparrowwallet.sparrow.wallet;
import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.ScriptType;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.CopyableLabel;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import org.controlsfx.control.RangeSlider;
import tornadofx.control.Fieldset;
import java.net.URL;
import java.util.ResourceBundle;
public class SettingsController extends WalletFormController implements Initializable {
@FXML
private ComboBox<PolicyType> policyType;
@FXML
private TextField policy;
@FXML
private ComboBox<ScriptType> scriptType;
@FXML
private Fieldset multisigFieldset;
@FXML
private RangeSlider multisigControl;
@FXML
private CopyableLabel multisigLowLabel;
@FXML
private CopyableLabel multisigHighLabel;
@FXML
private TabPane keystoreTabs;
@FXML ComboBox testType;
@Override
public void initialize(URL location, ResourceBundle resources) {
EventManager.get().register(this);
}
@Override
public void initializeView() {
policyType.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, policyType) -> {
scriptType.getSelectionModel().select(policyType.getDefaultScriptType());
multisigFieldset.setVisible(policyType.equals(PolicyType.MULTI));
});
multisigLowLabel.textProperty().bind(multisigControl.lowValueProperty().asString("%.0f") );
multisigHighLabel.textProperty().bind(multisigControl.highValueProperty().asString("%.0f"));
multisigFieldset.managedProperty().bind(multisigFieldset.visibleProperty());
if(walletForm.getWallet().getPolicyType() != null) {
policyType.getSelectionModel().select(walletForm.getWallet().getPolicyType());
} else {
policyType.getSelectionModel().select(0);
}
}
}

View file

@ -0,0 +1,61 @@
package com.sparrowwallet.sparrow.wallet;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.EventManager;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
public class WalletController extends WalletFormController implements Initializable {
@FXML
private BorderPane tabContent;
@FXML
private StackPane walletPane;
@FXML
private ToggleGroup walletMenu;
@Override
public void initialize(URL location, ResourceBundle resources) {
EventManager.get().register(this);
}
public void initializeView() {
walletMenu.selectedToggleProperty().addListener((observable, oldValue, selectedToggle) -> {
Function function = (Function)selectedToggle.getUserData();
boolean existing = false;
for(Node walletFunction : walletPane.getChildren()) {
if(walletFunction.getUserData().equals(function)) {
existing = true;
walletFunction.setViewOrder(1);
} else {
walletFunction.setViewOrder(0);
}
}
try {
if(!existing) {
FXMLLoader functionLoader = new FXMLLoader(AppController.class.getResource("wallet/" + function.toString().toLowerCase() + ".fxml"));
Node walletFunction = functionLoader.load();
WalletFormController controller = functionLoader.getController();
controller.setWalletForm(getWalletForm());
walletFunction.setViewOrder(1);
walletPane.getChildren().add(walletFunction);
}
} catch (IOException e) {
throw new IllegalStateException("Can't find pane", e);
}
});
}
}

View file

@ -0,0 +1,19 @@
package com.sparrowwallet.sparrow.wallet;
import com.sparrowwallet.drongo.wallet.Wallet;
public class WalletForm {
private Wallet wallet;
public WalletForm(Wallet wallet) {
this.wallet = wallet;
}
public Wallet getWallet() {
return wallet;
}
public void setWallet(Wallet wallet) {
this.wallet = wallet;
}
}

View file

@ -0,0 +1,16 @@
package com.sparrowwallet.sparrow.wallet;
public abstract class WalletFormController {
public WalletForm walletForm;
public WalletForm getWalletForm() {
return walletForm;
}
public void setWalletForm(WalletForm walletForm) {
this.walletForm = walletForm;
initializeView();
}
public abstract void initializeView();
}

View file

@ -8,4 +8,5 @@ open module com.sparrowwallet.sparrow {
requires com.sparrowwallet.drongo; requires com.sparrowwallet.drongo;
requires com.google.common; requires com.google.common;
requires flowless; requires flowless;
requires javafx.swing;
} }

BIN
src/main/resources/bird.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -12,6 +12,7 @@
<menus> <menus>
<Menu mnemonicParsing="false" text="File"> <Menu mnemonicParsing="false" text="File">
<items> <items>
<MenuItem mnemonicParsing="false" text="New Wallet" onAction="#newWallet"/>
<Menu mnemonicParsing="false" text="Open"> <Menu mnemonicParsing="false" text="Open">
<items> <items>
<MenuItem text="File..." onAction="#openFromFile"/> <MenuItem text="File..." onAction="#openFromFile"/>

View file

@ -0,0 +1,11 @@
.form .fieldset:horizontal .field {
-fx-pref-height: 40px;
}
.form .fieldset:horizontal .label-container {
-fx-alignment: center-left;
}
.form .fieldset:horizontal .input-container {
-fx-alignment: center-left;
}

View file

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.collections.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import tornadofx.control.*?>
<?import org.controlsfx.control.RangeSlider?>
<?import com.sparrowwallet.sparrow.control.CopyableLabel?>
<?import com.sparrowwallet.drongo.policy.PolicyType?>
<?import com.sparrowwallet.drongo.protocol.ScriptType?>
<GridPane hgap="10.0" vgap="10.0" stylesheets="@settings.css, @../general.css" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.sparrowwallet.sparrow.wallet.SettingsController">
<padding>
<Insets left="25.0" right="25.0" top="25.0" />
</padding>
<columnConstraints>
<ColumnConstraints percentWidth="50" />
<ColumnConstraints percentWidth="50" />
</columnConstraints>
<rowConstraints>
<RowConstraints />
<RowConstraints />
</rowConstraints>
<Form GridPane.columnIndex="0" GridPane.rowIndex="0">
<Fieldset inputGrow="SOMETIMES" text="Settings">
<Field text="Policy Type:">
<ComboBox fx:id="policyType">
<items>
<FXCollections fx:factory="observableArrayList">
<PolicyType fx:constant="SINGLE" />
<PolicyType fx:constant="MULTI" />
<PolicyType fx:constant="CUSTOM" />
</FXCollections>
</items>
</ComboBox>
</Field>
<Field text="Script Type:">
<ComboBox fx:id="scriptType">
<items>
<FXCollections fx:factory="observableArrayList">
<ScriptType fx:constant="P2PK" />
<ScriptType fx:constant="P2PKH" />
<ScriptType fx:constant="P2SH" />
<ScriptType fx:constant="P2SH_P2WPKH" />
<ScriptType fx:constant="P2SH_P2WSH" />
<ScriptType fx:constant="P2WPKH" />
<ScriptType fx:constant="P2WSH" />
</FXCollections>
</items>
</ComboBox>
</Field>
</Fieldset>
</Form>
<Form GridPane.columnIndex="1" GridPane.rowIndex="0">
<Fieldset inputGrow="SOMETIMES" text="" fx:id="multisigFieldset">
<Field text="Cosigners:">
<RangeSlider fx:id="multisigControl" showTickMarks="true" showTickLabels="true" blockIncrement="1" min="2" max="10" lowValue="2" highValue="3" snapToTicks="true" majorTickUnit="1" minorTickCount="0" />
</Field>
<Field text="M of N:">
<CopyableLabel fx:id="multisigLowLabel" />
<CopyableLabel text="/"/>
<CopyableLabel fx:id="multisigHighLabel" />
</Field>
</Fieldset>
</Form>
<Form GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.rowIndex="1">
<Fieldset inputGrow="SOMETIMES" text="Default Policy">
<Field text="Policy:">
<TextField fx:id="policy" />
</Field>
</Fieldset>
</Form>
<TabPane fx:id="keystoreTabs" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.rowIndex="2">
</TabPane>
</GridPane>

View file

@ -0,0 +1,21 @@
.list-menu {
-fx-pref-width: 180;
-fx-background-color: #3da0e3;
}
.list-item {
-fx-pref-width: 180;
-fx-background-color: #3da0e3;
}
.list-item * {
-fx-fill: #fff;
}
.list-item:hover {
-fx-background-color: #4aa7e5;
}
.list-item:selected {
-fx-background-color: #1e88cf;
}

View file

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import org.controlsfx.glyphfont.Glyph?>
<?import com.sparrowwallet.sparrow.wallet.Function?>
<BorderPane fx:id="tabContent" stylesheets="@wallet.css, @../general.css" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:controller="com.sparrowwallet.sparrow.wallet.WalletController">
<left>
<VBox styleClass="list-menu">
<ToggleButton VBox.vgrow="ALWAYS" text="Transactions" contentDisplay="TOP" styleClass="list-item" maxHeight="Infinity">
<toggleGroup>
<ToggleGroup fx:id="walletMenu" />
</toggleGroup>
<graphic>
<Glyph fontFamily="FontAwesome" icon="BTC" />
</graphic>
<userData>
<Function fx:constant="TRANSACTIONS"/>
</userData>
</ToggleButton>
<ToggleButton VBox.vgrow="ALWAYS" text="Send" contentDisplay="TOP" styleClass="list-item" maxHeight="Infinity" toggleGroup="$walletMenu">
<graphic>
<Glyph fontFamily="FontAwesome" icon="SEND" />
</graphic>
<userData>
<Function fx:constant="SEND"/>
</userData>
</ToggleButton>
<ToggleButton VBox.vgrow="ALWAYS" text="Receive" contentDisplay="TOP" styleClass="list-item" maxHeight="Infinity" toggleGroup="$walletMenu">
<graphic>
<Glyph fontFamily="FontAwesome" icon="ARROW_DOWN" />
</graphic>
<userData>
<Function fx:constant="RECEIVE"/>
</userData>
</ToggleButton>
<ToggleButton VBox.vgrow="ALWAYS" text="Addresses" contentDisplay="TOP" styleClass="list-item" maxHeight="Infinity" toggleGroup="$walletMenu">
<graphic>
<Glyph fontFamily="FontAwesome" icon="TH_LIST" />
</graphic>
<userData>
<Function fx:constant="ADDRESSES"/>
</userData>
</ToggleButton>
<ToggleButton VBox.vgrow="ALWAYS" text="Policies" contentDisplay="TOP" styleClass="list-item" maxHeight="Infinity" toggleGroup="$walletMenu">
<graphic>
<Glyph fontFamily="FontAwesome" icon="FILE_TEXT_ALT" />
</graphic>
<userData>
<Function fx:constant="POLICIES"/>
</userData>
</ToggleButton>
<ToggleButton VBox.vgrow="ALWAYS" text="Settings" contentDisplay="TOP" styleClass="list-item" maxHeight="Infinity" toggleGroup="$walletMenu">
<graphic>
<Glyph fontFamily="FontAwesome" icon="COG" />
</graphic>
<userData>
<Function fx:constant="SETTINGS"/>
</userData>
</ToggleButton>
</VBox>
</left>
<center>
<StackPane fx:id="walletPane">
</StackPane>
</center>
</BorderPane>