Added start of transaction edit page.

This commit is contained in:
Andrew Lalis 2024-01-11 08:46:57 -05:00
parent 89d7438ab1
commit 7ceaca7068
8 changed files with 70 additions and 24 deletions

View File

@ -84,7 +84,7 @@ public class PerfinApp extends Application {
router.map("account", PerfinApp.class.getResource("/account-view.fxml"));
router.map("edit-account", PerfinApp.class.getResource("/edit-account.fxml"));
router.map("transactions", PerfinApp.class.getResource("/transactions-view.fxml"));
router.map("create-transaction", PerfinApp.class.getResource("/create-transaction.fxml"));
router.map("edit-transaction", PerfinApp.class.getResource("/edit-transaction.fxml"));
router.map("create-balance-record", PerfinApp.class.getResource("/create-balance-record.fxml"));
router.map("balance-record", PerfinApp.class.getResource("/balance-record-view.fxml"));

View File

@ -1,11 +1,13 @@
package com.andrewlalis.perfin.control;
import com.andrewlalis.javafx_scene_router.RouteSelectionListener;
import com.andrewlalis.perfin.data.util.CurrencyUtil;
import com.andrewlalis.perfin.data.util.DateUtil;
import com.andrewlalis.perfin.data.util.FileUtil;
import com.andrewlalis.perfin.model.Account;
import com.andrewlalis.perfin.model.CreditAndDebitAccounts;
import com.andrewlalis.perfin.model.Profile;
import com.andrewlalis.perfin.model.Transaction;
import com.andrewlalis.perfin.view.AccountComboBoxCellFactory;
import com.andrewlalis.perfin.view.component.FileSelectionArea;
import com.andrewlalis.perfin.view.component.validation.ValidationApplier;
@ -31,7 +33,9 @@ import java.util.List;
import static com.andrewlalis.perfin.PerfinApp.router;
public class CreateTransactionController implements RouteSelectionListener {
public class EditTransactionController implements RouteSelectionListener {
@FXML public Label titleLabel;
@FXML public TextField timestampField;
@FXML public TextField amountField;
@FXML public ChoiceBox<Currency> currencyChoiceBox;
@ -55,15 +59,13 @@ public class CreateTransactionController implements RouteSelectionListener {
return ts != null && ts.isBefore(LocalDateTime.now());
}, "Timestamp cannot be in the future.")
).validatedInitially().attachToTextField(timestampField);
var amountValid = new ValidationApplier<>(
new CurrencyAmountValidator(() -> currencyChoiceBox.getValue(), false, false)
).validatedInitially().attachToTextField(amountField, currencyChoiceBox.valueProperty());
var descriptionValid = new ValidationApplier<>(new PredicateValidator<String>()
.addTerminalPredicate(s -> s == null || s.length() <= 255, "Description is too long.")
).validatedInitially().attach(descriptionField, descriptionField.textProperty());
// Linked accounts will use a property derived from both the debit and credit selections.
Property<CreditAndDebitAccounts> linkedAccountsProperty = new SimpleObjectProperty<>(getSelectedAccounts());
linkDebitAccountComboBox.valueProperty().addListener((observable, oldValue, newValue) -> linkedAccountsProperty.setValue(getSelectedAccounts()));
linkCreditAccountComboBox.valueProperty().addListener((observable, oldValue, newValue) -> linkedAccountsProperty.setValue(getSelectedAccounts()));
@ -85,6 +87,7 @@ public class CreateTransactionController implements RouteSelectionListener {
linkCreditAccountComboBox.setCellFactory(cellFactory);
linkCreditAccountComboBox.setButtonCell(cellFactory.call(null));
currencyChoiceBox.valueProperty().addListener((observable, oldValue, newValue) -> {
System.out.println("Set currency to " + newValue);
updateLinkAccountComboBoxes(newValue);
});
@ -123,25 +126,49 @@ public class CreateTransactionController implements RouteSelectionListener {
@Override
public void onRouteSelected(Object context) {
resetForm();
}
Transaction transaction = (Transaction) context;
boolean creatingNew = transaction == null;
private void resetForm() {
if (creatingNew) {
titleLabel.setText("Create New Transaction");
timestampField.setText(LocalDateTime.now().format(DateUtil.DEFAULT_DATETIME_FORMAT));
amountField.setText(null);
currencyChoiceBox.getSelectionModel().selectFirst();
descriptionField.setText(null);
attachmentsSelectionArea.clear();
Thread.ofVirtual().start(() -> {
Profile.getCurrent().getDataSource().useAccountRepository(repo -> {
} else {
titleLabel.setText("Edit Transaction #" + transaction.id);
timestampField.setText(DateUtil.formatUTCAsLocal(transaction.getTimestamp()));
amountField.setText(CurrencyUtil.formatMoneyAsBasicNumber(transaction.getMoneyAmount()));
currencyChoiceBox.setValue(transaction.getCurrency());
descriptionField.setText(transaction.getDescription());
// TODO: Add an editable list of attachments from which some can be added and removed.
Thread.ofVirtual().start(() -> Profile.getCurrent().getDataSource().useTransactionRepository(repo -> {
CreditAndDebitAccounts accounts = repo.findLinkedAccounts(transaction.id);
Platform.runLater(() -> {
System.out.println(linkCreditAccountComboBox.getItems().indexOf(accounts.creditAccount()));
// linkCreditAccountComboBox.getSelectionModel().select(accounts.creditAccount());
// linkCreditAccountComboBox.getButtonCell().updateIndex(linkCreditAccountComboBox.getSelectionModel().getSelectedIndex());
// linkDebitAccountComboBox.getSelectionModel().select(accounts.debitAccount());
// linkDebitAccountComboBox.getButtonCell().updateIndex(linkDebitAccountComboBox.getSelectionModel().getSelectedIndex());
});
}));
}
Thread.ofVirtual().start(() -> Profile.getCurrent().getDataSource().useAccountRepository(repo -> {
var currencies = repo.findAllUsedCurrencies().stream()
.sorted(Comparator.comparing(Currency::getCurrencyCode))
.toList();
Platform.runLater(() -> {
currencyChoiceBox.getItems().setAll(currencies);
if (creatingNew) {
currencyChoiceBox.getSelectionModel().selectFirst();
} else {
currencyChoiceBox.getSelectionModel().select(transaction.getCurrency());
}
});
});
});
}));
}
private CreditAndDebitAccounts getSelectedAccounts() {
@ -186,6 +213,7 @@ public class CreateTransactionController implements RouteSelectionListener {
linkCreditAccountComboBox.getItems().addAll(availableAccounts);
linkCreditAccountComboBox.getSelectionModel().selectLast();
linkCreditAccountComboBox.getButtonCell().updateIndex(availableAccounts.size() - 1);
System.out.println("link account boxes updated.");
});
});
});

