Added transaction descriptions to account history tiles.
This commit is contained in:
parent
4cf95dba85
commit
5ce2360f05
|
@ -179,7 +179,7 @@ public record JdbcAccountRepository(Connection conn, Path contentDir) implements
|
|||
SELECT id, timestamp, 'BALANCE_RECORD' AS type, account_id
|
||||
FROM balance_record
|
||||
)
|
||||
WHERE account_id = ? AND timestamp <= ?
|
||||
WHERE account_id = ? AND timestamp < ?
|
||||
ORDER BY timestamp DESC
|
||||
LIMIT\s""" + maxResults;
|
||||
try (var stmt = conn.prepareStatement(query)) {
|
||||
|
|
|
@ -3,12 +3,10 @@ package com.andrewlalis.perfin.view.component;
|
|||
import com.andrewlalis.perfin.control.TransactionsViewController;
|
||||
import com.andrewlalis.perfin.data.AccountRepository;
|
||||
import com.andrewlalis.perfin.data.DataSource;
|
||||
import com.andrewlalis.perfin.data.TransactionRepository;
|
||||
import com.andrewlalis.perfin.data.util.CurrencyUtil;
|
||||
import com.andrewlalis.perfin.data.util.DateUtil;
|
||||
import com.andrewlalis.perfin.model.AccountEntry;
|
||||
import com.andrewlalis.perfin.model.BalanceRecord;
|
||||
import com.andrewlalis.perfin.model.Profile;
|
||||
import com.andrewlalis.perfin.model.Timestamped;
|
||||
import com.andrewlalis.perfin.model.*;
|
||||
import com.andrewlalis.perfin.model.history.HistoryTextItem;
|
||||
import com.andrewlalis.perfin.view.BindingUtil;
|
||||
import javafx.application.Platform;
|
||||
|
@ -27,6 +25,8 @@ import javafx.scene.text.TextFlow;
|
|||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static com.andrewlalis.perfin.PerfinApp.router;
|
||||
|
||||
|
@ -60,7 +60,7 @@ public class AccountHistoryView extends ScrollPane {
|
|||
int maxItems = initialItemsToLoadProperty.get();
|
||||
DataSource ds = Profile.getCurrent().dataSource();
|
||||
ds.mapRepoAsync(AccountRepository.class, repo -> repo.findEventsBefore(accountId, lastTimestamp(), maxItems))
|
||||
.thenAccept(entities -> Platform.runLater(() -> addEntitiesToHistory(entities, maxItems)));
|
||||
.thenAccept(entities -> addEntitiesToHistory(entities, maxItems));
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
|
@ -91,56 +91,75 @@ public class AccountHistoryView extends ScrollPane {
|
|||
return lastTimestamp;
|
||||
}
|
||||
|
||||
private Node makeTile(Timestamped entity) {
|
||||
private CompletableFuture<Node> makeTile(Timestamped entity) {
|
||||
switch (entity) {
|
||||
case HistoryTextItem textItem -> {
|
||||
return new AccountHistoryTile(textItem.getTimestamp(), new TextFlow(new Text(textItem.getDescription())));
|
||||
return CompletableFuture.completedFuture(
|
||||
new AccountHistoryTile(textItem.getTimestamp(), new TextFlow(new Text(textItem.getDescription())))
|
||||
);
|
||||
}
|
||||
case AccountEntry ae -> {
|
||||
Hyperlink txLink = new Hyperlink("Transaction #" + ae.getTransactionId());
|
||||
txLink.setOnAction(event -> router.navigate("transactions", new TransactionsViewController.RouteContext(ae.getTransactionId())));
|
||||
String descriptionFormat = ae.getType() == AccountEntry.Type.CREDIT
|
||||
? "credited %s from this account."
|
||||
: "debited %s to this account.";
|
||||
String description = descriptionFormat.formatted(CurrencyUtil.formatMoney(ae.getMoneyValue()));
|
||||
TextFlow textFlow = new TextFlow(txLink, new Text(description));
|
||||
return new AccountHistoryTile(ae.getTimestamp(), textFlow);
|
||||
? "credited %s from this account"
|
||||
: "debited %s to this account";
|
||||
final String description = descriptionFormat.formatted(CurrencyUtil.formatMoney(ae.getMoneyValue()));
|
||||
|
||||
CompletableFuture<Node> future = new CompletableFuture<>();
|
||||
Profile.getCurrent().dataSource().useRepoAsync(TransactionRepository.class, repo -> {
|
||||
Optional<Transaction> optionalTransaction = repo.findById(ae.getTransactionId());
|
||||
String extraText = optionalTransaction.map(transaction -> ": " + transaction.getDescription())
|
||||
.orElse(". No transaction information found.");
|
||||
TextFlow textFlow = new TextFlow(txLink, new Text(description + extraText));
|
||||
future.complete(new AccountHistoryTile(ae.getTimestamp(), textFlow));
|
||||
});
|
||||
return future;
|
||||
|
||||
}
|
||||
case BalanceRecord br -> {
|
||||
Hyperlink brLink = new Hyperlink("Balance Record #" + br.id);
|
||||
brLink.setOnAction(event -> router.navigate("balance-record", br));
|
||||
return new AccountHistoryTile(br.getTimestamp(), new TextFlow(
|
||||
return CompletableFuture.completedFuture(new AccountHistoryTile(br.getTimestamp(), new TextFlow(
|
||||
brLink,
|
||||
new Text("added with a value of %s.".formatted(CurrencyUtil.formatMoney(br.getMoneyAmount())))
|
||||
));
|
||||
)));
|
||||
}
|
||||
default -> {
|
||||
return new AccountHistoryTile(entity.getTimestamp(), new TextFlow(new Text("Unsupported entity: " + entity.getClass().getName())));
|
||||
return CompletableFuture.completedFuture(
|
||||
new AccountHistoryTile(entity.getTimestamp(), new TextFlow(new Text("Unsupported entity: " + entity.getClass().getName())))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addEntitiesToHistory(List<Timestamped> entities, int requestedItems) {
|
||||
if (!itemsVBox.getChildren().isEmpty()) {
|
||||
itemsVBox.getChildren().add(new Separator(Orientation.HORIZONTAL));
|
||||
}
|
||||
itemsVBox.getChildren().addAll(entities.stream()
|
||||
.map(this::makeTile)
|
||||
.map(tile -> {
|
||||
// Use this to scrunch content to the left.
|
||||
AnchorPane ap = new AnchorPane(tile);
|
||||
AnchorPane.setLeftAnchor(tile, 0.0);
|
||||
return ap;
|
||||
})
|
||||
.toList());
|
||||
if (entities.size() < requestedItems) {
|
||||
canLoadMore.set(false);
|
||||
BorderPane endMarker = new BorderPane(new Label("This is the start of the history."));
|
||||
endMarker.getStyleClass().addAll("large-font", "italic-text");
|
||||
itemsVBox.getChildren().add(endMarker);
|
||||
}
|
||||
if (!entities.isEmpty()) {
|
||||
lastTimestamp = entities.getLast().getTimestamp();
|
||||
}
|
||||
var futures = entities.stream().map(this::makeTile).toList();
|
||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
|
||||
.thenRun(() -> {
|
||||
List<AnchorPane> tiles = futures.stream().map(CompletableFuture::join)
|
||||
.map(tile -> {
|
||||
// Use this to scrunch content to the left.
|
||||
AnchorPane ap = new AnchorPane(tile);
|
||||
AnchorPane.setLeftAnchor(tile, 0.0);
|
||||
return ap;
|
||||
})
|
||||
.toList();
|
||||
Platform.runLater(() -> {
|
||||
if (!itemsVBox.getChildren().isEmpty()) {
|
||||
itemsVBox.getChildren().add(new Separator(Orientation.HORIZONTAL));
|
||||
}
|
||||
itemsVBox.getChildren().addAll(tiles);
|
||||
if (entities.size() < requestedItems) {
|
||||
canLoadMore.set(false);
|
||||
BorderPane endMarker = new BorderPane(new Label("This is the start of the history."));
|
||||
endMarker.getStyleClass().addAll("large-font", "italic-text");
|
||||
itemsVBox.getChildren().add(endMarker);
|
||||
}
|
||||
if (!entities.isEmpty()) {
|
||||
lastTimestamp = entities.getLast().getTimestamp();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue