import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:intl/intl.dart'; import 'package:onufitness/constants/color_constant.dart'; import 'package:onufitness/constants/text_constant.dart'; import 'package:onufitness/routes/route_constant.dart'; import 'package:onufitness/screens/home/controllers/home_controller.dart'; import 'package:onufitness/screens/home/widgets/empty_data_widget.dart'; import 'package:onufitness/screens/rise/controllers/rise_controller.dart'; import 'package:onufitness/utils/custom_sneakbar.dart'; class ChallengePieChartSection extends StatelessWidget { final FitnessController controller; final RiseController riseController; const ChallengePieChartSection({ super.key, required this.controller, required this.riseController, }); @override Widget build(BuildContext context) { return Container( padding: EdgeInsets.all(16.w), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(20.r), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.05), blurRadius: 15, offset: Offset(0, 5), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ challengePieChartHeader(context), SizedBox(height: 30.h), Obx(() { if (controller.isChallengePieChartLoading.value) { return _buildLoadingChart(); } if (controller.challengePieChartData.value.data == null || controller .challengePieChartData .value .data! .dataCount! .isEmpty || controller .challengePieChartData .value .data! .dataPercentage! .isEmpty) { return emptyChartWidget(); } return InkWell( onTap: () async { Get.toNamed( RouteConstant.challengeListScreen, arguments: {'tabIndex': 2}, ); await riseController.fetchJoinedChallenges(isRefresh: true); await riseController.fetchOngoingChallenges(isRefresh: true); await riseController.fetchUpcomingChallenges(isRefresh: true); }, child: _buildPieChart(), ); }), ], ), ); } Widget challengePieChartHeader(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Challenge Progress Overview', style: TextStyle( fontSize: mediumSizeText, fontWeight: FontWeight.w600, color: Colors.black87, ), ), SizedBox(height: 16.h), Row( children: [ Expanded(child: _buildDateButtonForChallenge(context, true)), SizedBox(width: 12.w), Icon(Icons.arrow_forward, size: 20.w, color: Colors.grey), SizedBox(width: 12.w), Expanded(child: _buildDateButtonForChallenge(context, false)), ], ), ], ); } Widget _buildDateButtonForChallenge(BuildContext context, bool isStartDate) { return Obx(() { DateTime date = isStartDate ? controller.challengePieChartStartDate.value : controller.challengePieChartEndDate.value; return InkWell( onTap: () => _selectDateForChallenge(context, isStartDate), child: Container( padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 10.h), decoration: BoxDecoration( border: Border.all(color: Colors.grey[300]!), borderRadius: BorderRadius.circular(12.r), ), child: Row( children: [ Icon(Icons.calendar_today, size: 15.w, color: Colors.grey[600]), SizedBox(width: 8.w), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( isStartDate ? 'Start Date' : 'End Date', style: TextStyle( fontSize: verySmallSizeText, color: Colors.grey[600], ), ), Text( DateFormat('MMM dd, yyyy').format(date), style: TextStyle( fontSize: verySmallSizeText, fontWeight: FontWeight.w600, color: Colors.black, ), ), ], ), ), ], ), ), ); }); } Future _selectDateForChallenge( BuildContext context, bool isStartDate, ) async { DateTime initialDate = isStartDate ? controller.challengePieChartStartDate.value : controller.challengePieChartEndDate.value; final DateTime? picked = await showDatePicker( context: context, initialDate: initialDate, firstDate: DateTime(2020), lastDate: DateTime.now(), builder: (context, child) { return Theme( data: Theme.of(context).copyWith( colorScheme: ColorScheme.light( primary: Color(primaryColor), onPrimary: Colors.white, ), ), child: child!, ); }, ); if (picked != null) { if (isStartDate) { if (picked.isBefore(controller.challengePieChartEndDate.value)) { controller.updatePieChartDateRangeForChallenge( picked, controller.challengePieChartEndDate.value, ); } else { customSnackbar( title: 'Invalid Date Range', message: 'Start date must be before end date', duration: 2, ); } } else { if (picked.isAfter(controller.challengePieChartStartDate.value)) { controller.updatePieChartDateRangeForChallenge( controller.challengePieChartStartDate.value, picked, ); } else { customSnackbar( title: 'Invalid Date Range', message: 'End date must be after start date', duration: 2, ); } } } } Widget _buildPieChart() { final data = controller.challengePieChartData.value.data!; final colors = [ Color(primaryColor), Colors.orange, Colors.blue, Colors.purple, Colors.green, Colors.red, ]; List sections = []; for (int i = 0; i < data.labels!.length; i++) { sections.add( PieChartSectionData( value: data.dataPercentage![i], title: '${data.dataPercentage![i].toStringAsFixed(2)}%', color: colors[i % colors.length], radius: 80.r, titleStyle: TextStyle( fontSize: smallSizeText, fontWeight: FontWeight.bold, color: Colors.white, ), ), ); } return Column( children: [ SizedBox( height: 250.h, child: PieChart( PieChartData( sections: sections, sectionsSpace: 2, centerSpaceRadius: 40.r, ), ), ), SizedBox(height: 30.h), _buildLegend(data.labels!, data.dataCount!, colors), ], ); } Widget _buildLegend( List labels, List counts, List colors, ) { return Wrap( spacing: 16.w, runSpacing: 12.h, children: List.generate(labels.length, (index) { return Row( mainAxisSize: MainAxisSize.min, children: [ Container( width: 16.w, height: 16.h, decoration: BoxDecoration( color: colors[index % colors.length], shape: BoxShape.circle, ), ), SizedBox(width: 8.w), Text( '${labels[index]} (${counts[index]})', style: TextStyle(fontSize: smallSizeText, color: Colors.black87), ), ], ); }), ); } Widget _buildLoadingChart() { return SizedBox( height: 350.h, child: Center( child: CircularProgressIndicator(color: Color(primaryColor)), ), ); } }