LCOV - code coverage report
Current view: top level - lib/pages/currency - currency_page.dart Coverage Total Hit
Test: lcov.info Lines: 1.2 % 80 1
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/controller/focus_controller.dart';
       5              : import 'package:app_finance/_classes/herald/app_design.dart';
       6              : import 'package:app_finance/_classes/herald/app_locale.dart';
       7              : import 'package:app_finance/_classes/storage/history_data.dart';
       8              : import 'package:app_finance/_classes/structure/currency_app_data.dart';
       9              : import 'package:app_finance/_classes/storage/app_data.dart';
      10              : import 'package:app_finance/_classes/structure/navigation/app_route.dart';
      11              : import 'package:app_finance/_configs/screen_helper.dart';
      12              : import 'package:app_finance/_configs/theme_helper.dart';
      13              : import 'package:app_finance/_ext/build_context_ext.dart';
      14              : import 'package:app_finance/charts/trade_chart.dart';
      15              : import 'package:app_finance/design/button/toolbar_button_widget.dart';
      16              : import 'package:app_finance/design/wrapper/single_scroll_wrapper.dart';
      17              : import 'package:app_finance/pages/_interfaces/abstract_page_state.dart';
      18              : import 'package:app_finance/design/generic/notification_bar.dart';
      19              : import 'package:app_finance/design/form/simple_input.dart';
      20              : import 'package:app_finance/design/wrapper/row_widget.dart';
      21              : import 'package:material_ui/material_ui.dart';
      22              : 
      23              : class CurrencyPage extends StatefulWidget {
      24            2 :   const CurrencyPage({super.key});
      25              : 
      26            0 :   @override
      27            0 :   CurrencyPageState createState() => CurrencyPageState();
      28              : }
      29              : 
      30              : class CurrencyPageState extends AbstractPageState<CurrencyPage> {
      31              :   late FocusController focus;
      32              :   List<dynamic>? scope;
      33              : 
      34            0 :   @override
      35              :   void initState() {
      36            0 :     focus = FocusController();
      37            0 :     super.initState();
      38              :   }
      39              : 
      40            0 :   @override
      41              :   void dispose() {
      42            0 :     focus.dispose();
      43            0 :     super.dispose();
      44              :   }
      45              : 
      46            0 :   @override
      47            0 :   String getTitle() => AppLocale.labels.currencyHeadline;
      48              : 
      49            0 :   @override
      50            0 :   String getButtonName() => AppLocale.labels.currencyUpdateTooltip;
      51              : 
      52            0 :   @override
      53              :   Widget buildButton(BuildContext context, BoxConstraints constraints) {
      54            0 :     return FloatingActionButton(
      55              :       heroTag: 'currency_page',
      56            0 :       onPressed: () => updateAllRates(context),
      57            0 :       tooltip: getButtonName(),
      58              :       child: const Icon(Icons.save),
      59              :     );
      60              :   }
      61              : 
      62            0 :   @override
      63              :   List<Widget> getBarActions(NavigatorState nav) {
      64            0 :     return [
      65            0 :       ToolbarButtonWidget(
      66            0 :         isWide: ScreenHelper.state().isWide,
      67            0 :         tooltip: AppLocale.labels.currencyAddTooltip,
      68            0 :         onPressed: () => nav.pushNamed(AppRoute.currencyAddRoute),
      69              :         icon: Icons.add,
      70            0 :         semanticLabel: AppLocale.labels.currencyAddTooltip,
      71              :       ),
      72            0 :       ...super.getBarActions(nav)
      73              :     ];
      74              :   }
      75              : 
      76            0 :   List<CurrencyAppData>? _getItems() {
      77            0 :     List<CurrencyAppData>? tmp = state
      78            0 :         .getList(AppDataType.currencies)
      79            0 :         .where((v) =>
      80            0 :             v.currencyFrom != null && v.currency != null && v.currency.code != v.currencyFrom.code && v.details != 1.0)
      81            0 :         .toList()
      82            0 :         .cast();
      83            0 :     tmp.sort((a, b) => a.uuid.compareTo(b.uuid));
      84              :     return tmp;
      85              :   }
      86              : 
      87            0 :   void updateAllRates(BuildContext context) {
      88            0 :     for (CurrencyAppData rate in scope!) {
      89            0 :       if ((state.getByUuid(rate.uuid) as CurrencyAppData).details != rate.details) {
      90            0 :         state.update(rate.uuid, rate);
      91              :       }
      92              :     }
      93            0 :     NotificationBar.showSnackBar(context, AppLocale.labels.saveNotification);
      94              :   }
      95              : 
      96            0 :   void changeRate(CurrencyAppData initial, double? value) {
      97              :     if (value != null) {
      98            0 :       initial.details = value;
      99              :     }
     100              :   }
     101              : 
     102            0 :   @override
     103              :   Widget buildContent(BuildContext context, BoxConstraints constraints) {
     104            0 :     final tmp = _getItems();
     105            0 :     if (tmp?.length != scope?.length) {
     106            0 :       WidgetsBinding.instance.addPostFrameCallback((_) => setState(() => scope = tmp));
     107              :       return ThemeHelper.emptyBox;
     108              :     }
     109            0 :     final TextTheme textTheme = context.textTheme;
     110            0 :     final indent = ThemeHelper.getIndent();
     111            0 :     final now = DateTime.now();
     112            0 :     final cutDate = DateTime(now.year, now.month - 2);
     113            0 :     final crossAxisCount = ThemeHelper.getWidthCount(null, context);
     114            0 :     return SingleScrollWrapper(
     115            0 :       controller: focus,
     116            0 :       child: Padding(
     117            0 :         padding: EdgeInsets.all(indent),
     118            0 :         child: Wrap(
     119              :           spacing: indent,
     120            0 :           runSpacing: indent * 2,
     121            0 :           children: scope!.map((item) {
     122            0 :             final history = HistoryData.getStream(item.uuid, filter: (e) => e.timestamp.isBefore(cutDate))?.toList();
     123            0 :             return RowWidget(
     124              :               indent: indent,
     125            0 :               maxWidth: ThemeHelper.getWidth(context, 4, constraints) / crossAxisCount,
     126              :               chunk: const [85, null, 100],
     127            0 :               children: [
     128            0 :                 [
     129            0 :                   Column(
     130            0 :                     crossAxisAlignment: AppDesign.getAlignment(),
     131            0 :                     children: [
     132            0 :                       Text(
     133            0 :                         item.uuid,
     134            0 :                         style: textTheme.headlineMedium,
     135              :                         overflow: TextOverflow.ellipsis,
     136              :                       ),
     137            0 :                       Text(
     138            0 :                         item.updatedAtFormatted,
     139            0 :                         style: textTheme.bodySmall,
     140              :                         overflow: TextOverflow.ellipsis,
     141              :                       ),
     142              :                     ],
     143              :                   ),
     144              :                 ],
     145            0 :                 [
     146            0 :                   SimpleInput(
     147            0 :                     controller: TextEditingController(text: item.details.toString()),
     148              :                     type: TextInputType.number,
     149            0 :                     setState: (value) => changeRate(item, double.tryParse(value)),
     150              :                   )
     151              :                 ],
     152            0 :                 [
     153            0 :                   Padding(
     154            0 :                     padding: EdgeInsets.only(top: indent),
     155            0 :                     child: TradeChart(
     156            0 :                       data: history ?? [],
     157              :                       width: 100,
     158              :                       height: 40,
     159              :                     ),
     160              :                   ),
     161              :                 ],
     162              :               ],
     163              :             );
     164            0 :           }).toList(),
     165              :         ),
     166              :       ),
     167              :     );
     168              :   }
     169              : }
        

Generated by: LCOV version 2.0-1