LCOV - code coverage report
Current view: top level - lib/_classes/controller - exchange_controller.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 69 73 94.5 %
Date: 2024-10-04 11:12:13 Functions: 0 0 -

          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:flutter/material.dart';
       8             : import 'package:flutter_currency_picker/flutter_currency_picker.dart';
       9             : 
      10             : typedef ExchangeMap = Map<String, List<TextEditingController>>;
      11             : 
      12             : typedef ExchangeScope = ({
      13             :   String from,
      14             :   String to,
      15             :   TextEditingController rate,
      16             :   TextEditingController sum,
      17             : });
      18             : 
      19             : class ExchangeController extends ValueNotifier<ExchangeMap> {
      20             :   final Map<String, CurrencyAppData> rate = {};
      21             :   final List<String> pairs = [];
      22             :   final AppData store;
      23             :   final TextEditingController targetController;
      24             :   List<Currency?> source;
      25             :   Currency? target;
      26             : 
      27           1 :   ExchangeController(
      28             :     super.value, {
      29             :     required this.store,
      30             :     required this.target,
      31             :     required this.targetController,
      32             :     required this.source,
      33             :   }) {
      34           3 :     restate(source, target);
      35           3 :     targetController.addListener(_updateAll);
      36             :   }
      37             : 
      38           1 :   void restate(List<Currency?> source, Currency? target) {
      39           1 :     this.source = source;
      40           1 :     this.target = target;
      41           2 :     pairs.clear();
      42           1 :     if (source.isEmpty) {
      43             :       return;
      44             :     }
      45           2 :     _add(target?.code, source.first?.code);
      46           4 :     for (int i = 0; i < source.length - 1; i++) {
      47           4 :       _add(source[i]?.code, source[i + 1]?.code);
      48             :     }
      49           1 :     notifyListeners();
      50             :   }
      51             : 
      52           1 :   ExchangeScope get(int index) {
      53           2 :     final uuid = pairs[index];
      54           1 :     final keys = uuid.split('-');
      55             :     return (
      56           1 :       from: keys[0],
      57           1 :       to: keys[1],
      58           3 :       rate: value[uuid]![0],
      59           3 :       sum: value[uuid]![1],
      60             :     );
      61             :   }
      62             : 
      63           1 :   void save() {
      64           2 :     for (var uuid in pairs) {
      65           6 :       if (rate[uuid] == null || rate[uuid]?.details == 1.0) {
      66             :         continue;
      67             :       }
      68           4 :       store.update(uuid, rate[uuid]!, true);
      69             :     }
      70             :   }
      71             : 
      72           1 :   @override
      73             :   void dispose() {
      74           3 :     for (var scope in value.values) {
      75           5 :       for (int i = 0; i < source.length - 1; i++) {
      76           2 :         scope[i].dispose();
      77             :       }
      78             :     }
      79           2 :     value.clear();
      80           2 :     rate.clear();
      81           2 :     pairs.clear();
      82           1 :     super.dispose();
      83             :   }
      84             : 
      85           1 :   void _add(String? from, String? to) {
      86           5 :     final uuid = [from, to].map((v) => v ?? '?').toList().join('-');
      87           2 :     pairs.add(uuid);
      88           4 :     rate[uuid] ??= store.getByUuid(uuid) ??
      89           1 :         CurrencyAppData(
      90           1 :           currency: CurrencyProvider.find(to),
      91           1 :           currencyFrom: CurrencyProvider.find(from),
      92             :         );
      93           3 :     value[uuid] ??= [
      94           8 :       TextEditingController(text: rate[uuid]!.details.toString())..addListener(() => _updateSum(uuid)),
      95           6 :       TextEditingController(text: _getAmount(uuid)?.toString())..addListener(() => _updateRate(uuid)),
      96             :     ];
      97             :   }
      98             : 
      99           1 :   void _updateAll() {
     100           2 :     for (String uuid in pairs) {
     101           1 :       _updateSum(uuid);
     102             :     }
     103             :   }
     104             : 
     105           1 :   void _updateSum(String uuid) {
     106           2 :     List<TextEditingController> pair = value[uuid]!;
     107           5 :     if (pair[0].text != '' && rate[uuid] != null) {
     108           6 :       rate[uuid]!.details = double.tryParse(pair[0].text);
     109             :     }
     110           5 :     final amount = _getAmount(uuid)?.toFixed(CurrencyProvider.find(uuid.split('-')[1])?.decimalDigits);
     111           3 :     final current = double.tryParse(pair[1].text);
     112           1 :     if (amount != current) {
     113           3 :       pair[1].text = (amount ?? '').toString();
     114           2 :       pair[1].notifyListeners();
     115             :     }
     116             :   }
     117             : 
     118           1 :   void _updateRate(String uuid) {
     119           2 :     List<TextEditingController> pair = value[uuid]!;
     120           4 :     final sum = _getRate(uuid, double.tryParse(pair[1].text));
     121           3 :     final current = double.tryParse(pair[0].text);
     122           1 :     if (sum != current) {
     123           0 :       if (sum != null && rate[uuid] != null) {
     124           0 :         rate[uuid]!.details = sum;
     125             :       }
     126           0 :       pair[0].text = (sum ?? '').toString();
     127           0 :       pair[0].notifyListeners();
     128             :     }
     129             :   }
     130             : 
     131           1 :   double? _getRate(String uuid, double? amount) {
     132             :     if (amount == null) return null;
     133           3 :     double targetAmount = double.tryParse(targetController.text) ?? 0;
     134           2 :     final index = pairs.indexOf(uuid);
     135           9 :     double prev = index > 0 ? double.tryParse(value[pairs[index - 1]]?[1].text ?? '0') ?? 0 : targetAmount;
     136           2 :     return prev > 0 ? amount / prev : null;
     137             :   }
     138             : 
     139           1 :   double? _getAmount(String uuid) {
     140           3 :     double? result = rate[uuid]?.details;
     141           3 :     double? input = double.tryParse(targetController.text);
     142             :     if (result != null && input != null) {
     143           2 :       final index = pairs.indexOf(uuid);
     144           9 :       double amount = index > 0 ? double.tryParse(value[pairs[index - 1]]?[1].text ?? '0') ?? 0 : input;
     145           1 :       result *= amount;
     146             :     } else {
     147             :       result = null;
     148             :     }
     149             :     return result;
     150             :   }
     151             : }

Generated by: LCOV version 1.14