Improve pool selection ui

This commit is contained in:
/dev/fd0 2025-05-22 02:05:42 +05:30
parent 25f1ca2529
commit 865e3b8ee6
4 changed files with 310 additions and 93 deletions

View file

@ -3,6 +3,9 @@ package com.sparrowwallet.sparrow.joinstr;
import com.sparrowwallet.sparrow.joinstr.control.JoinstrInfoPane;
import com.sparrowwallet.sparrow.joinstr.control.JoinstrPoolList;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;
@ -16,26 +19,100 @@ public class OtherPoolsController extends JoinstrFormController {
@FXML
private TextField searchTextField;
private JoinstrPoolList joinstrPoolList;
private JoinstrInfoPane joinstrInfoPane;
@Override
public void initializeView() {
try {
joinstrPoolList = new JoinstrPoolList(JoinstrAction.JOIN);
JoinstrPoolList joinstrPoolList = new JoinstrPoolList(JoinstrAction.JOIN);
joinstrPoolList.configureWithJoinButtons();
JoinstrInfoPane joinstrInfoPane = new JoinstrInfoPane();
// Add sample pool data
addSamplePoolData();
joinstrInfoPane = new JoinstrInfoPane();
joinstrInfoPane.initInfoPane();
joinstrInfoPane.setVisible(false);
joinstrInfoPane.setManaged(false);
joinstrPoolList.setOnPoolSelectedListener(pool -> {
if (pool != null) {
joinstrInfoPane.setVisible(true);
joinstrInfoPane.setManaged(true);
joinstrInfoPane.updatePoolInfo(pool);
} else {
joinstrInfoPane.setVisible(false);
joinstrInfoPane.setManaged(false);
}
});
contentVBox.getChildren().addAll(joinstrPoolList, joinstrInfoPane);
searchTextField.textProperty().addListener((observable, oldValue, newValue) -> {
filterPools(newValue);
});
} catch (Exception e) {
if(e != null) {}
if(e != null) {
e.printStackTrace();
}
}
}
public void handleSearchButton(ActionEvent e) {
if(e.getSource()==searchTextField) {
System.out.println(searchTextField.getText());
};
private void addSamplePoolData() {
// Create the two sample pools
JoinstrPool pool1 = new JoinstrPool(
"relay.joinstr.xyz",
"03ab4...e92f",
"0.001 BTC",
"4/5",
"00:00:00 UTC"
);
JoinstrPool pool2 = new JoinstrPool(
"relay.joinstr.xyz",
"02c4f...19a3",
"0.005 BTC",
"3/7",
"00:00:00 UTC"
);
joinstrPoolList.addPool(pool1);
joinstrPoolList.addPool(pool2);
}
}
private void filterPools(String searchText) {
joinstrPoolList.filterPools(searchText);
}
public void handleSearchButton(ActionEvent e) {
if(e.getSource() == searchTextField) {
filterPools(searchTextField.getText());
}
}
public static class JoinstrPool {
private final SimpleStringProperty relay;
private final SimpleStringProperty pubkey;
private final SimpleStringProperty denomination;
private final SimpleStringProperty peers;
private final SimpleStringProperty timeout;
public JoinstrPool(String relay, String pubkey, String denomination,
String peers, String timeout) {
this.relay = new SimpleStringProperty(relay);
this.pubkey = new SimpleStringProperty(pubkey);
this.denomination = new SimpleStringProperty(denomination);
this.peers = new SimpleStringProperty(peers);
this.timeout = new SimpleStringProperty(timeout);
}
public String getRelay() { return relay.get(); }
public String getPubkey() { return pubkey.get(); }
public String getDenomination() { return denomination.get(); }
public String getPeers() { return peers.get(); }
public String getTimeout() { return timeout.get(); }
}
}

View file

