// ignore_for_file: deprecated_member_use_from_same_package import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:hoshan/core/utils/date_time.dart'; import 'package:hoshan/data/model/empty_states_enum.dart'; import 'package:hoshan/ui/screens/setting/bloc/report_of_use_bloc.dart'; import 'package:hoshan/ui/screens/setting/cubit/report_pi_coin_cubit.dart'; import 'package:hoshan/ui/theme/colors.dart'; import 'package:hoshan/ui/theme/cubit/theme_mode_cubit.dart'; import 'package:hoshan/ui/theme/responsive.dart'; import 'package:hoshan/ui/theme/text.dart'; import 'package:hoshan/ui/widgets/components/button/loading_button.dart'; import 'package:hoshan/ui/widgets/components/chart/custome_pi_chart.dart'; import 'package:hoshan/ui/widgets/components/dialog/dialog_handler.dart'; import 'package:hoshan/ui/widgets/components/text/credit_cost.dart'; import 'package:hoshan/ui/widgets/sections/empty/empty_states.dart'; import 'package:hoshan/ui/widgets/sections/header/reversible_appbar.dart'; import 'package:shamsi_date/shamsi_date.dart'; class UtilizationReportPage extends StatefulWidget { const UtilizationReportPage({super.key}); @override State createState() => _UtilizationReportPageState(); } class _UtilizationReportPageState extends State { ValueNotifier selectedDate = ValueNotifier(DateTimeUtils.getNowJalali()); @override Widget build(BuildContext context) { return Scaffold( appBar: ReversibleAppbar( context, titleText: 'گزارش میزان مصرف', ), body: Responsive(context).builder( desktop: SingleChildScrollView( physics: const BouncingScrollPhysics(), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Column( mainAxisAlignment: MainAxisAlignment.start, children: [ const SizedBox( height: 16, ), calenderBtn(), const SizedBox( height: 16, ), Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: chartBar(), ), const SizedBox( width: 16, ), Expanded( child: piChart(context), ), ], ), ], ), ), ), mobile: SingleChildScrollView( physics: const BouncingScrollPhysics(), child: Column( children: [ const SizedBox( height: 16, ), calenderBtn(), const SizedBox( height: 16, ), chartBar(), piChart(context) ], ), ), ), ); } ValueListenableBuilder calenderBtn() { return ValueListenableBuilder( valueListenable: selectedDate, builder: (context, date, _) { return LoadingButton( onPressed: () { DialogHandler(context: context).showShamsiYearMonthPicker( initailDate: date, onDateSelected: (selectedDate) { this.selectedDate.value = selectedDate; context.read().add(GetReport( startDate: selectedDate, )); context.read().getReport( startDate: selectedDate, ); }, ); }, child: Text( '${date.formatter.mN} ${date.year}', style: AppTextStyles.body4.copyWith(color: Colors.white), )); }); } Container piChart(BuildContext context) { return Container( margin: const EdgeInsets.all(16), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface, borderRadius: BorderRadius.circular(10)), child: Column( mainAxisSize: MainAxisSize.min, children: [ Text( 'اعتبار باقی مانده', style: AppTextStyles.headline6 .copyWith(color: Theme.of(context).colorScheme.onSurface), ), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'سکه', style: AppTextStyles.body4 .copyWith(color: Theme.of(context).colorScheme.onSurface), ), const SizedBox( width: 8, ), const CreditCost(), ], ), BlocBuilder( builder: (context, state) { if (state is ReportPiCoinEmpty || state is ReportPiCoinFail) { return Container( width: Responsive(context).isDesktop() ? 400 : MediaQuery.sizeOf(context).width * 0.7, height: Responsive(context).isDesktop() ? 400 : MediaQuery.sizeOf(context).width * 0.7, margin: const EdgeInsets.symmetric(horizontal: 32), padding: const EdgeInsets.all(38), decoration: BoxDecoration( border: Border.all( color: AppColors.secondryColor.defaultShade, width: 38), shape: BoxShape.circle), child: Center( child: Text( 'داده ای موجود نیست', style: AppTextStyles.headline5.copyWith( color: Theme.of(context).colorScheme.onSurface), textAlign: TextAlign.center, ), ), ); } if (state is ReportPiCoinSuccess) { return CustomePiChart( points: state.points, ); } return Padding( padding: const EdgeInsets.all(32.0), child: SpinKitDualRing( color: AppColors.secondryColor.defaultShade, size: Responsive(context).isDesktop() ? 200 : MediaQuery.sizeOf(context).width / 3, lineWidth: Responsive(context).isDesktop() ? 50 : MediaQuery.sizeOf(context).width / 8, ), ); }, ), ], ), ); } BlocBuilder chartBar() { return BlocBuilder( builder: (context, state) { if (state is ReportOfUseSuccess) { try { int maxVal = state.reportModel.report!.fold( 100, (previousValue, report) { try { if (report.coinUsage! > previousValue) { return report.coinUsage!; } } catch (e) { if (kDebugMode) { print('Error is: $e'); } } return previousValue; }, ); maxVal = maxVal + (maxVal % 100 == 0 ? 0 : (100 - (maxVal % 100))); final List leftTitle = [0]; do { leftTitle.add((leftTitle.last + (maxVal / 5).round())); } while (leftTitle.length < 6); final points = state.reportModel.report!.map( (e) { final date = DateTimeUtils.getDateFromString(false, e.date!); return FlSpot( date.day.toDouble(), ((e.coinUsage! * 5) / maxVal)); }, ).toList(); return AspectRatio( aspectRatio: 4 / 3, child: Container( margin: const EdgeInsets.all(16), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface, borderRadius: BorderRadius.circular(10)), child: LineChart(LineChartData( borderData: FlBorderData(show: false), gridData: FlGridData( show: true, horizontalInterval: 1, verticalInterval: 5, getDrawingHorizontalLine: (value) => FlLine( color: AppColors.gray[ context.read().isDark() ? 600 : 900] .withAlpha(50), strokeWidth: 0.5), getDrawingVerticalLine: (value) => FlLine( color: AppColors.gray[ context.read().isDark() ? 600 : 900] .withAlpha(50), strokeWidth: 0.5), ), titlesData: FlTitlesData( show: true, topTitles: const AxisTitles( sideTitles: SideTitles(showTitles: false)), rightTitles: const AxisTitles( sideTitles: SideTitles(showTitles: false)), bottomTitles: AxisTitles( sideTitles: SideTitles( showTitles: true, reservedSize: 30, interval: 5, getTitlesWidget: (value, meta) { return SideTitleWidget( fitInside: SideTitleFitInsideData.fromTitleMeta(meta), axisSide: AxisSide.bottom, child: Center( child: Padding( padding: EdgeInsets.only( left: value == 30 ? 40 : 0, right: value == 1 ? 12 : 0), child: Text( value == 31 ? '' : '${value.round()}', maxLines: 1, overflow: TextOverflow.ellipsis, style: AppTextStyles.body6.copyWith( color: Theme.of(context) .colorScheme .onSurface), ), ), ), ); }, )), leftTitles: AxisTitles( sideTitles: SideTitles( showTitles: true, reservedSize: 36, interval: 1, getTitlesWidget: (value, meta) { return Padding( padding: EdgeInsets.only( top: value == 0 ? 12 : 0.0, right: 8), child: Text( value == 0 ? 'سکه\nروز' : '${leftTitle[value.round()]}', textAlign: TextAlign.start, maxLines: 2, overflow: TextOverflow.ellipsis, style: AppTextStyles.body6.copyWith( color: Theme.of(context).colorScheme.onSurface), ), ); }, ))), minX: 1, maxX: 31, minY: 0, maxY: 5, lineTouchData: LineTouchData( touchTooltipData: LineTouchTooltipData( getTooltipColor: (touchedSpot) => Theme.of(context).colorScheme.onSurface, getTooltipItems: (List touchedBarSpots) { return touchedBarSpots.map((barSpot) { final flSpot = barSpot; if (flSpot.x == 0 || flSpot.x == 6) { return null; } final date = DateTimeUtils.getDateFromString( false, state.reportModel.report![flSpot.spotIndex] .date!) .formatter; return LineTooltipItem( '${(date.wN).replaceAll(' ', '\u200C')} ${date.d} ${date.mN} \n${state.reportModel.report![flSpot.spotIndex].coinUsage ?? 0} سکه', AppTextStyles.body5.copyWith( color: Theme.of(context).colorScheme.surface, ), textDirection: TextDirection.rtl); }).toList(); }, ), ), lineBarsData: [ LineChartBarData( spots: points, isCurved: false, curveSmoothness: 0.2, gradient: LinearGradient(colors: [ Theme.of(context).colorScheme.primary, Theme.of(context).colorScheme.secondary, ]), barWidth: 1.5, isStrokeCapRound: true, dotData: const FlDotData(show: false), belowBarData: BarAreaData( show: true, gradient: LinearGradient( colors: [ Theme.of(context).colorScheme.primary, Theme.of(context).colorScheme.secondary, ] .map( (color) => color.withValues(alpha: 0.3)) .toList()))) ], backgroundColor: Theme.of(context).colorScheme.surface, )), ), ); } catch (e) { if (kDebugMode) { print('Error is: $e'); } return const SizedBox.shrink(); } } return state is ReportOfUseFail || state is ReportOfUseEmpty ? Container( margin: const EdgeInsets.all(16), decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface, borderRadius: BorderRadius.circular(10)), child: Center( child: EmptyStates.getEmptyState( scale: 0.8, status: EmptyStatesEnum.amount, title: 'داده‌ای برای نمایش وجود ندارد'), ), ) : AspectRatio( aspectRatio: 4 / 3, child: Container( margin: const EdgeInsets.all(16), decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface, borderRadius: BorderRadius.circular(10)), child: Center( child: SpinKitThreeBounce( color: Theme.of(context).colorScheme.primary, size: 46, ), ), ), ); }, ); } }