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