View File

@ -69,6 +69,10 @@ public class TransactionViewController {
});
}
@FXML public void editTransaction() {
router.navigate("edit-transaction", this.transaction);
}
@FXML public void deleteTransaction() {
boolean confirm = Popups.confirm(
"Are you sure you want to delete this transaction? This will " +

View File

@ -158,7 +158,7 @@ public class TransactionsViewController implements RouteSelectionListener {
}
@FXML public void addTransaction() {
router.navigate("create-transaction");
router.navigate("edit-transaction");
}
@FXML public void exportTransactions() {

View File

@ -18,6 +18,12 @@ public class DateUtil {
.format(DEFAULT_DATETIME_FORMAT_WITH_ZONE);
}
public static String formatUTCAsLocal(LocalDateTime utcTimestamp) {
return utcTimestamp.atOffset(ZoneOffset.UTC)
.atZoneSameInstant(ZoneId.systemDefault())
.format(DEFAULT_DATETIME_FORMAT);
}
public static LocalDateTime localToUTC(LocalDateTime localTime, ZoneId localZone) {
return localTime.atZone(localZone).withZoneSameInstant(ZoneOffset.UTC).toLocalDateTime();
}

View File

@ -61,6 +61,10 @@ public class FileSelectionArea extends VBox {
selectedFiles.clear();
}
public void setSelectedFiles(List<Path> files) {
selectedFiles.setAll(files);
}
private Node buildFileItem(Path path) {
Label filenameLabel = new Label(path.getFileName().toString());
filenameLabel.getStyleClass().addAll("mono-font");

View File

@ -5,8 +5,11 @@
<?import javafx.scene.layout.*?>
<BorderPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="com.andrewlalis.perfin.control.CreateTransactionController"
fx:controller="com.andrewlalis.perfin.control.EditTransactionController"
>
<top>
<Label fx:id="titleLabel" styleClass="large-font,bold-text,std-padding"/>
</top>
<center>
<ScrollPane fitToWidth="true" fitToHeight="true">
<VBox style="-fx-max-width: 500px;">

View File

@ -43,9 +43,10 @@
</TextFlow>
</VBox>
<AttachmentsViewPane fx:id="attachmentsViewPane"/>
<FlowPane styleClass="std-padding, std-spacing">
<HBox styleClass="std-padding,std-spacing" alignment="CENTER_LEFT">
<Button text="Edit" onAction="#editTransaction"/>
<Button text="Delete this transaction" onAction="#deleteTransaction"/>
</FlowPane>
</HBox>
</VBox>
</ScrollPane>
</center>