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

            Line data    Source code
       1              : // Copyright 2025 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/controller/focus_controller.dart';
       6              : import 'package:app_finance/_classes/herald/app_design.dart';
       7              : import 'package:app_finance/_classes/herald/app_locale.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/_configs/account_type.dart';
      11              : import 'package:app_finance/_configs/screen_helper.dart';
      12              : import 'package:app_finance/_configs/theme_helper.dart';
      13              : import 'package:app_finance/_ext/build_context_ext.dart';
      14              : import 'package:app_finance/design/form/date_range_input.dart';
      15              : import 'package:app_finance/design/form/list_account_selector.dart';
      16              : import 'package:app_finance/design/form/simple_input.dart';
      17              : import 'package:app_finance/design/wrapper/input_wrapper.dart';
      18              : import 'package:app_finance/design/wrapper/row_widget.dart';
      19              : import 'package:app_finance/design/wrapper/single_scroll_wrapper.dart';
      20              : import 'package:app_finance/design/wrapper/text_wrapper.dart';
      21              : import 'package:app_finance/pages/bill/bill_page.dart';
      22              : import 'package:material_ui/material_ui.dart';
      23              : import 'package:flutter_currency_picker/flutter_currency_picker.dart';
      24              : 
      25              : class BillSearchPage extends StatefulWidget {
      26            0 :   const BillSearchPage({super.key});
      27              : 
      28            0 :   @override
      29            0 :   BillViewPageState createState() => BillViewPageState();
      30              : }
      31              : 
      32              : class BillViewPageState extends BillPageState<BillSearchPage> {
      33              :   String? account;
      34              :   String? budget;
      35              :   String? type;
      36              :   Currency? currency;
      37              :   DateTime? startDate;
      38              :   DateTime? endDate;
      39              :   late TextEditingController description;
      40              :   late TextEditingController amountFrom;
      41              :   late TextEditingController amountTo;
      42              :   late FocusController focus;
      43              :   late List<ListAccountSelectorItem> accountList =
      44              :       state.getList(AppDataType.accounts).map((item) => ListAccountSelectorItem(item: item)).toList();
      45              :   late List<ListAccountSelectorItem> budgetList =
      46              :       state.getList(AppDataType.budgets).map((item) => ListAccountSelectorItem(item: item)).toList();
      47              : 
      48            0 :   @override
      49              :   void initState() {
      50            0 :     description = TextEditingController();
      51            0 :     amountFrom = TextEditingController();
      52            0 :     amountTo = TextEditingController();
      53            0 :     focus = FocusController();
      54            0 :     super.initState();
      55              :   }
      56              : 
      57            0 :   @override
      58              :   dispose() {
      59            0 :     description.dispose();
      60            0 :     amountFrom.dispose();
      61            0 :     amountTo.dispose();
      62            0 :     focus.dispose();
      63            0 :     super.dispose();
      64              :   }
      65              : 
      66            0 :   @override
      67            0 :   String getTitle() => AppLocale.labels.searchTooltip;
      68              : 
      69            0 :   @override
      70            0 :   String getButtonName() => AppLocale.labels.searchTooltip;
      71              : 
      72            0 :   @override
      73              :   Widget buildButton(BuildContext context, BoxConstraints constraints) {
      74            0 :     return FloatingActionButton(
      75              :       heroTag: 'bill_search_page',
      76            0 :       onPressed: () => setState(clearState),
      77            0 :       tooltip: getButtonName(),
      78              :       child: const Icon(Icons.search),
      79              :     );
      80              :   }
      81              : 
      82            0 :   bool getContentFilter(BillAppData item) {
      83            0 :     final descriptionMatch = item.title.toLowerCase().contains(description.text.toLowerCase());
      84            0 :     final accountMatch = account == null || item.account == account;
      85            0 :     final budgetMatch = budget == null || item.category == budget;
      86            0 :     final typeMatch = type == null || state.getByUuid(item.account)?.type == type;
      87            0 :     final currencyMatch = currency == null || item.currency == currency;
      88            0 :     final startDateMatch = startDate == null || item.createdAt.isAfter(startDate!);
      89            0 :     final endDateMatch = endDate == null || item.createdAt.isBefore(endDate!);
      90            0 :     final amountFromMatch = amountFrom.text.isEmpty || item.details >= double.tryParse(amountFrom.text)!;
      91            0 :     final amountToMatch = amountTo.text.isEmpty || item.details <= double.tryParse(amountTo.text)!;
      92              :     return !(descriptionMatch &&
      93              :         accountMatch &&
      94              :         budgetMatch &&
      95              :         typeMatch &&
      96              :         currencyMatch &&
      97              :         startDateMatch &&
      98              :         endDateMatch &&
      99              :         amountFromMatch &&
     100              :         amountToMatch);
     101              :   }
     102              : 
     103            0 :   @override
     104            0 :   InterfaceIterator getContentStream() => state.getStream<BillAppData>(AppDataType.bills, filter: getContentFilter);
     105              : 
     106            0 :   @override
     107              :   Widget addHeaderWidget() {
     108            0 :     final width = ScreenHelper.state().width - ThemeHelper.getIndent(4);
     109            0 :     final indent = ThemeHelper.getIndent(2);
     110            0 :     return SliverToBoxAdapter(
     111            0 :       child: SingleScrollWrapper(
     112            0 :         controller: focus,
     113            0 :         child: Column(
     114            0 :           crossAxisAlignment: AppDesign.getAlignment(),
     115            0 :           children: [
     116            0 :             InputWrapper.text(
     117            0 :               title: AppLocale.labels.description,
     118            0 :               controller: description,
     119            0 :               tooltip: AppLocale.labels.descriptionTooltip,
     120              :             ),
     121            0 :             RowWidget(
     122              :               indent: indent,
     123            0 :               maxWidth: width + indent,
     124              :               chunk: const [0.5, 0.5],
     125            0 :               children: [
     126            0 :                 [
     127            0 :                   InputWrapper.text(
     128            0 :                     title: AppLocale.labels.amountFrom,
     129            0 :                     tooltip: AppLocale.labels.billSetTooltip,
     130            0 :                     controller: amountFrom,
     131              :                     inputType: const TextInputType.numberWithOptions(decimal: true),
     132            0 :                     formatter: [
     133            0 :                       SimpleInputFormatter.filterDouble,
     134              :                     ],
     135              :                   ),
     136              :                 ],
     137            0 :                 [
     138            0 :                   InputWrapper.text(
     139            0 :                     title: AppLocale.labels.amountTo,
     140            0 :                     tooltip: AppLocale.labels.billSetTooltip,
     141            0 :                     controller: amountTo,
     142              :                     inputType: const TextInputType.numberWithOptions(decimal: true),
     143            0 :                     formatter: [
     144            0 :                       SimpleInputFormatter.filterDouble,
     145              :                     ],
     146              :                   ),
     147              :                 ],
     148              :               ],
     149              :             ),
     150            0 :             InputWrapper.select(
     151            0 :               value: type,
     152            0 :               title: AppLocale.labels.accountType,
     153            0 :               tooltip: AppLocale.labels.accountTypeTooltip,
     154            0 :               options: AccountType.getList(),
     155            0 :               onChange: (value) => setState(() {
     156            0 :                 if (value != type) clearState();
     157            0 :                 type = value;
     158              :               }),
     159              :             ),
     160            0 :             InputWrapper(
     161              :               type: NamedInputType.accountSelector,
     162            0 :               value: account != null ? state.getByUuid(account!) : null,
     163            0 :               title: AppLocale.labels.account,
     164            0 :               tooltip: AppLocale.labels.titleAccountTooltip,
     165            0 :               state: state,
     166            0 :               options: accountList,
     167            0 :               onChange: (value) => setState(() {
     168            0 :                 if (value?.uuid != account) clearState();
     169            0 :                 account = value?.uuid;
     170              :               }),
     171              :               width: width,
     172              :             ),
     173            0 :             InputWrapper(
     174              :               type: NamedInputType.budgetSelector,
     175            0 :               value: budget != null ? state.getByUuid(budget!) : null,
     176            0 :               title: AppLocale.labels.budget,
     177            0 :               tooltip: AppLocale.labels.titleBudgetTooltip,
     178            0 :               state: state,
     179            0 :               options: budgetList,
     180            0 :               onChange: (value) => setState(() {
     181            0 :                 if (value?.uuid != budget) clearState();
     182            0 :                 budget = value?.uuid;
     183              :               }),
     184              :               width: width,
     185              :             ),
     186            0 :             InputWrapper.currency(
     187            0 :               value: currency,
     188            0 :               title: AppLocale.labels.currency,
     189            0 :               tooltip: AppLocale.labels.currencyTooltip,
     190            0 :               onChange: (value) => setState(() {
     191            0 :                 if (value != currency) clearState();
     192            0 :                 currency = value;
     193              :               }),
     194              :             ),
     195            0 :             TextWrapper(
     196            0 :               AppLocale.labels.dateRange,
     197            0 :               style: context.textTheme.bodyLarge,
     198              :             ),
     199            0 :             DateRangeInput(
     200            0 :               valueFrom: startDate,
     201            0 :               value: endDate,
     202            0 :               setState: (start, end) => setState(() {
     203            0 :                 startDate = start;
     204            0 :                 endDate = end;
     205            0 :                 clearState();
     206              :               }),
     207              :             ),
     208              :           ],
     209              :         ),
     210              :       ),
     211              :     );
     212              :   }
     213              : }
        

Generated by: LCOV version 2.0-1