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