Untitled

 avatar
unknown
plain_text
2 months ago
23 kB
5
Indexable
import 'dart:math';
import 'package:connectivity_widget/connectivity_widget.dart';
import 'package:ctexpeess/constants/dimensions.dart';
import 'package:ctexpeess/constants/routes.dart';
import 'package:ctexpeess/constants/styles.dart';
import 'package:ctexpeess/core/config/color.dart';
import 'package:ctexpeess/core/config/constant.dart';
import 'package:ctexpeess/core/utils/auth_app_bar.dart';
import 'package:ctexpeess/core/utils/date_time_formatter.dart';
import 'package:ctexpeess/core/utils/helper.dart';
import 'package:ctexpeess/core/widget/cus_elevated_button.dart';
import 'package:ctexpeess/core/widget/offline_snack.dart';
import 'package:ctexpeess/core/widget/pixel_perfect_wraper.dart';
import 'package:ctexpeess/feature/currency_converter/data/model/forex_rate.model.dart';
import 'package:ctexpeess/feature/currency_converter/presentation/view/forex_rate.cubit.dart';
import 'package:ctexpeess/feature/currency_converter/presentation/view/forex_rate.state.dart';
import 'package:ctexpeess/feature/currency_converter/view/widget/currency_bottom_sheet_widget.dart';
import 'package:ctexpeess/feature/currency_converter/view/widget/today_rate.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
import 'package:skeletonizer/skeletonizer.dart';
import 'package:ctexpeess/core/utils/bottom_sheet_container.dart';
import 'package:ctexpeess/core/widget/svg_builder.dart';

class CurrencyConverterPage extends StatefulWidget {
  const CurrencyConverterPage({super.key});
  @override
  State<CurrencyConverterPage> createState() => _CurrencyConverterPageState();
}

class _CurrencyConverterPageState extends State<CurrencyConverterPage> {
  // start of keys and controllers
  final TextEditingController _toAmountTxController = TextEditingController();
  final TextEditingController _fromAmountTxController = TextEditingController();
  // end of keys and controller

  // start of states
  String _lastUpdatedAt = "";
  final String _fromCurrency = 'AUD';
  final String _fromCurrencyFlag = SvgAsset.austrila;
  ForexRate? toCurrency;
  // end of states

  // start of functions
  _handleSearchClicked(bool isFromCurrency) async {
    final selectedCurrency = await showModalBottomSheet(
      context: context,
      useRootNavigator: true,
      useSafeArea: true,
      isScrollControlled: true,
      builder: (BuildContext context) {
        return BottomSheetContainer(
          size: 650,
          child: CurrencyBottomSheetWidget(
            onCurrencySelected: (selectedCurrency) {
              Navigator.pop(context, selectedCurrency);
            },
          ),
        );
      },
    );
    if (selectedCurrency != null) {
      setState(() {
        setState(() {
          toCurrency = selectedCurrency;
        });
        _updateToCountryCurrency();
      });
    }
  }

  _initCurrency() {
    ForexRateState forex = context.read<ForexRateCubit>().state;

    if (forex is ForexRateSuccess) {
      final nprCurrency = forex.forexRateModel.data.firstWhere(
        (currency) => currency.code == "NPR",
        orElse: () => forex.forexRateModel.data.first,
      );
      setState(() {
        toCurrency = nprCurrency;
      });
      _setLastUpdatedAt(forex.forexRateModel.data);
      _updateToCountryCurrency();
    }
  }

  _setLastUpdatedAt(List<ForexRate> currencies) {
    if (currencies.isEmpty) return;

    final latestCurrency = currencies.reduce((curr, next) {
      final currDate = DateTime.parse(curr.updatedAt).toUtc();
      final nextDate = DateTime.parse(next.updatedAt).toUtc();
      return currDate.compareTo(nextDate) > 0 ? curr : next;
    });

    setState(() {
      _lastUpdatedAt = ausDateTimeFormatter(
          DateTime.parse(latestCurrency.updatedAt).toUtc().toLocal());
    });
  }

  _getForexRate({bool force = false}) async {
    context.read<ForexRateCubit>().getForexRate(force: true);
    _initCurrency();
  }

