LCOV - code coverage report
Current view: top level - lib/_classes/controller - exchange_controller.dart Coverage Total Hit
Test: lcov.info Lines: 98.3 % 58 57
Test Date: 2026-11-14 15:08:11 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: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              : }
        

Generated by: LCOV version 2.0-1