diff --git a/pom.xml b/pom.xml
index a74db60..13c3211 100644
--- a/pom.xml
+++ b/pom.xml
@@ -29,7 +29,7 @@
com.andrewlalis
javafx-scene-router
- 1.1.0
+ 1.3.0
diff --git a/src/main/java/com/andrewlalis/perfin/PerfinApp.java b/src/main/java/com/andrewlalis/perfin/PerfinApp.java
index 3ad66d4..474f055 100644
--- a/src/main/java/com/andrewlalis/perfin/PerfinApp.java
+++ b/src/main/java/com/andrewlalis/perfin/PerfinApp.java
@@ -1,14 +1,12 @@
package com.andrewlalis.perfin;
import com.andrewlalis.javafx_scene_router.SceneRouter;
-import com.andrewlalis.perfin.control.MainViewController;
import com.andrewlalis.perfin.view.SplashScreenStage;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.nio.file.Path;
-import java.util.function.Consumer;
/**
* The class from which the JavaFX-based application starts.
@@ -39,16 +37,14 @@ public class PerfinApp extends Application {
private void initMainScreen(Stage stage) {
stage.hide();
- Scene mainViewScene = SceneUtil.load("/main-view.fxml", (Consumer) c -> {
- c.mainContainer.setCenter(router.getViewPane());
- router.navigate("accounts");
- });
+ Scene mainViewScene = SceneUtil.load("/main-view.fxml");
stage.setScene(mainViewScene);
stage.setTitle("Perfin");
}
private static void defineRoutes() {
- router.map("accounts", SceneUtil.loadNode("/accounts-view.fxml"));
- router.map("edit-account", SceneUtil.loadNode("/edit-account.fxml"));
+ router.map("accounts", PerfinApp.class.getResource("/accounts-view.fxml"));
+ router.map("account", PerfinApp.class.getResource("/account-view.fxml"));
+ router.map("edit-account", PerfinApp.class.getResource("/edit-account.fxml"));
}
}
\ No newline at end of file
diff --git a/src/main/java/com/andrewlalis/perfin/control/AccountTileController.java b/src/main/java/com/andrewlalis/perfin/control/AccountTileController.java
index 4f7cead..3e4cd09 100644
--- a/src/main/java/com/andrewlalis/perfin/control/AccountTileController.java
+++ b/src/main/java/com/andrewlalis/perfin/control/AccountTileController.java
@@ -8,6 +8,8 @@ import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
+import static com.andrewlalis.perfin.PerfinApp.router;
+
public class AccountTileController {
private Account account;
@@ -37,6 +39,7 @@ public class AccountTileController {
accountNameLabel.setText(account.getName());
container.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> {
System.out.println("Clicked on " + account.getAccountNumber());
+ router.navigate("account", account);
});
});
}
diff --git a/src/main/java/com/andrewlalis/perfin/control/AccountViewController.java b/src/main/java/com/andrewlalis/perfin/control/AccountViewController.java
new file mode 100644
index 0000000..f47b4cd
--- /dev/null
+++ b/src/main/java/com/andrewlalis/perfin/control/AccountViewController.java
@@ -0,0 +1,36 @@
+package com.andrewlalis.perfin.control;
+
+import com.andrewlalis.javafx_scene_router.RouteSelectionListener;
+import com.andrewlalis.perfin.model.Account;
+import javafx.fxml.FXML;
+import javafx.scene.control.Label;
+import javafx.scene.control.TextField;
+
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+
+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;
+
+ @Override
+ public void onRouteSelected(Object context) {
+ account = (Account) context;
+ titleLabel.setText("Account: " + account.getAccountNumber());
+
+ accountNameField.setText(account.getName());
+ accountNumberField.setText(account.getAccountNumber());
+ accountCurrencyField.setText(account.getCurrency().getDisplayName());
+ accountCreatedAtField.setText(account.getCreatedAt().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
+ }
+}
diff --git a/src/main/java/com/andrewlalis/perfin/control/AccountsViewController.java b/src/main/java/com/andrewlalis/perfin/control/AccountsViewController.java
index 86dc784..1d0f74d 100644
--- a/src/main/java/com/andrewlalis/perfin/control/AccountsViewController.java
+++ b/src/main/java/com/andrewlalis/perfin/control/AccountsViewController.java
@@ -1,23 +1,23 @@
package com.andrewlalis.perfin.control;
+import com.andrewlalis.javafx_scene_router.RouteSelectionListener;
import com.andrewlalis.perfin.SceneUtil;
import com.andrewlalis.perfin.model.Account;
import com.andrewlalis.perfin.model.Profile;
import com.andrewlalis.perfin.view.BindingUtil;
-import javafx.application.Platform;
import javafx.beans.property.SimpleListProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
-import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
-import javafx.stage.Stage;
import java.util.function.Consumer;
-public class AccountsViewController {
+import static com.andrewlalis.perfin.PerfinApp.router;
+
+public class AccountsViewController implements RouteSelectionListener {
@FXML
public BorderPane mainContainer;
@FXML
@@ -47,17 +47,21 @@ public class AccountsViewController {
noAccountsLabel.managedProperty().bind(noAccountsLabel.visibleProperty());
accountsPane.visibleProperty().bind(listProp.emptyProperty().not());
accountsPane.managedProperty().bind(accountsPane.visibleProperty());
-
- // Populate the list of accounts once a profile is available.
- Profile.whenLoaded(profile -> {
- accountsList.setAll(profile.getDataSource().getAccountRepository().findAll());
- });
}
@FXML
public void createNewAccount() {
- Stage mainStage = (Stage) mainContainer.getScene().getWindow();
- Scene editAccountScene = SceneUtil.load("/edit-account.fxml");
- mainStage.setScene(editAccountScene);
+ router.navigate("edit-account");
+ }
+
+ @Override
+ public void onRouteSelected(Object context) {
+ refreshAccounts();
+ }
+
+ public void refreshAccounts() {
+ Profile.whenLoaded(profile -> {
+ accountsList.setAll(profile.getDataSource().getAccountRepository().findAll());
+ });
}
}
diff --git a/src/main/java/com/andrewlalis/perfin/control/EditAccountController.java b/src/main/java/com/andrewlalis/perfin/control/EditAccountController.java
new file mode 100644
index 0000000..d65a0e9
--- /dev/null
+++ b/src/main/java/com/andrewlalis/perfin/control/EditAccountController.java
@@ -0,0 +1,93 @@
+package com.andrewlalis.perfin.control;
+
+import com.andrewlalis.javafx_scene_router.RouteSelectionListener;
+import com.andrewlalis.perfin.model.Account;
+import com.andrewlalis.perfin.model.AccountType;
+import com.andrewlalis.perfin.model.Profile;
+import javafx.fxml.FXML;
+import javafx.scene.control.ChoiceBox;
+import javafx.scene.control.ComboBox;
+import javafx.scene.control.Label;
+import javafx.scene.control.TextField;
+
+import java.util.Currency;
+
+import static com.andrewlalis.perfin.PerfinApp.router;
+
+public class EditAccountController implements RouteSelectionListener {
+ private Account account;
+ @FXML
+ public Label titleLabel;
+ @FXML
+ public TextField accountNameField;
+ @FXML
+ public TextField accountNumberField;
+ @FXML
+ public ComboBox accountCurrencyComboBox;
+ @FXML
+ public ChoiceBox accountTypeChoiceBox;
+
+ @FXML
+ public void initialize() {
+ final String[] currencies = {
+ "USD",
+ "EUR",
+ "GBP"
+ };
+ for (String currencyCode : currencies) {
+ accountCurrencyComboBox.getItems().add(Currency.getInstance(currencyCode));
+ }
+ accountCurrencyComboBox.getSelectionModel().select(Currency.getInstance("USD"));
+
+ accountTypeChoiceBox.getItems().add("Checking");
+ accountTypeChoiceBox.getItems().add("Savings");
+ accountTypeChoiceBox.getItems().add("Credit Card");
+ accountTypeChoiceBox.getSelectionModel().select("Checking");
+ }
+
+ @Override
+ public void onRouteSelected(Object context) {
+ this.account = (Account) context;
+ if (account == null) {
+ titleLabel.setText("Editing New Account");
+ } else {
+ titleLabel.setText("Editing Account: " + account.getName());
+ }
+ resetForm();
+ }
+
+ @FXML
+ public void save() {
+ if (account == null) {
+ // If we're editing a new account.
+ String name = accountNameField.getText().strip();
+ String number = accountNumberField.getText().strip();
+ AccountType type = AccountType.parse(accountTypeChoiceBox.getValue());
+ Currency currency = accountCurrencyComboBox.getValue();
+ Account newAccount = new Account(type, number, name, currency);
+ Profile.getCurrent().getDataSource().getAccountRepository().insert(newAccount);
+
+ // Once we create the new account, go to the account.
+ router.getHistory().clear();
+ router.navigate("accounts");
+ } else {
+ throw new IllegalStateException("Not implemented.");
+ }
+ }
+
+ @FXML
+ public void cancel() {
+ router.navigateBack();
+ }
+
+ public void resetForm() {
+ if (account == null) {
+ accountNameField.setText("");
+ accountNumberField.setText("");
+ accountTypeChoiceBox.getSelectionModel().selectFirst();
+ accountCurrencyComboBox.getSelectionModel().select(Currency.getInstance("USD"));
+ } else {
+ // TODO: Set to original account.
+ }
+ }
+}
diff --git a/src/main/java/com/andrewlalis/perfin/control/MainViewController.java b/src/main/java/com/andrewlalis/perfin/control/MainViewController.java
index 13363f8..a436872 100644
--- a/src/main/java/com/andrewlalis/perfin/control/MainViewController.java
+++ b/src/main/java/com/andrewlalis/perfin/control/MainViewController.java
@@ -1,7 +1,8 @@
package com.andrewlalis.perfin.control;
-import javafx.event.ActionEvent;
+import com.andrewlalis.perfin.view.BindingUtil;
import javafx.fxml.FXML;
+import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
@@ -12,15 +13,30 @@ public class MainViewController {
public BorderPane mainContainer;
@FXML
public HBox mainFooter;
+ @FXML
+ public HBox breadcrumbHBox;
@FXML
- public void goToAccounts() {
+ public void initialize() {
+ mainContainer.setCenter(router.getViewPane());
+ BindingUtil.mapContent(
+ breadcrumbHBox.getChildren(),
+ router.getBreadCrumbs(),
+ breadCrumb -> {
+ Label label = new Label("> " + breadCrumb.route());
+ if (breadCrumb.current()) {
+ label.setStyle("-fx-font-weight: bold");
+ }
+ return label;
+ }
+ );
+
router.navigate("accounts");
}
@FXML
- public void goToEditAccounts() {
- router.navigate("edit-account");
+ public void goToAccounts() {
+ router.navigate("accounts");
}
@FXML
diff --git a/src/main/java/com/andrewlalis/perfin/model/Account.java b/src/main/java/com/andrewlalis/perfin/model/Account.java
index 2b5ff05..6970096 100644
--- a/src/main/java/com/andrewlalis/perfin/model/Account.java
+++ b/src/main/java/com/andrewlalis/perfin/model/Account.java
@@ -47,4 +47,12 @@ public class Account {
public Currency getCurrency() {
return currency;
}
+
+ public LocalDateTime getCreatedAt() {
+ return createdAt;
+ }
+
+ public long getId() {
+ return id;
+ }
}
diff --git a/src/main/java/com/andrewlalis/perfin/model/AccountType.java b/src/main/java/com/andrewlalis/perfin/model/AccountType.java
index 827912e..ab70752 100644
--- a/src/main/java/com/andrewlalis/perfin/model/AccountType.java
+++ b/src/main/java/com/andrewlalis/perfin/model/AccountType.java
@@ -3,5 +3,15 @@ package com.andrewlalis.perfin.model;
public enum AccountType {
CHECKING,
SAVINGS,
- CREDIT_CARD
+ CREDIT_CARD;
+
+ public static AccountType parse(String s) {
+ s = s.strip().toUpperCase();
+ return switch (s) {
+ case "CHECKING" -> CHECKING;
+ case "SAVINGS" -> SAVINGS;
+ case "CREDIT CARD", "CREDITCARD" -> CREDIT_CARD;
+ default -> throw new IllegalArgumentException("Invalid AccountType string: " + s);
+ };
+ }
}
diff --git a/src/main/resources/account-view.fxml b/src/main/resources/account-view.fxml
new file mode 100644
index 0000000..250f23e
--- /dev/null
+++ b/src/main/resources/account-view.fxml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/edit-account.fxml b/src/main/resources/edit-account.fxml
index db7302f..c3ce635 100644
--- a/src/main/resources/edit-account.fxml
+++ b/src/main/resources/edit-account.fxml
@@ -2,32 +2,39 @@
-
-
+
-
+
-
+
-
+
-
+
-
-
+
+
+
+
-
-
+
+
diff --git a/src/main/resources/main-view.fxml b/src/main/resources/main-view.fxml
index 3184886..d29c343 100644
--- a/src/main/resources/main-view.fxml
+++ b/src/main/resources/main-view.fxml
@@ -1,8 +1,7 @@
-
-
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/style/account-view.css b/src/main/resources/style/account-view.css
new file mode 100644
index 0000000..392f1f1
--- /dev/null
+++ b/src/main/resources/style/account-view.css
@@ -0,0 +1,25 @@
+.main-container {
+ -fx-padding: 5px;
+}
+
+#titleLabel {
+ -fx-font-weight: bold;
+ -fx-font-size: large;
+}
+
+.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: 200px;
+}
+
+#accountNumberField {
+ -fx-font-family: monospace;
+}
diff --git a/src/main/resources/style/edit-account.css b/src/main/resources/style/edit-account.css
new file mode 100644
index 0000000..3bf0093
--- /dev/null
+++ b/src/main/resources/style/edit-account.css
@@ -0,0 +1,14 @@
+.main-container {
+ -fx-padding: 5px;
+}
+
+.fields-grid {
+ -fx-hgap: 3px;
+ -fx-vgap: 3px;
+ -fx-padding: 5px;
+}
+
+#titleLabel {
+ -fx-font-size: large;
+ -fx-font-weight: bold;
+}
diff --git a/src/main/resources/style/main-view.css b/src/main/resources/style/main-view.css
index 78504ff..d2bfef5 100644
--- a/src/main/resources/style/main-view.css
+++ b/src/main/resources/style/main-view.css
@@ -1,5 +1,11 @@
#mainHeader {
-fx-padding: 3px;
+ -fx-spacing: 3px;
+}
+
+#breadcrumbHBox {
+ -fx-spacing: 3px;
+ -fx-font-size: small;
}
#mainFooter {