  void _updateTextFieldValue(TextEditingController controller, String newValue,
      {int? cursorPosition}) {
    final previousCursorPosition = controller.selection.baseOffset;
    final usePosition = cursorPosition ?? previousCursorPosition;

    controller.value = TextEditingValue(
      text: newValue,
      selection: TextSelection.collapsed(
        offset: usePosition > -1
            ? min(usePosition, newValue.length)
            : newValue.length,
      ),
    );
  }

  _updateFromCountryCurrency({String? value}) {
    try {
      String toValue = _toAmountTxController.text.trim();

      if (toValue.isEmpty) {
        _updateTextFieldValue(_fromAmountTxController, '');
        return;
      }

      double? toAmount = _extractAmountFromFormatted(toValue);

      if (toAmount == null || toAmount == 0) {
        _updateTextFieldValue(
            _fromAmountTxController, formatCurrency(1, symbol: ''));
        return;
      }
      String formattedValue = formatCurrency(toAmount, symbol: '');
      //
      // if (formattedValue == toValue && value != null) {
      //   return;
      // }
      _updateTextFieldValue(_toAmountTxController, formattedValue);

      if (toCurrency == null) {
        _updateTextFieldValue(
            _fromAmountTxController, formatCurrency(1, symbol: ''));
        return;
      }

      double? rate = double.tryParse(toCurrency?.exchangeRate ?? '0');
      if (rate == null || rate == 0) {
        _updateTextFieldValue(
            _fromAmountTxController, formatCurrency(0, symbol: ''));
        return;
      }

      double fromAmount = toAmount / rate;
      _updateTextFieldValue(
          _fromAmountTxController, formatCurrency(fromAmount, symbol: ''));
    } catch (e) {
      _updateTextFieldValue(
          _fromAmountTxController, formatCurrency(1, symbol: ''));
    }
  }

  double? _extractAmountFromFormatted(String value) {
    double? fromAmount = double.tryParse(value.replaceAll(',', ''));
    return fromAmount;
  }

  _updateToCountryCurrency({String? value}) {
    try {
      String fromValue = _fromAmountTxController.text.trim();
      if (fromValue.isEmpty) {
        _updateTextFieldValue(_toAmountTxController, '');
        return;
      }

      double? fromAmount = _extractAmountFromFormatted(fromValue);
      if (fromAmount == null || fromAmount == 0) {
        _fromAmountTxController.text = formatCurrency(1, symbol: '');
        // _updateTextFieldValue(
        //     _toAmountTxController, formatCurrency(1, symbol: ''));
        return;
      }

      String formattedValue = formatCurrency(fromAmount, symbol: '');

      // if (formattedValue == fromValue && value != null) {
      //   return;
      // }
      _updateTextFieldValue(_fromAmountTxController, formattedValue);

      if (toCurrency == null) {
        _updateTextFieldValue(
            _toAmountTxController, formatCurrency(1, symbol: ''));
        return;
      }

      double? rate = double.tryParse(toCurrency?.exchangeRate ?? '0');
      if (rate == null || rate == 0) {
        _updateTextFieldValue(
            _toAmountTxController, formatCurrency(0, symbol: ''));
        return;
      }

      double toAmount = fromAmount * rate;
      _updateTextFieldValue(
          _toAmountTxController, formatCurrency(toAmount, symbol: ''));
    } catch (e) {
      _updateTextFieldValue(
          _toAmountTxController, formatCurrency(1, symbol: ''));
    }
  }
  // end of functions

  @override
  void initState() {
    _fromAmountTxController.text = '1';
    _getForexRate();
    super.initState();
  }

