// Flutter import 'package:flutter/material.dart'; import '/models/item_type.dart'; // Local import '/db.dart'; import '/widgets/cards.dart'; import '/models/tracked_item.dart'; /// TODO: /// - Projected Assets: /// - Allow customization? /// - Fix bug where editing an item does not reflect immediately when returning to Reports page. /// - Currently reflects after going back to Reports the 2nd time. double _assetTotal = 0, _expenseMonthly = 0, _expenseYearly = 0, _incomeMonthly = 0, _incomeYearly = 0; class ProjectionPage extends StatefulWidget { const ProjectionPage({ super.key, }); @override State createState() => _ProjectionPageState(); } class _ProjectionPageState extends State { @override Widget build(BuildContext context) { // Summaries for display as well as calculation of totals for projections. Widget expenseSummary = SummaryCardForTotals( list: DatabaseHelper.instance.getExpenses(), summaryTypeLabel: ItemType.expense.title, ); Widget incomeSummary = SummaryCardForTotals( list: DatabaseHelper.instance.getIncomes(), summaryTypeLabel: ItemType.income.title, ); Widget assetSummary = SummaryCardForTotals( list: DatabaseHelper.instance.getAssets(), summaryTypeLabel: ItemType.asset.title, ); // Calculations for the projections. double oneMonth = _assetTotal + _incomeMonthly - _expenseMonthly, threeMonths = _assetTotal + (3 * (_incomeMonthly - _expenseMonthly)), sixMonths = _assetTotal + (6 * (_incomeMonthly - _expenseMonthly)), oneYear = _assetTotal + (_incomeYearly - _expenseYearly), twoYears = _assetTotal + (2 * (_incomeYearly - _expenseYearly)), fiveYears = _assetTotal + (5 * (_incomeYearly - _expenseYearly)); // Widgets to show the projections. Widget proj1 = SummaryCard( name: "One month from now...", leftText: "", middleText: oneMonth.toStringAsFixed(2), rightText: "", ); Widget proj2 = SummaryCard( name: "Three months from now...", leftText: "", middleText: threeMonths.toStringAsFixed(2), rightText: "", ); Widget proj3 = SummaryCard( name: "Half a year from now...", leftText: "", middleText: sixMonths.toStringAsFixed(2), rightText: "", ); Widget proj4 = SummaryCard( name: "One year from now...", leftText: "", middleText: oneYear.toStringAsFixed(2), rightText: "", ); Widget proj5 = SummaryCard( name: "Two years from now...", leftText: "", middleText: twoYears.toStringAsFixed(2), rightText: "", ); Widget proj6 = SummaryCard( name: "Five years from now...", leftText: "", middleText: fiveYears.toStringAsFixed(2), rightText: "", ); // Return all of the UI elements. return ListView( children: [ TitleCard(title: "Summaries"), expenseSummary, incomeSummary, assetSummary, TitleCard(title: "Projections"), proj1, proj2, proj3, proj4, proj5, proj6, ], ); } } class SummaryCardForTotals extends StatelessWidget { const SummaryCardForTotals({ super.key, required this.list, required this.summaryTypeLabel, }); final Future> list; final String summaryTypeLabel; @override Widget build(BuildContext context) { return FutureBuilder>( future: list, builder: ( BuildContext context, AsyncSnapshot> snapshot, ) { if (!snapshot.hasData) { return Text('Loading $summaryTypeLabel Section...'); } // Calculate the total fields based on item type. double dailyTotal = 0, monthlyTotal = 0, yearlyTotal = 0; ItemType? itemType; for (TrackedItem e in snapshot.data!) { if (itemType == null) { itemType = e.type!; } else if (itemType != e.type) { throw "List in SummaryCardForTotals has multiple item types, abort!"; } if (e.type == ItemType.asset) { monthlyTotal += e.amount; } else { dailyTotal += e.calcComparableAmountDaily(); monthlyTotal += e.calcComparableAmountYearly() / 12; yearlyTotal += e.calcComparableAmountYearly(); } } /* Load page variables based on calculated totals. */ switch (itemType) { case null: break; case ItemType.asset: _assetTotal = monthlyTotal; break; case ItemType.expense: _expenseMonthly = monthlyTotal; _expenseYearly = yearlyTotal; break; case ItemType.income: _incomeMonthly = monthlyTotal; _incomeYearly = yearlyTotal; break; default: throw UnimplementedError( "Item type ${itemType.title} not handled in SummaryCardForTotals!", ); } /* Determine what needs displayed for the item type. */ // Header String plural = snapshot.data!.length == 1 ? "" : "s"; String header = "$summaryTypeLabel Total"; header += itemType == ItemType.asset ? "" : "s"; header += " (${snapshot.data!.length} Item$plural)"; // Total Fields String dailyEstimate = dailyTotal.toStringAsFixed(3).endsWith("0") ? "" : "~", monthlyEstimate = monthlyTotal.toStringAsFixed(3).endsWith("0") ? "" : "~", yearlyEstimate = yearlyTotal.toStringAsFixed(3).endsWith("0") ? "" : "~"; String leftText = "", middleText = "", rightText = ""; if (itemType == ItemType.asset) { middleText = "$monthlyEstimate${monthlyTotal.toStringAsFixed(2)}"; } else { leftText = "$dailyEstimate${dailyTotal.toStringAsFixed(2)} Daily"; middleText = "$monthlyEstimate${monthlyTotal.toStringAsFixed(2)} Monthly"; rightText = "$yearlyEstimate${yearlyTotal.toStringAsFixed(2)} Yearly"; } // Return the UI element. return SummaryCard( name: header, leftText: leftText, middleText: middleText, rightText: rightText, ); }); } }