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