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 1 : ProfitWidget({
28 : super.key,
29 : required this.store,
30 : required this.width,
31 : }) {
32 4 : goals = store.getList(AppDataType.goals).cast();
33 3 : maxValue = _getMaxValue(goals);
34 2 : valInvoice = _getValue(AppDataType.invoice);
35 2 : valBill = _getValue(AppDataType.bills);
36 : }
37 :
38 1 : double _getMaxValue(List<GoalAppData> goals) {
39 2 : final exchange = Exchange(store: store);
40 1 : final now = DateTime.now();
41 1 : 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 1 : double _getValue(AppDataType type) {
52 2 : final exchange = Exchange(store: store);
53 1 : return store
54 1 : .getActualList(type)
55 1 : .where((v) => type != AppDataType.invoice || (v as InvoiceAppData).accountFrom == null)
56 1 : .fold(0.0, (prev, e) => prev + exchange.reform(e.details, e.currency, Exchange.defaultCurrency));
57 : }
58 :
59 1 : @override
60 : Widget build(BuildContext context) {
61 1 : final indent = ThemeHelper.getIndent();
62 2 : final textStyle = context.textTheme.numberSmall;
63 3 : final value = valInvoice - valBill;
64 1 : return RowWidget(
65 1 : alignment: AppDesign.getAlignment<MainAxisAlignment>(),
66 : indent: indent,
67 1 : maxWidth: width,
68 : chunk: const [null, null],
69 1 : children: [
70 1 : [
71 5 : TextWrapper(AppLocale.labels.goalProfitTooltip, style: context.textTheme.bodyLarge),
72 1 : TextWrapper(
73 4 : AppLocale.labels.goalProfit(maxValue.toCurrency(withPattern: false)),
74 : style: textStyle,
75 : maxLines: 2,
76 : ),
77 1 : TextWrapper(
78 4 : AppLocale.labels.invoiceSum(valInvoice.toCurrency(withPattern: false)),
79 : style: textStyle,
80 : maxLines: 2,
81 : ),
82 1 : TextWrapper(
83 4 : AppLocale.labels.billSum(valBill.toCurrency(withPattern: false)),
84 : style: textStyle,
85 : maxLines: 2,
86 : ),
87 1 : TextWrapper(
88 3 : AppLocale.labels.netProfit(value.toCurrency(withPattern: false)),
89 : style: textStyle,
90 : maxLines: 2,
91 : ),
92 : ThemeHelper.hIndent,
93 : ],
94 1 : [
95 1 : GaugeChart(
96 : value: value,
97 2 : valueMax: maxValue * 2.2,
98 2 : width: width > 200 ? 200 : width,
99 : height: 100,
100 : ),
101 : ]
102 : ],
103 : );
104 : }
105 : }
|