Houshan-Basa/lib/ui/screens/setting/utilization_report_page.dart

420 lines
16 KiB
Dart

// 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<UtilizationReportPage> createState() => _UtilizationReportPageState();
}
class _UtilizationReportPageState extends State<UtilizationReportPage> {
ValueNotifier<Jalali> 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<Jalali> 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<ReportOfUseBloc>().add(GetReport(
startDate: selectedDate,
));
context.read<ReportPiCoinCubit>().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<ReportPiCoinCubit, ReportPiCoinState>(
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<ReportOfUseBloc, ReportOfUseState> chartBar() {
return BlocBuilder<ReportOfUseBloc, ReportOfUseState>(
builder: (context, state) {
if (state is ReportOfUseSuccess) {
try {
int maxVal = state.reportModel.report!.fold<int>(
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<int> 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<ThemeModeCubit>().isDark()
? 600
: 900]
.withAlpha(50),
strokeWidth: 0.5),
getDrawingVerticalLine: (value) => FlLine(
color: AppColors.gray[
context.read<ThemeModeCubit>().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<LineBarSpot> 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,
),
),
),
);
},
);
}
}