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/structure/currency/exchange.dart';
7 : import 'package:app_finance/_classes/structure/goal_app_data.dart';
8 : import 'package:app_finance/_classes/controller/focus_controller.dart';
9 : import 'package:app_finance/_classes/storage/app_data.dart';
10 : import 'package:app_finance/_configs/theme_helper.dart';
11 : import 'package:app_finance/_classes/storage/app_preferences.dart';
12 : import 'package:app_finance/design/wrapper/input_wrapper.dart';
13 : import 'package:app_finance/pages/_interfaces/abstract_add_page.dart';
14 : import 'package:app_finance/design/button/full_sized_button_widget.dart';
15 : import 'package:app_finance/design/form/simple_input.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:material_ui/material_ui.dart';
19 : import 'package:flutter_currency_picker/flutter_currency_picker.dart';
20 :
21 : class GoalAddPage extends AbstractAddPage {
22 : final String? title;
23 : final IconData? icon;
24 : final MaterialColor? color;
25 : final Currency? currency;
26 : final double? details;
27 : final DateTime? closedAt;
28 :
29 1 : const GoalAddPage({
30 : super.key,
31 : this.title,
32 : this.icon,
33 : this.color,
34 : this.currency,
35 : this.details,
36 : this.closedAt,
37 : });
38 :
39 0 : @override
40 0 : GoalAddPageState createState() => GoalAddPageState();
41 : }
42 :
43 : class GoalAddPageState<T extends GoalAddPage> extends AbstractAddPageState<T> {
44 : late FocusController focus;
45 : late TextEditingController title;
46 : late TextEditingController details;
47 : IconData? icon;
48 : MaterialColor? color;
49 : Currency? currency;
50 : DateTime? closedAt;
51 :
52 0 : @override
53 : void initState() {
54 0 : focus = FocusController();
55 0 : title = TextEditingController(text: widget.title);
56 0 : icon = widget.icon;
57 0 : color = widget.color;
58 0 : details = TextEditingController(text: widget.details != null ? widget.details.toString() : '');
59 0 : final currencyId = AppPreferences.get(AppPreferences.prefCurrency);
60 0 : currency = widget.currency ?? CurrencyProvider.find(currencyId);
61 0 : closedAt = widget.closedAt;
62 0 : super.initState();
63 : }
64 :
65 0 : @override
66 : void dispose() {
67 0 : focus.dispose();
68 0 : title.dispose();
69 0 : details.dispose();
70 0 : super.dispose();
71 : }
72 :
73 0 : @override
74 0 : String getTitle() => AppLocale.labels.createGoalHeader;
75 :
76 0 : @override
77 : bool hasFormErrors() {
78 0 : setState(() => hasError = title.text.isEmpty || closedAt == null);
79 0 : return hasError;
80 : }
81 :
82 0 : @override
83 : void updateStorage() {
84 0 : if (currency != null) {
85 0 : CurrencyProvider.pin(currency!);
86 : }
87 0 : state.add(GoalAppData(
88 0 : title: title.text,
89 0 : initial: Exchange(store: state).reform(state.getTotal(AppDataType.accounts), Exchange.defaultCurrency, currency),
90 : progress: 0.0,
91 0 : color: color,
92 : hidden: false,
93 0 : currency: currency,
94 0 : icon: icon,
95 0 : details: double.tryParse(details.text) ?? 0.0,
96 0 : closedAt: closedAt,
97 : ));
98 : }
99 :
100 0 : @override
101 0 : String getButtonName() => AppLocale.labels.createGoalTooltip;
102 :
103 0 : @override
104 : Widget buildButton(BuildContext context, BoxConstraints constraints) {
105 0 : NavigatorState nav = Navigator.of(context);
106 0 : return FullSizedButtonWidget(
107 : constraints: constraints,
108 0 : controller: focus,
109 0 : onPressed: () => triggerActionButton(nav),
110 0 : title: getButtonName(),
111 : icon: Icons.save,
112 : );
113 : }
114 :
115 0 : @override
116 : Widget buildContent(BuildContext context, BoxConstraints constraints) {
117 0 : double indent = ThemeHelper.getIndent(2);
118 0 : double width = ThemeHelper.getWidth(context, 6, constraints);
119 :
120 0 : return SingleScrollWrapper(
121 0 : controller: focus,
122 0 : child: Container(
123 0 : margin: EdgeInsets.fromLTRB(indent, indent, indent, 240),
124 0 : child: Column(
125 0 : crossAxisAlignment: AppDesign.getAlignment(),
126 0 : children: [
127 0 : InputWrapper.text(
128 0 : title: AppLocale.labels.titleGoal,
129 0 : showError: hasError && title.text.isEmpty,
130 0 : controller: title,
131 : isRequired: true,
132 0 : tooltip: AppLocale.labels.titleGoalTooltip,
133 : ),
134 0 : RowWidget(
135 : indent: indent,
136 0 : maxWidth: width + indent,
137 0 : alignment: AppDesign.getAlignment<MainAxisAlignment>(),
138 : chunk: const [null, null],
139 0 : children: [
140 0 : [
141 0 : InputWrapper.icon(
142 0 : title: AppLocale.labels.icon,
143 0 : value: icon,
144 0 : onChange: (value) => setState(() => icon = value),
145 : ),
146 : ],
147 0 : [
148 0 : InputWrapper.color(
149 0 : title: AppLocale.labels.color,
150 0 : value: color,
151 0 : onChange: (value) => setState(() => color = value),
152 : ),
153 : ],
154 : ],
155 : ),
156 0 : RowWidget(
157 : indent: indent,
158 0 : maxWidth: width + indent,
159 0 : alignment: AppDesign.getAlignment<MainAxisAlignment>(),
160 : chunk: const [100, null],
161 0 : children: [
162 0 : [
163 0 : InputWrapper.currency(
164 0 : title: AppLocale.labels.currency,
165 : type: NamedInputType.currencyShort,
166 0 : value: currency,
167 0 : tooltip: AppLocale.labels.currencyTooltip,
168 0 : onChange: (value) => setState(() => currency = value),
169 : ),
170 : ],
171 0 : [
172 0 : InputWrapper.text(
173 0 : title: AppLocale.labels.targetAmount,
174 0 : controller: details,
175 : inputType: const TextInputType.numberWithOptions(decimal: true),
176 0 : tooltip: AppLocale.labels.billSetTooltip,
177 0 : formatter: [
178 0 : SimpleInputFormatter.filterDouble,
179 : ],
180 : ),
181 : ],
182 : ],
183 : ),
184 0 : InputWrapper(
185 0 : title: AppLocale.labels.closedAt,
186 : type: NamedInputType.dateSelector,
187 0 : showError: hasError && closedAt == null,
188 0 : value: closedAt,
189 0 : onChange: (value) => setState(() => closedAt = value),
190 : ),
191 : ],
192 : ),
193 : ),
194 : );
195 : }
196 : }
|