Cleaned up CSS, and added a new transaction-view.fxml and associated controller for viewing the details of a transaction.
This commit is contained in:
		
							parent
							
								
									53bfea2bad
								
							
						
					
					
						commit
						2658fc5c58
					
				| 
						 | 
					@ -53,5 +53,6 @@ public class PerfinApp extends Application {
 | 
				
			||||||
        mapResourceRoute("edit-account", "/edit-account.fxml");
 | 
					        mapResourceRoute("edit-account", "/edit-account.fxml");
 | 
				
			||||||
        mapResourceRoute("transactions", "/transactions-view.fxml");
 | 
					        mapResourceRoute("transactions", "/transactions-view.fxml");
 | 
				
			||||||
        mapResourceRoute("create-transaction", "/create-transaction.fxml");
 | 
					        mapResourceRoute("create-transaction", "/create-transaction.fxml");
 | 
				
			||||||
 | 
					        mapResourceRoute("transaction", "/transaction-view.fxml");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -13,8 +13,6 @@ public class MainViewController {
 | 
				
			||||||
    @FXML
 | 
					    @FXML
 | 
				
			||||||
    public BorderPane mainContainer;
 | 
					    public BorderPane mainContainer;
 | 
				
			||||||
    @FXML
 | 
					    @FXML
 | 
				
			||||||
    public HBox mainFooter;
 | 
					 | 
				
			||||||
    @FXML
 | 
					 | 
				
			||||||
    public HBox breadcrumbHBox;
 | 
					    public HBox breadcrumbHBox;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @FXML
 | 
					    @FXML
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,14 @@
 | 
				
			||||||
 | 
					package com.andrewlalis.perfin.control;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javafx.scene.control.Alert;
 | 
				
			||||||
 | 
					import javafx.scene.control.ButtonType;
 | 
				
			||||||
 | 
					import javafx.stage.Modality;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class Popups {
 | 
				
			||||||
 | 
					    public static boolean confirm(String text) {
 | 
				
			||||||
 | 
					        Alert alert = new Alert(Alert.AlertType.CONFIRMATION, text);
 | 
				
			||||||
 | 
					        alert.initModality(Modality.APPLICATION_MODAL);
 | 
				
			||||||
 | 
					        var result = alert.showAndWait();
 | 
				
			||||||
 | 
					        return result.isPresent() && result.get() == ButtonType.OK;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,104 @@
 | 
				
			||||||
 | 
					package com.andrewlalis.perfin.control;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.andrewlalis.javafx_scene_router.RouteSelectionListener;
 | 
				
			||||||
 | 
					import com.andrewlalis.perfin.data.CurrencyUtil;
 | 
				
			||||||
 | 
					import com.andrewlalis.perfin.data.DateUtil;
 | 
				
			||||||
 | 
					import com.andrewlalis.perfin.model.CreditAndDebitAccounts;
 | 
				
			||||||
 | 
					import com.andrewlalis.perfin.model.Profile;
 | 
				
			||||||
 | 
					import com.andrewlalis.perfin.model.Transaction;
 | 
				
			||||||
 | 
					import com.andrewlalis.perfin.model.TransactionAttachment;
 | 
				
			||||||
 | 
					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.control.Hyperlink;
 | 
				
			||||||
 | 
					import javafx.scene.control.Label;
 | 
				
			||||||
 | 
					import javafx.scene.layout.HBox;
 | 
				
			||||||
 | 
					import javafx.scene.layout.VBox;
 | 
				
			||||||
 | 
					import javafx.scene.text.TextFlow;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static com.andrewlalis.perfin.PerfinApp.router;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class TransactionViewController implements RouteSelectionListener {
 | 
				
			||||||
 | 
					    private Transaction transaction;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @FXML public Label amountLabel;
 | 
				
			||||||
 | 
					    @FXML public Label timestampLabel;
 | 
				
			||||||
 | 
					    @FXML public Label descriptionLabel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @FXML public Hyperlink debitAccountLink;
 | 
				
			||||||
 | 
					    @FXML public Hyperlink creditAccountLink;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @FXML public VBox attachmentsContainer;
 | 
				
			||||||
 | 
					    @FXML public HBox attachmentsHBox;
 | 
				
			||||||
 | 
					    private final ObservableList<TransactionAttachment> attachmentsList = FXCollections.observableArrayList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void onRouteSelected(Object context) {
 | 
				
			||||||
 | 
					        this.transaction = (Transaction) context;
 | 
				
			||||||
 | 
					        amountLabel.setText(CurrencyUtil.formatMoney(transaction.getAmount(), transaction.getCurrency()));
 | 
				
			||||||
 | 
					        timestampLabel.setText(DateUtil.formatUTCAsLocalWithZone(transaction.getTimestamp()));
 | 
				
			||||||
 | 
					        descriptionLabel.setText(transaction.getDescription());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        configureAccountLinkBindings(debitAccountLink);
 | 
				
			||||||
 | 
					        configureAccountLinkBindings(creditAccountLink);
 | 
				
			||||||
 | 
					        Thread.ofVirtual().start(() -> {
 | 
				
			||||||
 | 
					            Profile.getCurrent().getDataSource().useTransactionRepository(repo -> {
 | 
				
			||||||
 | 
					                CreditAndDebitAccounts accounts = repo.findLinkedAccounts(transaction.getId());
 | 
				
			||||||
 | 
					                Platform.runLater(() -> {
 | 
				
			||||||
 | 
					                    if (accounts.hasDebit()) {
 | 
				
			||||||
 | 
					                        debitAccountLink.setText(accounts.debitAccount().getShortName());
 | 
				
			||||||
 | 
					                        debitAccountLink.setOnAction(event -> router.navigate("account", accounts.debitAccount()));
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    if (accounts.hasCredit()) {
 | 
				
			||||||
 | 
					                        creditAccountLink.setText(accounts.creditAccount().getShortName());
 | 
				
			||||||
 | 
					                        creditAccountLink.setOnAction(event -> router.navigate("account", accounts.creditAccount()));
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        attachmentsContainer.managedProperty().bind(attachmentsContainer.visibleProperty());
 | 
				
			||||||
 | 
					        attachmentsContainer.visibleProperty().bind(new SimpleListProperty<>(attachmentsList).emptyProperty().not());
 | 
				
			||||||
 | 
					        Thread.ofVirtual().start(() -> {
 | 
				
			||||||
 | 
					            Profile.getCurrent().getDataSource().useTransactionRepository(repo -> {
 | 
				
			||||||
 | 
					                List<TransactionAttachment> attachments = repo.findAttachments(transaction.getId());
 | 
				
			||||||
 | 
					                Platform.runLater(() -> attachmentsList.setAll(attachments));
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        BindingUtil.mapContent(attachmentsHBox.getChildren(), attachmentsList, attachment -> {
 | 
				
			||||||
 | 
					            VBox vbox = new VBox(
 | 
				
			||||||
 | 
					                    new Label(attachment.getFilename()),
 | 
				
			||||||
 | 
					                    new Label(attachment.getContentType())
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            return vbox;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @FXML public void deleteTransaction() {
 | 
				
			||||||
 | 
					        boolean confirm = Popups.confirm(
 | 
				
			||||||
 | 
					            "Are you sure you want to delete this transaction? This will " +
 | 
				
			||||||
 | 
					            "permanently remove the transaction and its effects on any linked " +
 | 
				
			||||||
 | 
					            "accounts, as well as remove any attachments from storage within " +
 | 
				
			||||||
 | 
					            "this app."
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        if (confirm) {
 | 
				
			||||||
 | 
					            Profile.getCurrent().getDataSource().useTransactionRepository(repo -> {
 | 
				
			||||||
 | 
					                // TODO: Delete attachments first!
 | 
				
			||||||
 | 
					                repo.delete(transaction.getId());
 | 
				
			||||||
 | 
					                router.getHistory().clear();
 | 
				
			||||||
 | 
					                router.navigate("transactions");
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void configureAccountLinkBindings(Hyperlink link) {
 | 
				
			||||||
 | 
					        TextFlow parent = (TextFlow) link.getParent();
 | 
				
			||||||
 | 
					        parent.managedProperty().bind(parent.visibleProperty());
 | 
				
			||||||
 | 
					        parent.visibleProperty().bind(link.textProperty().isNotEmpty());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -2,16 +2,14 @@ package com.andrewlalis.perfin.control.component;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.andrewlalis.perfin.data.CurrencyUtil;
 | 
					import com.andrewlalis.perfin.data.CurrencyUtil;
 | 
				
			||||||
import com.andrewlalis.perfin.data.DateUtil;
 | 
					import com.andrewlalis.perfin.data.DateUtil;
 | 
				
			||||||
import com.andrewlalis.perfin.model.Account;
 | 
					import com.andrewlalis.perfin.model.*;
 | 
				
			||||||
import com.andrewlalis.perfin.model.AccountEntry;
 | 
					 | 
				
			||||||
import com.andrewlalis.perfin.model.Profile;
 | 
					 | 
				
			||||||
import com.andrewlalis.perfin.model.Transaction;
 | 
					 | 
				
			||||||
import javafx.application.Platform;
 | 
					import javafx.application.Platform;
 | 
				
			||||||
import javafx.scene.Node;
 | 
					import javafx.scene.Node;
 | 
				
			||||||
import javafx.scene.control.Alert;
 | 
					import javafx.scene.control.Alert;
 | 
				
			||||||
import javafx.scene.control.ButtonType;
 | 
					import javafx.scene.control.ButtonType;
 | 
				
			||||||
import javafx.scene.control.Hyperlink;
 | 
					import javafx.scene.control.Hyperlink;
 | 
				
			||||||
import javafx.scene.control.Label;
 | 
					import javafx.scene.control.Label;
 | 
				
			||||||
 | 
					import javafx.scene.input.MouseEvent;
 | 
				
			||||||
import javafx.scene.layout.BorderPane;
 | 
					import javafx.scene.layout.BorderPane;
 | 
				
			||||||
import javafx.scene.layout.HBox;
 | 
					import javafx.scene.layout.HBox;
 | 
				
			||||||
import javafx.scene.layout.VBox;
 | 
					import javafx.scene.layout.VBox;
 | 
				
			||||||
| 
						 | 
					@ -35,11 +33,13 @@ public class TransactionTile extends BorderPane {
 | 
				
			||||||
                -fx-border-radius: 5px;
 | 
					                -fx-border-radius: 5px;
 | 
				
			||||||
                -fx-padding: 5px;
 | 
					                -fx-padding: 5px;
 | 
				
			||||||
                -fx-max-width: 500px;
 | 
					                -fx-max-width: 500px;
 | 
				
			||||||
 | 
					                -fx-cursor: hand;
 | 
				
			||||||
                """);
 | 
					                """);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        setTop(getHeader(transaction));
 | 
					        setTop(getHeader(transaction));
 | 
				
			||||||
        setCenter(getBody(transaction));
 | 
					        setCenter(getBody(transaction));
 | 
				
			||||||
        setBottom(getFooter(transaction, refresh));
 | 
					        setBottom(getFooter(transaction, refresh));
 | 
				
			||||||
 | 
					        addEventHandler(MouseEvent.MOUSE_CLICKED, event -> router.navigate("transaction", transaction));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private Node getHeader(Transaction transaction) {
 | 
					    private Node getHeader(Transaction transaction) {
 | 
				
			||||||
| 
						 | 
					@ -61,19 +61,18 @@ public class TransactionTile extends BorderPane {
 | 
				
			||||||
                descriptionLabel
 | 
					                descriptionLabel
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        getCreditAndDebitAccounts(transaction).thenAccept(accounts -> {
 | 
					        getCreditAndDebitAccounts(transaction).thenAccept(accounts -> {
 | 
				
			||||||
            Account creditAccount = accounts.getKey();
 | 
					            accounts.ifCredit(acc -> {
 | 
				
			||||||
            Account debitAccount = accounts.getValue();
 | 
					                Hyperlink link = new Hyperlink(acc.getShortName());
 | 
				
			||||||
            if (creditAccount != null) {
 | 
					                link.setOnAction(event -> router.navigate("account", acc));
 | 
				
			||||||
                Hyperlink link = new Hyperlink(creditAccount.getShortName());
 | 
					 | 
				
			||||||
                link.setOnAction(event -> router.navigate("account", creditAccount));
 | 
					 | 
				
			||||||
                TextFlow text = new TextFlow(new Text("Credited from"), link);
 | 
					                TextFlow text = new TextFlow(new Text("Credited from"), link);
 | 
				
			||||||
                Platform.runLater(() -> bodyVBox.getChildren().add(text));
 | 
					                Platform.runLater(() -> bodyVBox.getChildren().add(text));
 | 
				
			||||||
            } if (debitAccount != null) {
 | 
					            });
 | 
				
			||||||
                Hyperlink link = new Hyperlink(debitAccount.getShortName());
 | 
					            accounts.ifDebit(acc -> {
 | 
				
			||||||
                link.setOnAction(event -> router.navigate("account", debitAccount));
 | 
					                Hyperlink link = new Hyperlink(acc.getShortName());
 | 
				
			||||||
 | 
					                link.setOnAction(event -> router.navigate("account", acc));
 | 
				
			||||||
                TextFlow text = new TextFlow(new Text("Debited to"), link);
 | 
					                TextFlow text = new TextFlow(new Text("Debited to"), link);
 | 
				
			||||||
                Platform.runLater(() -> bodyVBox.getChildren().add(text));
 | 
					                Platform.runLater(() -> bodyVBox.getChildren().add(text));
 | 
				
			||||||
            }
 | 
					            });
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        return bodyVBox;
 | 
					        return bodyVBox;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -91,8 +90,7 @@ public class TransactionTile extends BorderPane {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        HBox footerHBox = new HBox(
 | 
					        HBox footerHBox = new HBox(
 | 
				
			||||||
                timestampLabel,
 | 
					                timestampLabel
 | 
				
			||||||
                deleteLink
 | 
					 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        footerHBox.setStyle("""
 | 
					        footerHBox.setStyle("""
 | 
				
			||||||
                -fx-spacing: 3px;
 | 
					                -fx-spacing: 3px;
 | 
				
			||||||
| 
						 | 
					@ -101,18 +99,12 @@ public class TransactionTile extends BorderPane {
 | 
				
			||||||
        return footerHBox;
 | 
					        return footerHBox;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private CompletableFuture<Pair<Account, Account>> getCreditAndDebitAccounts(Transaction transaction) {
 | 
					    private CompletableFuture<CreditAndDebitAccounts> getCreditAndDebitAccounts(Transaction transaction) {
 | 
				
			||||||
        CompletableFuture<Pair<Account, Account>> cf = new CompletableFuture<>();
 | 
					        CompletableFuture<CreditAndDebitAccounts> cf = new CompletableFuture<>();
 | 
				
			||||||
        Thread.ofVirtual().start(() -> {
 | 
					        Thread.ofVirtual().start(() -> {
 | 
				
			||||||
            Profile.getCurrent().getDataSource().useTransactionRepository(repo -> {
 | 
					            Profile.getCurrent().getDataSource().useTransactionRepository(repo -> {
 | 
				
			||||||
                var entriesAndAccounts = repo.findEntriesWithAccounts(transaction.getId());
 | 
					                CreditAndDebitAccounts accounts = repo.findLinkedAccounts(transaction.getId());
 | 
				
			||||||
                AccountEntry creditEntry = entriesAndAccounts.keySet().stream()
 | 
					                cf.complete(accounts);
 | 
				
			||||||
                        .filter(entry -> entry.getType() == AccountEntry.Type.CREDIT)
 | 
					 | 
				
			||||||
                        .findFirst().orElse(null);
 | 
					 | 
				
			||||||
                AccountEntry debitEntry = entriesAndAccounts.keySet().stream()
 | 
					 | 
				
			||||||
                        .filter(entry -> entry.getType() == AccountEntry.Type.DEBIT)
 | 
					 | 
				
			||||||
                        .findFirst().orElse(null);
 | 
					 | 
				
			||||||
                cf.complete(new Pair<>(entriesAndAccounts.get(creditEntry), entriesAndAccounts.get(debitEntry)));
 | 
					 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        return cf;
 | 
					        return cf;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,10 +2,7 @@ package com.andrewlalis.perfin.data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.andrewlalis.perfin.data.pagination.Page;
 | 
					import com.andrewlalis.perfin.data.pagination.Page;
 | 
				
			||||||
import com.andrewlalis.perfin.data.pagination.PageRequest;
 | 
					import com.andrewlalis.perfin.data.pagination.PageRequest;
 | 
				
			||||||
import com.andrewlalis.perfin.model.Account;
 | 
					import com.andrewlalis.perfin.model.*;
 | 
				
			||||||
import com.andrewlalis.perfin.model.AccountEntry;
 | 
					 | 
				
			||||||
import com.andrewlalis.perfin.model.Transaction;
 | 
					 | 
				
			||||||
import com.andrewlalis.perfin.model.TransactionAttachment;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
import java.util.Map;
 | 
					import java.util.Map;
 | 
				
			||||||
| 
						 | 
					@ -17,6 +14,7 @@ public interface TransactionRepository extends AutoCloseable {
 | 
				
			||||||
    Page<Transaction> findAll(PageRequest pagination);
 | 
					    Page<Transaction> findAll(PageRequest pagination);
 | 
				
			||||||
    Page<Transaction> findAllByAccounts(Set<Long> accountIds, PageRequest pagination);
 | 
					    Page<Transaction> findAllByAccounts(Set<Long> accountIds, PageRequest pagination);
 | 
				
			||||||
    Map<AccountEntry, Account> findEntriesWithAccounts(long transactionId);
 | 
					    Map<AccountEntry, Account> findEntriesWithAccounts(long transactionId);
 | 
				
			||||||
 | 
					    CreditAndDebitAccounts findLinkedAccounts(long transactionId);
 | 
				
			||||||
    List<TransactionAttachment> findAttachments(long transactionId);
 | 
					    List<TransactionAttachment> findAttachments(long transactionId);
 | 
				
			||||||
    void delete(long transactionId);
 | 
					    void delete(long transactionId);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,10 +4,7 @@ import com.andrewlalis.perfin.data.DbUtil;
 | 
				
			||||||
import com.andrewlalis.perfin.data.TransactionRepository;
 | 
					import com.andrewlalis.perfin.data.TransactionRepository;
 | 
				
			||||||
import com.andrewlalis.perfin.data.pagination.Page;
 | 
					import com.andrewlalis.perfin.data.pagination.Page;
 | 
				
			||||||
import com.andrewlalis.perfin.data.pagination.PageRequest;
 | 
					import com.andrewlalis.perfin.data.pagination.PageRequest;
 | 
				
			||||||
import com.andrewlalis.perfin.model.Account;
 | 
					import com.andrewlalis.perfin.model.*;
 | 
				
			||||||
import com.andrewlalis.perfin.model.AccountEntry;
 | 
					 | 
				
			||||||
import com.andrewlalis.perfin.model.Transaction;
 | 
					 | 
				
			||||||
import com.andrewlalis.perfin.model.TransactionAttachment;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.sql.Connection;
 | 
					import java.sql.Connection;
 | 
				
			||||||
import java.sql.ResultSet;
 | 
					import java.sql.ResultSet;
 | 
				
			||||||
| 
						 | 
					@ -127,6 +124,33 @@ public record JdbcTransactionRepository(Connection conn) implements TransactionR
 | 
				
			||||||
        return map;
 | 
					        return map;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public CreditAndDebitAccounts findLinkedAccounts(long transactionId) {
 | 
				
			||||||
 | 
					        Account creditAccount = DbUtil.findOne(
 | 
				
			||||||
 | 
					                conn,
 | 
				
			||||||
 | 
					                """
 | 
				
			||||||
 | 
					                        SELECT *
 | 
				
			||||||
 | 
					                        FROM account
 | 
				
			||||||
 | 
					                        LEFT JOIN account_entry ON account_entry.account_id = account.id
 | 
				
			||||||
 | 
					                        WHERE account_entry.transaction_id = ? AND account_entry.type = 'CREDIT'
 | 
				
			||||||
 | 
					                        """,
 | 
				
			||||||
 | 
					                List.of(transactionId),
 | 
				
			||||||
 | 
					                JdbcAccountRepository::parseAccount
 | 
				
			||||||
 | 
					        ).orElse(null);
 | 
				
			||||||
 | 
					        Account debitAccount = DbUtil.findOne(
 | 
				
			||||||
 | 
					                conn,
 | 
				
			||||||
 | 
					                """
 | 
				
			||||||
 | 
					                        SELECT *
 | 
				
			||||||
 | 
					                        FROM account
 | 
				
			||||||
 | 
					                        LEFT JOIN account_entry ON account_entry.account_id = account.id
 | 
				
			||||||
 | 
					                        WHERE account_entry.transaction_id = ? AND account_entry.type = 'DEBIT'
 | 
				
			||||||
 | 
					                        """,
 | 
				
			||||||
 | 
					                List.of(transactionId),
 | 
				
			||||||
 | 
					                JdbcAccountRepository::parseAccount
 | 
				
			||||||
 | 
					        ).orElse(null);
 | 
				
			||||||
 | 
					        return new CreditAndDebitAccounts(creditAccount, debitAccount);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public List<TransactionAttachment> findAttachments(long transactionId) {
 | 
					    public List<TransactionAttachment> findAttachments(long transactionId) {
 | 
				
			||||||
        return DbUtil.findAll(
 | 
					        return DbUtil.findAll(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,21 @@
 | 
				
			||||||
 | 
					package com.andrewlalis.perfin.model;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.function.Consumer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public record CreditAndDebitAccounts(Account creditAccount, Account debitAccount) {
 | 
				
			||||||
 | 
					    public boolean hasCredit() {
 | 
				
			||||||
 | 
					        return creditAccount != null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public boolean hasDebit() {
 | 
				
			||||||
 | 
					        return debitAccount != null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void ifCredit(Consumer<Account> accountConsumer) {
 | 
				
			||||||
 | 
					        if (hasCredit()) accountConsumer.accept(creditAccount);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void ifDebit(Consumer<Account> accountConsumer) {
 | 
				
			||||||
 | 
					        if (hasDebit()) accountConsumer.accept(debitAccount);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -6,14 +6,15 @@
 | 
				
			||||||
        xmlns="http://javafx.com/javafx"
 | 
					        xmlns="http://javafx.com/javafx"
 | 
				
			||||||
        xmlns:fx="http://javafx.com/fxml"
 | 
					        xmlns:fx="http://javafx.com/fxml"
 | 
				
			||||||
        fx:controller="com.andrewlalis.perfin.control.AccountViewController"
 | 
					        fx:controller="com.andrewlalis.perfin.control.AccountViewController"
 | 
				
			||||||
        stylesheets="@style/account-view.css"
 | 
					        stylesheets="@style/account-view.css,@style/base.css"
 | 
				
			||||||
        styleClass="main-container"
 | 
					 | 
				
			||||||
>
 | 
					>
 | 
				
			||||||
    <top>
 | 
					    <top>
 | 
				
			||||||
        <Label fx:id="titleLabel"/>
 | 
					        <HBox styleClass="std-padding,std-spacing">
 | 
				
			||||||
 | 
					            <Label fx:id="titleLabel" styleClass="large-text,bold-text"/>
 | 
				
			||||||
 | 
					        </HBox>
 | 
				
			||||||
    </top>
 | 
					    </top>
 | 
				
			||||||
    <center>
 | 
					    <center>
 | 
				
			||||||
        <VBox>
 | 
					        <VBox styleClass="std-padding,std-spacing">
 | 
				
			||||||
            <HBox>
 | 
					            <HBox>
 | 
				
			||||||
                <!-- Main account properties. -->
 | 
					                <!-- Main account properties. -->
 | 
				
			||||||
                <VBox HBox.hgrow="SOMETIMES" style="-fx-border-color: blue">
 | 
					                <VBox HBox.hgrow="SOMETIMES" style="-fx-border-color: blue">
 | 
				
			||||||
| 
						 | 
					@ -23,7 +24,7 @@
 | 
				
			||||||
                    </VBox>
 | 
					                    </VBox>
 | 
				
			||||||
                    <VBox styleClass="account-property-box">
 | 
					                    <VBox styleClass="account-property-box">
 | 
				
			||||||
                        <Label text="Number"/>
 | 
					                        <Label text="Number"/>
 | 
				
			||||||
                        <TextField fx:id="accountNumberField" editable="false"/>
 | 
					                        <TextField fx:id="accountNumberField" editable="false" styleClass="mono-font"/>
 | 
				
			||||||
                    </VBox>
 | 
					                    </VBox>
 | 
				
			||||||
                    <VBox styleClass="account-property-box">
 | 
					                    <VBox styleClass="account-property-box">
 | 
				
			||||||
                        <Label text="Currency"/>
 | 
					                        <Label text="Currency"/>
 | 
				
			||||||
| 
						 | 
					@ -45,8 +46,8 @@
 | 
				
			||||||
        </VBox>
 | 
					        </VBox>
 | 
				
			||||||
    </center>
 | 
					    </center>
 | 
				
			||||||
    <right>
 | 
					    <right>
 | 
				
			||||||
        <VBox styleClass="actions-box">
 | 
					        <VBox styleClass="std-padding,std-spacing">
 | 
				
			||||||
            <Label text="Actions" style="-fx-font-weight: bold;"/>
 | 
					            <Label text="Actions" styleClass="bold-text"/>
 | 
				
			||||||
            <Button text="Edit" onAction="#goToEditPage"/>
 | 
					            <Button text="Edit" onAction="#goToEditPage"/>
 | 
				
			||||||
            <Button text="Archive" onAction="#archiveAccount"/>
 | 
					            <Button text="Archive" onAction="#archiveAccount"/>
 | 
				
			||||||
            <Button text="Delete" onAction="#deleteAccount"/>
 | 
					            <Button text="Delete" onAction="#deleteAccount"/>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,10 +8,10 @@
 | 
				
			||||||
        xmlns="http://javafx.com/javafx/17.0.2-ea"
 | 
					        xmlns="http://javafx.com/javafx/17.0.2-ea"
 | 
				
			||||||
        xmlns:fx="http://javafx.com/fxml/1"
 | 
					        xmlns:fx="http://javafx.com/fxml/1"
 | 
				
			||||||
        fx:controller="com.andrewlalis.perfin.control.AccountsViewController"
 | 
					        fx:controller="com.andrewlalis.perfin.control.AccountsViewController"
 | 
				
			||||||
        stylesheets="@style/accounts-view.css"
 | 
					        stylesheets="@style/base.css"
 | 
				
			||||||
>
 | 
					>
 | 
				
			||||||
    <top>
 | 
					    <top>
 | 
				
			||||||
        <HBox styleClass="actionsBar">
 | 
					        <HBox styleClass="std-padding,std-spacing">
 | 
				
			||||||
            <Button text="Add an Account" onAction="#createNewAccount"/>
 | 
					            <Button text="Add an Account" onAction="#createNewAccount"/>
 | 
				
			||||||
            <Label fx:id="totalLabel"/>
 | 
					            <Label fx:id="totalLabel"/>
 | 
				
			||||||
        </HBox>
 | 
					        </HBox>
 | 
				
			||||||
| 
						 | 
					@ -19,9 +19,9 @@
 | 
				
			||||||
    <center>
 | 
					    <center>
 | 
				
			||||||
        <VBox>
 | 
					        <VBox>
 | 
				
			||||||
            <ScrollPane fitToHeight="true" fitToWidth="true" VBox.vgrow="ALWAYS">
 | 
					            <ScrollPane fitToHeight="true" fitToWidth="true" VBox.vgrow="ALWAYS">
 | 
				
			||||||
                <FlowPane fx:id="accountsPane" BorderPane.alignment="TOP_LEFT" vgap="5" hgap="5"/>
 | 
					                <FlowPane fx:id="accountsPane" BorderPane.alignment="TOP_LEFT" vgap="5" hgap="5" styleClass="std-padding"/>
 | 
				
			||||||
            </ScrollPane>
 | 
					            </ScrollPane>
 | 
				
			||||||
            <Label fx:id="noAccountsLabel" BorderPane.alignment="TOP_LEFT" text="No accounts have been added to this profile."/>
 | 
					            <Label fx:id="noAccountsLabel" BorderPane.alignment="TOP_LEFT" styleClass="std-padding" text="No accounts have been added to this profile."/>
 | 
				
			||||||
        </VBox>
 | 
					        </VBox>
 | 
				
			||||||
    </center>
 | 
					    </center>
 | 
				
			||||||
</BorderPane>
 | 
					</BorderPane>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,11 +5,11 @@
 | 
				
			||||||
<BorderPane xmlns="http://javafx.com/javafx"
 | 
					<BorderPane xmlns="http://javafx.com/javafx"
 | 
				
			||||||
            xmlns:fx="http://javafx.com/fxml"
 | 
					            xmlns:fx="http://javafx.com/fxml"
 | 
				
			||||||
            fx:controller="com.andrewlalis.perfin.control.CreateTransactionController"
 | 
					            fx:controller="com.andrewlalis.perfin.control.CreateTransactionController"
 | 
				
			||||||
            stylesheets="@style/create-transaction.css"
 | 
					            stylesheets="@style/base.css"
 | 
				
			||||||
>
 | 
					>
 | 
				
			||||||
    <center>
 | 
					    <center>
 | 
				
			||||||
        <ScrollPane fitToWidth="true" fitToHeight="true">
 | 
					        <ScrollPane fitToWidth="true" fitToHeight="true">
 | 
				
			||||||
            <VBox styleClass="form-container">
 | 
					            <VBox styleClass="std-spacing,std-padding" style="-fx-max-width: 500px;">
 | 
				
			||||||
                <!-- Basic properties -->
 | 
					                <!-- Basic properties -->
 | 
				
			||||||
                <VBox>
 | 
					                <VBox>
 | 
				
			||||||
                    <Label text="Timestamp" labelFor="${timestampField}" styleClass="bold-text"/>
 | 
					                    <Label text="Timestamp" labelFor="${timestampField}" styleClass="bold-text"/>
 | 
				
			||||||
| 
						 | 
					@ -28,12 +28,17 @@
 | 
				
			||||||
                <VBox>
 | 
					                <VBox>
 | 
				
			||||||
                    <Label text="Description" labelFor="${descriptionField}" styleClass="bold-text"/>
 | 
					                    <Label text="Description" labelFor="${descriptionField}" styleClass="bold-text"/>
 | 
				
			||||||
                    <Label text="Maximum of 255 characters." styleClass="small-text"/>
 | 
					                    <Label text="Maximum of 255 characters." styleClass="small-text"/>
 | 
				
			||||||
                    <TextArea fx:id="descriptionField" styleClass="mono-font" wrapText="true"/>
 | 
					                    <TextArea
 | 
				
			||||||
 | 
					                            fx:id="descriptionField"
 | 
				
			||||||
 | 
					                            styleClass="mono-font"
 | 
				
			||||||
 | 
					                            wrapText="true"
 | 
				
			||||||
 | 
					                            style="-fx-pref-height: 100px;-fx-min-height: 100px;"
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
                    <Label fx:id="descriptionErrorLabel" styleClass="error-text" wrapText="true"/>
 | 
					                    <Label fx:id="descriptionErrorLabel" styleClass="error-text" wrapText="true"/>
 | 
				
			||||||
                </VBox>
 | 
					                </VBox>
 | 
				
			||||||
                <!-- Container for linked accounts -->
 | 
					                <!-- Container for linked accounts -->
 | 
				
			||||||
                <VBox>
 | 
					                <VBox>
 | 
				
			||||||
                    <HBox spacing="3">
 | 
					                    <HBox styleClass="std-spacing">
 | 
				
			||||||
                        <VBox>
 | 
					                        <VBox>
 | 
				
			||||||
                            <Label text="Debited Account" labelFor="${linkDebitAccountComboBox}" styleClass="bold-text"/>
 | 
					                            <Label text="Debited Account" labelFor="${linkDebitAccountComboBox}" styleClass="bold-text"/>
 | 
				
			||||||
                            <ComboBox fx:id="linkDebitAccountComboBox">
 | 
					                            <ComboBox fx:id="linkDebitAccountComboBox">
 | 
				
			||||||
| 
						 | 
					@ -60,7 +65,7 @@
 | 
				
			||||||
                <VBox>
 | 
					                <VBox>
 | 
				
			||||||
                    <Label text="Attachments" styleClass="bold-text"/>
 | 
					                    <Label text="Attachments" styleClass="bold-text"/>
 | 
				
			||||||
                    <Label text="Attach receipts, invoices, or other content to this transaction." styleClass="small-text" wrapText="true"/>
 | 
					                    <Label text="Attach receipts, invoices, or other content to this transaction." styleClass="small-text" wrapText="true"/>
 | 
				
			||||||
                    <VBox fx:id="selectedFilesVBox" style="-fx-spacing: 3px; -fx-padding: 3px;" VBox.vgrow="NEVER"/>
 | 
					                    <VBox fx:id="selectedFilesVBox" styleClass="std-padding,std-spacing" VBox.vgrow="NEVER"/>
 | 
				
			||||||
                    <Label text="No attachments selected." fx:id="noSelectedFilesLabel"/>
 | 
					                    <Label text="No attachments selected." fx:id="noSelectedFilesLabel"/>
 | 
				
			||||||
                    <Button text="Select attachments" onAction="#selectAttachmentFile"/>
 | 
					                    <Button text="Select attachments" onAction="#selectAttachmentFile"/>
 | 
				
			||||||
                </VBox>
 | 
					                </VBox>
 | 
				
			||||||
| 
						 | 
					@ -68,7 +73,7 @@
 | 
				
			||||||
        </ScrollPane>
 | 
					        </ScrollPane>
 | 
				
			||||||
    </center>
 | 
					    </center>
 | 
				
			||||||
    <bottom>
 | 
					    <bottom>
 | 
				
			||||||
        <HBox styleClass="buttons-container">
 | 
					        <HBox styleClass="std-padding,std-spacing">
 | 
				
			||||||
            <Button text="Save" onAction="#save"/>
 | 
					            <Button text="Save" onAction="#save"/>
 | 
				
			||||||
            <Button text="Cancel" onAction="#cancel"/>
 | 
					            <Button text="Cancel" onAction="#cancel"/>
 | 
				
			||||||
        </HBox>
 | 
					        </HBox>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,14 +6,15 @@
 | 
				
			||||||
        xmlns="http://javafx.com/javafx/17.0.2-ea"
 | 
					        xmlns="http://javafx.com/javafx/17.0.2-ea"
 | 
				
			||||||
        xmlns:fx="http://javafx.com/fxml/1"
 | 
					        xmlns:fx="http://javafx.com/fxml/1"
 | 
				
			||||||
        fx:controller="com.andrewlalis.perfin.control.EditAccountController"
 | 
					        fx:controller="com.andrewlalis.perfin.control.EditAccountController"
 | 
				
			||||||
        stylesheets="@style/edit-account.css"
 | 
					        stylesheets="@style/edit-account.css,@style/base.css"
 | 
				
			||||||
        styleClass="main-container"
 | 
					 | 
				
			||||||
>
 | 
					>
 | 
				
			||||||
    <top>
 | 
					    <top>
 | 
				
			||||||
        <Label fx:id="titleLabel" text="Edit Account"/>
 | 
					        <HBox styleClass="std-padding,std-spacing">
 | 
				
			||||||
 | 
					            <Label text="Edit Account" styleClass="large-text,bold-text"/>
 | 
				
			||||||
 | 
					        </HBox>
 | 
				
			||||||
    </top>
 | 
					    </top>
 | 
				
			||||||
    <center>
 | 
					    <center>
 | 
				
			||||||
        <GridPane BorderPane.alignment="TOP_LEFT" styleClass="fields-grid">
 | 
					        <GridPane BorderPane.alignment="TOP_LEFT" styleClass="fields-grid,std-padding">
 | 
				
			||||||
            <columnConstraints>
 | 
					            <columnConstraints>
 | 
				
			||||||
                <ColumnConstraints hgrow="NEVER" minWidth="10.0" />
 | 
					                <ColumnConstraints hgrow="NEVER" minWidth="10.0" />
 | 
				
			||||||
                <ColumnConstraints hgrow="ALWAYS" minWidth="10.0" />
 | 
					                <ColumnConstraints hgrow="ALWAYS" minWidth="10.0" />
 | 
				
			||||||
| 
						 | 
					@ -32,7 +33,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <VBox fx:id="initialBalanceContent" GridPane.columnIndex="0" GridPane.rowIndex="4" GridPane.columnSpan="2">
 | 
					            <VBox fx:id="initialBalanceContent" GridPane.columnIndex="0" GridPane.rowIndex="4" GridPane.columnSpan="2">
 | 
				
			||||||
                <Separator/>
 | 
					                <Separator/>
 | 
				
			||||||
                <Label text="Initial Balance" style="-fx-font-weight: bold;"/>
 | 
					                <Label text="Initial Balance" styleClass="bold-text"/>
 | 
				
			||||||
                <TextField fx:id="initialBalanceField"/>
 | 
					                <TextField fx:id="initialBalanceField"/>
 | 
				
			||||||
            </VBox>
 | 
					            </VBox>
 | 
				
			||||||
        </GridPane>
 | 
					        </GridPane>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,22 +7,21 @@
 | 
				
			||||||
        xmlns:fx="http://javafx.com/fxml"
 | 
					        xmlns:fx="http://javafx.com/fxml"
 | 
				
			||||||
        fx:id="mainContainer"
 | 
					        fx:id="mainContainer"
 | 
				
			||||||
        fx:controller="com.andrewlalis.perfin.control.MainViewController"
 | 
					        fx:controller="com.andrewlalis.perfin.control.MainViewController"
 | 
				
			||||||
        stylesheets="@style/main-view.css"
 | 
					        stylesheets="@style/base.css"
 | 
				
			||||||
>
 | 
					>
 | 
				
			||||||
    <top>
 | 
					    <top>
 | 
				
			||||||
        <VBox>
 | 
					        <VBox>
 | 
				
			||||||
            <HBox style="-fx-spacing: 3px; -fx-padding: 3px;">
 | 
					            <HBox styleClass="std-padding,std-spacing">
 | 
				
			||||||
                <Button text="Back" onAction="#goBack"/>
 | 
					                <Button text="Back" onAction="#goBack"/>
 | 
				
			||||||
                <Button text="Forward" onAction="#goForward"/>
 | 
					                <Button text="Forward" onAction="#goForward"/>
 | 
				
			||||||
                <Button text="Accounts" onAction="#goToAccounts"/>
 | 
					                <Button text="Accounts" onAction="#goToAccounts"/>
 | 
				
			||||||
                <Button text="Transactions" onAction="#goToTransactions"/>
 | 
					                <Button text="Transactions" onAction="#goToTransactions"/>
 | 
				
			||||||
            </HBox>
 | 
					            </HBox>
 | 
				
			||||||
            <HBox fx:id="breadcrumbHBox"/>
 | 
					            <HBox fx:id="breadcrumbHBox" styleClass="std-spacing,small-text"/>
 | 
				
			||||||
            <Separator/>
 | 
					 | 
				
			||||||
        </VBox>
 | 
					        </VBox>
 | 
				
			||||||
    </top>
 | 
					    </top>
 | 
				
			||||||
    <bottom>
 | 
					    <bottom>
 | 
				
			||||||
        <HBox fx:id="mainFooter" spacing="5">
 | 
					        <HBox styleClass="std-padding,std-spacing">
 | 
				
			||||||
            <Label text="Perfin v0.0.1"/>
 | 
					            <Label text="Perfin v0.0.1"/>
 | 
				
			||||||
        </HBox>
 | 
					        </HBox>
 | 
				
			||||||
    </bottom>
 | 
					    </bottom>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,12 +1,3 @@
 | 
				
			||||||
.main-container {
 | 
					 | 
				
			||||||
    -fx-padding: 5px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#titleLabel {
 | 
					 | 
				
			||||||
    -fx-font-weight: bold;
 | 
					 | 
				
			||||||
    -fx-font-size: large;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.account-property-box {
 | 
					.account-property-box {
 | 
				
			||||||
    -fx-padding: 5px 0 5px 0;
 | 
					    -fx-padding: 5px 0 5px 0;
 | 
				
			||||||
    -fx-spacing: 3px;
 | 
					    -fx-spacing: 3px;
 | 
				
			||||||
| 
						 | 
					@ -21,14 +12,6 @@
 | 
				
			||||||
    -fx-max-width: 300px;
 | 
					    -fx-max-width: 300px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#accountNumberField {
 | 
					 | 
				
			||||||
    -fx-font-family: monospace;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.actions-box {
 | 
					 | 
				
			||||||
    -fx-spacing: 3px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.actions-box > Button {
 | 
					.actions-box > Button {
 | 
				
			||||||
    -fx-max-width: 500px;
 | 
					    -fx-max-width: 500px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,11 +0,0 @@
 | 
				
			||||||
#accountsPane {
 | 
					 | 
				
			||||||
    -fx-padding: 3px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#noAccountsLabel {
 | 
					 | 
				
			||||||
    -fx-padding: 3px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.actionsBar {
 | 
					 | 
				
			||||||
    -fx-padding: 3px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,11 @@
 | 
				
			||||||
    -fx-font-family: monospace;
 | 
					    -fx-font-family: monospace;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.error-text {
 | 
				
			||||||
 | 
					    -fx-font-size: small;
 | 
				
			||||||
 | 
					    -fx-text-fill: red;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.bold-text {
 | 
					.bold-text {
 | 
				
			||||||
    -fx-font-weight: bold;
 | 
					    -fx-font-weight: bold;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -10,23 +15,14 @@
 | 
				
			||||||
    -fx-font-size: small;
 | 
					    -fx-font-size: small;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.error-text {
 | 
					.large-text {
 | 
				
			||||||
    -fx-font-size: small;
 | 
					    -fx-font-size: large;
 | 
				
			||||||
    -fx-text-fill: red;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.form-container {
 | 
					.std-padding {
 | 
				
			||||||
    -fx-max-width: 500px;
 | 
					 | 
				
			||||||
    -fx-spacing: 3px;
 | 
					 | 
				
			||||||
    -fx-padding: 3px;
 | 
					    -fx-padding: 3px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.buttons-container {
 | 
					.std-spacing {
 | 
				
			||||||
    -fx-padding: 3px;
 | 
					 | 
				
			||||||
    -fx-spacing: 3px;
 | 
					    -fx-spacing: 3px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
#descriptionField {
 | 
					 | 
				
			||||||
    -fx-pref-height: 100px;
 | 
					 | 
				
			||||||
    -fx-min-height: 100px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,15 +1,5 @@
 | 
				
			||||||
.main-container {
 | 
					 | 
				
			||||||
    -fx-padding: 5px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.fields-grid {
 | 
					.fields-grid {
 | 
				
			||||||
    -fx-hgap: 3px;
 | 
					    -fx-hgap: 3px;
 | 
				
			||||||
    -fx-vgap: 3px;
 | 
					    -fx-vgap: 3px;
 | 
				
			||||||
    -fx-padding: 5px;
 | 
					 | 
				
			||||||
    -fx-max-width: 500px;
 | 
					    -fx-max-width: 500px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
#titleLabel {
 | 
					 | 
				
			||||||
    -fx-font-size: large;
 | 
					 | 
				
			||||||
    -fx-font-weight: bold;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,13 +0,0 @@
 | 
				
			||||||
#mainHeader {
 | 
					 | 
				
			||||||
    -fx-padding: 3px;
 | 
					 | 
				
			||||||
    -fx-spacing: 3px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#breadcrumbHBox {
 | 
					 | 
				
			||||||
    -fx-spacing: 3px;
 | 
					 | 
				
			||||||
    -fx-font-size: small;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#mainFooter {
 | 
					 | 
				
			||||||
    -fx-padding: 3px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,56 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<?import javafx.scene.control.*?>
 | 
				
			||||||
 | 
					<?import javafx.scene.layout.*?>
 | 
				
			||||||
 | 
					<?import javafx.scene.text.Text?>
 | 
				
			||||||
 | 
					<?import javafx.scene.text.TextFlow?>
 | 
				
			||||||
 | 
					<BorderPane xmlns="http://javafx.com/javafx"
 | 
				
			||||||
 | 
					            xmlns:fx="http://javafx.com/fxml"
 | 
				
			||||||
 | 
					            fx:controller="com.andrewlalis.perfin.control.TransactionViewController"
 | 
				
			||||||
 | 
					>
 | 
				
			||||||
 | 
					    <top>
 | 
				
			||||||
 | 
					        <HBox styleClass="std-padding,std-spacing">
 | 
				
			||||||
 | 
					            <Label text="Transaction" styleClass="large-text,bold-text"/>
 | 
				
			||||||
 | 
					        </HBox>
 | 
				
			||||||
 | 
					    </top>
 | 
				
			||||||
 | 
					    <center>
 | 
				
			||||||
 | 
					        <VBox styleClass="std-padding,std-spacing">
 | 
				
			||||||
 | 
					            <VBox>
 | 
				
			||||||
 | 
					                <Label text="Amount" styleClass="bold-text"/>
 | 
				
			||||||
 | 
					                <Label fx:id="amountLabel" styleClass="mono-font"/>
 | 
				
			||||||
 | 
					            </VBox>
 | 
				
			||||||
 | 
					            <VBox>
 | 
				
			||||||
 | 
					                <Label text="Timestamp" styleClass="bold-text"/>
 | 
				
			||||||
 | 
					                <Label fx:id="timestampLabel" styleClass="mono-font"/>
 | 
				
			||||||
 | 
					            </VBox>
 | 
				
			||||||
 | 
					            <VBox>
 | 
				
			||||||
 | 
					                <Label text="Description" styleClass="bold-text"/>
 | 
				
			||||||
 | 
					                <Label fx:id="descriptionLabel" wrapText="true"/>
 | 
				
			||||||
 | 
					            </VBox>
 | 
				
			||||||
 | 
					            <Separator/>
 | 
				
			||||||
 | 
					            <VBox>
 | 
				
			||||||
 | 
					                <TextFlow>
 | 
				
			||||||
 | 
					                    <Text text="Debited to"/>
 | 
				
			||||||
 | 
					                    <Hyperlink fx:id="debitAccountLink"/>
 | 
				
			||||||
 | 
					                </TextFlow>
 | 
				
			||||||
 | 
					                <TextFlow>
 | 
				
			||||||
 | 
					                    <Text text="Credited from"/>
 | 
				
			||||||
 | 
					                    <Hyperlink fx:id="creditAccountLink"/>
 | 
				
			||||||
 | 
					                </TextFlow>
 | 
				
			||||||
 | 
					            </VBox>
 | 
				
			||||||
 | 
					            <Separator/>
 | 
				
			||||||
 | 
					            <VBox fx:id="attachmentsContainer">
 | 
				
			||||||
 | 
					                <Label text="Attachments" styleClass="bold-text"/>
 | 
				
			||||||
 | 
					                <ScrollPane fitToWidth="true" fitToHeight="true">
 | 
				
			||||||
 | 
					                    <HBox fx:id="attachmentsHBox" styleClass="std-padding,std-spacing"/>
 | 
				
			||||||
 | 
					                </ScrollPane>
 | 
				
			||||||
 | 
					            </VBox>
 | 
				
			||||||
 | 
					        </VBox>
 | 
				
			||||||
 | 
					    </center>
 | 
				
			||||||
 | 
					    <right>
 | 
				
			||||||
 | 
					        <VBox styleClass="std-padding,std-spacing">
 | 
				
			||||||
 | 
					            <Label text="Actions" styleClass="bold-text"/>
 | 
				
			||||||
 | 
					            <Button text="Delete" onAction="#deleteTransaction"/>
 | 
				
			||||||
 | 
					        </VBox>
 | 
				
			||||||
 | 
					    </right>
 | 
				
			||||||
 | 
					</BorderPane>
 | 
				
			||||||
		Loading…
	
		Reference in New Issue