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