LCOV - code coverage report
Current view: top level - lib/pages/bill - bill_page.dart Coverage Total Hit
Test: lcov.info Lines: 1.1 % 91 1
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/controller/iterator_controller.dart';
       5              : import 'package:app_finance/_classes/herald/app_start_of_month.dart';
       6              : import 'package:app_finance/_classes/storage/app_data.dart';
       7              : import 'package:app_finance/_classes/herald/app_locale.dart';
       8              : import 'package:app_finance/_classes/structure/bill_app_data.dart';
       9              : import 'package:app_finance/_configs/screen_helper.dart';
      10              : import 'package:app_finance/_configs/theme_helper.dart';
      11              : import 'package:app_finance/_classes/structure/navigation/app_route.dart';
      12              : import 'package:app_finance/_ext/date_time_ext.dart';
      13              : import 'package:app_finance/design/wrapper/background_wrapper.dart';
      14              : import 'package:app_finance/pages/_interfaces/abstract_page_state.dart';
      15              : import 'package:app_finance/pages/bill/widgets/bill_line_widget.dart';
      16              : import 'package:app_finance/pages/bill/widgets/sliver_header_delegate.dart';
      17              : import 'package:app_finance/design/generic/base_header_widget.dart';
      18              : import 'package:app_finance/design/generic/base_swipe_widget.dart';
      19              : import 'package:material_ui/material_ui.dart';
      20              : 
      21              : class BillPage extends StatefulWidget {
      22            2 :   const BillPage({super.key});
      23              : 
      24            0 :   @override
      25            0 :   BillPageState createState() => BillPageState();
      26              : }
      27              : 
      28              : class BillPageState<T extends StatefulWidget> extends AbstractPageState<T> {
      29              :   InterfaceIterator? stream;
      30              :   List<Widget> itemsShown = [];
      31              :   DateTime timer = DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day);
      32              :   final _scrollController = ScrollController();
      33              :   final batch = 25;
      34              : 
      35            0 :   @override
      36              :   void initState() {
      37            0 :     super.initState();
      38            0 :     _scrollController.addListener(() {
      39            0 :       if (_scrollController.position.extentAfter < 200 && !stream!.isFinished) {
      40            0 :         setState(() => _addItems());
      41              :       }
      42              :     });
      43              :   }
      44              : 
      45            0 :   @override
      46              :   void dispose() {
      47            0 :     _scrollController.dispose();
      48            0 :     super.dispose();
      49              :   }
      50              : 
      51            0 :   Widget addHeaderWidget() {
      52            0 :     final width = ScreenHelper.state().width - ThemeHelper.getIndent(4);
      53            0 :     DateTime startingDay = DateTime.now().getStartingDay(AppStartOfMonth.get());
      54            0 :     return SliverToBoxAdapter(
      55            0 :       child: BaseHeaderWidget(
      56              :         route: AppRoute.homeRoute,
      57            0 :         tooltip: AppLocale.labels.homeTooltip,
      58              :         width: width,
      59            0 :         total: state.getTotal(AppDataType.bills),
      60            0 :         title: '${AppLocale.labels.billHeadline}, ${startingDay.fullMonth()}',
      61              :         searchRoute: AppRoute.billSearchRoute,
      62              :       ),
      63              :     );
      64              :   }
      65              : 
      66            0 :   Widget addLineWidget(dynamic item) {
      67            0 :     final width = ScreenHelper.state().width - ThemeHelper.getIndent(4);
      68            0 :     final account = state.getByUuid(item.account);
      69            0 :     final budget = state.getByUuid(item.category);
      70            0 :     final countWidth = ThemeHelper.getWidthCount(null, context);
      71            0 :     return BaseSwipeWidget(
      72              :       routePath: AppRoute.billEditRoute,
      73            0 :       uuid: item.uuid!,
      74            0 :       child: BillLineWidget(
      75            0 :         uuid: item.uuid!,
      76              :         count: countWidth,
      77            0 :         title: item.title,
      78            0 :         description: account != null ? '${account.title} (${account.description})' : '',
      79            0 :         descriptionColor: account?.color ?? Colors.transparent,
      80            0 :         details: item.detailsFormatted,
      81            0 :         progress: item.progress,
      82            0 :         color: budget?.color ?? Colors.transparent,
      83            0 :         icon: budget?.icon ?? Icons.radio_button_unchecked_sharp,
      84            0 :         iconTooltip: budget?.title ?? '?',
      85            0 :         hidden: item.hidden,
      86              :         width: width,
      87              :         route: AppRoute.billViewRoute,
      88              :       ),
      89              :     );
      90              :   }
      91              : 
      92            0 :   List<dynamic> getItems(DateTime timer) {
      93            0 :     return stream!.getTill(0.0 + timer.millisecondsSinceEpoch);
      94              :   }
      95              : 
      96            0 :   void _addItems() {
      97            0 :     if (itemsShown.isEmpty) {
      98            0 :       itemsShown.add(addHeaderWidget());
      99              :     }
     100            0 :     if (stream == null || stream?.isFinished == true) {
     101              :       return;
     102              :     }
     103              :     String marker = '';
     104            0 :     List<dynamic> items = [];
     105              :     do {
     106            0 :       marker = timer.yMEd();
     107            0 :       items = getItems(timer);
     108            0 :       timer = timer.add(const Duration(days: -1));
     109            0 :     } while (items.isEmpty && !stream!.isFinished);
     110              : 
     111            0 :     itemsShown.add(
     112            0 :       SliverMainAxisGroup(
     113            0 :         slivers: [
     114            0 :           SliverPersistentHeader(
     115              :             pinned: true,
     116            0 :             delegate: SliverHeaderDelegate(marker),
     117              :           ),
     118            0 :           SliverPadding(
     119            0 :             padding: EdgeInsets.symmetric(vertical: ThemeHelper.getIndent(0.5)),
     120            0 :             sliver: SliverList.builder(
     121            0 :               itemCount: items.length,
     122            0 :               itemBuilder: (context, int index) {
     123            0 :                 final item = items[index];
     124            0 :                 return BackgroundWrapper(
     125              :                   index: index,
     126            0 :                   child: addLineWidget(item),
     127              :                 );
     128              :               },
     129              :             ),
     130              :           ),
     131              :         ],
     132              :       ),
     133              :     );
     134            0 :     WidgetsBinding.instance.addPostFrameCallback((_) {
     135            0 :       if (_scrollController.position.maxScrollExtent == 0) {
     136            0 :         setState(() => _addItems());
     137              :       }
     138              :     });
     139              :   }
     140              : 
     141            0 :   @override
     142            0 :   String getTitle() => AppLocale.labels.billHeadline;
     143              : 
     144            0 :   @override
     145            0 :   String getButtonName() => AppLocale.labels.addMainTooltip;
     146              : 
     147            0 :   @override
     148              :   Widget buildButton(BuildContext context, BoxConstraints constraints) {
     149            0 :     NavigatorState nav = Navigator.of(context);
     150            0 :     return FloatingActionButton(
     151              :       heroTag: 'bill_page',
     152            0 :       onPressed: () => nav.pushNamed(AppRoute.billAddRoute),
     153            0 :       tooltip: getButtonName(),
     154              :       child: const Icon(Icons.add),
     155              :     );
     156              :   }
     157              : 
     158            0 :   InterfaceIterator getContentStream() => state.getStream<BillAppData>(AppDataType.bills);
     159              : 
     160            0 :   void clearState() {
     161            0 :     itemsShown = [];
     162            0 :     final now = DateTime.now();
     163            0 :     timer = DateTime(now.year, now.month, now.day);
     164            0 :     stream = null;
     165              :   }
     166              : 
     167            0 :   @override
     168              :   Widget buildContent(BuildContext context, BoxConstraints constraints) {
     169            0 :     state.addListener(clearState);
     170            0 :     if (stream == null) {
     171            0 :       WidgetsBinding.instance.addPostFrameCallback(
     172            0 :         (_) => setState(() {
     173            0 :           stream = getContentStream();
     174            0 :           _addItems();
     175              :         }),
     176              :       );
     177              :     }
     178            0 :     return Padding(
     179            0 :       padding: EdgeInsets.all(ThemeHelper.getIndent()),
     180            0 :       child: CustomScrollView(
     181            0 :         controller: _scrollController,
     182            0 :         slivers: itemsShown,
     183              :       ),
     184              :     );
     185              :   }
     186              : }
        

Generated by: LCOV version 2.0-1