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 'dart:math';
5 :
6 : import 'package:app_finance/_classes/herald/app_design.dart';
7 : import 'package:app_finance/_classes/herald/app_locale.dart';
8 : import 'package:app_finance/_classes/storage/app_data.dart';
9 : import 'package:app_finance/_classes/structure/bill_app_data.dart';
10 : import 'package:app_finance/_classes/structure/currency/exchange.dart';
11 : import 'package:app_finance/_classes/structure/interface_app_data.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/column_chart.dart';
15 : import 'package:app_finance/charts/data/data_handler.dart';
16 : import 'package:app_finance/charts/interface/chart_data.dart';
17 : import 'package:app_finance/design/wrapper/row_widget.dart';
18 : import 'package:app_finance/design/wrapper/text_wrapper.dart';
19 : import 'package:material_ui/material_ui.dart';
20 : import 'package:provider/provider.dart';
21 :
22 : class BillYtdChart extends StatelessWidget {
23 2 : const BillYtdChart({super.key});
24 :
25 0 : List<ChartData> getData(AppData store) {
26 0 : final currentYear = DateTime(DateTime.now().year);
27 0 : final prevYear = DateTime(currentYear.year - 1);
28 0 : final scope = store.getStream<BillAppData>(AppDataType.bills, filter: (e) => e.createdAt.isBefore(prevYear));
29 :
30 0 : final exchange = Exchange(store: store);
31 0 : return [
32 0 : ChartData(
33 0 : DataHandler.getAmountGroupedByMonth(
34 0 : scope.getTill(0.0 + currentYear.millisecondsSinceEpoch).cast(),
35 : exchange: exchange,
36 : ),
37 : color: Colors.blue,
38 : ),
39 0 : ChartData(
40 0 : DataHandler.getAmountGroupedByMonth(
41 0 : scope.toList().cast<InterfaceAppData>().map((e) {
42 0 : e.createdAt = e.createdAt.add(const Duration(days: 365));
43 : return e;
44 0 : }).toList(),
45 : exchange: exchange,
46 : ),
47 : color: Colors.grey,
48 : ),
49 : ];
50 : }
51 :
52 0 : double getMax(List<ChartData> data) {
53 : double yMax = 0;
54 0 : if (data.isNotEmpty && data.first.data.isNotEmpty) {
55 0 : yMax = data.first.data.reduce((max, current) => current.dy > max.dy ? current : max).dy;
56 0 : if (data.last.data.isNotEmpty) {
57 0 : double yPrevMax = data.last.data.reduce((max, current) => current.dy > max.dy ? current : max).dy;
58 0 : yMax = yMax > yPrevMax ? yMax : yPrevMax;
59 : }
60 : }
61 : return yMax;
62 : }
63 :
64 0 : @override
65 : Widget build(BuildContext context) {
66 0 : final TextTheme textTheme = context.textTheme;
67 0 : final indent = ThemeHelper.getIndent();
68 0 : final year = DateTime.now().year;
69 0 : return Consumer<AppData>(builder: (context, appState, _) {
70 0 : final data = getData(appState);
71 0 : return LayoutBuilder(builder: (context, constraints) {
72 0 : final width = constraints.maxWidth - indent * 2;
73 0 : return Column(
74 0 : crossAxisAlignment: AppDesign.getAlignment(),
75 0 : children: [
76 0 : TextWrapper(
77 0 : '${AppLocale.labels.chartYtdExpense}, ${Exchange.defaultCurrency?.code}',
78 0 : style: textTheme.bodyLarge,
79 : ),
80 0 : ColumnChart(
81 : width: width,
82 0 : height: [constraints.maxHeight - 6 * indent, 200].reduce(min).toDouble(),
83 : indent: indent,
84 : data: data,
85 0 : yMax: getMax(data) * 1.2,
86 : ),
87 0 : RowWidget(
88 : maxWidth: width,
89 : indent: indent,
90 : chunk: const [null, null],
91 0 : children: [
92 0 : [
93 0 : Padding(
94 0 : padding: EdgeInsets.only(left: indent * 2),
95 0 : child: TextWrapper(
96 0 : year.toString(),
97 0 : style: textTheme.bodySmall?.copyWith(color: Colors.blue),
98 : ),
99 : ),
100 : ],
101 0 : [
102 0 : Align(
103 : alignment: Alignment.centerRight,
104 0 : child: TextWrapper(
105 0 : (year - 1).toString(),
106 0 : style: textTheme.bodySmall?.copyWith(color: Colors.grey),
107 : ),
108 : ),
109 : ],
110 : ],
111 : ),
112 : ],
113 : );
114 : });
115 : });
116 : }
117 : }
|