-Adds Joinstr to the Tool menu

-Adds Joinstr main display and some controls
This commit is contained in:
QcMrHyde 2025-05-13 23:59:57 -04:00
parent c77f52f7f6
commit b8820b3f44
21 changed files with 538 additions and 3 deletions

View file

@ -19,6 +19,8 @@ import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
import com.sparrowwallet.sparrow.io.*;
import com.sparrowwallet.sparrow.io.bbqr.BBQR;
import com.sparrowwallet.sparrow.io.bbqr.BBQRType;
import com.sparrowwallet.sparrow.joinstr.JoinstrController;
import com.sparrowwallet.sparrow.joinstr.JoinstrForm;
import com.sparrowwallet.sparrow.net.ElectrumServer;
import com.sparrowwallet.sparrow.net.ServerType;
import com.sparrowwallet.sparrow.settings.SettingsGroup;
@ -49,8 +51,6 @@ import javafx.geometry.Side;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
@ -537,6 +537,46 @@ public class AppController implements Initializable {
aboutStage.show();
}
public void showJoinstr(ActionEvent event) {
Stage joinstrStage = getJoinstrStage();
joinstrStage.show();
}
private Stage getJoinstrStage() {
try {
FXMLLoader loader = new FXMLLoader(AppController.class.getResource("joinstr/joinstr.fxml"));
BorderPane root = loader.load();
if(OsType.getCurrent() == OsType.WINDOWS) {
root.setBorder(new Border(new BorderStroke(Color.DARKGRAY, BorderStrokeStyle.SOLID, CornerRadii.EMPTY, BorderWidths.DEFAULT)));
}
Stage stage = new Stage(StageStyle.DECORATED);
stage.setTitle("Joinstr with " + getSelectedWalletForm().getWallet().getFullName());
stage.initOwner(tabs.getScene().getWindow());
JoinstrController controller = loader.getController();
JoinstrForm joinstrForm = new JoinstrForm(getSelectedWalletForm().getStorage(), getSelectedWalletForm().getWallet());
controller.setJoinstrForm(joinstrForm);
Scene scene = new Scene(root);
AppServices.onEscapePressed(scene, stage::close);
stage.setScene(scene);
controller.setStage(stage);
controller.initializeView();
setStageIcon(stage);
stage.setOnShowing(event -> {
AppServices.moveToActiveWindowScreen(stage, 600, 460);
});
return stage;
} catch(IOException e) {
log.error("Error loading about stage", e);
}
return null;
}
private Stage getAboutStage() {
try {
FXMLLoader loader = new FXMLLoader(AppController.class.getResource("about.fxml"));

View file

@ -0,0 +1,8 @@
package com.sparrowwallet.sparrow.joinstr;
public class HistoryController extends JoinstrFormController {
@Override
public void initializeView() {
}
}

View file

@ -0,0 +1,96 @@
package com.sparrowwallet.sparrow.joinstr;
import com.sparrowwallet.sparrow.AppServices;
import java.io.IOException;
import java.net.URL;
import java.util.Locale;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.control.Toggle;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class JoinstrController extends JoinstrFormController {
private Stage stage;
@FXML
private StackPane joinstrPane;
@FXML
private VBox joinstrMenuBox;
@FXML
private ToggleGroup joinstrMenu;
public void initializeView() {
joinstrMenu.selectedToggleProperty().addListener((observable, oldValue, selectedToggle) -> {
if(selectedToggle == null) {
oldValue.setSelected(true);
return;
}
JoinstrDisplay display = (JoinstrDisplay)selectedToggle.getUserData();
boolean existing = false;
for(Node joinstrDisplay : joinstrPane.getChildren()) {
if(joinstrDisplay.getUserData().equals(display)) {
existing = true;
joinstrDisplay.setViewOrder(0);
} else if(display != JoinstrDisplay.LOCK) {
joinstrDisplay.setViewOrder(1);
}
}
try {
if(!existing) {
URL url = AppServices.class.getResource("joinstr/" + display.toString().toLowerCase(Locale.ROOT) + ".fxml");
if(url == null) {
throw new IllegalStateException("Cannot find joinstr/" + display.toString().toLowerCase(Locale.ROOT) + ".fxml");
}
FXMLLoader displayLoader = new FXMLLoader(url);
Node joinstrDisplay = displayLoader.load();
joinstrDisplay.setUserData(display);
joinstrDisplay.setViewOrder(1);
JoinstrFormController controller = displayLoader.getController();
JoinstrForm joinstrForm = getJoinstrForm();
controller.setJoinstrForm(joinstrForm);
joinstrPane.getChildren().add(joinstrDisplay);
}
} catch (IOException e) {
throw new IllegalStateException("Can't find pane", e);
}
});
for(Toggle toggle : joinstrMenu.getToggles()) {
ToggleButton toggleButton = (ToggleButton) toggle;
toggleButton.managedProperty().bind(toggleButton.visibleProperty());
}
joinstrMenuBox.managedProperty().bind(joinstrMenuBox.visibleProperty());
joinstrMenuBox.visibleProperty().bind(getJoinstrForm().lockedProperty().not());
}
public void setStage(Stage stage) {
this.stage = stage;
}
public void close(ActionEvent event) {
stage.close();
}
}

View file

@ -0,0 +1,9 @@
package com.sparrowwallet.sparrow.joinstr;
public enum JoinstrDisplay {
NEW_POOL,
MY_POOLS,
OTHER_POOLS,
HISTORY,
LOCK
}

View file

@ -0,0 +1,34 @@
package com.sparrowwallet.sparrow.joinstr;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.io.Storage;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
public class JoinstrForm {
private final BooleanProperty lockedProperty = new SimpleBooleanProperty(false);
private final Storage storage;
protected Wallet wallet;
public JoinstrForm(Storage storage, Wallet currentWallet) {
this.storage = storage;
this.wallet = currentWallet;
}
public Wallet getWallet() {
return wallet;
}
public Storage getStorage() {
return storage;
}
public BooleanProperty lockedProperty() {
return lockedProperty;
}
}

View file

@ -0,0 +1,20 @@
package com.sparrowwallet.sparrow.joinstr;
import com.sparrowwallet.sparrow.BaseController;
public abstract class JoinstrFormController extends BaseController {
public JoinstrForm joinstrForm;
public JoinstrForm getJoinstrForm() {
return joinstrForm;
}
public void setJoinstrForm(JoinstrForm joinstrForm) {
this.joinstrForm = joinstrForm;
initializeView();
}
public abstract void initializeView();
}

View file

@ -0,0 +1,8 @@
package com.sparrowwallet.sparrow.joinstr;
public class MyPoolsController extends JoinstrFormController {
@Override
public void initializeView() {
}
}

View file

@ -0,0 +1,8 @@
package com.sparrowwallet.sparrow.joinstr;
public class NewPoolController extends JoinstrFormController {
@Override
public void initializeView() {
}
}

View file

@ -0,0 +1,16 @@
package com.sparrowwallet.sparrow.joinstr;
import com.sparrowwallet.sparrow.joinstr.control.JoinstrPoolList;
import javafx.fxml.FXML;
public class OtherPoolsController extends JoinstrFormController {
@FXML
private JoinstrPoolList joinstrPoolList;
@Override
public void initializeView() {
joinstrPoolList.fillList();
}
}

View file

@ -0,0 +1,48 @@
package com.sparrowwallet.sparrow.joinstr.control;
import com.sparrowwallet.sparrow.AppController;
import java.io.IOException;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.VBox;
import javafx.scene.layout.Pane;
public class JoinstrPoolList extends Pane {
@FXML
private VBox listVBox;
public JoinstrPoolList() {
FXMLLoader loader = new FXMLLoader(AppController.class.getResource("joinstr/control/joinstrpoollist.fxml"));
loader.setRoot(this);
loader.setController(this);
try {
loader.load();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void fillList() {
JoinstrPoolListItem listItem1 = new JoinstrPoolListItem();
listItem1.setLabel("Pool #1");
listVBox.getChildren().add(listItem1);
JoinstrPoolListItem listItem2 = new JoinstrPoolListItem();
listItem2.setLabel("Pool #2");
listVBox.getChildren().add(listItem2);
JoinstrPoolListItem listItem3 = new JoinstrPoolListItem();
listItem3.setLabel("Pool #3");
listVBox.getChildren().add(listItem3);
}
}

View file

@ -0,0 +1,35 @@
package com.sparrowwallet.sparrow.joinstr.control;
import com.sparrowwallet.sparrow.AppController;
import java.io.IOException;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
public class JoinstrPoolListItem extends Pane {
@FXML
private Label lblTest;
public JoinstrPoolListItem() {
FXMLLoader loader = new FXMLLoader(AppController.class.getResource("joinstr/control/joinstrpoollistitem.fxml"));
loader.setRoot(this);
loader.setController(this);
try {
loader.load();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void setLabel(String txt) {
lblTest.setText(txt);
}
}

View file

@ -11,7 +11,7 @@
<?import com.sparrowwallet.sparrow.Theme?>
<?import impl.org.controlsfx.skin.DecorationPane?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="200" minWidth="350" prefHeight="770.0" prefWidth="1070.0" fx:controller="com.sparrowwallet.sparrow.AppController" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1">
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="200" minWidth="350" prefHeight="770.0" prefWidth="1070.0" fx:controller="com.sparrowwallet.sparrow.AppController" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml">
<children>
<MenuBar useSystemMenuBar="true">
<menus>
@ -148,6 +148,8 @@
<MenuItem styleClass="osxHide,windowsHide" mnemonicParsing="false" text="Install Udev Rules" onAction="#installUdevRules"/>
<CheckMenuItem fx:id="preventSleep" mnemonicParsing="false" text="Prevent Computer Sleep" onAction="#preventSleep"/>
<Menu fx:id="restart" mnemonicParsing="false" text="Restart In" />
<SeparatorMenuItem />
<MenuItem text="Joinstr..." onAction="#showJoinstr"/>
</Menu>
<Menu fx:id="helpMenu" mnemonicParsing="false" text="Help">
<MenuItem mnemonicParsing="false" text="Show Introduction" onAction="#showIntroduction"/>

View file

@ -0,0 +1,18 @@
pool-list {
}
pool-header {
-fx-background-color: #000000;
}
pool-list-item {
-fx-insets:10, 10, 10, 10;
-fx-border-radius:10, 10, 10, 10;
-fx-background-color: #1D2124;
}
pool-list-item:hover {
-fx-background-color: #164768;
-fx-border-color: #4E99D3;
}

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.*?>
<fx:root type="javafx.scene.layout.Pane" stylesheets="@control.css" styleClass="pool-list" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml">
<VBox>
<HBox styleClass="pool-header">
<Label>Relay</Label>
<Label>Pubkey (Shortened)</Label>
<Label>Denomination</Label>
<Label>Peers</Label>
<Label>Timeout</Label>
<Label>Action</Label>
</HBox>
<VBox fx:id="listVBox" />
</VBox>
</fx:root>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<fx:root type="javafx.scene.layout.Pane" stylesheets="@control.css" styleClass="pool-list-item" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml">
<Label fx:id="lblTest" />
</fx:root>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane stylesheets="@joinstr.css, @../wallet/wallet.css, @../general.css" styleClass="wallet-pane" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:controller="com.sparrowwallet.sparrow.joinstr.HistoryController">
<center>
<Label>HISTORY</Label>
</center>
</BorderPane>

View file

@ -0,0 +1,34 @@
.spacerV50 {
-fx-padding:50, 0, 0, 0;
}
.spacerV25 {
-fx-padding:25, 0, 0, 0;
}
.balance-container {
-fx-padding:30, 0, 30, 0;
-fx-background-color: #164768;
-fx-text-alignment: center;
}
.title {
-fx-padding:0, 10, 0, 10;
-fx-font-size: 2em;
-fx-font-weight: bold;
}
.sub-title {
-fx-padding:0, 10, 0, 10;
-fx-font-size: 1.5em;
}
.list-menu {
-fx-background-color: #3da0e3;
}
.list-item * {
-fx-fill: #fff;
-fx-font-size: 1.5em;
}

View file

@ -0,0 +1,63 @@
<?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 com.sparrowwallet.sparrow.joinstr.JoinstrDisplay?>
<?import org.controlsfx.glyphfont.Glyph?>
<BorderPane stylesheets="@joinstr.css, @../general.css" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:controller="com.sparrowwallet.sparrow.joinstr.JoinstrController"
maxHeight="-Infinity" maxWidth="-Infinity" minHeight="200" minWidth="350" prefHeight="770.0" prefWidth="1070.0">
<left>
<VBox fx:id="joinstrMenuBox" styleClass="list-menu">
<Pane styleClass="spacerV50" />
<ToggleButton VBox.vgrow="ALWAYS" text="New pool" contentDisplay="CENTER" styleClass="list-item" maxHeight="Infinity">
<toggleGroup>
<ToggleGroup fx:id="joinstrMenu" />
</toggleGroup>
<userData>
<JoinstrDisplay fx:constant="NEW_POOL"/>
</userData>
</ToggleButton>
<ToggleButton VBox.vgrow="ALWAYS" text="My Pools" contentDisplay="CENTER" styleClass="list-item" maxHeight="Infinity" toggleGroup="$joinstrMenu">
<userData>
<JoinstrDisplay fx:constant="MY_POOLS"/>
</userData>
</ToggleButton>
<ToggleButton VBox.vgrow="ALWAYS" text="Other pools" contentDisplay="CENTER" styleClass="list-item" maxHeight="Infinity" toggleGroup="$joinstrMenu">
<userData>
<JoinstrDisplay fx:constant="OTHER_POOLS"/>
</userData>
</ToggleButton>
<ToggleButton VBox.vgrow="ALWAYS" text="History" contentDisplay="CENTER" styleClass="list-item" maxHeight="Infinity" toggleGroup="$joinstrMenu">
<userData>
<JoinstrDisplay fx:constant="HISTORY"/>
</userData>
</ToggleButton>
<VBox>
<Pane styleClass="spacerV25" />
<HBox>
<VBox maxWidth="Infinity" HBox.hgrow="ALWAYS" styleClass="balance-container">
<Label fx:id="joinstrBalanceTitle" styleClass="balance-label">
Current balance:
</Label>
<Label fx:id="joinstrBalanceValue" styleClass="balance-label">
0.00000001
<graphic>
<Glyph fontFamily="FontAwesome" icon="BTC" fontSize="20" />
</graphic>
</Label>
</VBox>
</HBox>
<Pane styleClass="spacer25" />
</VBox>
</VBox>
</left>
<center>
<StackPane fx:id="joinstrPane" styleClass="joinstr-pane">
</StackPane>
</center>
</BorderPane>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane stylesheets="@joinstr.css, @../wallet/wallet.css, @../general.css" styleClass="wallet-pane" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:controller="com.sparrowwallet.sparrow.joinstr.MyPoolsController">
<center>
<Label>MY POOLS</Label>
</center>
</BorderPane>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane stylesheets="@joinstr.css, @../wallet/wallet.css, @../general.css" styleClass="wallet-pane" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:controller="com.sparrowwallet.sparrow.joinstr.NewPoolController">
<center>
<Label>NEW POOL</Label>
</center>
</BorderPane>

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.geometry.Insets?>
<?import com.sparrowwallet.sparrow.joinstr.control.JoinstrPoolList ?>
<BorderPane stylesheets="@joinstr.css, @../wallet/wallet.css, @../general.css" styleClass="wallet-pane" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:controller="com.sparrowwallet.sparrow.joinstr.OtherPoolsController">
<padding>
<Insets top="30" right="30" bottom="30" left="30"/>
</padding>
<center>
<VBox maxWidth="Infinity" HBox.hgrow="ALWAYS">
<Pane maxWidth="Infinity" HBox.hgrow="ALWAYS">
<padding>
<Insets top="0" right="0" bottom="10" left="0"/>
</padding>
<GridPane maxWidth="Infinity" HBox.hgrow="ALWAYS" hgap="10.0" vgap="10.0">
<columnConstraints>
<ColumnConstraints percentWidth="80" />
<ColumnConstraints percentWidth="20" />
</columnConstraints>
<children>
<VBox maxWidth="Infinity" HBox.hgrow="ALWAYS" GridPane.rowIndex="0" GridPane.columnIndex="0">
<Label styleClass="title">Available Pools</Label>
<Label styleClass="sub-title">Select a pool to join</Label>
</VBox>
<TextField GridPane.rowIndex="0" GridPane.columnIndex="1" fx:id="searchPoolsTextField" promptText="Search pools..." />
</children>
</GridPane>
</Pane>
<JoinstrPoolList fx:id="joinstrPoolList"/>
</VBox>
</center>
</BorderPane>