diff --git a/lib/routes/home/stats_tab.dart b/lib/routes/home/stats_tab.dart index d7fe0a55..33ad8aaa 100644 --- a/lib/routes/home/stats_tab.dart +++ b/lib/routes/home/stats_tab.dart @@ -2,10 +2,11 @@ import "dart:ui"; import "package:auto_size_text/auto_size_text.dart"; import "package:flow/data/flow_report.dart"; +import "package:flow/prefs.dart"; +import "package:flow/routes/home/stats_tab/info_card_with_delta.dart"; +import "package:flow/theme/theme.dart"; import "package:flow/widgets/general/frame.dart"; -import "package:flow/widgets/general/money_text.dart"; import "package:flow/widgets/general/spinner.dart"; -import "package:flow/widgets/home/home/info_card.dart"; import "package:flow/widgets/home/stats/range_daily_chart.dart"; import "package:flow/widgets/time_range_selector.dart"; import "package:flutter/material.dart"; @@ -25,6 +26,9 @@ class _StatsTabState extends State final AutoSizeGroup autoSizeGroup = AutoSizeGroup(); + late final bool initiallyAbbreviated = + !LocalPreferences().preferFullAmounts.get(); + bool busy = false; @override @@ -75,63 +79,71 @@ class _StatsTabState extends State ], ), ), - const SizedBox(height: 96.0), - Frame( - child: Row( - children: [ - Expanded( - child: InfoCard( - title: "Avg. daily expense", - moneyText: MoneyText( - report!.dailyAvgExpenditure, - tapToToggleAbbreviation: true, - autoSizeGroup: autoSizeGroup, - ), - ), - ), - const SizedBox(width: 16.0), - Expanded( - child: InfoCard( - title: "Avg. daily income", - moneyText: MoneyText( - report!.dailyAvgIncome, - tapToToggleAbbreviation: true, - autoSizeGroup: autoSizeGroup, - ), - ), - ), - ], - ), - ), - const SizedBox(height: 16.0), - Frame( - child: Row( + const SizedBox(height: 24.0), + DefaultTextStyle( + style: context.textTheme.displaySmall!, + child: Column( + mainAxisSize: MainAxisSize.min, children: [ - Expanded( - child: InfoCard( - title: - "Forecast for ${report!.current.format()}", - moneyText: MoneyText( - report!.currentExpenseSumForecast, - tapToToggleAbbreviation: true, - autoSizeGroup: autoSizeGroup, - ), + Frame( + child: Row( + children: [ + Expanded( + child: InfoCardWithDelta( + title: "Avg. daily expense", + autoSizeGroup: autoSizeGroup, + money: report!.dailyAvgExpenditure, + previousMoney: + report!.previousDailyAvgExpenditure, + invertDelta: true, + ), + ), + const SizedBox(width: 16.0), + Expanded( + child: InfoCardWithDelta( + title: "Avg. daily income", + autoSizeGroup: autoSizeGroup, + money: report!.dailyAvgIncome, + previousMoney: + report!.previousDailyAvgIncome, + ), + ), + ], ), ), - const SizedBox(width: 16.0), - Expanded( - child: InfoCard( - title: "Avg. daily flow", - moneyText: MoneyText( - report!.dailyAvgFlow, - tapToToggleAbbreviation: true, - autoSizeGroup: autoSizeGroup, - ), + const SizedBox(height: 16.0), + Frame( + child: Row( + children: [ + if (report!.currentExpenseSumForecast != null) + Expanded( + child: InfoCardWithDelta( + title: + "Forecast for ${report!.current.format()}", + autoSizeGroup: autoSizeGroup, + money: + report!.currentExpenseSumForecast!, + previousMoney: + report!.previousExpenseSum, + ), + ), + const SizedBox(width: 16.0), + Expanded( + child: InfoCardWithDelta( + title: "Avg. daily flow", + autoSizeGroup: autoSizeGroup, + money: report!.dailyAvgFlow, + previousMoney: + report!.previousDailyAvgFlow, + ), + ), + ], ), ), ], ), ), + const SizedBox(height: 96.0), ], ), ) diff --git a/lib/routes/home/stats_tab/info_card_with_delta.dart b/lib/routes/home/stats_tab/info_card_with_delta.dart new file mode 100644 index 00000000..8ac51089 --- /dev/null +++ b/lib/routes/home/stats_tab/info_card_with_delta.dart @@ -0,0 +1,78 @@ +import "package:auto_size_text/auto_size_text.dart"; +import "package:flow/data/money.dart"; +import "package:flow/prefs.dart"; +import "package:flow/theme/theme.dart"; +import "package:flow/widgets/general/money_text.dart"; +import "package:flow/widgets/home/home/info_card.dart"; +import "package:flutter/material.dart"; +import "package:material_symbols_icons/symbols.dart"; + +class InfoCardWithDelta extends StatelessWidget { + final Money money; + final Money? previousMoney; + + final bool invertDelta; + + final AutoSizeGroup? autoSizeGroup; + + final String title; + + const InfoCardWithDelta({ + super.key, + required this.money, + required this.previousMoney, + required this.autoSizeGroup, + required this.title, + this.invertDelta = false, + }); + + @override + Widget build(BuildContext context) { + final double hundredPercent = previousMoney?.amount ?? 0; + final double delta = (hundredPercent == 0 || + hundredPercent.isNaN || + hundredPercent.isInfinite) + ? 0 + : (money.amount - hundredPercent) / hundredPercent; + + final String deltaString = "${(delta.abs() * 100).toStringAsFixed(1)}%"; + + final bool downtrend = invertDelta ^ delta.isNegative; + + final Color color = + downtrend ? context.flowColors.expense : context.flowColors.income; + + return InfoCard( + title: title, + moneyText: MoneyText( + money, + tapToToggleAbbreviation: true, + initiallyAbbreviated: !LocalPreferences().preferFullAmounts.get(), + autoSize: true, + autoSizeGroup: autoSizeGroup, + style: context.textTheme.displaySmall, + ), + delta: delta != 0.0 + ? Row( + mainAxisSize: MainAxisSize.min, + spacing: 4.0, + children: [ + Icon( + delta.isNegative + ? Symbols.arrow_downward + : Symbols.arrow_upward, + size: context.textTheme.titleSmall!.fontSize, + color: color, + ), + Text( + deltaString, + style: context.textTheme.titleSmall!.copyWith( + color: color, + ), + ) + ], + ) + : null, + ); + } +} diff --git a/lib/widgets/home/home/info_card.dart b/lib/widgets/home/home/info_card.dart index bad59467..5622b1a8 100644 --- a/lib/widgets/home/home/info_card.dart +++ b/lib/widgets/home/home/info_card.dart @@ -6,6 +6,7 @@ class InfoCard extends StatelessWidget { final String title; final Widget? moneyText; + final Widget? delta; final Widget? icon; @@ -14,6 +15,7 @@ class InfoCard extends StatelessWidget { required this.title, this.icon, this.moneyText, + this.delta, }); @override @@ -44,7 +46,8 @@ class InfoCard extends StatelessWidget { ], ], ), - if (moneyText != null) moneyText! + if (moneyText != null) moneyText!, + if (delta != null) delta! ], ), ), diff --git a/pubspec.yaml b/pubspec.yaml index c33fc537..4f814386 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,7 +3,7 @@ description: A personal finance managing app publish_to: "none" # Remove this line if you wish to publish to pub.dev -version: "0.11.0+103" +version: "0.11.0+104" environment: sdk: ">=3.5.0 <4.0.0"