Projections are working! Just 1 issue noticed so far.
This commit is contained in:
		@@ -7,9 +7,16 @@ import '/db.dart';
 | 
			
		||||
import '/models/tracked_item.dart';
 | 
			
		||||
 | 
			
		||||
/// TODO:
 | 
			
		||||
/// - Projected Assets in:
 | 
			
		||||
///     - 1 week, 1 month, 1 quarter, 1 year
 | 
			
		||||
///     - 1/2 year? 2 years? 5 years? Allow customization?
 | 
			
		||||
/// - 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({
 | 
			
		||||
@@ -23,6 +30,7 @@ class ProjectionPage extends StatefulWidget {
 | 
			
		||||
class _ProjectionPageState extends State<ProjectionPage> {
 | 
			
		||||
  @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,
 | 
			
		||||
@@ -36,16 +44,93 @@ class _ProjectionPageState extends State<ProjectionPage> {
 | 
			
		||||
      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 TitleCard extends StatelessWidget {
 | 
			
		||||
  const TitleCard({
 | 
			
		||||
    super.key,
 | 
			
		||||
    required this.title,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  final String title;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    return Padding(
 | 
			
		||||
      padding: const EdgeInsets.all(8.0),
 | 
			
		||||
      child: Center(
 | 
			
		||||
        child: Text(
 | 
			
		||||
          title,
 | 
			
		||||
          style: TextStyle(fontSize: 20),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class SummaryCardForTotals extends StatelessWidget {
 | 
			
		||||
  const SummaryCardForTotals({
 | 
			
		||||
    super.key,
 | 
			
		||||
@@ -70,11 +155,16 @@ class SummaryCardForTotals extends StatelessWidget {
 | 
			
		||||
 | 
			
		||||
          // Calculate the total fields based on item type.
 | 
			
		||||
          double dailyTotal = 0, monthlyTotal = 0, yearlyTotal = 0;
 | 
			
		||||
          bool isAsset = false;
 | 
			
		||||
          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;
 | 
			
		||||
              isAsset = true;
 | 
			
		||||
            } else {
 | 
			
		||||
              dailyTotal += e.calcComparableAmountDaily();
 | 
			
		||||
              monthlyTotal += e.calcComparableAmountYearly() / 12;
 | 
			
		||||
@@ -82,11 +172,33 @@ class SummaryCardForTotals extends StatelessWidget {
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          /* Load page variables based on calculated totals. */
 | 
			
		||||
          switch (itemType) {
 | 
			
		||||
            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 += isAsset ? "" : "s";
 | 
			
		||||
          header += itemType == ItemType.asset ? "" : "s";
 | 
			
		||||
          header += " (${snapshot.data!.length} Item$plural)";
 | 
			
		||||
 | 
			
		||||
          // Total Fields
 | 
			
		||||
@@ -97,7 +209,7 @@ class SummaryCardForTotals extends StatelessWidget {
 | 
			
		||||
              yearlyEstimate =
 | 
			
		||||
                  yearlyTotal.toStringAsFixed(3).endsWith("0") ? "" : "~";
 | 
			
		||||
          String leftText = "", middleText = "", rightText = "";
 | 
			
		||||
          if (isAsset) {
 | 
			
		||||
          if (itemType == ItemType.asset) {
 | 
			
		||||
            middleText = "$monthlyEstimate${monthlyTotal.toStringAsFixed(2)}";
 | 
			
		||||
          } else {
 | 
			
		||||
            leftText = "$dailyEstimate${dailyTotal.toStringAsFixed(2)} Daily";
 | 
			
		||||
@@ -118,7 +230,7 @@ class SummaryCardForTotals extends StatelessWidget {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class SummaryCard extends StatelessWidget {
 | 
			
		||||
class SummaryCard extends StatefulWidget {
 | 
			
		||||
  const SummaryCard({
 | 
			
		||||
    super.key,
 | 
			
		||||
    required this.name,
 | 
			
		||||
@@ -132,6 +244,11 @@ class SummaryCard extends StatelessWidget {
 | 
			
		||||
  final String middleText;
 | 
			
		||||
  final String rightText;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  State<SummaryCard> createState() => _SummaryCardState();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class _SummaryCardState extends State<SummaryCard> {
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    return Card(
 | 
			
		||||
@@ -143,7 +260,7 @@ class SummaryCard extends StatelessWidget {
 | 
			
		||||
          child: Column(
 | 
			
		||||
            children: [
 | 
			
		||||
              Text(
 | 
			
		||||
                name,
 | 
			
		||||
                widget.name,
 | 
			
		||||
                style: TextStyle(
 | 
			
		||||
                  decoration: TextDecoration.underline,
 | 
			
		||||
                  fontSize: 16,
 | 
			
		||||
@@ -155,19 +272,19 @@ class SummaryCard extends StatelessWidget {
 | 
			
		||||
                    flex: 3,
 | 
			
		||||
                  ),
 | 
			
		||||
                  Text(
 | 
			
		||||
                    leftText,
 | 
			
		||||
                    widget.leftText,
 | 
			
		||||
                  ),
 | 
			
		||||
                  Spacer(
 | 
			
		||||
                    flex: 1,
 | 
			
		||||
                  ),
 | 
			
		||||
                  Text(
 | 
			
		||||
                    middleText,
 | 
			
		||||
                    widget.middleText,
 | 
			
		||||
                  ),
 | 
			
		||||
                  Spacer(
 | 
			
		||||
                    flex: 1,
 | 
			
		||||
                  ),
 | 
			
		||||
                  Text(
 | 
			
		||||
                    rightText,
 | 
			
		||||
                    widget.rightText,
 | 
			
		||||
                  ),
 | 
			
		||||
                  Spacer(
 | 
			
		||||
                    flex: 3,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user