LCOV - code coverage report
Current view: top level - lib/pages/metrics/widgets - budget_tab.dart Coverage Total Hit
Test: lcov.info Lines: 0.0 % 56 0
Test Date: 2026-11-14 15:04:37 Functions: - 0 0

            Line data    Source code
       1              : // Copyright 2023 The terCAD team. All rights reserved.
       2              : // Use of this source code is governed by a CC BY-NC-ND 4.0 license that can be found in the LICENSE file.
       3              : 
       4              : import 'package:app_finance/_classes/herald/app_design.dart';
       5              : import 'package:app_finance/_classes/herald/app_locale.dart';
       6              : import 'package:app_finance/_classes/herald/app_sorting.dart';
       7              : import 'package:app_finance/_classes/herald/app_start_of_month.dart';
       8              : import 'package:app_finance/_classes/storage/app_data.dart';
       9              : import 'package:app_finance/_classes/structure/bill_app_data.dart';
      10              : import 'package:app_finance/_classes/structure/budget_app_data.dart';
      11              : import 'package:app_finance/_classes/structure/currency/exchange.dart';
      12              : import 'package:app_finance/_classes/structure/navigation/app_route.dart';
      13              : import 'package:app_finance/_configs/theme_helper.dart';
      14              : import 'package:app_finance/_ext/build_context_ext.dart';
      15              : import 'package:app_finance/_ext/date_time_ext.dart';
      16              : import 'package:app_finance/_ext/double_ext.dart';
      17              : import 'package:app_finance/components/widgets/budget_forecast_chart.dart';
      18              : import 'package:app_finance/components/widgets/budget_ytd_chart.dart';
      19              : import 'package:app_finance/design/generic/text_widget.dart';
      20              : import 'package:app_finance/design/wrapper/table_widget.dart';
      21              : import 'package:app_finance/design/wrapper/tap_widget.dart';
      22              : import 'package:material_ui/material_ui.dart';
      23              : import 'package:provider/provider.dart';
      24              : 
      25              : class BudgetTab extends StatelessWidget {
      26              :   final AppData store;
      27              : 
      28            0 :   const BudgetTab({
      29              :     super.key,
      30              :     required this.store,
      31              :   });
      32              : 
      33            0 :   Widget _getField(BudgetAppData budget, List<BillAppData> bills, DateTime date) {
      34              :     Color? color;
      35              :     String? text = '-';
      36            0 :     if (budget.amountLimit > 0) {
      37            0 :       final ex = Exchange(store: store);
      38            0 :       double value = bills.fold(0.0, (v, e) => v + ex.reform(e.details, e.currency, ex.getDefaultCurrency()));
      39            0 :       value = 100 * value / ex.reform(budget.amountLimit, budget.currency, ex.getDefaultCurrency());
      40            0 :       text = '${value.toFixed(2)}%';
      41            0 :       if (value < 50) {
      42              :         color = Colors.green;
      43            0 :       } else if (value < 120) {
      44              :         color = Colors.yellow;
      45              :       } else {
      46              :         color = Colors.pink;
      47              :       }
      48              :     }
      49            0 :     return TapWidget(
      50            0 :       tooltip: '${budget.title}, ${date.fullMonth()}: $text',
      51            0 :       route: RouteSettings(
      52              :         name: AppRoute.billScopeViewRoute,
      53            0 :         arguments: {routeArguments.search: date.toString(), routeArguments.uuid: budget.uuid},
      54              :       ),
      55            0 :       child: Container(
      56              :         alignment: Alignment.centerRight,
      57            0 :         color: color?.withValues(alpha: 0.2),
      58            0 :         child: TextWidget(text),
      59              :       ),
      60              :     );
      61              :   }
      62              : 
      63            0 :   List<List<Widget>> _generateTable(int Function(dynamic, dynamic) fnSort) {
      64            0 :     final date = DateTime.now();
      65            0 :     final List<List<Widget>> result = [
      66            0 :       [
      67              :         const Icon(Icons.category),
      68            0 :         TextWidget(AppLocale.labels.title),
      69            0 :         Align(alignment: Alignment.centerRight, child: TextWidget(date.fullMonth())),
      70            0 :         Align(alignment: Alignment.centerRight, child: TextWidget(date.getPreviousMonth(1).fullMonth())),
      71            0 :         Align(alignment: Alignment.centerRight, child: TextWidget(date.getPreviousMonth(2).fullMonth())),
      72              :       ]
      73              :     ];
      74            0 :     final day = AppStartOfMonth.get();
      75            0 :     final bills = store.getStream(AppDataType.bills);
      76            0 :     final dateFirst = date.getStartingDay(day);
      77            0 :     final billFirst = bills.getTill(dateFirst.millisecondsSinceEpoch.toDouble()).cast<BillAppData>();
      78            0 :     final dateSecond = date.getPreviousMonth(1).getStartingDay(day);
      79            0 :     final billSecond = bills.getTill(dateSecond.millisecondsSinceEpoch.toDouble()).cast<BillAppData>();
      80            0 :     final dateThird = date.getPreviousMonth(2).getStartingDay(day);
      81            0 :     final billThird = bills.getTill(dateThird.millisecondsSinceEpoch.toDouble()).cast<BillAppData>();
      82            0 :     final items = store.getList(AppDataType.budgets);
      83            0 :     items.sort(fnSort);
      84            0 :     for (BudgetAppData budget in items) {
      85            0 :       bool fnCategory(bill) => bill.category == budget.uuid;
      86            0 :       result.add([
      87            0 :         Icon(budget.icon, color: budget.color),
      88            0 :         TextWidget(budget.title),
      89            0 :         _getField(budget, billFirst.where(fnCategory).toList(), dateFirst),
      90            0 :         _getField(budget, billSecond.where(fnCategory).toList(), dateSecond),
      91            0 :         _getField(budget, billThird.where(fnCategory).toList(), dateThird),
      92              :       ]);
      93              :     }
      94              :     return result;
      95              :   }
      96              : 
      97            0 :   @override
      98              :   Widget build(BuildContext context) {
      99            0 :     final sorting = Provider.of<AppSorting>(context, listen: true);
     100            0 :     final indent = ThemeHelper.getIndent(2);
     101            0 :     return SingleChildScrollView(
     102            0 :       child: Padding(
     103            0 :         padding: EdgeInsets.all(indent),
     104            0 :         child: Column(
     105            0 :           crossAxisAlignment: AppDesign.getAlignment(),
     106            0 :           children: [
     107              :             const BudgetForecastChart(),
     108              :             ThemeHelper.hIndent4x,
     109              :             const BudgetYtdChart(),
     110              :             ThemeHelper.hIndent4x,
     111            0 :             LayoutBuilder(builder: (context, constraints) {
     112            0 :               return TableWidget(
     113            0 :                 shadowColor: context.colorScheme.onSurface.withValues(alpha: 0.1),
     114            0 :                 width: constraints.maxWidth,
     115              :                 chunk: const [20, 72, null, null, null],
     116            0 :                 data: _generateTable(sorting.getSortFunction(context)),
     117              :               );
     118              :             }),
     119              :             ThemeHelper.formEndBox,
     120              :           ],
     121              :         ),
     122              :       ),
     123              :     );
     124              :   }
     125              : }
        

Generated by: LCOV version 2.0-1