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/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/history_data.dart';
8 : import 'package:app_finance/_classes/structure/currency_app_data.dart';
9 : import 'package:app_finance/_classes/storage/app_data.dart';
10 : import 'package:app_finance/_classes/structure/navigation/app_route.dart';
11 : import 'package:app_finance/_configs/screen_helper.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/charts/trade_chart.dart';
15 : import 'package:app_finance/design/button/toolbar_button_widget.dart';
16 : import 'package:app_finance/design/wrapper/single_scroll_wrapper.dart';
17 : import 'package:app_finance/pages/_interfaces/abstract_page_state.dart';
18 : import 'package:app_finance/design/generic/notification_bar.dart';
19 : import 'package:app_finance/design/form/simple_input.dart';
20 : import 'package:app_finance/design/wrapper/row_widget.dart';
21 : import 'package:flutter/material.dart';
22 :
23 : class CurrencyPage extends StatefulWidget {
24 5 : const CurrencyPage({super.key});
25 :
26 0 : @override
27 0 : CurrencyPageState createState() => CurrencyPageState();
28 : }
29 :
30 : class CurrencyPageState extends AbstractPageState<CurrencyPage> {
31 : late FocusController focus;
32 : List<dynamic>? scope;
33 :
34 0 : @override
35 : void initState() {
36 0 : focus = FocusController();
37 0 : super.initState();
38 : }
39 :
40 0 : @override
41 : void dispose() {
42 0 : focus.dispose();
43 0 : super.dispose();
44 : }
45 :
46 0 : @override
47 0 : String getTitle() => AppLocale.labels.currencyHeadline;
48 :
49 0 : @override
50 0 : String getButtonName() => AppLocale.labels.currencyUpdateTooltip;
51 :
52 0 : @override
53 : Widget buildButton(BuildContext context, BoxConstraints constraints) {
54 0 : return FloatingActionButton(
55 : heroTag: 'currency_page',
56 0 : onPressed: () => updateAllRates(context),
57 0 : tooltip: getButtonName(),
58 : child: const Icon(Icons.save),
59 : );
60 : }
61 :
62 0 : @override
63 : List<Widget> getBarActions(NavigatorState nav) {
64 0 : return [
65 0 : ToolbarButtonWidget(
66 0 : isWide: ScreenHelper.state().isWide,
67 0 : tooltip: AppLocale.labels.currencyAddTooltip,
68 0 : onPressed: () => nav.pushNamed(AppRoute.currencyAddRoute),
69 : icon: Icons.add,
70 : color: Colors.white70,
71 0 : semanticLabel: AppLocale.labels.currencyAddTooltip,
72 : ),
73 0 : ...super.getBarActions(nav)
74 : ];
75 : }
76 :
77 0 : List<CurrencyAppData>? _getItems() {
78 0 : List<CurrencyAppData>? tmp = state
79 0 : .getList(AppDataType.currencies)
80 0 : .where((v) =>
81 0 : v.currencyFrom != null && v.currency != null && v.currency.code != v.currencyFrom.code && v.details != 1.0)
82 0 : .toList()
83 0 : .cast();
84 0 : tmp.sort((a, b) => a.uuid.compareTo(b.uuid));
85 : return tmp;
86 : }
87 :
88 0 : void updateAllRates(BuildContext context) {
89 0 : for (CurrencyAppData rate in scope!) {
90 0 : if ((state.getByUuid(rate.uuid) as CurrencyAppData).details != rate.details) {
91 0 : state.update(rate.uuid, rate);
92 : }
93 : }
94 0 : NotificationBar.showSnackBar(context, AppLocale.labels.saveNotification);
95 : }
96 :
97 0 : void changeRate(CurrencyAppData initial, double? value) {
98 : if (value != null) {
99 0 : initial.details = value;
100 : }
101 : }
102 :
103 0 : @override
104 : Widget buildContent(BuildContext context, BoxConstraints constraints) {
105 0 : final tmp = _getItems();
106 0 : if (tmp?.length != scope?.length) {
107 0 : WidgetsBinding.instance.addPostFrameCallback((_) => setState(() => scope = tmp));
108 : return ThemeHelper.emptyBox;
109 : }
110 0 : final TextTheme textTheme = context.textTheme;
111 0 : final indent = ThemeHelper.getIndent();
112 0 : final now = DateTime.now();
113 0 : final cutDate = DateTime(now.year, now.month - 2);
114 0 : final crossAxisCount = ThemeHelper.getWidthCount(null, context);
115 0 : return SingleScrollWrapper(
116 0 : controller: focus,
117 0 : child: Padding(
118 0 : padding: EdgeInsets.all(indent),
119 0 : child: Wrap(
120 : spacing: indent,
121 0 : runSpacing: indent * 2,
122 0 : children: scope!.map((item) {
123 0 : final history = HistoryData.getStream(item.uuid, filter: (e) => e.timestamp.isBefore(cutDate))?.toList();
124 0 : return RowWidget(
125 : indent: indent,
126 0 : maxWidth: ThemeHelper.getWidth(context, 4, constraints) / crossAxisCount,
127 : chunk: const [85, null, 100],
128 0 : children: [
129 0 : [
130 0 : Column(
131 0 : crossAxisAlignment: AppDesign.getAlignment(),
132 0 : children: [
133 0 : Text(
134 0 : item.uuid,
135 0 : style: textTheme.headlineMedium,
136 : overflow: TextOverflow.ellipsis,
137 : ),
138 0 : Text(
139 0 : item.updatedAtFormatted,
140 0 : style: textTheme.bodySmall,
141 : overflow: TextOverflow.ellipsis,
142 : ),
143 : ],
144 : ),
145 : ],
146 0 : [
147 0 : SimpleInput(
148 0 : controller: TextEditingController(text: item.details.toString()),
149 : type: TextInputType.number,
150 0 : setState: (value) => changeRate(item, double.tryParse(value)),
151 : )
152 : ],
153 0 : [
154 0 : Padding(
155 0 : padding: EdgeInsets.only(top: indent),
156 0 : child: TradeChart(
157 0 : data: history ?? [],
158 : width: 100,
159 : height: 40,
160 : ),
161 : ),
162 : ],
163 : ],
164 : );
165 0 : }).toList(),
166 : ),
167 : ),
168 : );
169 : }
170 : }
|