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/herald/app_design.dart';
5 : import 'package:app_finance/_classes/herald/app_locale.dart';
6 : import 'package:app_finance/_classes/storage/app_data.dart';
7 : import 'package:app_finance/design/form/currency_selector_code.dart';
8 : import 'package:app_finance/design/form/date_input.dart';
9 : import 'package:app_finance/design/form/list_selector_item.dart';
10 : import 'package:app_finance/_configs/screen_helper.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/form/color_selector.dart';
14 : import 'package:app_finance/design/form/currency_selector.dart';
15 : import 'package:app_finance/design/form/icon_selector.dart';
16 : import 'package:app_finance/design/form/list_account_selector.dart';
17 : import 'package:app_finance/design/form/list_budget_selector.dart';
18 : import 'package:app_finance/design/form/list_selector.dart';
19 : import 'package:app_finance/design/form/month_year_input.dart';
20 : import 'package:app_finance/design/form/simple_input.dart';
21 : import 'package:app_finance/design/wrapper/required_widget.dart';
22 : import 'package:app_finance/design/wrapper/text_wrapper.dart';
23 : import 'package:material_ui/material_ui.dart';
24 : import 'package:flutter/services.dart';
25 :
26 : enum NamedInputType {
27 : accountSelector,
28 : budgetSelector,
29 : colorSelector,
30 : currencySelector,
31 : currencyShort,
32 : iconSelector,
33 : listSelector,
34 : textInput,
35 : ymSelector,
36 : dateSelector,
37 : }
38 :
39 : class InputWrapper extends StatelessWidget {
40 : final NamedInputType type;
41 : final bool isRequired;
42 : final bool isDisabled;
43 : final bool showError;
44 : final String title;
45 : final List<dynamic>? options;
46 : final Function? onChange;
47 : final String? tooltip;
48 : final TextEditingController? controller;
49 : final dynamic value;
50 : final List<TextInputFormatter>? formatter;
51 : final AppData? state;
52 : final double? width;
53 : final TextInputType? inputType;
54 :
55 24 : Key getKey() => ValueKey(key?.hashCode ?? '$title $tooltip');
56 :
57 4 : ({bool min, String? hint, Color? hintColor}) getHintState(BuildContext context) {
58 4 : final screenState = ScreenHelper.state();
59 : final min = screenState.isRight || screenState.isWearable;
60 4 : String? hint = min ? title : tooltip;
61 : Color? hintColor;
62 4 : if (isRequired && min) {
63 0 : if (showError) {
64 0 : hint = '$hint [!] ${AppLocale.labels.isRequired}';
65 0 : hintColor = context.colorScheme.primary;
66 : } else {
67 0 : hint = '$hint*';
68 : }
69 : }
70 :
71 : return (min: min, hint: hint, hintColor: hintColor);
72 : }
73 :
74 4 : const InputWrapper({
75 : super.key,
76 : required this.type,
77 : required this.title,
78 : this.tooltip,
79 : this.controller,
80 : this.onChange,
81 : this.options,
82 : this.value,
83 : this.formatter,
84 : this.isRequired = false,
85 : this.isDisabled = false,
86 : this.showError = false,
87 : this.state,
88 : this.width,
89 : this.inputType,
90 : });
91 :
92 4 : const InputWrapper.text({
93 : super.key,
94 : this.type = NamedInputType.textInput,
95 : required this.title,
96 : required this.controller,
97 : this.tooltip,
98 : this.isRequired = false,
99 : this.isDisabled = false,
100 : this.showError = false,
101 : this.onChange,
102 : this.options,
103 : this.value,
104 : this.formatter,
105 : this.state,
106 : this.width,
107 : this.inputType,
108 : });
109 :
110 2 : const InputWrapper.select({
111 : super.key,
112 : this.type = NamedInputType.listSelector,
113 : required this.title,
114 : required this.options,
115 : required this.onChange,
116 : required this.value,
117 : this.tooltip,
118 : this.isRequired = false,
119 : this.isDisabled = false,
120 : this.showError = false,
121 : this.controller,
122 : this.formatter,
123 : this.state,
124 : this.width,
125 : this.inputType,
126 : });
127 :
128 0 : const InputWrapper.icon({
129 : super.key,
130 : this.type = NamedInputType.iconSelector,
131 : required this.title,
132 : required this.onChange,
133 : this.controller,
134 : this.tooltip,
135 : this.isRequired = false,
136 : this.isDisabled = false,
137 : this.showError = false,
138 : this.options,
139 : this.value,
140 : this.formatter,
141 : this.state,
142 : this.width,
143 : this.inputType,
144 : });
145 :
146 0 : const InputWrapper.color({
147 : super.key,
148 : this.type = NamedInputType.colorSelector,
149 : required this.title,
150 : required this.onChange,
151 : this.controller,
152 : this.tooltip,
153 : this.isRequired = false,
154 : this.isDisabled = false,
155 : this.showError = false,
156 : this.options,
157 : this.value,
158 : this.formatter,
159 : this.state,
160 : this.width,
161 : this.inputType,
162 : });
163 :
164 2 : const InputWrapper.currency({
165 : super.key,
166 : this.type = NamedInputType.currencySelector,
167 : required this.value,
168 : required this.title,
169 : required this.onChange,
170 : this.controller,
171 : this.tooltip,
172 : this.isRequired = false,
173 : this.isDisabled = false,
174 : this.showError = false,
175 : this.options,
176 : this.formatter,
177 : this.state,
178 : this.width,
179 : this.inputType,
180 : });
181 :
182 8 : Widget buildTextInput({required bool min, required String? hint, Color? hintColor}) => SimpleInput(
183 4 : key: getKey(),
184 4 : controller: controller!,
185 : tooltip: hint,
186 : withLabel: min,
187 : hintColor: hintColor,
188 4 : formatter: formatter,
189 4 : type: inputType ?? TextInputType.text,
190 8 : obscure: inputType == TextInputType.visiblePassword,
191 : );
192 :
193 2 : Widget buildListSelector({required bool min, required String? hint, Color? hintColor}) =>
194 2 : ListSelector<ListSelectorItem>(
195 2 : key: getKey(),
196 6 : value: value != null ? ListSelectorItem(id: value, name: '') : null,
197 2 : tooltip: tooltip,
198 : hintText: hint,
199 : hintColor: hintColor,
200 2 : options: options as List<ListSelectorItem>,
201 0 : setState: (ListSelectorItem? v) => onChange?.call(v?.id),
202 : withLabel: min,
203 2 : isDisabled: isDisabled,
204 : );
205 :
206 0 : Widget buildIconSelector({required bool min, required String? hint}) => IconSelector(
207 0 : key: getKey(),
208 0 : value: value != null ? IconSelectorItem(value, name: value.toString()) : null,
209 0 : setState: (v) => onChange?.call((v as IconSelectorItem?)?.value),
210 : hintText: hint,
211 : withLabel: min,
212 : );
213 :
214 0 : Widget buildColorSelector({required bool min}) => ColorSelector(
215 0 : key: getKey(),
216 0 : value: value,
217 0 : setState: (v) => onChange?.call(v),
218 : withLabel: min,
219 : );
220 :
221 0 : Widget buildCurrencySelector({required bool min, required String? hint}) => BaseCurrencySelector(
222 0 : key: getKey(),
223 0 : value: value != null ? BaseListSelectorItem(value) : null,
224 0 : setState: (v) => onChange?.call((v as BaseListSelectorItem?)?.item),
225 : withLabel: min,
226 0 : tooltip: tooltip,
227 : hintText: hint,
228 : );
229 :
230 4 : Widget buildCurrencyShortSelector({required bool min, required String? hint}) => CodeCurrencySelector(
231 2 : key: getKey(),
232 6 : value: value != null ? CodeCurrencySelectorItem(value) : null,
233 0 : setState: (v) => onChange?.call((v as CodeCurrencySelectorItem?)?.item),
234 : withLabel: min,
235 2 : tooltip: tooltip,
236 : hintText: hint,
237 : );
238 :
239 0 : Widget buildMonthYearSelector({required bool min}) => MonthYearInput(
240 0 : key: getKey(),
241 0 : value: value,
242 0 : setState: onChange!,
243 : withLabel: min,
244 0 : labelText: title,
245 : );
246 :
247 4 : Widget buildDateSelector({required bool min}) => DateInput(
248 2 : value: value,
249 2 : setState: onChange!,
250 : withLabel: min,
251 : );
252 :
253 8 : Widget buildAccountSelector({required bool min, required String? hint}) => ListAccountSelector(
254 4 : key: getKey(),
255 6 : value: value != null ? ListAccountSelectorItem(item: value) : null,
256 : hintText: hint,
257 4 : tooltip: tooltip,
258 4 : state: state!,
259 0 : setState: (v) => onChange?.call((v as ListAccountSelectorItem?)?.item),
260 4 : width: width!,
261 : withLabel: min,
262 8 : options: options?.cast() ?? [],
263 : );
264 :
265 8 : Widget buildBudgetSelector({required bool min, required String? hint}) => ListBudgetSelector(
266 4 : key: getKey(),
267 6 : value: value != null ? ListBudgetSelectorItem(item: value) : null,
268 : hintText: hint,
269 4 : tooltip: tooltip,
270 4 : state: state!,
271 0 : setState: (v) => onChange?.call((v as ListBudgetSelectorItem?)?.item),
272 4 : width: width!,
273 : withLabel: min,
274 : );
275 :
276 4 : Widget buildInput({required bool min, required String? hint, Color? hintColor}) {
277 4 : return switch (type) {
278 8 : NamedInputType.textInput => buildTextInput(min: min, hint: hint, hintColor: hintColor),
279 6 : NamedInputType.listSelector => buildListSelector(min: min, hint: hint, hintColor: hintColor),
280 4 : NamedInputType.iconSelector => buildIconSelector(min: min, hint: hint),
281 4 : NamedInputType.colorSelector => buildColorSelector(min: min),
282 4 : NamedInputType.currencySelector => buildCurrencySelector(min: min, hint: hint),
283 6 : NamedInputType.currencyShort => buildCurrencyShortSelector(min: min, hint: hint),
284 4 : NamedInputType.ymSelector => buildMonthYearSelector(min: min),
285 6 : NamedInputType.dateSelector => buildDateSelector(min: min),
286 8 : NamedInputType.accountSelector => buildAccountSelector(min: min, hint: hint),
287 8 : NamedInputType.budgetSelector => buildBudgetSelector(min: min, hint: hint),
288 : };
289 : }
290 :
291 4 : Widget buildTitle(BuildContext context, {required bool min}) {
292 : if (min) {
293 : return ThemeHelper.emptyBox;
294 : }
295 :
296 4 : return isRequired
297 12 : ? RequiredWidget(title: title, showError: showError)
298 16 : : TextWrapper(title, style: context.textTheme.bodyLarge);
299 : }
300 :
301 4 : @override
302 : Widget build(BuildContext context) {
303 4 : final hintState = getHintState(context);
304 : final min = hintState.min;
305 4 : return Column(
306 4 : mainAxisAlignment: AppDesign.getAlignment<MainAxisAlignment>(),
307 4 : crossAxisAlignment: AppDesign.getAlignment(),
308 4 : children: [
309 4 : if (!min) buildTitle(context, min: min),
310 4 : buildInput(min: min, hint: hintState.hint, hintColor: hintState.hintColor),
311 4 : ThemeHelper.hIndent2x,
312 : ],
313 : );
314 : }
315 : }
|