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/exchange_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/structure/currency/exchange.dart';
8 : import 'package:app_finance/_classes/structure/invoice_app_data.dart';
9 : import 'package:app_finance/_classes/controller/focus_controller.dart';
10 : import 'package:app_finance/_classes/storage/app_preferences.dart';
11 : import 'package:app_finance/_classes/storage/app_data.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/wrapper/input_wrapper.dart';
15 : import 'package:app_finance/pages/_interfaces/interface_page_inject.dart';
16 : import 'package:app_finance/design/form/currency_exchange_input.dart';
17 : import 'package:app_finance/design/form/date_time_input.dart';
18 : import 'package:app_finance/design/button/full_sized_button_widget.dart';
19 : import 'package:app_finance/design/form/simple_input.dart';
20 : import 'package:app_finance/design/wrapper/row_widget.dart';
21 : import 'package:app_finance/design/wrapper/single_scroll_wrapper.dart';
22 : import 'package:material_ui/material_ui.dart';
23 : import 'package:flutter_currency_picker/flutter_currency_picker.dart';
24 :
25 : class IncomeTab<T> extends StatefulWidget {
26 : final String? account;
27 : final String? description;
28 : final Currency? currency;
29 : final double? amount;
30 : final DateTime? createdAt;
31 : final AppData state;
32 : final bool isLeft;
33 : final FnPageCallback callback;
34 :
35 1 : const IncomeTab({
36 : super.key,
37 : required this.state,
38 : required this.callback,
39 : this.account,
40 : this.description,
41 : this.currency,
42 : this.amount,
43 : this.createdAt,
44 : this.isLeft = false,
45 : });
46 :
47 0 : @override
48 0 : IncomeTabState createState() => IncomeTabState();
49 : }
50 :
51 : class IncomeTabState<T extends IncomeTab> extends State<IncomeTab> {
52 : late FocusController focus;
53 : String? account;
54 : Currency? accountCurrency;
55 : Currency? currency;
56 : late TextEditingController amount;
57 : late TextEditingController description;
58 : late ExchangeController exchange;
59 : late DateTime createdAt;
60 : bool hasErrors = false;
61 :
62 0 : @override
63 : void initState() {
64 0 : focus = FocusController();
65 0 : final value = AppPreferences.get(AppPreferences.prefAccount);
66 0 : final obj = widget.state.getByUuid(value ?? '');
67 0 : account = widget.account ?? obj?.uuid;
68 0 : currency = widget.currency ?? obj?.currency ?? Exchange.defaultCurrency;
69 0 : createdAt = widget.createdAt ?? DateTime.now();
70 0 : amount = TextEditingController(text: widget.amount != null ? widget.amount.toString() : '');
71 0 : description = TextEditingController(text: widget.description);
72 0 : accountCurrency = widget.state.getByUuid(account ?? '')?.currency;
73 0 : exchange = ExchangeController(
74 0 : {},
75 0 : store: widget.state,
76 0 : targetController: amount,
77 0 : target: currency,
78 0 : source: [accountCurrency, Exchange.defaultCurrency],
79 : );
80 :
81 0 : widget.callback((
82 0 : buildButton: buildButton,
83 0 : buttonName: getButtonName(),
84 0 : title: getTitle(),
85 : ));
86 0 : super.initState();
87 : }
88 :
89 0 : @override
90 : dispose() {
91 0 : description.dispose();
92 0 : exchange.dispose();
93 0 : amount.dispose();
94 0 : focus.dispose();
95 0 : super.dispose();
96 : }
97 :
98 0 : String getTitle() => AppLocale.labels.createBillHeader;
99 :
100 0 : bool hasFormErrors() => account == null;
101 :
102 0 : void updateStorage() {
103 0 : AppPreferences.set(AppPreferences.prefAccount, account ?? '');
104 0 : exchange.save();
105 0 : widget.state.add(getValues());
106 : }
107 :
108 0 : InvoiceAppData getValues() => InvoiceAppData(
109 0 : title: description.text,
110 0 : color: widget.state.getByUuid(account ?? '')?.color,
111 0 : account: account ?? '',
112 0 : details: double.tryParse(amount.text) ?? 0.0,
113 0 : currency: currency,
114 0 : createdAt: createdAt,
115 : );
116 :
117 0 : String getButtonName() => AppLocale.labels.createIncomeTooltip;
118 :
119 0 : Widget buildButton(BuildContext context, BoxConstraints constraints) {
120 0 : NavigatorState nav = Navigator.of(context);
121 0 : return FullSizedButtonWidget(
122 : constraints: constraints,
123 0 : controller: focus,
124 0 : onPressed: () {
125 0 : if (!mounted) {
126 : return;
127 : }
128 0 : if (hasFormErrors()) {
129 0 : setState(() => hasErrors = true);
130 : return;
131 : }
132 0 : updateStorage();
133 0 : nav.pop();
134 : },
135 0 : title: getButtonName(),
136 : icon: Icons.save,
137 : );
138 : }
139 :
140 0 : @override
141 : Widget build(BuildContext context) {
142 0 : final textTheme = context.textTheme;
143 0 : final indent = ThemeHelper.getIndent(2);
144 0 : return SingleScrollWrapper(
145 0 : controller: focus,
146 0 : child: Container(
147 0 : margin: EdgeInsets.fromLTRB(indent, indent, indent, 240),
148 0 : child: LayoutBuilder(builder: (context, constraints) {
149 0 : double width = constraints.maxWidth;
150 0 : return Column(
151 0 : crossAxisAlignment: AppDesign.getAlignment(),
152 0 : children: [
153 0 : InputWrapper(
154 : type: NamedInputType.accountSelector,
155 : isRequired: true,
156 0 : value: account != null ? widget.state.getByUuid(account!) : null,
157 0 : title: AppLocale.labels.account,
158 0 : tooltip: AppLocale.labels.titleAccountTooltip,
159 0 : showError: hasErrors && account == null,
160 0 : state: widget.state,
161 0 : onChange: (value) => setState(() {
162 0 : account = value?.uuid;
163 : if (value != null) {
164 0 : currency = value.currency;
165 0 : accountCurrency = currency;
166 : }
167 : }),
168 : width: width,
169 : ),
170 0 : RowWidget(
171 : indent: indent,
172 : maxWidth: width,
173 : chunk: const [125, null],
174 0 : children: [
175 0 : [
176 0 : InputWrapper.currency(
177 : type: NamedInputType.currencyShort,
178 0 : value: currency,
179 0 : title: AppLocale.labels.currency,
180 0 : tooltip: AppLocale.labels.currencyTooltip,
181 0 : onChange: (value) => setState(() => currency = value),
182 : ),
183 : ],
184 0 : [
185 0 : InputWrapper.text(
186 0 : title: AppLocale.labels.income,
187 0 : tooltip: AppLocale.labels.billSetTooltip,
188 0 : controller: amount,
189 : inputType: const TextInputType.numberWithOptions(decimal: true),
190 0 : formatter: [
191 0 : SimpleInputFormatter.filterDouble,
192 : ],
193 : ),
194 : ],
195 : ],
196 : ),
197 0 : CurrencyExchangeInput(
198 0 : key: ValueKey('income${currency?.code}${accountCurrency?.code}'),
199 0 : width: width + indent,
200 : indent: indent,
201 0 : target: currency,
202 0 : controller: exchange,
203 0 : source: [accountCurrency, Exchange.defaultCurrency],
204 : ),
205 0 : InputWrapper.text(
206 0 : title: AppLocale.labels.description,
207 0 : tooltip: AppLocale.labels.incomeTooltip,
208 0 : controller: description,
209 : ),
210 0 : Text(
211 0 : AppLocale.labels.balanceDate,
212 0 : style: textTheme.bodyLarge,
213 : ),
214 0 : DateTimeInput(
215 0 : width: width - indent,
216 0 : value: createdAt,
217 0 : setState: (value) => setState(() => createdAt = value),
218 : ),
219 : ThemeHelper.formEndBox,
220 : ],
221 : );
222 : }),
223 : ),
224 : );
225 : }
226 : }
|