Compare commits
No commits in common. "b6fef8d42fc16a30fee10ec844bb386197afdc0a" and "a3558b33e6f4cfa97e6cb46d9efa5e62383d7489" have entirely different histories.
b6fef8d42f
...
a3558b33e6
|
@ -2,7 +2,6 @@ package com.andrewlalis.perfin.control;
|
||||||
|
|
||||||
import com.andrewlalis.javafx_scene_router.RouteSelectionListener;
|
import com.andrewlalis.javafx_scene_router.RouteSelectionListener;
|
||||||
import com.andrewlalis.perfin.model.Profile;
|
import com.andrewlalis.perfin.model.Profile;
|
||||||
import com.andrewlalis.perfin.view.component.module.TotalAssetsGraphModule;
|
|
||||||
import com.andrewlalis.perfin.view.component.module.*;
|
import com.andrewlalis.perfin.view.component.module.*;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.geometry.Bounds;
|
import javafx.geometry.Bounds;
|
||||||
|
@ -31,10 +30,7 @@ public class DashboardController implements RouteSelectionListener {
|
||||||
var m4 = new VendorSpendChartModule(modulesFlowPane);
|
var m4 = new VendorSpendChartModule(modulesFlowPane);
|
||||||
m4.columnsProperty.set(2);
|
m4.columnsProperty.set(2);
|
||||||
|
|
||||||
var m5 = new TotalAssetsGraphModule(modulesFlowPane);
|
modulesFlowPane.getChildren().addAll(accountsModule, transactionsModule, m3, m4);
|
||||||
m5.columnsProperty.set(1);
|
|
||||||
|
|
||||||
modulesFlowPane.getChildren().addAll(accountsModule, transactionsModule, m3, m4, m5);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -9,7 +9,6 @@ import javafx.application.Platform;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
@ -112,16 +111,15 @@ public interface DataSource {
|
||||||
/**
|
/**
|
||||||
* Gets a list of combined total assets for each currency that's tracked,
|
* Gets a list of combined total assets for each currency that's tracked,
|
||||||
* ordered with highest assets first.
|
* ordered with highest assets first.
|
||||||
* @param timestamp The timestamp at which to get the balance.
|
|
||||||
* @return A future that resolves to the list of amounts for each currency.
|
* @return A future that resolves to the list of amounts for each currency.
|
||||||
*/
|
*/
|
||||||
default CompletableFuture<List<MoneyValue>> getCombinedAccountBalances(Instant timestamp) {
|
default CompletableFuture<List<MoneyValue>> getCombinedAccountBalances() {
|
||||||
return mapRepoAsync(AccountRepository.class, repo -> {
|
return mapRepoAsync(AccountRepository.class, repo -> {
|
||||||
List<Account> accounts = repo.findAll(PageRequest.unpaged()).items();
|
List<Account> accounts = repo.findAll(PageRequest.unpaged()).items();
|
||||||
Map<Currency, BigDecimal> totals = new HashMap<>();
|
Map<Currency, BigDecimal> totals = new HashMap<>();
|
||||||
for (var account : accounts) {
|
for (var account : accounts) {
|
||||||
BigDecimal currencyTotal = totals.computeIfAbsent(account.getCurrency(), c -> BigDecimal.ZERO);
|
BigDecimal currencyTotal = totals.computeIfAbsent(account.getCurrency(), c -> BigDecimal.ZERO);
|
||||||
BigDecimal accountBalance = repo.deriveBalance(account.id, timestamp);
|
BigDecimal accountBalance = repo.deriveCurrentBalance(account.id);
|
||||||
if (account.getType() == AccountType.CREDIT_CARD) accountBalance = accountBalance.negate();
|
if (account.getType() == AccountType.CREDIT_CARD) accountBalance = accountBalance.negate();
|
||||||
totals.put(account.getCurrency(), currencyTotal.add(accountBalance));
|
totals.put(account.getCurrency(), currencyTotal.add(accountBalance));
|
||||||
}
|
}
|
||||||
|
@ -133,8 +131,4 @@ public interface DataSource {
|
||||||
return values;
|
return values;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
default CompletableFuture<List<MoneyValue>> getCombinedAccountBalances() {
|
|
||||||
return getCombinedAccountBalances(Instant.now());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,6 @@ public abstract class PieChartModule extends DashboardModule {
|
||||||
|
|
||||||
this.timeRangeChoiceBox.getItems().addAll(RANGE_CHOICES);
|
this.timeRangeChoiceBox.getItems().addAll(RANGE_CHOICES);
|
||||||
this.timeRangeChoiceBox.getSelectionModel().select("All Time");
|
this.timeRangeChoiceBox.getSelectionModel().select("All Time");
|
||||||
this.currencyChoiceBox.managedProperty().bind(this.currencyChoiceBox.visibleProperty());
|
|
||||||
|
|
||||||
PieChart chart = new PieChart(chartData);
|
PieChart chart = new PieChart(chartData);
|
||||||
chart.setLegendVisible(false);
|
chart.setLegendVisible(false);
|
||||||
|
@ -69,7 +68,9 @@ public abstract class PieChartModule extends DashboardModule {
|
||||||
chartData.clear();
|
chartData.clear();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
timeRangeChoiceBox.valueProperty().addListener((observable, oldValue, newValue) -> renderChart());
|
timeRangeChoiceBox.valueProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
renderChart();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -135,7 +136,6 @@ public abstract class PieChartModule extends DashboardModule {
|
||||||
} else {
|
} else {
|
||||||
currencyChoiceBox.getSelectionModel().selectFirst();
|
currencyChoiceBox.getSelectionModel().selectFirst();
|
||||||
}
|
}
|
||||||
currencyChoiceBox.setVisible(orderedCurrencies.size() > 1);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
package com.andrewlalis.perfin.view.component.module;
|
|
||||||
|
|
||||||
import com.andrewlalis.perfin.model.Profile;
|
|
||||||
import javafx.application.Platform;
|
|
||||||
import javafx.collections.FXCollections;
|
|
||||||
import javafx.collections.ObservableList;
|
|
||||||
import javafx.scene.chart.*;
|
|
||||||
import javafx.scene.layout.Pane;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.time.ZoneId;
|
|
||||||
import java.time.temporal.ChronoUnit;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A module for visualizing the total asset value in the user's profile over
|
|
||||||
* a configurable period of time.
|
|
||||||
*/
|
|
||||||
public class TotalAssetsGraphModule extends DashboardModule {
|
|
||||||
private final ObservableList<XYChart.Data<String, Number>> totalAssetDataPoints = FXCollections.observableArrayList();
|
|
||||||
|
|
||||||
public TotalAssetsGraphModule(Pane parent) {
|
|
||||||
super(parent);
|
|
||||||
Axis<String> xAxis = new CategoryAxis();
|
|
||||||
Axis<Number> yAxis = new NumberAxis();
|
|
||||||
|
|
||||||
LineChart<String, Number> chart = new LineChart<>(xAxis, yAxis, FXCollections.observableArrayList(
|
|
||||||
new XYChart.Series<>("Total Assets", totalAssetDataPoints)
|
|
||||||
));
|
|
||||||
chart.setLegendVisible(false);
|
|
||||||
this.getChildren().add(new ModuleHeader(
|
|
||||||
"Total Assets over Time"
|
|
||||||
));
|
|
||||||
this.getChildren().add(chart);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void refreshContents() {
|
|
||||||
totalAssetDataPoints.clear();
|
|
||||||
String[] dateLabels = new String[12];
|
|
||||||
double[] values = new double[12];
|
|
||||||
CompletableFuture<?>[] futures = new CompletableFuture[12];
|
|
||||||
for (int i = 0; i < 12; i++) {
|
|
||||||
final int idx = i;
|
|
||||||
Instant timestamp = Instant.now().minus((12 - i - 1) * 30, ChronoUnit.DAYS);
|
|
||||||
dateLabels[i] = LocalDate.from(timestamp.atZone(ZoneId.systemDefault())).toString();
|
|
||||||
futures[i] = Profile.getCurrent().dataSource().getCombinedAccountBalances(timestamp)
|
|
||||||
.thenAccept(moneyValues -> {
|
|
||||||
values[idx] = moneyValues.getFirst().amount().doubleValue();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
CompletableFuture.allOf(futures).thenRun(() -> {
|
|
||||||
List<XYChart.Data<String, Number>> dataPoints = new ArrayList<>(12);
|
|
||||||
for (int i = 0; i < 12; i++) {
|
|
||||||
dataPoints.add(new XYChart.Data<>(dateLabels[i], values[i]));
|
|
||||||
}
|
|
||||||
Platform.runLater(() -> totalAssetDataPoints.addAll(dataPoints));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -20,5 +20,4 @@ module com.andrewlalis.perfin {
|
||||||
opens com.andrewlalis.perfin.view.component to javafx.fxml;
|
opens com.andrewlalis.perfin.view.component to javafx.fxml;
|
||||||
opens com.andrewlalis.perfin.view.component.validation to javafx.fxml;
|
opens com.andrewlalis.perfin.view.component.validation to javafx.fxml;
|
||||||
exports com.andrewlalis.perfin.model.history to javafx.graphics;
|
exports com.andrewlalis.perfin.model.history to javafx.graphics;
|
||||||
opens com.andrewlalis.perfin.view.component.module to javafx.fxml;
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue