Untitled
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