Added properties pane and improved the account view.
This commit is contained in:
parent
32fb7e8eb8
commit
4c69cd1662
|
@ -7,9 +7,15 @@ import com.andrewlalis.perfin.model.Profile;
|
|||
import com.andrewlalis.perfin.model.history.AccountHistoryItem;
|
||||
import com.andrewlalis.perfin.view.component.AccountHistoryItemTile;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.binding.BooleanExpression;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
@ -21,27 +27,44 @@ public class AccountViewController implements RouteSelectionListener {
|
|||
private Account account;
|
||||
|
||||
@FXML public Label titleLabel;
|
||||
@FXML public TextField accountNameField;
|
||||
@FXML public TextField accountNumberField;
|
||||
@FXML public TextField accountCreatedAtField;
|
||||
@FXML public TextField accountCurrencyField;
|
||||
@FXML public TextField accountBalanceField;
|
||||
|
||||
@FXML public Label accountNameLabel;
|
||||
@FXML public Label accountNumberLabel;
|
||||
@FXML public Label accountCurrencyLabel;
|
||||
@FXML public Label accountCreatedAtLabel;
|
||||
@FXML public Label accountBalanceLabel;
|
||||
@FXML public BooleanProperty accountArchivedProperty = new SimpleBooleanProperty(false);
|
||||
|
||||
@FXML public VBox historyItemsVBox;
|
||||
@FXML public Button loadMoreHistoryButton;
|
||||
private LocalDateTime loadHistoryFrom;
|
||||
private final int historyLoadSize = 5;
|
||||
|
||||
@FXML public VBox actionsVBox;
|
||||
|
||||
@FXML public void initialize() {
|
||||
actionsVBox.getChildren().forEach(node -> {
|
||||
Button button = (Button) node;
|
||||
BooleanExpression buttonActive = accountArchivedProperty;
|
||||
if (button.getText().equalsIgnoreCase("Unarchive")) {
|
||||
buttonActive = buttonActive.not();
|
||||
}
|
||||
button.disableProperty().bind(buttonActive);
|
||||
button.managedProperty().bind(button.visibleProperty());
|
||||
button.visibleProperty().bind(button.disableProperty().not());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRouteSelected(Object context) {
|
||||
account = (Account) context;
|
||||
accountArchivedProperty.set(account.isArchived());
|
||||
titleLabel.setText("Account #" + account.id);
|
||||
|
||||
accountNameField.setText(account.getName());
|
||||
accountNumberField.setText(account.getAccountNumber());
|
||||
accountCurrencyField.setText(account.getCurrency().getDisplayName());
|
||||
accountCreatedAtField.setText(DateUtil.formatUTCAsLocalWithZone(account.getCreatedAt()));
|
||||
Profile.getCurrent().getDataSource().getAccountBalanceText(account, accountBalanceField::setText);
|
||||
accountNameLabel.setText(account.getName());
|
||||
accountNumberLabel.setText(account.getAccountNumber());
|
||||
accountCurrencyLabel.setText(account.getCurrency().getDisplayName());
|
||||
accountCreatedAtLabel.setText(DateUtil.formatUTCAsLocalWithZone(account.getCreatedAt()));
|
||||
Profile.getCurrent().getDataSource().getAccountBalanceText(account, accountBalanceLabel::setText);
|
||||
|
||||
reloadHistory();
|
||||
}
|
||||
|
@ -73,12 +96,16 @@ public class AccountViewController implements RouteSelectionListener {
|
|||
"later if you need to."
|
||||
).showAndWait();
|
||||
if (confirmResult.isPresent() && confirmResult.get() == ButtonType.OK) {
|
||||
Profile.getCurrent().getDataSource().useAccountRepository(repo -> repo.archive(account));
|
||||
Profile.getCurrent().getDataSource().useAccountRepository(repo -> repo.archive(account.id));
|
||||
router.getHistory().clear();
|
||||
router.navigate("accounts");
|
||||
}
|
||||
}
|
||||
|
||||
@FXML public void unarchiveAccount() {
|
||||
System.out.println("Unarchiving");
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void deleteAccount() {
|
||||
var confirmResult = new Alert(
|
||||
|
|
|
@ -21,7 +21,8 @@ public interface AccountRepository extends AutoCloseable {
|
|||
void updateName(long id, String name);
|
||||
void update(Account account);
|
||||
void delete(Account account);
|
||||
void archive(Account account);
|
||||
void archive(long accountId);
|
||||
void unarchive(long accountId);
|
||||
|
||||
BigDecimal deriveBalance(long accountId, Instant timestamp);
|
||||
default BigDecimal deriveCurrentBalance(long accountId) {
|
||||
|
|
|
@ -147,8 +147,19 @@ public record JdbcAccountRepository(Connection conn) implements AccountRepositor
|
|||
}
|
||||
|
||||
@Override
|
||||
public void archive(Account account) {
|
||||
DbUtil.updateOne(conn, "UPDATE account SET archived = TRUE WHERE id = ?", List.of(account.id));
|
||||
public void archive(long accountId) {
|
||||
DbUtil.doTransaction(conn, () -> {
|
||||
DbUtil.updateOne(conn, "UPDATE account SET archived = TRUE WHERE id = ?", List.of(accountId));
|
||||
new JdbcAccountHistoryItemRepository(conn).recordText(DateUtil.nowAsUTC(), accountId, "Account has been archived.");
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unarchive(long accountId) {
|
||||
DbUtil.doTransaction(conn, () -> {
|
||||
DbUtil.updateOne(conn, "UPDATE account SET archived = FALSE WHERE id = ?", List.of(accountId));
|
||||
new JdbcAccountHistoryItemRepository(conn).recordText(DateUtil.nowAsUTC(), accountId, "Account has been unarchived.");
|
||||
});
|
||||
}
|
||||
|
||||
public static Account parseAccount(ResultSet rs) throws SQLException {
|
||||
|
|
|
@ -10,11 +10,9 @@ import javafx.beans.property.SimpleBooleanProperty;
|
|||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.*;
|
||||
import javafx.scene.text.Text;
|
||||
import javafx.scene.text.TextAlignment;
|
||||
import javafx.scene.text.TextFlow;
|
||||
|
@ -54,9 +52,11 @@ public class DataSourcePaginationControls extends BorderPane {
|
|||
maxPagesText.managedProperty().bind(maxPagesText.visibleProperty());
|
||||
maxPagesText.visibleProperty().bind(maxPages.greaterThan(0));
|
||||
TextFlow pageText = new TextFlow(new Text("Page "), currentPageLabel, maxPagesText);
|
||||
pageText.setTextAlignment(TextAlignment.CENTER);
|
||||
BorderPane pageTextContainer = new BorderPane(pageText);
|
||||
BorderPane.setAlignment(pageText, Pos.CENTER);
|
||||
AnchorPane pageTextContainer = new AnchorPane(pageText);
|
||||
AnchorPane.setTopAnchor(pageText, 4.0);
|
||||
AnchorPane.setRightAnchor(pageText, 0.0);
|
||||
AnchorPane.setBottomAnchor(pageText, 0.0);
|
||||
AnchorPane.setLeftAnchor(pageText, 0.0);
|
||||
|
||||
|
||||
Button previousPageButton = new Button("Previous Page");
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
package com.andrewlalis.perfin.view.component;
|
||||
|
||||
import javafx.geometry.HPos;
|
||||
import javafx.geometry.VPos;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.layout.ColumnConstraints;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.RowConstraints;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A specially-formatted {@link GridPane} that arranges its children into a
|
||||
* two-column grid representing key-value pairs.
|
||||
*/
|
||||
public class PropertiesPane extends GridPane {
|
||||
public PropertiesPane() {
|
||||
ColumnConstraints keyConstraints = new ColumnConstraints();
|
||||
keyConstraints.setHgrow(Priority.NEVER);
|
||||
keyConstraints.setHalignment(HPos.LEFT);
|
||||
keyConstraints.setMinWidth(10.0);
|
||||
ColumnConstraints valueConstraints = new ColumnConstraints();
|
||||
valueConstraints.setHgrow(Priority.ALWAYS);
|
||||
valueConstraints.setHalignment(HPos.LEFT);
|
||||
valueConstraints.setMinWidth(10.0);
|
||||
getColumnConstraints().setAll(keyConstraints, valueConstraints);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void layoutChildren() {
|
||||
// Apply grid positioning to all children in the order in which they appear, like so:
|
||||
// key 1 value 1
|
||||
// key 2 value 2
|
||||
// ... and so on.
|
||||
int rowCount = getManagedChildren().size() / 2;
|
||||
List<RowConstraints> rows = new ArrayList<>(rowCount);
|
||||
for (int i = 0; i < rowCount; i++) {
|
||||
RowConstraints c = new RowConstraints();
|
||||
c.setValignment(VPos.TOP);
|
||||
c.setVgrow(Priority.NEVER);
|
||||
rows.add(c);
|
||||
}
|
||||
getRowConstraints().setAll(rows);
|
||||
for (int i = 0; i < getManagedChildren().size(); i++) {
|
||||
Node child = getManagedChildren().get(i);
|
||||
int column = i % 2;
|
||||
int row = i / 2;
|
||||
GridPane.setRowIndex(child, row);
|
||||
GridPane.setColumnIndex(child, column);
|
||||
}
|
||||
super.layoutChildren();
|
||||
}
|
||||
}
|
|
@ -1,17 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import com.andrewlalis.perfin.view.component.PropertiesPane?>
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.scene.text.Text?>
|
||||
<BorderPane
|
||||
xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml"
|
||||
fx:controller="com.andrewlalis.perfin.control.AccountViewController"
|
||||
stylesheets="@style/account-view.css,@style/base.css"
|
||||
stylesheets="@style/base.css"
|
||||
>
|
||||
<top>
|
||||
<HBox styleClass="std-padding,std-spacing">
|
||||
<Label fx:id="titleLabel" styleClass="large-text,bold-text"/>
|
||||
</HBox>
|
||||
<Label fx:id="titleLabel" styleClass="std-padding,large-text,bold-text"/>
|
||||
</top>
|
||||
<center>
|
||||
<VBox>
|
||||
|
@ -19,50 +19,53 @@
|
|||
<BorderPane>
|
||||
<center>
|
||||
<VBox styleClass="std-padding,std-spacing">
|
||||
<HBox>
|
||||
<FlowPane>
|
||||
<!-- Main account properties. -->
|
||||
<VBox HBox.hgrow="SOMETIMES">
|
||||
<VBox styleClass="account-property-box">
|
||||
<Label text="Name"/>
|
||||
<TextField fx:id="accountNameField" editable="false"/>
|
||||
<PropertiesPane vgap="5" hgap="5">
|
||||
<Label text="Name" styleClass="bold-text"/>
|
||||
<Label fx:id="accountNameLabel"/>
|
||||
|
||||
<Label text="Number" styleClass="bold-text"/>
|
||||
<Label fx:id="accountNumberLabel" styleClass="mono-font"/>
|
||||
|
||||
<Label text="Currency" styleClass="bold-text"/>
|
||||
<Label fx:id="accountCurrencyLabel"/>
|
||||
|
||||
<Label text="Created At" styleClass="bold-text"/>
|
||||
<Label fx:id="accountCreatedAtLabel" styleClass="mono-font"/>
|
||||
|
||||
<VBox>
|
||||
<Label text="Current Balance" styleClass="bold-text" fx:id="balanceLabel"/>
|
||||
<Text
|
||||
style="-fx-font-size: x-small; -fx-fill: grey"
|
||||
wrappingWidth="${balanceLabel.width}"
|
||||
>Computed using the last recorded balance and all transactions since.</Text>
|
||||
</VBox>
|
||||
<VBox styleClass="account-property-box">
|
||||
<Label text="Number"/>
|
||||
<TextField fx:id="accountNumberField" editable="false" styleClass="mono-font"/>
|
||||
</VBox>
|
||||
<VBox styleClass="account-property-box">
|
||||
<Label text="Currency"/>
|
||||
<TextField fx:id="accountCurrencyField" editable="false"/>
|
||||
</VBox>
|
||||
<VBox styleClass="account-property-box">
|
||||
<Label text="Created At"/>
|
||||
<TextField fx:id="accountCreatedAtField" editable="false"/>
|
||||
</VBox>
|
||||
<VBox styleClass="account-property-box">
|
||||
<Label text="Current Balance"/>
|
||||
<TextField fx:id="accountBalanceField" editable="false"/>
|
||||
</VBox>
|
||||
</VBox>
|
||||
<Label fx:id="accountBalanceLabel" styleClass="mono-font"/>
|
||||
</PropertiesPane>
|
||||
<VBox HBox.hgrow="SOMETIMES">
|
||||
<Label text="Panel 2"/>
|
||||
</VBox>
|
||||
</HBox>
|
||||
</FlowPane>
|
||||
</VBox>
|
||||
</center>
|
||||
<right>
|
||||
<VBox styleClass="std-padding,std-spacing">
|
||||
<Label text="Actions" styleClass="bold-text"/>
|
||||
<Button text="Edit" onAction="#goToEditPage"/>
|
||||
<Button text="Record Balance" onAction="#goToCreateBalanceRecord"/>
|
||||
<Button text="Archive" onAction="#archiveAccount"/>
|
||||
<Button text="Delete" onAction="#deleteAccount"/>
|
||||
<VBox fx:id="actionsVBox" styleClass="std-spacing">
|
||||
<Button text="Edit" onAction="#goToEditPage"/>
|
||||
<Button text="Record Balance" onAction="#goToCreateBalanceRecord"/>
|
||||
<Button text="Archive" onAction="#archiveAccount"/>
|
||||
<Button text="Delete" onAction="#deleteAccount"/>
|
||||
<Button text="Unarchive" onAction="#unarchiveAccount"/>
|
||||
</VBox>
|
||||
</VBox>
|
||||
</right>
|
||||
</BorderPane>
|
||||
|
||||
<!-- Account history -->
|
||||
<VBox VBox.vgrow="ALWAYS">
|
||||
<Label text="History" styleClass="bold-text"/>
|
||||
<Label text="History" styleClass="bold-text,std-padding"/>
|
||||
<VBox>
|
||||
<ScrollPane fitToHeight="true" fitToWidth="true">
|
||||
<VBox fx:id="historyItemsVBox" style="-fx-padding: 10px; -fx-spacing: 10px;"/>
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
.account-property-box {
|
||||
-fx-padding: 5px 0 5px 0;
|
||||
-fx-spacing: 3px;
|
||||
}
|
||||
|
||||
.account-property-box > Label {
|
||||
-fx-font-weight: bold;
|
||||
}
|
||||
|
||||
.account-property-box > TextField {
|
||||
-fx-min-width: 100px;
|
||||
-fx-max-width: 300px;
|
||||
}
|
||||
|
||||
.actions-box > Button {
|
||||
-fx-max-width: 500px;
|
||||
}
|
Loading…
Reference in New Issue