@ -1,49 +1,81 @@
package com.sparrowwallet.sparrow.joinstr.control;
import com.sparrowwallet.sparrow.joinstr.OtherPoolsController.JoinstrPool;
import javafx.geometry.Insets;
import javafx.scene.control.Label;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
public class JoinstrInfoPane extends AnchorPane {
public class JoinstrInfoPane extends VBox {
public JoinstrInfoPane() { super(); }
private Label titleLabel;
private Label relayLabel;
private Label pubkeyLabel;
private Label denominationLabel;
private Label relayValueLabel;
private Label pubkeyValueLabel;
private Label denominationValueLabel;
public void initInfoPane() {
GridPane mainGridPane = new GridPane();
Label relayTitleLabel = new Label();
relayTitleLabel.setText("Relay:");
GridPane.setRowIndex(relayTitleLabel, 0);
GridPane.setColumnIndex(relayTitleLabel, 0);
Label pubkeyTitleLabel = new Label();
pubkeyTitleLabel.setText("Pubkey:");
GridPane.setRowIndex(pubkeyTitleLabel, 1);
GridPane.setColumnIndex(pubkeyTitleLabel, 0);
Label denominationTitleLabel = new Label();
denominationTitleLabel.setText("Denomination:");
GridPane.setRowIndex(denominationTitleLabel, 2);
GridPane.setColumnIndex(denominationTitleLabel, 0);
Label relayDescLabel = new Label();
relayDescLabel.setText("Relay desc");
GridPane.setRowIndex(relayDescLabel, 0);
GridPane.setColumnIndex(relayDescLabel, 1);
Label pubkeyDescLabel = new Label();
pubkeyDescLabel.setText("Pubkey desc");
GridPane.setRowIndex(pubkeyDescLabel, 1);
GridPane.setColumnIndex(pubkeyDescLabel, 1);
Label denominationDescLabel = new Label();
denominationDescLabel.setText("Denomination desc");
GridPane.setRowIndex(denominationDescLabel, 2);
GridPane.setColumnIndex(denominationDescLabel, 1);
getChildren().add(mainGridPane);
public JoinstrInfoPane() {
setStyle("-fx-background-color: #222222; -fx-padding: 15;");
setSpacing(10);
}
}
public void initInfoPane() {
titleLabel = new Label("Selected Pool Details");
titleLabel.setStyle("-fx-font-size: 16px; -fx-text-fill: white; -fx-font-weight: bold;");
getChildren().add(titleLabel);
GridPane detailsGrid = new GridPane();
detailsGrid.setHgap(10);
detailsGrid.setVgap(10);
ColumnConstraints column1 = new ColumnConstraints();
column1.setPrefWidth(100);
ColumnConstraints column2 = new ColumnConstraints();
column2.setPrefWidth(400);
detailsGrid.getColumnConstraints().addAll(column1, column2);
relayLabel = new Label("Relay:");
relayLabel.setStyle("-fx-text-fill: #aaaaaa;");
relayValueLabel = new Label();
relayValueLabel.setStyle("-fx-text-fill: white;");
pubkeyLabel = new Label("Pubkey:");
pubkeyLabel.setStyle("-fx-text-fill: #aaaaaa;");
pubkeyValueLabel = new Label();
pubkeyValueLabel.setStyle("-fx-text-fill: white;");
denominationLabel = new Label("Denomination:");
denominationLabel.setStyle("-fx-text-fill: #aaaaaa;");
denominationValueLabel = new Label();
denominationValueLabel.setStyle("-fx-text-fill: white;");
detailsGrid.add(relayLabel, 0, 0);
detailsGrid.add(relayValueLabel, 1, 0);
detailsGrid.add(pubkeyLabel, 0, 1);
detailsGrid.add(pubkeyValueLabel, 1, 1);
detailsGrid.add(denominationLabel, 0, 2);
detailsGrid.add(denominationValueLabel, 1, 2);
getChildren().add(detailsGrid);
}
public void updatePoolInfo(JoinstrPool pool) {
if (pool != null) {
relayValueLabel.setText(pool.getRelay());
pubkeyValueLabel.setText(pool.getPubkey());
denominationValueLabel.setText(pool.getDenomination());
} else {
clearPoolInfo();
}
}
public void clearPoolInfo() {
relayValueLabel.setText("");
pubkeyValueLabel.setText("");
denominationValueLabel.setText("");
}
}

View file

@ -1,39 +1,149 @@
package com.sparrowwallet.sparrow.joinstr.control;
import com.sparrowwallet.sparrow.joinstr.JoinstrAction;
import com.sparrowwallet.sparrow.joinstr.JoinstrPool;
import com.sparrowwallet.sparrow.joinstr.OtherPoolsController.JoinstrPool;
import javafx.scene.layout.*;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.scene.control.Button;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
import javafx.util.Callback;
import java.util.function.Consumer;
public class JoinstrPoolList extends VBox {
private final JoinstrAction action;
private TableView<JoinstrPool> poolTableView;
private ObservableList<JoinstrPool> poolData;
private FilteredList<JoinstrPool> filteredData;
private Consumer<JoinstrPool> onPoolSelectedListener;
public JoinstrPoolList(JoinstrAction action) {
super();
this.action = action;
initialize();
}
setPrefHeight(500);
setPrefWidth(500);
setSpacing(10);
private void initialize() {
// Create the table
poolTableView = new TableView<>();
poolTableView.setStyle("-fx-background-color: #222222; -fx-text-fill: white;");
setMaxWidth(Double.MAX_VALUE);
setMaxHeight(Double.MAX_VALUE);
// Create data storage
poolData = FXCollections.observableArrayList();
filteredData = new FilteredList<>(poolData, p -> true);
poolTableView.setItems(filteredData);
JoinstrPoolListRow header = new JoinstrPoolListRow();
getChildren().add(header);
// Create standard columns
TableColumn<JoinstrPool, String> relayColumn = new TableColumn<>("Relay");
relayColumn.setCellValueFactory(new PropertyValueFactory<>("relay"));
relayColumn.setPrefWidth(150);
JoinstrPool[] poolsDummy = getDummyData();
TableColumn<JoinstrPool, String> pubkeyColumn = new TableColumn<>("Pubkey");
pubkeyColumn.setCellValueFactory(new PropertyValueFactory<>("pubkey"));
pubkeyColumn.setPrefWidth(200);
for (JoinstrPool joinstrPool : poolsDummy) {
JoinstrPoolListRow joinstrRow = new JoinstrPoolListRow(joinstrPool, action);
getChildren().add(joinstrRow);
TableColumn<JoinstrPool, String> denominationColumn = new TableColumn<>("Denomination");
denominationColumn.setCellValueFactory(new PropertyValueFactory<>("denomination"));
denominationColumn.setPrefWidth(150);
TableColumn<JoinstrPool, String> peersColumn = new TableColumn<>("Peers");
peersColumn.setCellValueFactory(new PropertyValueFactory<>("peers"));
peersColumn.setPrefWidth(80);
TableColumn<JoinstrPool, String> timeoutColumn = new TableColumn<>("Timeout");
timeoutColumn.setCellValueFactory(new PropertyValueFactory<>("timeout"));
timeoutColumn.setPrefWidth(100);
poolTableView.getColumns().addAll(
relayColumn,
pubkeyColumn,
denominationColumn,
peersColumn,
timeoutColumn
);
poolTableView.getSelectionModel().selectedItemProperty().addListener(
(obs, oldSelection, newSelection) -> {
if (onPoolSelectedListener != null) {
onPoolSelectedListener.accept(newSelection);
}
}
);
getChildren().add(poolTableView);
setVgrow(poolTableView, javafx.scene.layout.Priority.ALWAYS);
}
public void configureWithJoinButtons() {
TableColumn<JoinstrPool, Void> joinButtonColumn = new TableColumn<>("");
joinButtonColumn.setPrefWidth(100);
joinButtonColumn.setCellFactory(new Callback<>() {
@Override
public TableCell<JoinstrPool, Void> call(final TableColumn<JoinstrPool, Void> param) {
return new TableCell<>() {
private final Button joinButton = new Button("Join");
{
joinButton.setStyle(
"-fx-background-color: #2196F3; " +
"-fx-text-fill: white; " +
"-fx-cursor: hand;"
);
joinButton.setOnAction(event -> {
JoinstrPool pool = getTableView().getItems().get(getIndex());
System.out.println("Join button clicked for pool: " + pool.getPubkey());
});
}
@Override
public void updateItem(Void item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
} else {
setGraphic(joinButton);
}
}
};
}
});
poolTableView.getColumns().add(joinButtonColumn);
}
public void addPool(JoinstrPool pool) {
poolData.add(pool);
}
public void clearPools() {
poolData.clear();
}
public void filterPools(String searchText) {
if (searchText == null || searchText.isEmpty()) {
filteredData.setPredicate(p -> true);
} else {
String lowercaseFilter = searchText.toLowerCase();
filteredData.setPredicate(pool ->
pool.getRelay().toLowerCase().contains(lowercaseFilter) ||
pool.getPubkey().toLowerCase().contains(lowercaseFilter) ||
pool.getDenomination().toLowerCase().contains(lowercaseFilter)
);
}
}
private JoinstrPool[] getDummyData() {
return new JoinstrPool[]{ new JoinstrPool("Relay1", 1234, "pubkey1", 0.001),
new JoinstrPool("Relay2", 1234, "pubkey2", 0.002),
new JoinstrPool("Relay3", 1234, "pubkey3", 0.005)};
public void setOnPoolSelectedListener(Consumer<JoinstrPool> listener) {
this.onPoolSelectedListener = listener;
}
}
public JoinstrPool getSelectedPool() {
return poolTableView.getSelectionModel().getSelectedItem();
}
}

View file

@ -4,28 +4,26 @@
<?import javafx.scene.layout.*?>
<?import javafx.geometry.Insets?>
<?import com.sparrowwallet.sparrow.joinstr.control.JoinstrPoolList ?>
<?import com.sparrowwallet.sparrow.joinstr.control.JoinstrInfoPane ?>
<HBox xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:controller="com.sparrowwallet.sparrow.joinstr.OtherPoolsController">
<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" fx:id="contentVBox">
<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="searchTextField" promptText="Search pools..." onAction="#handleSearchButton" />
</children>
</GridPane>
</VBox>
</center>
</BorderPane>
<BorderPane HBox.hgrow="ALWAYS" style="-fx-background-color: #333333;">
<padding>
<Insets top="20" right="20" bottom="20" left="20"/>
</padding>
<top>
<VBox spacing="10">
<HBox alignment="CENTER_LEFT" spacing="20">
<Label text="Available Pools" style="-fx-font-size: 24px; -fx-text-fill: white;"/>
<Region HBox.hgrow="ALWAYS" />
<TextField fx:id="searchTextField" promptText="Search pools..." prefWidth="250" style="-fx-background-color: #444444; -fx-text-fill: white; -fx-prompt-text-fill: #888888;" onAction="#handleSearchButton"/>
</HBox>
<Label text="Select a pool to join" style="-fx-font-size: 14px; -fx-text-fill: #aaaaaa;"/>
</VBox>
</top>
<center>
<VBox fx:id="contentVBox" spacing="10">
</VBox>
</center>
</BorderPane>
</HBox>