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/_classes/structure/account_app_data.dart';
8 : import 'package:app_finance/_classes/structure/currency/exchange.dart';
9 : import 'package:app_finance/_configs/theme_helper.dart';
10 : import 'package:app_finance/_ext/build_context_ext.dart';
11 : import 'package:app_finance/charts/bar_vertical_single.dart';
12 : import 'package:app_finance/charts/interface/chart_value.dart';
13 : import 'package:app_finance/charts/pie_radius_chart.dart';
14 : import 'package:app_finance/components/widgets/account_flow_chart.dart';
15 : import 'package:app_finance/components/widgets/account_health_chart.dart';
16 : import 'package:app_finance/design/generic/text_widget.dart';
17 : import 'package:app_finance/design/wrapper/row_widget.dart';
18 : import 'package:app_finance/design/wrapper/table_widget.dart';
19 : import 'package:material_ui/material_ui.dart';
20 : import 'package:intl/intl.dart';
21 :
22 : class AccountTab extends StatelessWidget {
23 : final AppData store;
24 :
25 0 : const AccountTab({
26 : super.key,
27 : required this.store,
28 : });
29 :
30 0 : List<ChartValue> _getCurrencyDistribution(List<AccountAppData> accounts) {
31 0 : final exchange = Exchange(store: store);
32 0 : final result = <String, ChartValue>{};
33 0 : for (int i = 0; i < accounts.length; i++) {
34 0 : final code = accounts[i].currency?.code ?? '?';
35 0 : final value = exchange.reform(accounts[i].details, accounts[i].currency, Exchange.defaultCurrency);
36 0 : if (!result.containsKey(code)) {
37 0 : result[code] = ChartValue(0, color: accounts[i].color ?? Colors.grey, tooltip: code);
38 : }
39 0 : result[code]!.value += value;
40 : }
41 0 : final scope = result.values.toList();
42 0 : scope.sort((a, b) => b.value.compareTo(a.value));
43 : return scope;
44 : }
45 :
46 0 : List<List<Widget>> _generateCurrencyTable(List<ChartValue> data) {
47 0 : final formatter = NumberFormat.compact();
48 0 : final max = data.fold(0.0, (v, o) => v + o.value.abs());
49 0 : final List<List<Widget>> result = [
50 0 : [
51 : const Text(''),
52 0 : TextWidget(AppLocale.labels.currencyShort),
53 0 : Align(
54 : alignment: Alignment.centerRight,
55 0 : child: TextWidget(AppLocale.labels.currencyIn(Exchange.defaultCurrency?.code ?? '?')),
56 : ),
57 0 : Align(alignment: Alignment.centerRight, child: TextWidget(AppLocale.labels.currencyDistribution)),
58 : ]
59 : ];
60 0 : for (int i = 0; i < data.length; i++) {
61 0 : final grade = data[i].value > 0 ? 100 * data[i].value / max : 0.0;
62 0 : result.add([
63 0 : BarVerticalSingle(color: data[i].color, value: 1, height: 6),
64 0 : TextWidget(data[i].tooltip),
65 0 : Align(alignment: Alignment.centerRight, child: TextWidget(formatter.format(data[i].value))),
66 0 : Align(alignment: Alignment.centerRight, child: TextWidget('${grade.toStringAsFixed(2)}%')),
67 : ]);
68 : }
69 : return result;
70 : }
71 :
72 0 : @override
73 : Widget build(BuildContext context) {
74 0 : double indent = ThemeHelper.getIndent();
75 0 : final accountList = store.getList(AppDataType.accounts).cast<AccountAppData>();
76 0 : final currency = _getCurrencyDistribution(accountList);
77 0 : return SingleChildScrollView(
78 0 : child: Padding(
79 0 : padding: EdgeInsets.all(indent * 2),
80 0 : child: LayoutBuilder(builder: (context, constraints) {
81 0 : final width = constraints.maxWidth;
82 0 : double pieWidth = width > 600 ? 280 : width * 0.4;
83 0 : return Column(
84 0 : crossAxisAlignment: AppDesign.getAlignment(),
85 0 : children: [
86 : const AccountHealthChart(),
87 : ThemeHelper.hIndent2x,
88 : const AccountFlowChart(),
89 : ThemeHelper.hIndent3x,
90 0 : RowWidget(
91 : maxWidth: width,
92 : indent: indent,
93 0 : chunk: [null, pieWidth],
94 0 : children: [
95 0 : [
96 0 : TableWidget(
97 0 : shadowColor: context.colorScheme.onSurface.withValues(alpha: 0.1),
98 0 : width: width - pieWidth - 2 * indent,
99 : chunk: const [8, 34, null, null],
100 0 : data: _generateCurrencyTable(currency),
101 : ),
102 : ],
103 0 : [
104 0 : PieRadiusChart(
105 : data: currency,
106 : width: pieWidth,
107 : ),
108 : ]
109 : ],
110 : ),
111 : ThemeHelper.formEndBox,
112 : ],
113 : );
114 : }),
115 : ),
116 : );
117 : }
118 : }
|