Added start of transaction edit page.
This commit is contained in:
parent
89d7438ab1
commit
7ceaca7068
|
@ -84,7 +84,7 @@ public class PerfinApp extends Application {
|
||||||
router.map("account", PerfinApp.class.getResource("/account-view.fxml"));
|
router.map("account", PerfinApp.class.getResource("/account-view.fxml"));
|
||||||
router.map("edit-account", PerfinApp.class.getResource("/edit-account.fxml"));
|
router.map("edit-account", PerfinApp.class.getResource("/edit-account.fxml"));
|
||||||
router.map("transactions", PerfinApp.class.getResource("/transactions-view.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("create-balance-record", PerfinApp.class.getResource("/create-balance-record.fxml"));
|
||||||
router.map("balance-record", PerfinApp.class.getResource("/balance-record-view.fxml"));
|
router.map("balance-record", PerfinApp.class.getResource("/balance-record-view.fxml"));
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
package com.andrewlalis.perfin.control;
|
package com.andrewlalis.perfin.control;
|
||||||
|
|
||||||
import com.andrewlalis.javafx_scene_router.RouteSelectionListener;
|
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.DateUtil;
|
||||||
import com.andrewlalis.perfin.data.util.FileUtil;
|
import com.andrewlalis.perfin.data.util.FileUtil;
|
||||||
import com.andrewlalis.perfin.model.Account;
|
import com.andrewlalis.perfin.model.Account;
|
||||||
import com.andrewlalis.perfin.model.CreditAndDebitAccounts;
|
import com.andrewlalis.perfin.model.CreditAndDebitAccounts;
|
||||||
import com.andrewlalis.perfin.model.Profile;
|
import com.andrewlalis.perfin.model.Profile;
|
||||||
|
import com.andrewlalis.perfin.model.Transaction;
|
||||||
import com.andrewlalis.perfin.view.AccountComboBoxCellFactory;
|
import com.andrewlalis.perfin.view.AccountComboBoxCellFactory;
|
||||||
import com.andrewlalis.perfin.view.component.FileSelectionArea;
|
import com.andrewlalis.perfin.view.component.FileSelectionArea;
|
||||||
import com.andrewlalis.perfin.view.component.validation.ValidationApplier;
|
import com.andrewlalis.perfin.view.component.validation.ValidationApplier;
|
||||||
|
@ -31,7 +33,9 @@ import java.util.List;
|
||||||
|
|
||||||
import static com.andrewlalis.perfin.PerfinApp.router;
|
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 timestampField;
|
||||||
@FXML public TextField amountField;
|
@FXML public TextField amountField;
|
||||||
@FXML public ChoiceBox<Currency> currencyChoiceBox;
|
@FXML public ChoiceBox<Currency> currencyChoiceBox;
|
||||||
|
@ -55,15 +59,13 @@ public class CreateTransactionController implements RouteSelectionListener {
|
||||||
return ts != null && ts.isBefore(LocalDateTime.now());
|
return ts != null && ts.isBefore(LocalDateTime.now());
|
||||||
}, "Timestamp cannot be in the future.")
|
}, "Timestamp cannot be in the future.")
|
||||||
).validatedInitially().attachToTextField(timestampField);
|
).validatedInitially().attachToTextField(timestampField);
|
||||||
|
|
||||||
var amountValid = new ValidationApplier<>(
|
var amountValid = new ValidationApplier<>(
|
||||||
new CurrencyAmountValidator(() -> currencyChoiceBox.getValue(), false, false)
|
new CurrencyAmountValidator(() -> currencyChoiceBox.getValue(), false, false)
|
||||||
).validatedInitially().attachToTextField(amountField, currencyChoiceBox.valueProperty());
|
).validatedInitially().attachToTextField(amountField, currencyChoiceBox.valueProperty());
|
||||||
|
|
||||||
var descriptionValid = new ValidationApplier<>(new PredicateValidator<String>()
|
var descriptionValid = new ValidationApplier<>(new PredicateValidator<String>()
|
||||||
.addTerminalPredicate(s -> s == null || s.length() <= 255, "Description is too long.")
|
.addTerminalPredicate(s -> s == null || s.length() <= 255, "Description is too long.")
|
||||||
).validatedInitially().attach(descriptionField, descriptionField.textProperty());
|
).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());
|
Property<CreditAndDebitAccounts> linkedAccountsProperty = new SimpleObjectProperty<>(getSelectedAccounts());
|
||||||
linkDebitAccountComboBox.valueProperty().addListener((observable, oldValue, newValue) -> linkedAccountsProperty.setValue(getSelectedAccounts()));
|
linkDebitAccountComboBox.valueProperty().addListener((observable, oldValue, newValue) -> linkedAccountsProperty.setValue(getSelectedAccounts()));
|
||||||
linkCreditAccountComboBox.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.setCellFactory(cellFactory);
|
||||||
linkCreditAccountComboBox.setButtonCell(cellFactory.call(null));
|
linkCreditAccountComboBox.setButtonCell(cellFactory.call(null));
|
||||||
currencyChoiceBox.valueProperty().addListener((observable, oldValue, newValue) -> {
|
currencyChoiceBox.valueProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
System.out.println("Set currency to " + newValue);
|
||||||
updateLinkAccountComboBoxes(newValue);
|
updateLinkAccountComboBoxes(newValue);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -123,25 +126,49 @@ public class CreateTransactionController implements RouteSelectionListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRouteSelected(Object context) {
|
public void onRouteSelected(Object context) {
|
||||||
resetForm();
|
Transaction transaction = (Transaction) context;
|
||||||
}
|
boolean creatingNew = transaction == null;
|
||||||
|
|
||||||
private void resetForm() {
|
if (creatingNew) {
|
||||||
timestampField.setText(LocalDateTime.now().format(DateUtil.DEFAULT_DATETIME_FORMAT));
|
titleLabel.setText("Create New Transaction");
|
||||||
amountField.setText(null);
|
timestampField.setText(LocalDateTime.now().format(DateUtil.DEFAULT_DATETIME_FORMAT));
|
||||||
descriptionField.setText(null);
|
amountField.setText(null);
|
||||||
attachmentsSelectionArea.clear();
|
currencyChoiceBox.getSelectionModel().selectFirst();
|
||||||
Thread.ofVirtual().start(() -> {
|
descriptionField.setText(null);
|
||||||
Profile.getCurrent().getDataSource().useAccountRepository(repo -> {
|
attachmentsSelectionArea.clear();
|
||||||
var currencies = repo.findAllUsedCurrencies().stream()
|
|
||||||
.sorted(Comparator.comparing(Currency::getCurrencyCode))
|
} else {
|
||||||
.toList();
|
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(() -> {
|
Platform.runLater(() -> {
|
||||||
currencyChoiceBox.getItems().setAll(currencies);
|
System.out.println(linkCreditAccountComboBox.getItems().indexOf(accounts.creditAccount()));
|
||||||
currencyChoiceBox.getSelectionModel().selectFirst();
|
// 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() {
|
private CreditAndDebitAccounts getSelectedAccounts() {
|
||||||
|
@ -186,6 +213,7 @@ public class CreateTransactionController implements RouteSelectionListener {
|
||||||
linkCreditAccountComboBox.getItems().addAll(availableAccounts);
|
linkCreditAccountComboBox.getItems().addAll(availableAccounts);
|
||||||
linkCreditAccountComboBox.getSelectionModel().selectLast();
|
linkCreditAccountComboBox.getSelectionModel().selectLast();
|
||||||
linkCreditAccountComboBox.getButtonCell().updateIndex(availableAccounts.size() - 1);
|
linkCreditAccountComboBox.getButtonCell().updateIndex(availableAccounts.size() - 1);
|
||||||
|
System.out.println("link account boxes updated.");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -69,6 +69,10 @@ public class TransactionViewController {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@FXML public void editTransaction() {
|
||||||
|
router.navigate("edit-transaction", this.transaction);
|
||||||
|
}
|
||||||
|
|
||||||
@FXML public void deleteTransaction() {
|
@FXML public void deleteTransaction() {
|
||||||
boolean confirm = Popups.confirm(
|
boolean confirm = Popups.confirm(
|
||||||
"Are you sure you want to delete this transaction? This will " +
|
"Are you sure you want to delete this transaction? This will " +
|
||||||
|
|
|
@ -158,7 +158,7 @@ public class TransactionsViewController implements RouteSelectionListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML public void addTransaction() {
|
@FXML public void addTransaction() {
|
||||||
router.navigate("create-transaction");
|
router.navigate("edit-transaction");
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML public void exportTransactions() {
|
@FXML public void exportTransactions() {
|
||||||
|
|
|
@ -18,6 +18,12 @@ public class DateUtil {
|
||||||
.format(DEFAULT_DATETIME_FORMAT_WITH_ZONE);
|
.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) {
|
public static LocalDateTime localToUTC(LocalDateTime localTime, ZoneId localZone) {
|
||||||
return localTime.atZone(localZone).withZoneSameInstant(ZoneOffset.UTC).toLocalDateTime();
|
return localTime.atZone(localZone).withZoneSameInstant(ZoneOffset.UTC).toLocalDateTime();
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,10 @@ public class FileSelectionArea extends VBox {
|
||||||
selectedFiles.clear();
|
selectedFiles.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setSelectedFiles(List<Path> files) {
|
||||||
|
selectedFiles.setAll(files);
|
||||||
|
}
|
||||||
|
|
||||||
private Node buildFileItem(Path path) {
|
private Node buildFileItem(Path path) {
|
||||||
Label filenameLabel = new Label(path.getFileName().toString());
|
Label filenameLabel = new Label(path.getFileName().toString());
|
||||||
filenameLabel.getStyleClass().addAll("mono-font");
|
filenameLabel.getStyleClass().addAll("mono-font");
|
||||||
|
|
|
@ -5,8 +5,11 @@
|
||||||
<?import javafx.scene.layout.*?>
|
<?import javafx.scene.layout.*?>
|
||||||
<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.EditTransactionController"
|
||||||
>
|
>
|
||||||
|
<top>
|
||||||
|
<Label fx:id="titleLabel" styleClass="large-font,bold-text,std-padding"/>
|
||||||
|
</top>
|
||||||
<center>
|
<center>
|
||||||
<ScrollPane fitToWidth="true" fitToHeight="true">
|
<ScrollPane fitToWidth="true" fitToHeight="true">
|
||||||
<VBox style="-fx-max-width: 500px;">
|
<VBox style="-fx-max-width: 500px;">
|
|
@ -43,9 +43,10 @@
|
||||||
</TextFlow>
|
</TextFlow>
|
||||||
</VBox>
|
</VBox>
|
||||||
<AttachmentsViewPane fx:id="attachmentsViewPane"/>
|
<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"/>
|
<Button text="Delete this transaction" onAction="#deleteTransaction"/>
|
||||||
</FlowPane>
|
</HBox>
|
||||||
</VBox>
|
</VBox>
|
||||||
</ScrollPane>
|
</ScrollPane>
|
||||||
</center>
|
</center>
|
||||||
|
|
Loading…
Reference in New Issue