new widget types
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
library;
|
||||
|
||||
import '../models/bank.dart';
|
||||
import '../models/home_filter_widget.dart';
|
||||
import '../models/transaction_meta.dart';
|
||||
import '../providers/tx_meta_provider.dart';
|
||||
import '../utils/tx_calendar.dart';
|
||||
@@ -23,15 +24,40 @@ class TxFilterMetrics {
|
||||
double get net => amountIn - amountOut;
|
||||
}
|
||||
|
||||
class HomeBudgetMetrics {
|
||||
const HomeBudgetMetrics({
|
||||
required this.monthNet,
|
||||
required this.target,
|
||||
required this.averageMonths,
|
||||
});
|
||||
|
||||
/// Net (in − out) for the current calendar month.
|
||||
final double monthNet;
|
||||
|
||||
/// Positive budget ceiling (fixed amount or avg |net| of last N months).
|
||||
final double target;
|
||||
|
||||
final int averageMonths;
|
||||
|
||||
/// How much of the ceiling is used, based on |monthNet|.
|
||||
double get used => monthNet.abs();
|
||||
|
||||
double get progress => target <= 0 ? 0 : used / target;
|
||||
|
||||
bool get overBudget => target > 0 && used > target;
|
||||
}
|
||||
|
||||
/// Filter [all] the same way Transactions does (pool → search → flow/amount).
|
||||
List<BankTransaction> applyTransactionFilter({
|
||||
required List<BankTransaction> all,
|
||||
required TxMetaController meta,
|
||||
required TransactionFilterSelection filter,
|
||||
DateTime? month,
|
||||
bool forceMonthOnly = false,
|
||||
}) {
|
||||
final nowMonth = monthStart(month ?? DateTime.now());
|
||||
final pool = filter.monthOnly
|
||||
final limitToMonth = forceMonthOnly || filter.monthOnly;
|
||||
final pool = limitToMonth
|
||||
? [
|
||||
for (final tx in all)
|
||||
if (_txInMonth(tx, nowMonth)) tx,
|
||||
@@ -55,12 +81,14 @@ TxFilterMetrics computeTxFilterMetrics({
|
||||
required TxMetaController meta,
|
||||
required TransactionFilterSelection filter,
|
||||
DateTime? month,
|
||||
bool forceMonthOnly = false,
|
||||
}) {
|
||||
final filtered = applyTransactionFilter(
|
||||
all: all,
|
||||
meta: meta,
|
||||
filter: filter,
|
||||
month: month,
|
||||
forceMonthOnly: forceMonthOnly,
|
||||
);
|
||||
var amountIn = 0.0;
|
||||
var amountOut = 0.0;
|
||||
@@ -80,6 +108,50 @@ TxFilterMetrics computeTxFilterMetrics({
|
||||
);
|
||||
}
|
||||
|
||||
/// Budget progress: this month’s |net| vs fixed or average-of-last-N-months cap.
|
||||
HomeBudgetMetrics computeHomeBudgetMetrics({
|
||||
required List<BankTransaction> all,
|
||||
required TxMetaController meta,
|
||||
required HomeFilterWidget widget,
|
||||
DateTime? now,
|
||||
}) {
|
||||
final today = now ?? DateTime.now();
|
||||
final currentMonth = monthStart(today);
|
||||
final monthFilter = widget.filter;
|
||||
final monthNet = computeTxFilterMetrics(
|
||||
all: all,
|
||||
meta: meta,
|
||||
filter: monthFilter,
|
||||
month: currentMonth,
|
||||
forceMonthOnly: true,
|
||||
).net;
|
||||
|
||||
final months = widget.budgetAverageMonths.clamp(1, 36);
|
||||
final double target;
|
||||
if (widget.budgetCapMode == HomeBudgetCapMode.fixed) {
|
||||
target = widget.budgetFixedAmount.abs();
|
||||
} else {
|
||||
var sum = 0.0;
|
||||
for (var i = 1; i <= months; i++) {
|
||||
final month = addMonths(currentMonth, -i);
|
||||
sum += computeTxFilterMetrics(
|
||||
all: all,
|
||||
meta: meta,
|
||||
filter: monthFilter,
|
||||
month: month,
|
||||
forceMonthOnly: true,
|
||||
).net.abs();
|
||||
}
|
||||
target = sum / months;
|
||||
}
|
||||
|
||||
return HomeBudgetMetrics(
|
||||
monthNet: monthNet,
|
||||
target: target,
|
||||
averageMonths: months,
|
||||
);
|
||||
}
|
||||
|
||||
bool _txInMonth(BankTransaction tx, DateTime month) {
|
||||
final date = DateTime.tryParse(tx.date);
|
||||
if (date == null) return false;
|
||||
|
||||
Reference in New Issue
Block a user