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/screens/echoboard/controllers/connection_and_tribe_controller.dart'; import 'package:onufitness/screens/echoboard/views/friend_request_screen.dart'; import 'package:onufitness/screens/home/controllers/home_controller.dart'; import 'package:onufitness/screens/home/widgets/empty_data_widget.dart'; import 'package:onufitness/utils/custom_sneakbar.dart'; class ConnectionReportSection extends StatelessWidget { final FitnessController controller; final SocialConnectionController socialConnectionController; const ConnectionReportSection({ super.key, required this.controller, required this.socialConnectionController, }); @override Widget build(BuildContext context) { return InkWell( onTap: () { Get.to(() => FriendRequestScreen(isFriendTab: true)); socialConnectionController.currentTab.value = "Friends"; socialConnectionController.changeTab("Friends"); }, child: 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: [ connectionChartHeader(context), SizedBox(height: 20.h), Obx(() { if (controller.isConnectionReportLoading.value) { return _buildLoadingChart(); } if (controller.connectionReport.value.data == null || controller.connectionReport.value.data!.isEmpty) { return emptyChartWidget(); } return _buildChart(); }), ], ), ), ); } Widget connectionChartHeader(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Connection Report', style: TextStyle( fontSize: mediumSizeText, fontWeight: FontWeight.w600, color: Colors.black87, ), ), SizedBox(height: 16.h), Row( children: [ Expanded(child: dateButtonsForConnectionChart(context, true)), SizedBox(width: 12.w), Icon(Icons.arrow_forward, size: 20.w, color: Colors.grey), SizedBox(width: 12.w), Expanded(child: dateButtonsForConnectionChart(context, false)), ], ), ], ); } Widget dateButtonsForConnectionChart(BuildContext context, bool isStartDate) { return Obx(() { DateTime date = isStartDate ? controller.startDate.value : controller.endDate.value; return InkWell( onTap: () => _selectDate(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.black87, ), ), ], ), ), ], ), ), ); }); } Future _selectDate(BuildContext context, bool isStartDate) async { DateTime initialDate = isStartDate ? controller.startDate.value : controller.endDate.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) { final daysDifference = controller.endDate.value.difference(picked).inDays; if (daysDifference >= 7) { controller.updateDateRange(picked, controller.endDate.value); } else { customSnackbar( title: 'Invalid Date Range', message: 'There must be at least 7 days gap between start and end date', duration: 2, ); } } else { final daysDifference = picked.difference(controller.startDate.value).inDays; if (daysDifference >= 7) { controller.updateDateRange(controller.startDate.value, picked); } else { customSnackbar( title: 'Invalid Date Range', message: 'There must be at least 7 days gap between start and end date', duration: 2, ); } } } } double _calculateInterval(double maxValue) { if (maxValue <= 10) return 2; if (maxValue <= 25) return 5; if (maxValue <= 50) return 10; if (maxValue <= 100) return 20; if (maxValue <= 200) return 40; if (maxValue <= 500) return 100; return (maxValue / 5).ceilToDouble(); } Widget _buildChart() { final data = controller.connectionReport.value.data!; final maxConnections = data .map((e) => e.totalConnections ?? 0) .reduce((a, b) => a > b ? a : b) .toDouble(); final interval = _calculateInterval(maxConnections); final maxY = ((maxConnections / interval).ceil() + 1) * interval; final double itemWidth = 70.w; final double chartWidth = data.length * itemWidth; final double minWidth = Get.width - 100.w; return SizedBox( height: 250.h, child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: Container( width: chartWidth > minWidth ? chartWidth : minWidth, padding: EdgeInsets.only(top: 10.h, right: 20.w), child: LineChart( LineChartData( gridData: FlGridData(show: false), titlesData: FlTitlesData( leftTitles: AxisTitles( sideTitles: SideTitles( showTitles: true, reservedSize: 45.w, interval: interval, getTitlesWidget: (value, meta) { return Text( '${value.toInt()}', style: TextStyle( fontSize: verySmallSizeText, color: Colors.grey[400], fontWeight: FontWeight.w400, ), ); }, ), ), bottomTitles: AxisTitles( sideTitles: SideTitles( showTitles: true, reservedSize: 45.h, interval: 1, getTitlesWidget: (value, meta) { if (value.toInt() >= 0 && value.toInt() < data.length) { final date = data[value.toInt()].date; if (date != null) { String label = DateFormat('MMM dd').format(date); return Padding( padding: EdgeInsets.only(top: 8.h), child: Text( label, style: TextStyle( fontSize: verySmallSizeText, color: Colors.grey[400], fontWeight: FontWeight.w400, ), textAlign: TextAlign.center, ), ); } } return SizedBox.shrink(); }, ), ), topTitles: AxisTitles( sideTitles: SideTitles(showTitles: false), ), rightTitles: AxisTitles( sideTitles: SideTitles(showTitles: false), ), ), borderData: FlBorderData(show: false), lineBarsData: [ LineChartBarData( spots: data .asMap() .entries .map( (e) => FlSpot( e.key.toDouble(), (e.value.totalConnections ?? 0).toDouble(), ), ) .toList(), isCurved: true, curveSmoothness: 0.35, color: Color(primaryColor), barWidth: 3.w, dotData: FlDotData(show: false), belowBarData: BarAreaData( show: true, gradient: LinearGradient( colors: [ Color(primaryColor), Color(primaryColor).withValues(alpha: 0.3), Color(primaryColor).withValues(alpha: 0.1), ], begin: Alignment.topCenter, end: Alignment.bottomCenter, ), ), ), ], minY: 0, maxY: maxY, ), ), ), ), ); } Widget _buildLoadingChart() { return SizedBox( height: 250.h, child: Center( child: CircularProgressIndicator(color: Color(primaryColor)), ), ); } }