184 lines
5.1 KiB
Dart

// Flutter
import 'package:flutter/material.dart';
import 'package:flutter_expense_tracker/models/item_type.dart';
// Local
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?
class ProjectionPage extends StatefulWidget {
const ProjectionPage({
super.key,
});
@override
State<ProjectionPage> createState() => _ProjectionPageState();
}
class _ProjectionPageState extends State<ProjectionPage> {
@override
Widget build(BuildContext context) {
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,
);
return ListView(
children: [
expenseSummary,
incomeSummary,
assetSummary,
],
);
}
}
class SummaryCardForTotals extends StatelessWidget {
const SummaryCardForTotals({
super.key,
required this.list,
required this.summaryTypeLabel,
});
final Future<List<TrackedItem>> list;
final String summaryTypeLabel;
@override
Widget build(BuildContext context) {
return FutureBuilder<List<TrackedItem>>(
future: list,
builder: (
BuildContext context,
AsyncSnapshot<List<TrackedItem>> snapshot,
) {
if (!snapshot.hasData) {
return Text('Loading $summaryTypeLabel Section...');
}
// Calculate the total fields based on item type.
double dailyTotal = 0, monthlyTotal = 0, yearlyTotal = 0;
bool isAsset = false;
for (TrackedItem e in snapshot.data!) {
if (e.type == ItemType.asset) {
monthlyTotal += e.amount;
isAsset = true;
} else {
dailyTotal += e.calcComparableAmountDaily();
monthlyTotal += e.calcComparableAmountYearly() / 12;
yearlyTotal += e.calcComparableAmountYearly();
}
}
/* Determine what needs displayed for the item type. */
// Header
String plural = snapshot.data!.length == 1 ? "" : "s";
String header = "$summaryTypeLabel Total";
header += isAsset ? "" : "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 (isAsset) {
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,
);
});
}
}
class SummaryCard extends StatelessWidget {
const SummaryCard({
super.key,
required this.name,
required this.leftText,
required this.middleText,
required this.rightText,
});
final String name;
final String leftText;
final String middleText;
final String rightText;
@override
Widget build(BuildContext context) {
return Card(
color: Theme.of(context).cardColor,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
color: Theme.of(context).highlightColor,
child: Column(
children: [
Text(
name,
style: TextStyle(
decoration: TextDecoration.underline,
fontSize: 16,
),
),
Row(
children: [
Spacer(
flex: 3,
),
Text(
leftText,
),
Spacer(
flex: 1,
),
Text(
middleText,
),
Spacer(
flex: 1,
),
Text(
rightText,
),
Spacer(
flex: 3,
),
],
),
],
),
),
),
);
}
}