Added account tile, more model definitions, and improved scene and node loading.
This commit is contained in:
parent
050f9c8a6b
commit
53ff257323
17
pom.xml
17
pom.xml
|
@ -28,9 +28,20 @@
|
|||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.xerial</groupId>
|
||||
<artifactId>sqlite-jdbc</artifactId>
|
||||
<version>3.44.1.0</version>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.16.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>2.16.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>2.2.224</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
|
|
@ -1,28 +1,39 @@
|
|||
package com.andrewlalis.perfin;
|
||||
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.net.URL;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class SceneUtil {
|
||||
public static Scene load(String fxml, Object controller) {
|
||||
public static <T> Parent loadNode(String fxml, Consumer<T> controllerConfig) {
|
||||
FXMLLoader loader = new FXMLLoader(SceneUtil.class.getResource(fxml));
|
||||
if (controller != null) {
|
||||
if (loader.getController() != null) {
|
||||
throw new IllegalStateException("Cannot set loader for resource " + fxml + " because it has declared one already.");
|
||||
}
|
||||
loader.setController(controller);
|
||||
}
|
||||
try {
|
||||
return new Scene(loader.load());
|
||||
Parent p = loader.load();
|
||||
if (controllerConfig != null) {
|
||||
T controller = loader.getController();
|
||||
if (controller == null) throw new NullPointerException("Could not get controller from " + fxml);
|
||||
controllerConfig.accept(controller);
|
||||
}
|
||||
return p;
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Parent loadNode(String fxml) {
|
||||
return loadNode(fxml, null);
|
||||
}
|
||||
|
||||
public static <T> Scene load(String fxml, Consumer<T> controllerConfig) {
|
||||
return new Scene(loadNode(fxml, controllerConfig));
|
||||
}
|
||||
|
||||
public static Scene load(String fxml) {
|
||||
return load(fxml, null);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
package com.andrewlalis.perfin.control;
|
||||
|
||||
import com.andrewlalis.perfin.model.Account;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.event.EventType;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
public class AccountTileController {
|
||||
private Account account;
|
||||
|
||||
@FXML
|
||||
public VBox container;
|
||||
@FXML
|
||||
public Label accountNumberLabel;
|
||||
@FXML
|
||||
public Label accountBalanceLabel;
|
||||
@FXML
|
||||
public VBox accountNameBox;
|
||||
@FXML
|
||||
public Label accountNameLabel;
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
ObservableValue<Boolean> accountNameTextPresent = accountNameLabel.textProperty().map(t -> t != null && !t.isBlank());
|
||||
accountNameBox.visibleProperty().bind(accountNameTextPresent);
|
||||
accountNameBox.managedProperty().bind(accountNameTextPresent);
|
||||
}
|
||||
|
||||
public void setAccount(Account account) {
|
||||
this.account = account;
|
||||
Platform.runLater(() -> {
|
||||
accountNumberLabel.setText(account.getAccountNumber());
|
||||
accountBalanceLabel.setText(account.getCurrency().getSymbol() + " " + account.getCurrentBalance().toPlainString());
|
||||
accountNameLabel.setText(account.getName());
|
||||
container.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> {
|
||||
System.out.println("Clicked on " + account.getAccountNumber());
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,10 +1,47 @@
|
|||
package com.andrewlalis.perfin.control;
|
||||
|
||||
import com.andrewlalis.perfin.SceneUtil;
|
||||
import com.andrewlalis.perfin.model.Account;
|
||||
import com.andrewlalis.perfin.model.AccountType;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.layout.FlowPane;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Currency;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class MainController {
|
||||
@FXML
|
||||
public BorderPane mainContainer;
|
||||
@FXML
|
||||
public FlowPane accountsPane;
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
accountsPane.minWidthProperty().bind(mainContainer.widthProperty());
|
||||
accountsPane.prefWidthProperty().bind(mainContainer.widthProperty());
|
||||
accountsPane.prefWrapLengthProperty().bind(mainContainer.widthProperty());
|
||||
accountsPane.maxWidthProperty().bind(mainContainer.widthProperty());
|
||||
List<Account> tempAccounts = List.of(
|
||||
new Account(AccountType.CHECKING, "1234-4324-4321-4143", BigDecimal.valueOf(3745.01), "Main Checking", Currency.getInstance("USD")),
|
||||
new Account(AccountType.CHECKING, "1234-4324-4321-4143", BigDecimal.valueOf(3745.01), "Main Checking", Currency.getInstance("USD")),
|
||||
new Account(AccountType.CHECKING, "1234-4324-4321-4143", BigDecimal.valueOf(3745.01), "Main Checking", Currency.getInstance("USD")),
|
||||
new Account(AccountType.CHECKING, "1234-4324-4321-4143", BigDecimal.valueOf(3745.01), "Main Checking", Currency.getInstance("USD"))
|
||||
);
|
||||
populateAccounts(tempAccounts);
|
||||
}
|
||||
|
||||
private void populateAccounts(List<Account> accounts) {
|
||||
accountsPane.getChildren().clear();
|
||||
for (var account : accounts) {
|
||||
Parent node = SceneUtil.loadNode(
|
||||
"/account-tile.fxml",
|
||||
(Consumer<AccountTileController>) c -> c.setAccount(account)
|
||||
);
|
||||
accountsPane.getChildren().add(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ public class StartupSplashScreenController {
|
|||
}
|
||||
|
||||
printlnLater("Perfin initialized. Starting the app now.");
|
||||
Thread.sleep(50000);
|
||||
Thread.sleep(500);
|
||||
|
||||
Platform.runLater(() -> getSplashStage().setDone());
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package com.andrewlalis.perfin.model;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Currency;
|
||||
|
||||
/**
|
||||
* The representation of a physical account of some sort (checking, savings,
|
||||
* credit-card, etc.).
|
||||
*/
|
||||
public class Account {
|
||||
private long id;
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
private AccountType type;
|
||||
private String accountNumber;
|
||||
private BigDecimal currentBalance;
|
||||
private String name;
|
||||
private Currency currency;
|
||||
|
||||
public Account(AccountType type, String accountNumber, BigDecimal currentBalance, String name, Currency currency) {
|
||||
this.type = type;
|
||||
this.accountNumber = accountNumber;
|
||||
this.currentBalance = currentBalance;
|
||||
this.name = name;
|
||||
this.currency = currency;
|
||||
}
|
||||
|
||||
public AccountType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getAccountNumber() {
|
||||
return accountNumber;
|
||||
}
|
||||
|
||||
public BigDecimal getCurrentBalance() {
|
||||
return currentBalance;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Currency getCurrency() {
|
||||
return currency;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package com.andrewlalis.perfin.model;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Currency;
|
||||
|
||||
/**
|
||||
* A single entry depicting a credit or debit to an account.
|
||||
* <p>
|
||||
* The following rules apply in determining the type of an entry:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>A <em>debit</em> indicates an increase in assets or decrease in liability.</li>
|
||||
* <li>A <em>credit</em> indicates a decrease in assets or increase in liability.</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class AccountEntry {
|
||||
public enum Type {
|
||||
CREDIT,
|
||||
DEBIT
|
||||
}
|
||||
|
||||
private long id;
|
||||
private LocalDateTime timestamp;
|
||||
private long accountId;
|
||||
private BigDecimal amount;
|
||||
private Type type;
|
||||
private Currency currency;
|
||||
|
||||
public AccountEntry(long id, LocalDateTime timestamp, long accountId, BigDecimal amount, Type type, Currency currency) {
|
||||
this.id = id;
|
||||
this.timestamp = timestamp;
|
||||
this.accountId = accountId;
|
||||
this.amount = amount;
|
||||
this.type = type;
|
||||
this.currency = currency;
|
||||
}
|
||||
|
||||
public AccountEntry(long accountId, BigDecimal amount, Type type, Currency currency) {
|
||||
this.accountId = accountId;
|
||||
this.amount = amount;
|
||||
this.type = type;
|
||||
this.currency = currency;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.andrewlalis.perfin.model;
|
||||
|
||||
public enum AccountType {
|
||||
CHECKING,
|
||||
SAVINGS,
|
||||
CREDIT_CARD
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.andrewlalis.perfin.model;
|
||||
|
||||
/**
|
||||
* A profile is essentially a complete set of data that the application can
|
||||
* operate on, sort of like a save file or user account. The profile contains
|
||||
* a set of accounts, transaction records, attached documents, historical data,
|
||||
* and more. A profile can be imported or exported easily from the application,
|
||||
* and can be encrypted for additional security. Each profile also has its own
|
||||
* settings.
|
||||
* Practically, each profile is stored as its own isolated database file, with
|
||||
* a name corresponding to the profile's name.
|
||||
*/
|
||||
public class Profile {
|
||||
private String name;
|
||||
|
||||
}
|
|
@ -3,9 +3,6 @@ package com.andrewlalis.perfin.view;
|
|||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.shape.Rectangle;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.StageStyle;
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ module com.andrewlalis.perfin {
|
|||
requires javafx.fxml;
|
||||
requires javafx.graphics;
|
||||
|
||||
requires org.xerial.sqlitejdbc;
|
||||
requires com.fasterxml.jackson.databind;
|
||||
|
||||
exports com.andrewlalis.perfin to javafx.graphics;
|
||||
opens com.andrewlalis.perfin.control to javafx.fxml;
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
|
||||
<VBox
|
||||
styleClass="account-tile-container"
|
||||
prefHeight="100.0"
|
||||
prefWidth="200.0"
|
||||
stylesheets="@style/account-tile.css"
|
||||
xmlns="http://javafx.com/javafx/17.0.2-ea"
|
||||
xmlns:fx="http://javafx.com/fxml/1"
|
||||
fx:controller="com.andrewlalis.perfin.control.AccountTileController"
|
||||
fx:id="container"
|
||||
>
|
||||
<Label styleClass="main-label" text="Account Info" />
|
||||
<Separator prefWidth="200.0" />
|
||||
<Label text="Account Number" styleClass="property-label"/>
|
||||
<Label fx:id="accountNumberLabel" styleClass="property-value" text="Account Number placeholder" />
|
||||
<Label text="Account Balance" styleClass="property-label"/>
|
||||
<Label fx:id="accountBalanceLabel" styleClass="property-value" text="account balance placeholder" />
|
||||
<VBox fx:id="accountNameBox">
|
||||
<Label text="Account Name" styleClass="property-label"/>
|
||||
<Label fx:id="accountNameLabel" styleClass="property-value" text="account name placeholder"/>
|
||||
</VBox>
|
||||
</VBox>
|
|
@ -1,24 +1,31 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
|
||||
|
||||
<BorderPane xmlns="http://javafx.com/javafx/17.0.2-ea"
|
||||
<?import javafx.scene.layout.BorderPane?>
|
||||
<?import javafx.scene.layout.FlowPane?>
|
||||
<BorderPane
|
||||
minHeight="400.0"
|
||||
minWidth="600.0"
|
||||
xmlns="http://javafx.com/javafx/17.0.2-ea"
|
||||
xmlns:fx="http://javafx.com/fxml/1"
|
||||
fx:controller="com.andrewlalis.perfin.control.MainController"
|
||||
minWidth="600.0" minHeight="400.0">
|
||||
fx:id="mainContainer"
|
||||
stylesheets="@style/main.css"
|
||||
>
|
||||
<top>
|
||||
<MenuBar BorderPane.alignment="CENTER">
|
||||
<Menu mnemonicParsing="false" text="File">
|
||||
<MenuItem mnemonicParsing="false" text="Close"/>
|
||||
<MenuItem mnemonicParsing="false" text="Close" />
|
||||
</Menu>
|
||||
<Menu mnemonicParsing="false" text="Edit">
|
||||
<MenuItem mnemonicParsing="false" text="Delete"/>
|
||||
<MenuItem mnemonicParsing="false" text="Delete" />
|
||||
</Menu>
|
||||
<Menu mnemonicParsing="false" text="Help">
|
||||
<MenuItem mnemonicParsing="false" text="About"/>
|
||||
<MenuItem mnemonicParsing="false" text="About" />
|
||||
</Menu>
|
||||
</MenuBar>
|
||||
</top>
|
||||
<center>
|
||||
<FlowPane fx:id="accountsPane" BorderPane.alignment="TOP_LEFT" vgap="5" hgap="5"/>
|
||||
</center>
|
||||
</BorderPane>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
xmlns="http://javafx.com/javafx/17.0.2-ea"
|
||||
xmlns:fx="http://javafx.com/fxml/1"
|
||||
fx:controller="com.andrewlalis.perfin.control.StartupSplashScreenController"
|
||||
stylesheets="/startup-splash-screen.css"
|
||||
stylesheets="@style/startup-splash-screen.css"
|
||||
>
|
||||
<center>
|
||||
<TextArea fx:id="content" wrapText="true" editable="false" focusTraversable="false"/>
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
.account-tile-container {
|
||||
-fx-border-color: lightgray;
|
||||
-fx-border-width: 1px;
|
||||
-fx-border-style: solid;
|
||||
-fx-padding: 5px;
|
||||
}
|
||||
|
||||
.account-tile-container:hover {
|
||||
-fx-cursor: hand;
|
||||
}
|
||||
|
||||
.main-label {
|
||||
-fx-font-weight: bold;
|
||||
-fx-font-size: large;
|
||||
}
|
||||
|
||||
.property-label {
|
||||
-fx-font-weight: bold;
|
||||
}
|
||||
|
||||
.property-value {
|
||||
-fx-font-family: monospace;
|
||||
-fx-font-size: large;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
#accountsPane {
|
||||
-fx-padding: 5px;
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
#sceneRoot {
|
||||
-fx-background-image: url("images/splash-screen.png");
|
||||
-fx-background-image: url("../images/splash-screen.png");
|
||||
-fx-background-repeat: stretch;
|
||||
-fx-background-size: 400 200;
|
||||
-fx-background-color: transparent;
|
Loading…
Reference in New Issue