  @override
  void dispose() {
    _toAmountTxController.dispose();
    _fromAmountTxController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return BlocConsumer<ForexRateCubit, ForexRateState>(
        listenWhen: (previous, current) => previous != current,
        listener: (_, forex) {
          if (forex is ForexRateSuccess &&
              forex.forexRateModel.data.isNotEmpty) {
            final nprCurrency = forex.forexRateModel.data.firstWhere(
              (currency) => currency.code == "NPR",
              orElse: () => forex.forexRateModel.data.first,
            );
            setState(() {
              toCurrency = nprCurrency;
            });
            _setLastUpdatedAt(forex.forexRateModel.data);
            _updateToCountryCurrency();
          }
        },
        builder: (context, state) {
          return PixelPerfectWrapper(
            assetPath: ImageAsset.kCurrencyConverterPage,
            child: Scaffold(
              appBar: authAppBar(context,
                  title: "Currency Converter", showBackButton: true),
              body: ConnectivityWidget(
                onlineCallback: () => _getForexRate(force: true),
                offlineBanner: const OfflineSnack(),
                builder: (_, isOnline) =>
                    LayoutBuilder(builder: (context, constraints) {
                  return SingleChildScrollView(
                    child: ConstrainedBox(
                      constraints: BoxConstraints(
                        minHeight: constraints.minHeight,
                      ),
                      child: IntrinsicHeight(
                        child: Padding(
                          padding: const EdgeInsets.only(
                              left: Dimensions.HORIZONTAL_PADDING,
                              right: Dimensions.HORIZONTAL_PADDING,
                              top: Dimensions.P20),
                          child: Column(children: [
                            Text(
                              "Set your default currencies in the settings for quicker access.",
                              style: bodyCaptionStyle.copyWith(
                                  color: CusColor.kBlack300),
                            ),
                            const SizedBox(
                              height: Spacers.SPACER_20,
                            ),
                            Container(
                              height: 48,
                              padding: const EdgeInsets.symmetric(
                                  horizontal: Dimensions.P8),
                              decoration: BoxDecoration(
                                border: Border.all(color: CusColor.kBlack800),
                                borderRadius: BorderRadius.circular(
                                    RadiusDimensions.ROUND_6),
                              ),
                              child: Row(
                                children: [
                                  SvgBuilder(
                                    svgPath: _fromCurrencyFlag,
                                    height: 24,
                                    width: 24,
                                  ),
                                  const SizedBox(
                                    width: 10,
                                  ),
                                  Text(_fromCurrency.toUpperCase(),
                                      style: paragraphStyle.copyWith(
                                          color: CusColor.kBlack100)),
                                  const SizedBox(
                                    width: Spacers.SPACER_24,
                                  ),
                                  Expanded(
                                    child: TextField(
                                      controller: _fromAmountTxController,
                                      textAlign: TextAlign.end,
                                      keyboardType: TextInputType.number,
                                      inputFormatters: const [],
                                      decoration: const InputDecoration(
                                        hintStyle: TextStyle(
                                            fontSize: 16,
                                            color: CusColor.kBlack),
                                        border: InputBorder.none,
                                      ),
                                      onChanged: (value) {
                                        _updateToCountryCurrency(value: value);
                                      },
                                    ),
                                  )
                                ],
                              ),
                            ),
                            const Padding(
                              padding: EdgeInsets.all(Dimensions.P8),
                              child: SvgBuilder(
                                  svgPath: SvgAsset.kAIcDropDown, height: 24),
                            ),
                            Skeletonizer(
                              enabled: state is ForexRateLoading,
                              child: Container(
                                height: 48,
                                padding: const EdgeInsets.symmetric(
                                    horizontal: Dimensions.P8),
                                decoration: BoxDecoration(
                                  border: Border.all(color: CusColor.kBlack800),
                                  borderRadius: BorderRadius.circular(
                                      RadiusDimensions.ROUND_6),
                                ),
                                child: GestureDetector(
                                  onTap: () => _handleSearchClicked(true),
                                  child: Row(
                                    children: [
                                      SvgBuilder(
                                        svgUrl: toCurrency?.photoUrl ?? '',
                                        height: 24,
                                        width: 24,
                                      ),
                                      const SizedBox(
                                        width: 10,
                                      ),
                                      Text(toCurrency?.code ?? ''.toUpperCase(),
                                          style: paragraphStyle.copyWith(
                                              color: CusColor.kBlack100)),
                                      const Icon(
                                        Icons.arrow_drop_down,
                                        color: CusColor.kBlack100,
                                      ),
                                      const SizedBox(
                                        width: Spacers.SPACER_24,
                                      ),
                                      Expanded(
                                        child: TextField(
                                          controller: _toAmountTxController,
                                          textAlign: TextAlign.end,
                                          keyboardType: const TextInputType
                                              .numberWithOptions(decimal: true),
                                          inputFormatters: const [],
                                          decoration: const InputDecoration(
                                            hintText: '',
                                            hintStyle: TextStyle(
                                                fontSize: 16,
                                                color: CusColor.kBlack),
                                            border: InputBorder.none,
                                          ),
                                          onChanged: (value) {
                                            _updateFromCountryCurrency(
                                                value: value);
                                          },
                                        ),
                                      ),
                                    ],
                                  ),
                                ),
                              ),
                            ),
                            const SizedBox(
                              height: Spacers.SPACER_12,
                            ),
                            SizedBox(
                                width: double.infinity,
                                child: CusElevatedButton(
                                  onPressed: () {
                                    context.push(Routes.routeUrl(
                                        Routes.TRANSFER_FRAGMENT));
                                  },
                                  text: 'Create Transfer',
                                  disabled: state is ForexRateInitial ||
                                      state is ForexRateLoading,
                                )),
                            const SizedBox(
                              height: Spacers.SPACER_12,
                            ),
                            Container(
                              padding: const EdgeInsets.all(Dimensions.P8),
                              decoration: BoxDecoration(
                                  color: CusColor.kY1000,
                                  borderRadius: BorderRadius.circular(
                                      RadiusDimensions.ROUND_4)),
                              child: Row(
                                crossAxisAlignment: CrossAxisAlignment.start,
                                mainAxisAlignment:
                                    MainAxisAlignment.spaceBetween,
                                children: [
                                  Flexible(
                                    child: Row(
                                      crossAxisAlignment:
                                          CrossAxisAlignment.start,
                                      mainAxisSize: MainAxisSize.min,
                                      children: [
                                        const Padding(
                                          padding:
                                              EdgeInsets.all(Dimensions.P2),
                                          child: SvgBuilder(
                                            width: 18,
                                            height: 18,
                                            color: CusColor.kB100,
                                            svgPath: SvgAsset.infoCircleSolid,
                                          ),
                                        ),
                                        const SizedBox(
                                          width: Spacers.SPACER_8,
                                        ),
                                        Flexible(
                                          child: Text(
                                            "Service fees will be shown after creating the transfer.",
                                            maxLines: 2,
                                            overflow: TextOverflow.ellipsis,
                                            style:
                                                paragraphSemiBoldStyle.copyWith(
                                                    color: CusColor.kB100),
                                          ),
                                        )
                                      ],
                                    ),
                                  ),
                                ],
                              ),
                            ),
                            const SizedBox(
                              height: Spacers.SPACER_24,
                            ),
                            Flexible(
                              child: Column(
                                crossAxisAlignment: CrossAxisAlignment.start,
                                mainAxisSize: MainAxisSize.min,
                                children: [
                                  Text(
                                    "Today's Rate",
                                    style: bodyBoldStyle.copyWith(
                                        color: CusColor.kBlack100),
                                  ),
                                  Skeletonizer(
                                    enabled: state is! ForexRateSuccess,
                                    child: Text(
                                      "Last updated: $_lastUpdatedAt",
                                      style: paragraphStyle.copyWith(
                                          color: CusColor.kBlack300),
                                    ),
                                  ),
                                  const SizedBox(
                                    height: Spacers.SPACER_20,
                                  ),
                                  Row(
                                    mainAxisAlignment:
                                        MainAxisAlignment.spaceBetween,
                                    children: [
                                      Text(
                                        "Currency",
                                        style: bodyMediumStyle.copyWith(
                                            color: CusColor.kBlack100),
                                      ),
                                      Text(
                                        "Rate",
                                        style: bodyMediumStyle.copyWith(
                                            color: CusColor.kBlack100),
                                      ),
                                    ],
                                  ),
                                  const SizedBox(
                                    height: Spacers.SPACER_12,
                                  ),
                                  SizedBox(
                                    height: max(250, constraints.minHeight),
                                    child: CurrencyListWidget(
                                      onCurrencySelected: (selectedCurrency) {
                                        setState(() {
                                          toCurrency = selectedCurrency;
                                        });
                                        _updateToCountryCurrency();
                                      },
                                    ),
                                  ),
                                ],
                              ),
                            )
                          ]),
                        ),
                      ),
                    ),
                  );
                }),
              ),
            ),
          );
        });
  }
}
Editor is loading...
Leave a Comment