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 @@ - - + -
- +
-