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

Generated by: LCOV version 2.0-1