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/currency/exchange.dart';
8 : import 'package:app_finance/_classes/structure/goal_app_data.dart';
9 : import 'package:app_finance/_classes/structure/invoice_app_data.dart';
10 : import 'package:app_finance/_configs/custom_text_theme.dart';
11 : import 'package:app_finance/_configs/theme_helper.dart';
12 : import 'package:app_finance/_ext/build_context_ext.dart';
13 : import 'package:app_finance/charts/gauge_chart.dart';
14 : import 'package:app_finance/design/wrapper/row_widget.dart';
15 : import 'package:app_finance/design/wrapper/text_wrapper.dart';
16 : import 'package:flutter/material.dart';
17 : import 'package:flutter_currency_picker/flutter_currency_picker.dart';
18 :
19 : class ProfitWidget extends StatelessWidget {
20 : final AppData store;
21 : final double width;
22 : late final List<GoalAppData> goals;
23 : late final double maxValue;
24 : late final double valInvoice;
25 : late final double valBill;
26 :
27 0 : ProfitWidget({
28 : super.key,
29 : required this.store,
30 : required this.width,
31 : }) {
32 0 : goals = store.getList(AppDataType.goals).cast();
33 0 : maxValue = _getMaxValue(goals);
34 0 : valInvoice = _getValue(AppDataType.invoice);
35 0 : valBill = _getValue(AppDataType.bills);
36 : }
37 :
38 0 : double _getMaxValue(List<GoalAppData> goals) {
39 0 : final exchange = Exchange(store: store);
40 0 : final now = DateTime.now();
41 0 : return goals.fold(0.0, (prev, e) {
42 0 : double left = e.closedAt.difference(now).inDays / 30;
43 0 : if (left < 1) {
44 : left = 1;
45 : }
46 0 : double value = (1 - e.progress) * exchange.reform(e.details, e.currency, Exchange.defaultCurrency);
47 0 : return prev + value / left;
48 : });
49 : }
50 :
51 0 : double _getValue(AppDataType type) {
52 0 : final exchange = Exchange(store: store);
53 0 : return store
54 0 : .getActualList(type)
55 0 : .where((v) => type != AppDataType.invoice || (v as InvoiceAppData).accountFrom == null)
56 0 : .fold(0.0, (prev, e) => prev + exchange.reform(e.details, e.currency, Exchange.defaultCurrency));
57 : }
58 :
59 0 : @override
60 : Widget build(BuildContext context) {
61 0 : final indent = ThemeHelper.getIndent();
62 0 : final textStyle = context.textTheme.numberSmall;
63 0 : final value = valInvoice - valBill;
64 0 : return RowWidget(
65 0 : alignment: AppDesign.getAlignment<MainAxisAlignment>(),
66 : indent: indent,
67 0 : maxWidth: width,
68 : chunk: const [null, null],
69 0 : children: [
70 0 : [
71 0 : TextWrapper(AppLocale.labels.goalProfitTooltip, style: context.textTheme.bodyLarge),
72 0 : TextWrapper(
73 0 : AppLocale.labels.goalProfit(maxValue.toCurrency(withPattern: false)),
74 : style: textStyle,
75 : maxLines: 2,
76 : ),
77 0 : TextWrapper(
78 0 : AppLocale.labels.invoiceSum(valInvoice.toCurrency(withPattern: false)),
79 : style: textStyle,
80 : maxLines: 2,
81 : ),
82 0 : TextWrapper(
83 0 : AppLocale.labels.billSum(valBill.toCurrency(withPattern: false)),
84 : style: textStyle,
85 : maxLines: 2,
86 : ),
87 0 : TextWrapper(
88 0 : AppLocale.labels.netProfit(value.toCurrency(withPattern: false)),
89 : style: textStyle,
90 : maxLines: 2,
91 : ),
92 : ThemeHelper.hIndent,
93 : ],
94 0 : [
95 0 : GaugeChart(
96 : value: value,
97 0 : valueMax: maxValue * 2.2,
98 0 : width: width > 200 ? 200 : width,
99 : height: 100,
100 : ),
101 : ]
102 : ],
103 : );
104 : }
105 : }
|