LCOV - code coverage report
Current view: top level - lib/pages/budget - budget_view_page.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 95 0.0 %
Date: 2024-10-04 11:09:33 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 'dart:collection';
       5             : 
       6             : import 'package:app_finance/_classes/controller/iterator_controller.dart';
       7             : import 'package:app_finance/_classes/herald/app_locale.dart';
       8             : import 'package:app_finance/_classes/controller/flow_state_machine.dart';
       9             : import 'package:app_finance/_classes/storage/app_data.dart';
      10             : import 'package:app_finance/_classes/storage/history_data.dart';
      11             : import 'package:app_finance/_classes/structure/account_app_data.dart';
      12             : import 'package:app_finance/_classes/structure/bill_app_data.dart';
      13             : import 'package:app_finance/_classes/structure/budget_app_data.dart';
      14             : import 'package:app_finance/_classes/structure/currency/exchange.dart';
      15             : import 'package:app_finance/_configs/account_type.dart';
      16             : import 'package:app_finance/_configs/theme_helper.dart';
      17             : import 'package:app_finance/_classes/structure/navigation/app_route.dart';
      18             : import 'package:app_finance/_ext/date_time_ext.dart';
      19             : import 'package:app_finance/pages/_interfaces/abstract_page_state.dart';
      20             : import 'package:app_finance/pages/budget/widgets/budget_header_widget.dart';
      21             : import 'package:app_finance/design/generic/base_line_widget.dart';
      22             : import 'package:app_finance/design/generic/base_list_infinite_widget.dart';
      23             : import 'package:app_finance/design/wrapper/confirmation_wrapper.dart';
      24             : import 'package:app_finance/design/wrapper/tab_widget.dart';
      25             : import 'package:flutter/material.dart';
      26             : import 'package:flutter_currency_picker/flutter_currency_picker.dart';
      27             : import 'package:intl/intl.dart';
      28             : 
      29             : class BudgetViewPage extends StatefulWidget {
      30             :   final String uuid;
      31             : 
      32           0 :   const BudgetViewPage({
      33             :     super.key,
      34             :     required this.uuid,
      35             :   });
      36             : 
      37           0 :   @override
      38           0 :   BudgetViewPageState createState() => BudgetViewPageState();
      39             : }
      40             : 
      41             : class BudgetViewPageState extends AbstractPageState<BudgetViewPage> with TickerProviderStateMixin {
      42             :   late double width;
      43             :   int focus = 0;
      44             : 
      45           0 :   @override
      46             :   String getTitle() {
      47           0 :     final item = super.state.getByUuid(widget.uuid) as BudgetAppData;
      48           0 :     return item.title;
      49             :   }
      50             : 
      51           0 :   @override
      52             :   String getButtonName() => '';
      53             : 
      54           0 :   @override
      55             :   Widget buildButton(BuildContext context, BoxConstraints constraints) {
      56           0 :     double indent = ThemeHelper.getIndent(4);
      57           0 :     NavigatorState nav = Navigator.of(context);
      58           0 :     return Container(
      59           0 :       margin: EdgeInsets.only(left: 2 * indent, right: 2 * indent),
      60           0 :       child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
      61           0 :         FloatingActionButton(
      62             :           heroTag: 'budget_view_page_edit',
      63           0 :           onPressed: () => nav.pushNamed(AppRoute.budgetEditRoute, arguments: {routeArguments.uuid: widget.uuid}),
      64           0 :           tooltip: AppLocale.labels.editBudgetTooltip,
      65             :           child: const Icon(Icons.edit),
      66             :         ),
      67           0 :         FloatingActionButton(
      68             :           heroTag: 'budget_view_page_deactivate',
      69           0 :           onPressed: () => ConfirmationWrapper.show(
      70             :             context,
      71           0 :             () => FlowStateMachine.deactivate(nav, store: super.state, uuid: widget.uuid),
      72             :           ),
      73           0 :           tooltip: AppLocale.labels.deleteBudgetTooltip,
      74             :           child: const Icon(Icons.delete),
      75             :         ),
      76             :       ]),
      77             :     );
      78             :   }
      79             : 
      80           0 :   Widget buildListWidget(item, BuildContext context) {
      81           0 :     final value = (item.delta as double).toCurrency(currency: item.currency, withPattern: false);
      82           0 :     return BaseLineWidget(
      83             :       uuid: '',
      84             :       title: '',
      85           0 :       description: (item.timestamp as DateTime).yMEd(),
      86             :       progress: 1.0,
      87           0 :       details: item.delta > 0 ? '+$value' : value,
      88             :       color: Colors.transparent,
      89           0 :       width: width,
      90             :     );
      91             :   }
      92             : 
      93           0 :   Widget buildLineWidget(item, BuildContext context) {
      94           0 :     return BaseLineWidget(
      95           0 :       uuid: item.uuid ?? '',
      96           0 :       title: item.title ?? '',
      97           0 :       description: item.description ?? '',
      98           0 :       details: item.detailsFormatted,
      99           0 :       progress: item.progress,
     100           0 :       color: item.color ?? Colors.transparent,
     101           0 :       icon: item.icon ?? Icons.radio_button_unchecked_sharp,
     102           0 :       hidden: item.hidden,
     103           0 :       width: width,
     104             :       route: AppRoute.billViewRoute,
     105             :     );
     106             :   }
     107             : 
     108           0 :   InterfaceIterator<num, dynamic, dynamic> _getSummary() {
     109           0 :     var exchange = Exchange(store: state);
     110           0 :     var category = super.state.getByUuid(widget.uuid) as BudgetAppData;
     111           0 :     var bills = state.getStream(AppDataType.bills, filter: (o) => o.category != widget.uuid);
     112           0 :     DateTime now = DateTime.now();
     113           0 :     DateTime curr = DateTime(now.year, now.month, 1);
     114             :     int iteration = 0;
     115             :     BillAppData? item;
     116           0 :     AccountAppData summary = AccountAppData(
     117           0 :       type: AppAccountType.cash.toString(),
     118           0 :       title: DateFormat.MMMM().format(curr),
     119           0 :       description: curr.year.toString(),
     120           0 :       currency: category.currency,
     121             :       progress: 1,
     122             :     );
     123           0 :     var data = SplayTreeMap<num, AccountAppData>();
     124             :     while (true) {
     125           0 :       item = bills.next;
     126           0 :       if (item == null || item.createdAt.isBefore(curr)) {
     127           0 :         if (category.amountLimit < summary.details) {
     128           0 :           summary.color = Colors.red;
     129             :         }
     130           0 :         data[iteration] = summary.clone();
     131             :         if (item == null) {
     132             :           break;
     133             :         }
     134           0 :         iteration++;
     135           0 :         curr = DateTime(now.year, now.month - iteration, 1);
     136           0 :         summary.details = 0;
     137           0 :         summary.color = null;
     138           0 :         summary.title = DateFormat.MMMM().format(curr);
     139           0 :         summary.description = curr.year.toString();
     140             :       }
     141           0 :       summary.details = summary.details + exchange.reform(item.details ?? 0.0, item.currency, summary.currency);
     142             :     }
     143           0 :     return IteratorController(data, transform: (v) => v);
     144             :   }
     145             : 
     146           0 :   @override
     147             :   Widget buildContent(BuildContext context, BoxConstraints constraints) {
     148           0 :     final indent = ThemeHelper.getIndent();
     149           0 :     final pageWidth = ThemeHelper.getWidth(context, 3, constraints);
     150           0 :     width = pageWidth - indent;
     151           0 :     bool isLeft = ThemeHelper.isNavRight(context, constraints);
     152             :     if (isLeft) {
     153           0 :       width -= ThemeHelper.barHeight;
     154             :     }
     155           0 :     final boundary = DateTime(DateTime.now().year, DateTime.now().month).millisecondsSinceEpoch + 0.0;
     156           0 :     return Padding(
     157           0 :       padding: EdgeInsets.only(top: indent),
     158           0 :       child: Column(
     159           0 :         children: [
     160           0 :           BudgetHeaderWidget(item: state.getByUuid(widget.uuid) as BudgetAppData, width: pageWidth),
     161             :           ThemeHelper.hIndent05,
     162             :           const Divider(height: 2),
     163           0 :           Expanded(
     164           0 :             child: TabWidget(
     165             :               type: TabType.secondary,
     166             :               isLeft: isLeft,
     167           0 :               focus: focus,
     168           0 :               callback: (data) => setState(() => focus = data),
     169           0 :               tabs: [
     170           0 :                 Tab(text: AppLocale.labels.billHeadline),
     171           0 :                 Tab(text: AppLocale.labels.summary),
     172           0 :                 Tab(text: AppLocale.labels.budgetLimitHeadline),
     173             :               ],
     174           0 :               children: [
     175           0 :                 BaseListInfiniteWidget(
     176             :                   stream:
     177           0 :                       state.getStream(AppDataType.bills, boundary: boundary, filter: (o) => o.category != widget.uuid),
     178           0 :                   width: width,
     179           0 :                   buildListWidget: buildLineWidget,
     180             :                 ),
     181           0 :                 BaseListInfiniteWidget(
     182           0 :                   stream: _getSummary(),
     183           0 :                   width: width,
     184           0 :                   buildListWidget: buildLineWidget,
     185             :                 ),
     186           0 :                 BaseListInfiniteWidget(
     187           0 :                   stream: HistoryData.getStream(widget.uuid),
     188           0 :                   width: width,
     189           0 :                   buildListWidget: buildListWidget,
     190             :                 ),
     191             :               ],
     192             :             ),
     193             :           ),
     194             :         ],
     195             :       ),
     196             :     );
     197             :   }
     198             : }

Generated by: LCOV version 1.14