From 53ff257323ad0a8312c24908f536027bc0a7d363 Mon Sep 17 00:00:00 2001 From: andrewlalis Date: Fri, 15 Dec 2023 11:04:26 -0500 Subject: [PATCH] Added account tile, more model definitions, and improved scene and node loading. --- pom.xml | 17 +++++-- .../com/andrewlalis/perfin/SceneUtil.java | 27 +++++++---- .../perfin/control/AccountTileController.java | 45 +++++++++++++++++ .../perfin/control/MainController.java | 37 ++++++++++++++ .../StartupSplashScreenController.java | 2 +- .../com/andrewlalis/perfin/model/Account.java | 48 +++++++++++++++++++ .../perfin/model/AccountEntry.java | 45 +++++++++++++++++ .../andrewlalis/perfin/model/AccountType.java | 7 +++ .../com/andrewlalis/perfin/model/Profile.java | 16 +++++++ .../perfin/view/SplashScreenStage.java | 3 -- src/main/java/module-info.java | 2 +- src/main/resources/account-tile.fxml | 26 ++++++++++ src/main/resources/main.fxml | 27 +++++++---- src/main/resources/startup-splash-screen.fxml | 2 +- src/main/resources/style/account-tile.css | 24 ++++++++++ src/main/resources/style/main.css | 3 ++ .../{ => style}/startup-splash-screen.css | 2 +- 17 files changed, 305 insertions(+), 28 deletions(-) create mode 100644 src/main/java/com/andrewlalis/perfin/control/AccountTileController.java create mode 100644 src/main/java/com/andrewlalis/perfin/model/Account.java create mode 100644 src/main/java/com/andrewlalis/perfin/model/AccountEntry.java create mode 100644 src/main/java/com/andrewlalis/perfin/model/AccountType.java create mode 100644 src/main/java/com/andrewlalis/perfin/model/Profile.java create mode 100644 src/main/resources/account-tile.fxml create mode 100644 src/main/resources/style/account-tile.css create mode 100644 src/main/resources/style/main.css rename src/main/resources/{ => style}/startup-splash-screen.css (91%) diff --git a/pom.xml b/pom.xml index 928fd11..9745481 100644 --- a/pom.xml +++ b/pom.xml @@ -28,9 +28,20 @@ - org.xerial - sqlite-jdbc - 3.44.1.0 + com.fasterxml.jackson.core + jackson-databind + 2.16.0 + + + com.fasterxml.jackson.core + jackson-core + 2.16.0 + + + + com.h2database + h2 + 2.2.224 diff --git a/src/main/java/com/andrewlalis/perfin/SceneUtil.java b/src/main/java/com/andrewlalis/perfin/SceneUtil.java index 7c984a3..e46ef50 100644 --- a/src/main/java/com/andrewlalis/perfin/SceneUtil.java +++ b/src/main/java/com/andrewlalis/perfin/SceneUtil.java @@ -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 Parent loadNode(String fxml, Consumer 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 Scene load(String fxml, Consumer controllerConfig) { + return new Scene(loadNode(fxml, controllerConfig)); + } + public static Scene load(String fxml) { return load(fxml, null); } diff --git a/src/main/java/com/andrewlalis/perfin/control/AccountTileController.java b/src/main/java/com/andrewlalis/perfin/control/AccountTileController.java new file mode 100644 index 0000000..9b90203 --- /dev/null +++ b/src/main/java/com/andrewlalis/perfin/control/AccountTileController.java @@ -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 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()); + }); + }); + } +} diff --git a/src/main/java/com/andrewlalis/perfin/control/MainController.java b/src/main/java/com/andrewlalis/perfin/control/MainController.java index c8847c3..125cb74 100644 --- a/src/main/java/com/andrewlalis/perfin/control/MainController.java +++ b/src/main/java/com/andrewlalis/perfin/control/MainController.java @@ -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 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 accounts) { + accountsPane.getChildren().clear(); + for (var account : accounts) { + Parent node = SceneUtil.loadNode( + "/account-tile.fxml", + (Consumer) c -> c.setAccount(account) + ); + accountsPane.getChildren().add(node); + } } } diff --git a/src/main/java/com/andrewlalis/perfin/control/StartupSplashScreenController.java b/src/main/java/com/andrewlalis/perfin/control/StartupSplashScreenController.java index a998601..4c908a5 100644 --- a/src/main/java/com/andrewlalis/perfin/control/StartupSplashScreenController.java +++ b/src/main/java/com/andrewlalis/perfin/control/StartupSplashScreenController.java @@ -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) { diff --git a/src/main/java/com/andrewlalis/perfin/model/Account.java b/src/main/java/com/andrewlalis/perfin/model/Account.java new file mode 100644 index 0000000..bd3654e --- /dev/null +++ b/src/main/java/com/andrewlalis/perfin/model/Account.java @@ -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; + } +} diff --git a/src/main/java/com/andrewlalis/perfin/model/AccountEntry.java b/src/main/java/com/andrewlalis/perfin/model/AccountEntry.java new file mode 100644 index 0000000..50eba0c --- /dev/null +++ b/src/main/java/com/andrewlalis/perfin/model/AccountEntry.java @@ -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. + *

+ * The following rules apply in determining the type of an entry: + *

+ *
    + *
  • A debit indicates an increase in assets or decrease in liability.
  • + *
  • A credit indicates a decrease in assets or increase in liability.
  • + *
+ */ +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; + } +} diff --git a/src/main/java/com/andrewlalis/perfin/model/AccountType.java b/src/main/java/com/andrewlalis/perfin/model/AccountType.java new file mode 100644 index 0000000..827912e --- /dev/null +++ b/src/main/java/com/andrewlalis/perfin/model/AccountType.java @@ -0,0 +1,7 @@ +package com.andrewlalis.perfin.model; + +public enum AccountType { + CHECKING, + SAVINGS, + CREDIT_CARD +} diff --git a/src/main/java/com/andrewlalis/perfin/model/Profile.java b/src/main/java/com/andrewlalis/perfin/model/Profile.java new file mode 100644 index 0000000..1a39e47 --- /dev/null +++ b/src/main/java/com/andrewlalis/perfin/model/Profile.java @@ -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; + +} diff --git a/src/main/java/com/andrewlalis/perfin/view/SplashScreenStage.java b/src/main/java/com/andrewlalis/perfin/view/SplashScreenStage.java index f5fcb90..159b0c7 100644 --- a/src/main/java/com/andrewlalis/perfin/view/SplashScreenStage.java +++ b/src/main/java/com/andrewlalis/perfin/view/SplashScreenStage.java @@ -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; diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index b4b18d2..ea1442c 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -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; diff --git a/src/main/resources/account-tile.fxml b/src/main/resources/account-tile.fxml new file mode 100644 index 0000000..8988e68 --- /dev/null +++ b/src/main/resources/account-tile.fxml @@ -0,0 +1,26 @@ + + + + + + + diff --git a/src/main/resources/main.fxml b/src/main/resources/main.fxml index 7776e5a..b88c606 100644 --- a/src/main/resources/main.fxml +++ b/src/main/resources/main.fxml @@ -1,24 +1,31 @@ - - - - + + + - + - + - + +
+ +
diff --git a/src/main/resources/startup-splash-screen.fxml b/src/main/resources/startup-splash-screen.fxml index 1b66411..ff47cdf 100644 --- a/src/main/resources/startup-splash-screen.fxml +++ b/src/main/resources/startup-splash-screen.fxml @@ -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" >