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/focus_controller.dart';
5 : import 'package:app_finance/_classes/herald/app_design.dart';
6 : import 'package:app_finance/_classes/herald/app_locale.dart';
7 : import 'package:app_finance/_classes/storage/app_data.dart';
8 : import 'package:app_finance/_classes/structure/invoice_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/_ext/build_context_ext.dart';
12 : import 'package:app_finance/design/form/date_range_input.dart';
13 : import 'package:app_finance/design/form/list_account_selector.dart';
14 : import 'package:app_finance/design/form/simple_input.dart';
15 : import 'package:app_finance/design/wrapper/input_wrapper.dart';
16 : import 'package:app_finance/design/wrapper/row_widget.dart';
17 : import 'package:app_finance/design/wrapper/single_scroll_wrapper.dart';
18 : import 'package:app_finance/design/wrapper/text_wrapper.dart';
19 : import 'package:app_finance/pages/invoice/invoice_transfer_page.dart';
20 : import 'package:material_ui/material_ui.dart';
21 :
22 : class InvoiceTransferSearchPage extends StatefulWidget {
23 0 : const InvoiceTransferSearchPage({super.key});
24 :
25 0 : @override
26 0 : InvoiceTransferSearchPageState createState() => InvoiceTransferSearchPageState();
27 : }
28 :
29 : class InvoiceTransferSearchPageState extends InvoiceTransferPageState<InvoiceTransferSearchPage> {
30 : String? accountFrom;
31 : String? accountTo;
32 : DateTime? startDate;
33 : DateTime? endDate;
34 : late TextEditingController description;
35 : late TextEditingController amountFrom;
36 : late TextEditingController amountTo;
37 : late FocusController focus;
38 :
39 : late List<ListAccountSelectorItem> accountList =
40 : state.getList(AppDataType.accounts).map((item) => ListAccountSelectorItem(item: item)).toList();
41 :
42 0 : @override
43 : void initState() {
44 0 : description = TextEditingController();
45 0 : amountFrom = TextEditingController();
46 0 : amountTo = TextEditingController();
47 0 : focus = FocusController();
48 0 : super.initState();
49 : }
50 :
51 0 : @override
52 : dispose() {
53 0 : description.dispose();
54 0 : amountFrom.dispose();
55 0 : amountTo.dispose();
56 0 : focus.dispose();
57 0 : super.dispose();
58 : }
59 :
60 0 : @override
61 0 : String getTitle() => AppLocale.labels.searchTooltip;
62 :
63 0 : @override
64 0 : String getButtonName() => AppLocale.labels.searchTooltip;
65 :
66 0 : @override
67 : Widget buildButton(BuildContext context, BoxConstraints constraints) {
68 0 : return FloatingActionButton(
69 : heroTag: 'invoice_transfer_search_page',
70 0 : onPressed: () => setState(clearState),
71 0 : tooltip: getButtonName(),
72 : child: const Icon(Icons.search),
73 : );
74 : }
75 :
76 0 : @override
77 : bool getContentFilter(InvoiceAppData o) {
78 0 : final descriptionMatch = o.title.toLowerCase().contains(description.text.toLowerCase());
79 0 : final accountFromMatch = accountFrom == null || o.accountFrom == accountFrom;
80 0 : final accountToMatch = accountTo == null || o.account == accountTo;
81 0 : final startDateMatch = startDate == null || o.createdAt.isAfter(startDate!);
82 0 : final endDateMatch = endDate == null || o.createdAt.isBefore(endDate!);
83 0 : final amountFromMatch = amountFrom.text.isEmpty || o.details >= double.tryParse(amountFrom.text)!;
84 0 : final amountToMatch = amountTo.text.isEmpty || o.details <= double.tryParse(amountTo.text)!;
85 : return !(descriptionMatch &&
86 : accountFromMatch &&
87 : accountToMatch &&
88 : startDateMatch &&
89 : endDateMatch &&
90 : amountFromMatch &&
91 : amountToMatch) ||
92 0 : o.accountFrom == null;
93 : }
94 :
95 0 : @override
96 : Widget addHeaderWidget() {
97 0 : final width = ScreenHelper.state().width - ThemeHelper.getIndent(4);
98 0 : final indent = ThemeHelper.getIndent(2);
99 0 : return SliverToBoxAdapter(
100 0 : child: SingleScrollWrapper(
101 0 : controller: focus,
102 0 : child: Column(
103 0 : crossAxisAlignment: AppDesign.getAlignment(),
104 0 : children: [
105 0 : InputWrapper.text(
106 0 : title: AppLocale.labels.description,
107 0 : controller: description,
108 0 : tooltip: AppLocale.labels.descriptionTooltip,
109 : ),
110 0 : RowWidget(
111 : indent: indent,
112 0 : maxWidth: width + indent,
113 : chunk: const [0.5, 0.5],
114 0 : children: [
115 0 : [
116 0 : InputWrapper.text(
117 0 : title: AppLocale.labels.amountFrom,
118 0 : tooltip: AppLocale.labels.billSetTooltip,
119 0 : controller: amountFrom,
120 : inputType: const TextInputType.numberWithOptions(decimal: true),
121 0 : formatter: [
122 0 : SimpleInputFormatter.filterDouble,
123 : ],
124 : ),
125 : ],
126 0 : [
127 0 : InputWrapper.text(
128 0 : title: AppLocale.labels.amountTo,
129 0 : tooltip: AppLocale.labels.billSetTooltip,
130 0 : controller: amountTo,
131 : inputType: const TextInputType.numberWithOptions(decimal: true),
132 0 : formatter: [
133 0 : SimpleInputFormatter.filterDouble,
134 : ],
135 : ),
136 : ],
137 : ],
138 : ),
139 0 : InputWrapper(
140 : type: NamedInputType.accountSelector,
141 0 : value: accountTo != null ? state.getByUuid(accountTo!) : null,
142 0 : title: AppLocale.labels.accountTo,
143 0 : tooltip: AppLocale.labels.titleAccountTooltip,
144 0 : state: state,
145 0 : options: accountList,
146 0 : onChange: (value) => setState(() {
147 0 : if (value?.uuid != accountTo) clearState();
148 0 : accountTo = value?.uuid;
149 : }),
150 : width: width,
151 : ),
152 0 : InputWrapper(
153 : type: NamedInputType.accountSelector,
154 0 : value: accountFrom != null ? state.getByUuid(accountFrom!) : null,
155 0 : title: AppLocale.labels.accountFrom,
156 0 : tooltip: AppLocale.labels.titleAccountTooltip,
157 0 : state: state,
158 0 : options: accountList,
159 0 : onChange: (value) => setState(() {
160 0 : if (value?.uuid != accountFrom) clearState();
161 0 : accountFrom = value?.uuid;
162 : }),
163 : width: width,
164 : ),
165 0 : TextWrapper(
166 0 : AppLocale.labels.dateRange,
167 0 : style: context.textTheme.bodyLarge,
168 : ),
169 0 : DateRangeInput(
170 0 : valueFrom: startDate,
171 0 : value: endDate,
172 0 : setState: (start, end) => setState(() {
173 0 : startDate = start;
174 0 : endDate = end;
175 0 : clearState();
176 : }),
177 : ),
178 : ],
179 : ),
180 : ),
181 : );
182 : }
183 : }
|