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/storage/app_data.dart';
5 : import 'package:app_finance/_classes/structure/currency_app_data.dart';
6 : import 'package:app_finance/_ext/double_ext.dart';
7 : import 'package:material_ui/material_ui.dart';
8 : import 'package:flutter_currency_picker/flutter_currency_picker.dart';
9 :
10 : typedef ExchangeScope = ({
11 : String from,
12 : String to,
13 : CurrencyAppData currency,
14 : TextEditingController rate,
15 : TextEditingController sum,
16 : });
17 :
18 : typedef ExchangeMap = Map<String, ExchangeScope>;
19 :
20 : class ExchangeController extends ValueNotifier<ExchangeMap> {
21 : final AppData store;
22 : final TextEditingController targetController;
23 : Currency? target;
24 : List<Currency?> source;
25 :
26 2 : ExchangeController(
27 : super.value, {
28 : required this.store,
29 : required this.target,
30 : required this.targetController,
31 : required this.source,
32 : }) {
33 6 : restate(source, target);
34 6 : targetController.addListener(_updateAll);
35 : }
36 :
37 6 : int get length => value.length;
38 :
39 2 : @override
40 : void dispose() {
41 2 : clear();
42 2 : super.dispose();
43 : }
44 :
45 2 : void clear() {
46 4 : for (var scope in value.values) {
47 0 : scope.rate.dispose();
48 0 : scope.sum.dispose();
49 : }
50 4 : value.clear();
51 : }
52 :
53 2 : void restate(List<Currency?> source, Currency? target) {
54 2 : this.source = source;
55 2 : this.target = target;
56 2 : clear();
57 :
58 2 : if (source.isEmpty) {
59 : return;
60 : }
61 :
62 6 : for (int i = 0; i < source.length; i++) {
63 12 : final uuid = [target, source[i]].map((v) => v?.code ?? '?').toList().join('-');
64 6 : if (target == null || source[i] == null || target.code == source[i]!.code || value[uuid] != null) {
65 : continue;
66 : }
67 0 : final currency = store.getByUuid(uuid) ?? CurrencyAppData(currency: source[i], currencyFrom: target);
68 0 : final amount = (double.tryParse(targetController.text) ?? 0.0) * currency.details;
69 0 : value[uuid] = (
70 : from: target.code,
71 0 : to: source[i]!.code,
72 : currency: currency,
73 0 : rate: TextEditingController(text: currency.details.toString())..addListener(() => _updateSum(uuid)),
74 0 : sum: TextEditingController(text: amount.toString())..addListener(() => _updateRate(uuid)),
75 : );
76 : }
77 2 : notifyListeners();
78 : }
79 :
80 0 : ExchangeScope get(int index) => value.values.elementAt(index);
81 :
82 0 : void save() {
83 0 : for (var item in value.values) {
84 0 : double rate = double.tryParse(item.rate.text) ?? 0.0;
85 0 : item.currency.details = rate;
86 0 : store.update(item.currency.uuid, item.currency, true);
87 : }
88 : }
89 :
90 2 : void _updateAll() {
91 4 : for (var uuid in value.keys) {
92 0 : _updateSum(uuid);
93 : }
94 : }
95 :
96 0 : int _getDecimals(ExchangeScope pair) {
97 0 : final fromDecimals = pair.currency.currencyFrom?.decimalDigits ?? 0;
98 0 : final toDecimals = pair.currency.currency?.decimalDigits ?? 0;
99 0 : return fromDecimals > toDecimals ? fromDecimals : toDecimals;
100 : }
101 :
102 0 : void _updateSum(String uuid) {
103 0 : ExchangeScope pair = value[uuid]!;
104 0 : double rate = double.tryParse(pair.rate.text) ?? 0.0;
105 0 : double amount = (double.tryParse(targetController.text) ?? 0.0) * rate;
106 0 : double? current = double.tryParse(pair.sum.text);
107 0 : final decimals = _getDecimals(pair);
108 0 : if (targetController.text != '' && amount.toFixed(decimals).isNotEqual(current?.toFixed(decimals))) {
109 0 : pair.sum.text = amount.toString();
110 : // pair.sum.notifyListeners();
111 : }
112 : }
113 :
114 0 : void _updateRate(String uuid) {
115 0 : ExchangeScope pair = value[uuid]!;
116 0 : double rate = double.tryParse(pair.rate.text) ?? 0.0;
117 0 : double val = double.tryParse(targetController.text) ?? 0.0;
118 0 : double amount = double.tryParse(pair.sum.text) ?? 0.0;
119 0 : double newAmount = val * rate;
120 0 : double newRate = val > 0 ? amount / val : 0.0;
121 0 : final decimals = _getDecimals(pair);
122 0 : if (targetController.text != '' && amount.toFixed(decimals).isNotEqual(newAmount.toFixed(decimals))) {
123 0 : pair.rate.text = newRate.toString();
124 : // pair.rate.notifyListeners();
125 : }
126 : }
127 : }
|