LCOV - code coverage report
Current view: top level - lib/pages/account - account_view_page.dart Coverage Total Hit
Test: lcov.info Lines: 0.0 % 146 0
Test Date: 2026-11-14 15:08:11 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_design.dart';
       8              : import 'package:app_finance/_classes/herald/app_locale.dart';
       9              : import 'package:app_finance/_classes/controller/flow_state_machine.dart';
      10              : import 'package:app_finance/_classes/herald/app_start_of_month.dart';
      11              : import 'package:app_finance/_classes/storage/app_data.dart';
      12              : import 'package:app_finance/_classes/structure/account_app_data.dart';
      13              : import 'package:app_finance/_classes/structure/account_summary_data.dart';
      14              : import 'package:app_finance/_classes/structure/bill_app_data.dart';
      15              : import 'package:app_finance/_classes/structure/currency/exchange.dart';
      16              : import 'package:app_finance/_classes/structure/invoice_app_data.dart';
      17              : import 'package:app_finance/_configs/custom_text_theme.dart';
      18              : import 'package:app_finance/_configs/screen_helper.dart';
      19              : import 'package:app_finance/_configs/theme_helper.dart';
      20              : import 'package:app_finance/_classes/structure/navigation/app_route.dart';
      21              : import 'package:app_finance/_ext/build_context_ext.dart';
      22              : import 'package:app_finance/_ext/date_time_ext.dart';
      23              : import 'package:app_finance/design/wrapper/row_widget.dart';
      24              : import 'package:app_finance/design/wrapper/text_wrapper.dart';
      25              : import 'package:app_finance/pages/_interfaces/abstract_page_state.dart';
      26              : import 'package:app_finance/pages/account/widgets/account_line_widget.dart';
      27              : import 'package:app_finance/design/generic/base_line_widget.dart';
      28              : import 'package:app_finance/design/generic/base_list_infinite_widget.dart';
      29              : import 'package:app_finance/design/wrapper/confirmation_wrapper.dart';
      30              : import 'package:app_finance/design/wrapper/tab_widget.dart';
      31              : import 'package:material_ui/material_ui.dart';
      32              : import 'package:flutter_currency_picker/flutter_currency_picker.dart';
      33              : import 'package:intl/intl.dart' as intl;
      34              : 
      35              : class AccountViewPage extends StatefulWidget {
      36              :   final String uuid;
      37              : 
      38            0 :   const AccountViewPage({
      39              :     super.key,
      40              :     required this.uuid,
      41              :   });
      42              : 
      43            0 :   @override
      44            0 :   AccountViewPageState createState() => AccountViewPageState();
      45              : }
      46              : 
      47              : class AccountViewPageState extends AbstractPageState<AccountViewPage> {
      48              :   late double width;
      49              :   int focus = 0;
      50              : 
      51            0 :   @override
      52              :   String getTitle() {
      53            0 :     final item = super.state.getByUuid(widget.uuid) as AccountAppData;
      54            0 :     return item.title;
      55              :   }
      56              : 
      57            0 :   @override
      58              :   String getButtonName() => '';
      59              : 
      60            0 :   @override
      61              :   Widget buildButton(BuildContext context, BoxConstraints constraints) {
      62            0 :     double indent = ThemeHelper.getIndent(4);
      63            0 :     NavigatorState nav = Navigator.of(context);
      64            0 :     return Container(
      65            0 :       margin: EdgeInsets.only(left: 2 * indent, right: 2 * indent),
      66            0 :       child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
      67            0 :         FloatingActionButton(
      68              :           heroTag: 'account_view_page_edit',
      69            0 :           onPressed: () => nav.pushNamed(AppRoute.accountEditRoute, arguments: {routeArguments.uuid: widget.uuid}),
      70            0 :           tooltip: AppLocale.labels.editAccountTooltip,
      71              :           child: const Icon(Icons.edit),
      72              :         ),
      73            0 :         FloatingActionButton(
      74              :           heroTag: 'account_view_page_deactivate',
      75            0 :           onPressed: () => ConfirmationWrapper.show(
      76              :             context,
      77            0 :             () => FlowStateMachine.deactivate(nav, store: super.state, uuid: widget.uuid),
      78              :           ),
      79            0 :           tooltip: AppLocale.labels.deleteAccountTooltip,
      80              :           child: const Icon(Icons.delete),
      81              :         ),
      82              :       ]),
      83              :     );
      84              :   }
      85              : 
      86            0 :   String _getTitle(dynamic item) {
      87              :     String prefix = '';
      88            0 :     if (item is InvoiceAppData && item.accountFrom != null) {
      89            0 :       if (item.accountFrom == widget.uuid) {
      90            0 :         final obj = state.getByUuid(item.account) as AccountAppData;
      91            0 :         prefix = "[${AppLocale.labels.transferHeadline} ${AppLocale.labels.to} '${obj.title}'] ";
      92              :       } else {
      93            0 :         final obj = state.getByUuid(item.accountFrom!) as AccountAppData;
      94            0 :         prefix = "[${AppLocale.labels.transferHeadline} ${AppLocale.labels.from} '${obj.title}'] ";
      95              :       }
      96              :     }
      97            0 :     return item != null ? '$prefix${item.title}' : '';
      98              :   }
      99              : 
     100            0 :   String _getRoute(dynamic item) => switch (item.runtimeType) {
     101            0 :         BillAppData => AppRoute.billViewRoute,
     102            0 :         InvoiceAppData => AppRoute.invoiceViewRoute,
     103              :         _ => '',
     104              :       };
     105              : 
     106            0 :   InterfaceIterator<num, dynamic, dynamic> _getSummary() {
     107            0 :     var exchange = Exchange(store: state);
     108            0 :     var account = super.state.getByUuid(widget.uuid) as AccountAppData;
     109            0 :     var bills = state.getStream(AppDataType.bills, filter: (o) => o.account != widget.uuid);
     110            0 :     var inv = state.getStream(AppDataType.invoice, filter: (o) => o.account != widget.uuid || o.accountFrom != null);
     111            0 :     DateTime now = DateTime.now();
     112            0 :     int startingDay = AppStartOfMonth.get();
     113            0 :     DateTime curr = now.getStartingDay(startingDay);
     114            0 :     var data = SplayTreeMap<num, AccountSummaryData>();
     115              :     int increment = 0;
     116            0 :     while (!(bills.isFinished && inv.isFinished)) {
     117            0 :       var boundary = curr.millisecondsSinceEpoch.toDouble();
     118            0 :       var billList = bills.getTill(boundary);
     119            0 :       var invList = inv.getTill(boundary);
     120            0 :       data[increment] = AccountSummaryData(
     121            0 :         title: intl.DateFormat.MMMM().format(curr),
     122            0 :         description: curr.year.toString(),
     123            0 :         currency: account.currency,
     124            0 :         invoices: invList.fold(0.0, (v, e) => v + exchange.reform(e.details ?? 0.0, e.currency, account.currency)),
     125            0 :         bills: billList.fold(0.0, (v, e) => v + exchange.reform(e.details ?? 0.0, e.currency, account.currency)),
     126              :       );
     127            0 :       increment++;
     128            0 :       curr = DateTime(now.year, now.month - increment, now.day).getStartingDay(startingDay);
     129              :     }
     130            0 :     return IteratorController(data, transform: (v) => v);
     131              :   }
     132              : 
     133            0 :   Widget buildSummaryWidget(item, BuildContext context) {
     134            0 :     final textTheme = context.textTheme;
     135            0 :     final indent = ThemeHelper.getIndent();
     136            0 :     final alignment = AppDesign.isRightToLeft() ? Alignment.centerLeft : Alignment.centerRight;
     137            0 :     return RowWidget(
     138              :       indent: indent,
     139            0 :       alignment: AppDesign.getAlignment<MainAxisAlignment>(),
     140            0 :       maxWidth: width,
     141            0 :       chunk: [indent, null, null, null, indent],
     142            0 :       children: [
     143              :         const [ThemeHelper.emptyBox],
     144            0 :         [
     145            0 :           Column(
     146            0 :             crossAxisAlignment: AppDesign.getAlignment(),
     147            0 :             children: [
     148            0 :               TextWrapper(
     149            0 :                 item.title,
     150            0 :                 style: textTheme.headlineMedium,
     151              :               ),
     152            0 :               TextWrapper(
     153            0 :                 item.description,
     154            0 :                 style: textTheme.bodySmall,
     155              :               ),
     156              :               ThemeHelper.hIndent
     157              :             ],
     158              :           ),
     159              :         ],
     160            0 :         [
     161            0 :           Align(
     162              :             alignment: alignment,
     163            0 :             child: TextWrapper(
     164            0 :               (item.bills as double).toCurrency(currency: item.currency, withPattern: true),
     165            0 :               style: textTheme.numberMedium,
     166              :             ),
     167              :           ),
     168              :         ],
     169            0 :         [
     170            0 :           Align(
     171              :             alignment: alignment,
     172            0 :             child: TextWrapper(
     173            0 :               (item.invoices as double).toCurrency(currency: item.currency, withPattern: true),
     174            0 :               style: textTheme.numberMedium,
     175              :             ),
     176              :           ),
     177              :         ],
     178              :         const [ThemeHelper.emptyBox],
     179              :       ],
     180              :     );
     181              :   }
     182              : 
     183            0 :   Widget buildLineWidget(item, BuildContext context) {
     184            0 :     return BaseLineWidget(
     185            0 :       uuid: item.uuid ?? '',
     186            0 :       title: _getTitle(item),
     187            0 :       description: item.description ?? '',
     188            0 :       details: item.detailsFormatted,
     189            0 :       progress: item.progress,
     190            0 :       color: item.color ?? Colors.transparent,
     191            0 :       icon: item.icon ?? Icons.radio_button_unchecked_sharp,
     192            0 :       hidden: item.hidden,
     193            0 :       skip: item.skip,
     194            0 :       width: width,
     195            0 :       route: _getRoute(item),
     196              :     );
     197              :   }
     198              : 
     199            0 :   Widget buildLineTransferWidget(item, BuildContext context) {
     200            0 :     final account = state.getByUuid(item?.accountFrom ?? '');
     201            0 :     return BaseLineWidget(
     202            0 :       uuid: item.uuid ?? '',
     203            0 :       title: _getTitle(item),
     204            0 :       description: item.description ?? '',
     205            0 :       details: item.detailsFormatted,
     206            0 :       progress: item.progress,
     207            0 :       color: account?.color ?? Colors.transparent,
     208            0 :       icon: account?.icon ?? Icons.radio_button_unchecked_sharp,
     209            0 :       hidden: item.hidden,
     210            0 :       skip: item.skip,
     211            0 :       width: width,
     212            0 :       route: _getRoute(item),
     213              :     );
     214              :   }
     215              : 
     216            0 :   @override
     217              :   Widget buildContent(BuildContext context, BoxConstraints constraints) {
     218            0 :     width = ThemeHelper.getWidth(context, 4, constraints);
     219            0 :     final isLeft = ScreenHelper.state().isLeftBar;
     220              :     if (isLeft) {
     221            0 :       width -= ThemeHelper.barHeight;
     222              :     }
     223            0 :     return Padding(
     224            0 :       padding: EdgeInsets.only(top: ThemeHelper.getIndent()),
     225            0 :       child: Column(
     226            0 :         children: [
     227            0 :           AccountLineWidget(item: state.getByUuid(widget.uuid) as AccountAppData, width: width, count: 1),
     228              :           ThemeHelper.hIndent05,
     229              :           const Divider(height: 2),
     230            0 :           Expanded(
     231            0 :             child: TabWidget(
     232              :               type: TabType.secondary,
     233              :               isLeft: isLeft,
     234            0 :               focus: focus,
     235            0 :               callback: (data) => setState(() => focus = data),
     236            0 :               tabs: [
     237            0 :                 Tab(text: AppLocale.labels.summary),
     238            0 :                 Tab(text: AppLocale.labels.billHeadline),
     239            0 :                 Tab(text: AppLocale.labels.invoiceHeadline),
     240            0 :                 Tab(text: AppLocale.labels.transfersHeadline),
     241              :               ],
     242            0 :               children: [
     243            0 :                 BaseListInfiniteWidget(
     244            0 :                   stream: _getSummary(),
     245            0 :                   width: width,
     246            0 :                   buildListWidget: buildSummaryWidget,
     247              :                 ),
     248            0 :                 BaseListInfiniteWidget(
     249            0 :                   stream: state.getStream(AppDataType.bills, filter: (o) => o.account != widget.uuid),
     250            0 :                   width: width,
     251            0 :                   buildListWidget: buildLineWidget,
     252              :                 ),
     253            0 :                 BaseListInfiniteWidget(
     254            0 :                   stream: state.getStream(
     255              :                     AppDataType.invoice,
     256            0 :                     filter: (o) => o.account != widget.uuid || o.accountFrom != null,
     257              :                   ),
     258            0 :                   width: width,
     259            0 :                   buildListWidget: buildLineWidget,
     260              :                 ),
     261            0 :                 BaseListInfiniteWidget(
     262            0 :                   stream: state.getStream(
     263              :                     AppDataType.invoice,
     264            0 :                     filter: (o) => o.account != widget.uuid && o.accountFrom != widget.uuid || o.accountFrom == null,
     265              :                   ),
     266            0 :                   width: width,
     267            0 :                   buildListWidget: buildLineTransferWidget,
     268              :                 ),
     269              :               ],
     270              :             ),
     271              :           ),
     272              :         ],
     273              :       ),
     274              :     );
     275              :   }
     276              : }
        

Generated by: LCOV version 2.0-1