From 23c290a9b86a489b623d2768b2c3bfaf17080e22 Mon Sep 17 00:00:00 2001 From: venbaittech Date: Mon, 24 Mar 2025 17:46:45 +0530 Subject: [PATCH] charts and bugs fix --- android/app/build.gradle | 4 +- .../Screens/charts/widgets/chart_widget.dart | 2929 +++++++++-------- .../drawer_routes/Drawer Items/feedback.dart | 7 +- .../notification/notification.dart | 32 +- pubspec.yaml | 2 +- 5 files changed, 1570 insertions(+), 1404 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 85b1ce96..4d3532ef 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -20,12 +20,12 @@ if (project.hasProperty('google-services.json')) { def flutterVersionCode = localProperties.getProperty("flutter.versionCode") if (flutterVersionCode == null) { - flutterVersionCode = "42" + flutterVersionCode = "43" } def flutterVersionName = localProperties.getProperty("flutter.versionName") if (flutterVersionName == null) { - flutterVersionName = "1.0.41" + flutterVersionName = "1.0.42" } def keystorePropertiesFile = rootProject.file("key.properties") diff --git a/lib/presentation/Screens/charts/widgets/chart_widget.dart b/lib/presentation/Screens/charts/widgets/chart_widget.dart index cc917b4c..195daf1a 100644 --- a/lib/presentation/Screens/charts/widgets/chart_widget.dart +++ b/lib/presentation/Screens/charts/widgets/chart_widget.dart @@ -7,12 +7,12 @@ import 'package:flutter/material.dart'; // import 'package:syncfusion_flutter_charts/charts.dart'; class ChartWidget extends StatelessWidget { - ChartWidget( - {Key? key, - required this.chartData, - required this.bodyColor, - required this.chartHeader}) - : super(key: key); + ChartWidget({ + Key? key, + required this.chartData, + required this.bodyColor, + required this.chartHeader, + }) : super(key: key); final dynamic chartData; final Color bodyColor; final String chartHeader; @@ -71,41 +71,20 @@ class ChartWidget extends StatelessWidget { }; final Map> colorMapForThree = { - "ECONOMY": [ - Color(0xFF648CBA), - Color(0xFF90B0D5), - Color(0xFF98BCE5), - ], - "SOCIAL": [ - Color(0xFFD9BB99), - Color(0xFF87766E), - Color(0xFFC6A885), - ], - "ENVIRONMENT": [ - Color(0xFF376C79), - Color(0xFF578D9C), - Color(0xFF7DAFBC), - ], + "ECONOMY": [Color(0xFF648CBA), Color(0xFF90B0D5), Color(0xFF98BCE5)], + "SOCIAL": [Color(0xFFD9BB99), Color(0xFF87766E), Color(0xFFC6A885)], + "ENVIRONMENT": [Color(0xFF376C79), Color(0xFF578D9C), Color(0xFF7DAFBC)], }; // Define color lists final Map> colorMapForTwo = { - "ECONOMY": [ - Color(0xFF648CBA), - Color(0xFF90B0D5), - ], - "SOCIAL": [ - Color(0xFFD9BB99), - Color(0xFF87766E), - ], - "ENVIRONMENT": [ - Color(0xFF376C79), - Color(0xFF578D9C), - ], + "ECONOMY": [Color(0xFF648CBA), Color(0xFF90B0D5)], + "SOCIAL": [Color(0xFFD9BB99), Color(0xFF87766E)], + "ENVIRONMENT": [Color(0xFF376C79), Color(0xFF578D9C)], }; // List get uniqueColors => colorMap[chartHeader] ?? [Colors.grey]; // Default to grey if header is unknown -// Function to get colors for both English & Arabic keys + // Function to get colors for both English & Arabic keys List get uniqueColors { final Map translations = { 'اقتصاد': 'ECONOMY', @@ -211,21 +190,26 @@ class ChartWidget extends StatelessWidget { } else if (chartConversion == 'K') { return '${(baseValue / 1e3).toStringAsFixed(2)}K'; // Convert to Thousand } else { - return baseValue - .toStringAsFixed(2); // Default: Show value with 2 decimals + return baseValue.toStringAsFixed( + 2, + ); // Default: Show value with 2 decimals } } List parseStackedBarChartData( - dynamic chartData, String groupByKey, String groupByValue) { + dynamic chartData, + String groupByKey, + String groupByValue, + ) { return chartData['response'] .where((entry) => entry['ObsKey'][groupByKey] == groupByValue) .map((entry) { - return ChartData( - x: entry['ObsKey']['TIME_PERIOD'], - y: double.tryParse(entry['ObsValue']['Value']) ?? 0.0, - ); - }).toList(); + return ChartData( + x: entry['ObsKey']['TIME_PERIOD'], + y: double.tryParse(entry['ObsValue']['Value']) ?? 0.0, + ); + }) + .toList(); } List parseColumnChartData(dynamic chartData) { @@ -273,8 +257,10 @@ class ChartWidget extends StatelessWidget { lightnessFactor = lightnessFactor.clamp(0.3, 0.7); // Keeps colors darker // Adjust opacity: Making it darker with alpha between 160-230 - int alphaFactor = - (230 - (index % 4) * 20).clamp(160, 230); // Darker opacity + int alphaFactor = (230 - (index % 4) * 20).clamp( + 160, + 230, + ); // Darker opacity return hsl .withLightness(lightnessFactor) @@ -289,10 +275,9 @@ class ChartWidget extends StatelessWidget { ) { debugPrint('Chart Data: ${jsonEncode(chartData)}'); - return chartData['response'] - .asMap() - .entries - .map((entry) { + return chartData['response'].asMap().entries.map(( + entry, + ) { int index = entry.key; var data = entry.value; @@ -320,12 +305,12 @@ class ChartWidget extends StatelessWidget { // color: adjustColor(bodyColor, index), // Adjust alpha dynamically color: uniqueColors[index % uniqueColors.length], // title: '${percentage.toStringAsFixed(1)}%', - title: percentage > 1 ? '${percentage.toStringAsFixed(1)}%' : '', + title: percentage >= 0.1 ? '${percentage.toStringAsFixed(1)}%' : '', radius: isTouched ? 70 : 50, // Increase size when touched titleStyle: TextStyle( - fontSize: isTouched ? 12 : 10, + fontSize: isTouched ? 12 : (percentage < 1 ? 10 : 11), fontWeight: FontWeight.bold, color: Colors.black, // color: Colors.white, @@ -395,10 +380,7 @@ class ChartWidget extends StatelessWidget { // ]; // } - List generateIndicators( - dynamic chartData, - double totalValue, - ) { + List generateIndicators(dynamic chartData, double totalValue) { var groupByKeyValue; if (chartData['chart_type_json']['chart_type'] == 'bar_chart_horizontal' || chartData['chart_type_json']['chart_type'] == 'horizontal_rotate') { @@ -430,9 +412,10 @@ class ChartWidget extends StatelessWidget { } // double percentage = (value / totalValue) * 100; - String percentage = (totalValue > 0) - ? ((value / totalValue) * 100).toStringAsFixed(1) - : "0.0"; + String percentage = + (totalValue > 0) + ? ((value / totalValue) * 100).toStringAsFixed(1) + : "0.0"; // bool isTouched = index == touchedIndex; return Row( @@ -451,8 +434,9 @@ class ChartWidget extends StatelessWidget { data: TooltipThemeData( decoration: BoxDecoration( color: Colors.blueGrey[800], // Change background color - borderRadius: - BorderRadius.circular(8), // Optional: rounded corners + borderRadius: BorderRadius.circular( + 8, + ), // Optional: rounded corners ), textStyle: TextStyle(color: Colors.white), // Change text color ), @@ -463,9 +447,7 @@ class ChartWidget extends StatelessWidget { constraints: BoxConstraints(maxWidth: 250), child: Text( '$title -- $percentage%', - style: TextStyle( - fontSize: 12, - ), + style: TextStyle(fontSize: 12), softWrap: true, maxLines: 2, // overflow: TextOverflow.ellipsis, // Ensures text doesn't overflow @@ -480,7 +462,9 @@ class ChartWidget extends StatelessWidget { } List generateIndicatorsBar( - Map chartData, List groupByValues) { + Map chartData, + List groupByValues, + ) { List indicators = []; for (int i = 0; i < groupByValues.length; i++) { @@ -634,15 +618,17 @@ class ChartWidget extends StatelessWidget { ), ); case 'pie_chart': - double totalValue = chartData['response'].map((entry) { - var value = entry['ObsValue']['Value']; - // print('Processing value: $value, type: ${value.runtimeType}'); - return (value is num) - ? value.toDouble() - : value is String + double totalValue = chartData['response'] + .map((entry) { + var value = entry['ObsValue']['Value']; + // print('Processing value: $value, type: ${value.runtimeType}'); + return (value is num) + ? value.toDouble() + : value is String ? double.tryParse(value) ?? 0.0 : 0.0; - }).fold(0.0, (prev, element) => prev + element); + }) + .fold(0.0, (prev, element) => prev + element); ValueNotifier touchedIndex = ValueNotifier(null); @@ -651,19 +637,13 @@ class ChartWidget extends StatelessWidget { Text( chartData['chart_heading'] ?? 'Pie Chart', // Chart title from data - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w400, - ), + style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400), textAlign: TextAlign.center, ), SizedBox(height: 15), Text( chartData['chart_sub_heading'] ?? '', - style: TextStyle( - fontSize: 13, - fontWeight: FontWeight.w300, - ), + style: TextStyle(fontSize: 13, fontWeight: FontWeight.w300), textAlign: TextAlign.center, ), SizedBox(height: 70), @@ -674,7 +654,10 @@ class ChartWidget extends StatelessWidget { return PieChart( PieChartData( sections: parsePieChartData( - chartData, totalValue, touchedIndex.value), + chartData, + totalValue, + touchedIndex.value, + ), borderData: FlBorderData(show: false), sectionsSpace: 2, centerSpaceRadius: 50, @@ -682,8 +665,10 @@ class ChartWidget extends StatelessWidget { touchCallback: (FlTouchEvent event, pieTouchResponse) { if (pieTouchResponse?.touchedSection != null && event is! FlTapUpEvent) { - touchedIndex.value = pieTouchResponse! - .touchedSection!.touchedSectionIndex; + touchedIndex.value = + pieTouchResponse! + .touchedSection! + .touchedSectionIndex; } else { touchedIndex.value = null; // Reset when not touching @@ -706,11 +691,16 @@ class ChartWidget extends StatelessWidget { child: Center( child: Container( width: double.infinity, - constraints: - BoxConstraints(minHeight: 3), // Allow dynamic height + constraints: BoxConstraints( + minHeight: 3, + ), // Allow dynamic height child: Padding( padding: const EdgeInsets.only( - left: 2.0, right: 2.0, bottom: 8.0, top: 30), + left: 2.0, + right: 2.0, + bottom: 8.0, + top: 30, + ), child: Column( // Change Row to Column crossAxisAlignment: CrossAxisAlignment.start, @@ -732,29 +722,24 @@ class ChartWidget extends StatelessWidget { for (int i = 0; i < groupByValuesList.length; i += chunkSize) { chunkedGroupByValues.add( groupByValuesList.sublist( - i, - i + chunkSize > groupByValuesList.length - ? groupByValuesList.length - : i + chunkSize), + i, + i + chunkSize > groupByValuesList.length + ? groupByValuesList.length + : i + chunkSize, + ), ); } return Column( children: [ Text( chartData['chart_heading'] ?? '', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w400, - ), + style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400), textAlign: TextAlign.center, ), SizedBox(height: 5), Text( chartData['chart_sub_heading'] ?? '', - style: TextStyle( - fontSize: 13, - fontWeight: FontWeight.w300, - ), + style: TextStyle(fontSize: 13, fontWeight: FontWeight.w300), textAlign: TextAlign.center, ), SizedBox(height: 15), @@ -770,12 +755,18 @@ class ChartWidget extends StatelessWidget { fitInsideVertically: true, // tooltipPadding: const EdgeInsets.all(8), tooltipPadding: const EdgeInsets.symmetric( - horizontal: 4, vertical: 8), // Optional + horizontal: 4, + vertical: 8, + ), // Optional tooltipHorizontalAlignment: FLHorizontalAlignment.left, tooltipMargin: 16, getTooltipColor: (colorMap) => Colors.black, - getTooltipItem: - (groupData, groupIndex, rodData, rodIndex) { + getTooltipItem: ( + groupData, + groupIndex, + rodData, + rodIndex, + ) { // Get the list of group names dynamically List groupNames = []; @@ -805,24 +796,29 @@ class ChartWidget extends StatelessWidget { (value / 1000).toStringAsFixed(1) + 'K'; } else { formattedValue = value.toStringAsFixed( - 0); // for values smaller than 1000 + 0, + ); // for values smaller than 1000 } // Get the color for the current group Color groupColor = _getColorForGroup( - i); // Replace with your color logic + i, + ); // Replace with your color logic // Add a TextSpan for the colored circle and the group name with value tooltipTextSpans.addAll([ TextSpan( text: ' ● ', style: TextStyle( - color: groupColor, - fontSize: 14), // Circle color + color: groupColor, + fontSize: 14, + ), // Circle color ), TextSpan( text: '$groupName - $formattedValue\n', - style: - TextStyle(color: Colors.white, fontSize: 12), + style: TextStyle( + color: Colors.white, + fontSize: 12, + ), ), ]); } @@ -855,10 +851,12 @@ class ChartWidget extends StatelessWidget { getTitlesWidget: _generateLeftTitles, ), ), - topTitles: - AxisTitles(sideTitles: SideTitles(showTitles: false)), - rightTitles: - AxisTitles(sideTitles: SideTitles(showTitles: false)), + topTitles: AxisTitles( + sideTitles: SideTitles(showTitles: false), + ), + rightTitles: AxisTitles( + sideTitles: SideTitles(showTitles: false), + ), ), gridData: FlGridData(show: false), borderData: FlBorderData(show: false), @@ -872,49 +870,50 @@ class ChartWidget extends StatelessWidget { child: Wrap( spacing: 10, // Horizontal spacing between items runSpacing: 5, // Vertical spacing between rows - children: chunkedGroupByValues.expand((chunk) { - return chunk.map((group) { - List groupByValuesList = groupByValues.toList(); - int index = groupByValuesList.indexOf(group); - Color groupColor = _getColorForGroup(index); + children: + chunkedGroupByValues.expand((chunk) { + return chunk.map((group) { + List groupByValuesList = groupByValues.toList(); + int index = groupByValuesList.indexOf(group); + Color groupColor = _getColorForGroup(index); - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - width: 10, - height: 10, - decoration: BoxDecoration( - color: groupColor, - shape: BoxShape.circle, - ), - ), - SizedBox(width: 5), - Tooltip( - message: group, - waitDuration: Duration(milliseconds: 500), - showDuration: Duration(seconds: 2), - decoration: BoxDecoration( - color: Colors.black, - // color: Colors.blueGrey[900], - borderRadius: BorderRadius.circular(4), - ), - textStyle: TextStyle(color: Colors.white), - child: Text( - group, - // group.length > 10 - // ? '${group.substring(0, 10)}...' - // : group, - // overflow: TextOverflow.ellipsis, - style: TextStyle(fontSize: 11), - ), - ) - ], - ); - }).toList(); - }).toList(), + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: 10, + height: 10, + decoration: BoxDecoration( + color: groupColor, + shape: BoxShape.circle, + ), + ), + SizedBox(width: 5), + Tooltip( + message: group, + waitDuration: Duration(milliseconds: 500), + showDuration: Duration(seconds: 2), + decoration: BoxDecoration( + color: Colors.black, + // color: Colors.blueGrey[900], + borderRadius: BorderRadius.circular(4), + ), + textStyle: TextStyle(color: Colors.white), + child: Text( + group, + // group.length > 10 + // ? '${group.substring(0, 10)}...' + // : group, + // overflow: TextOverflow.ellipsis, + style: TextStyle(fontSize: 11), + ), + ), + ], + ); + }).toList(); + }).toList(), ), - ) + ), ], ); case 'line_trend': @@ -939,15 +938,18 @@ class ChartWidget extends StatelessWidget { print('LnTrnd1'); // Extract all years from the chart data - List years = (chartData['response'] as List) - .map((entry) => - int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0) - .toList(); + List years = + (chartData['response'] as List) + .map( + (entry) => + int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0, + ) + .toList(); // Sort in ascending order years.sort(); -// Sort in descending order -// years.sort((a, b) => b.compareTo(a)); + // Sort in descending order + // years.sort((a, b) => b.compareTo(a)); print(years); @@ -972,9 +974,10 @@ class ChartWidget extends StatelessWidget { // Filter chart data to only include entries within the last 5 years List filteredData = (chartData['response'] as List).where((entry) { - int year = int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0; - return year >= minYear && year <= maxYear; - }).toList(); + int year = + int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0; + return year >= minYear && year <= maxYear; + }).toList(); print('LnTrnd2 $filteredData'); // Set uniqueXValues = filteredData @@ -982,31 +985,32 @@ class ChartWidget extends StatelessWidget { // (entry) => double.parse(entry['ObsKey']['TIME_PERIOD'])) // .toSet(); - Set uniqueXValues = filteredData.map((entry) { - String? timePeriod = - entry['ObsKey']['TIME_PERIOD']; // Nullable String - print('TIME_PERIOD- $timePeriod'); + Set uniqueXValues = + filteredData.map((entry) { + String? timePeriod = + entry['ObsKey']['TIME_PERIOD']; // Nullable String + print('TIME_PERIOD- $timePeriod'); - if (timePeriod == null) { - print('TIME_PERIOD is null'); - return ''; // Or handle the null case appropriately - } + if (timePeriod == null) { + print('TIME_PERIOD is null'); + return ''; // Or handle the null case appropriately + } - // Check format using regex - if (RegExp(r'^\d{4}$').hasMatch(timePeriod)) { - print('Year format detected: $timePeriod'); - return timePeriod; // Year only - } else if (RegExp(r'^\d{4}-\d{2}$').hasMatch(timePeriod)) { - print('Year-Month format detected: $timePeriod'); - return timePeriod; // Year-Month - } else if (RegExp(r'^\d{4}-[A-Za-z]{3}$').hasMatch(timePeriod)) { - print('Year-MonthAbbr format detected: $timePeriod'); - return timePeriod; // Year-MonthAbbr - } else { - print('Unknown format: $timePeriod'); - return timePeriod; // Keep it as is - } - }).toSet(); + // Check format using regex + if (RegExp(r'^\d{4}$').hasMatch(timePeriod)) { + print('Year format detected: $timePeriod'); + return timePeriod; // Year only + } else if (RegExp(r'^\d{4}-\d{2}$').hasMatch(timePeriod)) { + print('Year-Month format detected: $timePeriod'); + return timePeriod; // Year-Month + } else if (RegExp(r'^\d{4}-[A-Za-z]{3}$').hasMatch(timePeriod)) { + print('Year-MonthAbbr format detected: $timePeriod'); + return timePeriod; // Year-MonthAbbr + } else { + print('Unknown format: $timePeriod'); + return timePeriod; // Keep it as is + } + }).toSet(); print("Unique X Values: $uniqueXValues"); @@ -1015,8 +1019,9 @@ class ChartWidget extends StatelessWidget { if (RegExp(r'^\d{4}$').hasMatch(timePeriod)) { return double.parse(timePeriod); // Year-only (2019 → 2019.0) } else if (RegExp(r'^\d{4}-\d{2}$').hasMatch(timePeriod)) { - return double.parse(timePeriod.replaceAll( - '-', '.')); // Year-Month (2019-11 → 2019.11) + return double.parse( + timePeriod.replaceAll('-', '.'), + ); // Year-Month (2019-11 → 2019.11) } else if (RegExp(r'^\d{4}-[A-Za-z]{3}$').hasMatch(timePeriod)) { // Year-MonthAbbr (2019-Nov) Map monthMap = { @@ -1031,23 +1036,25 @@ class ChartWidget extends StatelessWidget { 'Sep': 9, 'Oct': 10, 'Nov': 11, - 'Dec': 12 + 'Dec': 12, }; List parts = timePeriod.split('-'); int month = monthMap[parts[1]] ?? 1; // Default to January if unknown return double.parse( - '${parts[0]}.$month'); // Convert to format (2019-Nov → 2019.11) + '${parts[0]}.$month', + ); // Convert to format (2019-Nov → 2019.11) } throw FormatException("Invalid TIME_PERIOD format: $timePeriod"); } - Set uniqueXValuesProcessed = uniqueXValues - .where((value) => value.isNotEmpty) // Remove any empty strings - .map(parseTimePeriod) - .toSet(); + Set uniqueXValuesProcessed = + uniqueXValues + .where((value) => value.isNotEmpty) // Remove any empty strings + .map(parseTimePeriod) + .toSet(); print('Processed X Values: $uniqueXValuesProcessed'); print('LnTrnd2.1'); @@ -1062,12 +1069,15 @@ class ChartWidget extends StatelessWidget { var chartBarColorsRaw = chartData['chart_bar_color'] ?? {}; // Convert LinkedMap to Map - Map chartBarColrs = - Map.from(chartBarColorsRaw); + Map chartBarColrs = Map.from( + chartBarColorsRaw, + ); // Now map to Color - Map parsedChartBarColors = - chartBarColrs.map((key, value) { + Map parsedChartBarColors = chartBarColrs.map(( + key, + value, + ) { return MapEntry(key, _hexToColor(value)); }); @@ -1086,79 +1096,79 @@ class ChartWidget extends StatelessWidget { // Generate line bars for the chart List lineBars = lineBarsData( - filteredData, groupByValues, groupByKey, parsedChartBarColors); + filteredData, + groupByValues, + groupByKey, + parsedChartBarColors, + ); print('LnTrnd3'); - return Column(children: [ - Text( - chartData['chart_heading'] ?? '', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w400, + return Column( + children: [ + Text( + chartData['chart_heading'] ?? '', + style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400), + textAlign: TextAlign.center, ), - textAlign: TextAlign.center, - ), - SizedBox(height: 5), - Text( - chartData['chart_sub_heading'] ?? '', - style: TextStyle( - fontSize: 13, - fontWeight: FontWeight.w300, + SizedBox(height: 5), + Text( + chartData['chart_sub_heading'] ?? '', + style: TextStyle(fontSize: 13, fontWeight: FontWeight.w300), + textAlign: TextAlign.center, ), - textAlign: TextAlign.center, - ), - SizedBox(height: 10), - // Chart - Expanded( - child: LineChart(LineChartData( - // showingTooltipIndicators: showingTooltipOnSpots.map((index) { - // return ShowingTooltipIndicators([ - // LineBarSpot( - // tooltipsOnBar, - // lineBarsData.indexOf(tooltipsOnBar), - // tooltipsOnBar.spots[index], - // ), - // ]); - // }).toList(), - - lineTouchData: lineTouchData1(), - gridData: gridData(), - // titlesData: titlesData1(uniqueXValues), - titlesData: titlesData1(uniqueXValuesProcessed), - borderData: borderData(), - lineBarsData: lineBars, - // minY: 10000, - // minX: uniqueXValues.reduce((a, b) => a < b ? a : b), - // maxX: uniqueXValues.reduce((a, b) => a > b ? a : b), - // minX: uniqueXValuesProcessed.reduce((a, b) => a < b ? a : b), - // maxX: uniqueXValuesProcessed.reduce((a, b) => a > b ? a : b), - ))), - Padding( - padding: const EdgeInsets.all(8.0), - child: Wrap( - spacing: 12, - runSpacing: 8, - children: groupByValues.map((group) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - width: 12, - height: 12, - color: groupColorMap[group], - ), - SizedBox(width: 6), - Text( - group, - style: TextStyle(fontSize: 14), - ), - ], - ); - }).toList(), + SizedBox(height: 10), + // Chart + Expanded( + child: LineChart( + LineChartData( + // showingTooltipIndicators: showingTooltipOnSpots.map((index) { + // return ShowingTooltipIndicators([ + // LineBarSpot( + // tooltipsOnBar, + // lineBarsData.indexOf(tooltipsOnBar), + // tooltipsOnBar.spots[index], + // ), + // ]); + // }).toList(), + lineTouchData: lineTouchData1(), + gridData: gridData(), + // titlesData: titlesData1(uniqueXValues), + titlesData: titlesData1(uniqueXValuesProcessed), + borderData: borderData(), + lineBarsData: lineBars, + // minY: 10000, + // minX: uniqueXValues.reduce((a, b) => a < b ? a : b), + // maxX: uniqueXValues.reduce((a, b) => a > b ? a : b), + // minX: uniqueXValuesProcessed.reduce((a, b) => a < b ? a : b), + // maxX: uniqueXValuesProcessed.reduce((a, b) => a > b ? a : b), + ), + ), ), - ), - ]); + Padding( + padding: const EdgeInsets.all(8.0), + child: Wrap( + spacing: 12, + runSpacing: 8, + children: + groupByValues.map((group) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: 12, + height: 12, + color: groupColorMap[group], + ), + SizedBox(width: 6), + Text(group, style: TextStyle(fontSize: 14)), + ], + ); + }).toList(), + ), + ), + ], + ); case 'line_trend_population': final List uniqueColorsLine_trend_2 = [ Color(0xFF6097CD), @@ -1175,10 +1185,13 @@ class ChartWidget extends StatelessWidget { // } // Extract all years from the chart data - List years = (chartData['response'] as List) - .map((entry) => - int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0) - .toList(); + List years = + (chartData['response'] as List) + .map( + (entry) => + int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0, + ) + .toList(); if (years.isEmpty) { // Return an empty chart if no data @@ -1199,14 +1212,17 @@ class ChartWidget extends StatelessWidget { // Filter chart data to include only the selected years List filteredData = (chartData['response'] as List).where((entry) { - int year = int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0; - return selectedYears.contains(year); - }).toList(); + int year = + int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0; + return selectedYears.contains(year); + }).toList(); - Set uniqueXValues = filteredData - .map( - (entry) => double.parse(entry['ObsKey']['TIME_PERIOD'])) - .toSet(); + Set uniqueXValues = + filteredData + .map( + (entry) => double.parse(entry['ObsKey']['TIME_PERIOD']), + ) + .toSet(); var chartBarColors = chartData['chart_bar_color'] ?? {}; Map barColorsMap = {}; @@ -1235,8 +1251,9 @@ class ChartWidget extends StatelessWidget { // Convert to a map for easy lookup Map parsedChartBarColors = {}; for (int i = 0; i < keys.length; i++) { - parsedChartBarColors[keys[i].toString()] = - _hexToColor(colors[i].toString()); + parsedChartBarColors[keys[i].toString()] = _hexToColor( + colors[i].toString(), + ); } print('RTLinr1 - $parsedChartBarColors'); @@ -1253,73 +1270,74 @@ class ChartWidget extends StatelessWidget { // Generate line bars for the chart List lineBars = lineBarsData( - filteredData, groupByValues, groupByKey, parsedChartBarColors); + filteredData, + groupByValues, + groupByKey, + parsedChartBarColors, + ); - return Column(children: [ - Text( - chartData['chart_heading'] ?? '', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w400, + return Column( + children: [ + Text( + chartData['chart_heading'] ?? '', + style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400), + textAlign: TextAlign.center, ), - textAlign: TextAlign.center, - ), - SizedBox(height: 5), - Text( - chartData['chart_sub_heading'] ?? '', - style: TextStyle( - fontSize: 13, - fontWeight: FontWeight.w300, + SizedBox(height: 5), + Text( + chartData['chart_sub_heading'] ?? '', + style: TextStyle(fontSize: 13, fontWeight: FontWeight.w300), + textAlign: TextAlign.center, ), - textAlign: TextAlign.center, - ), - SizedBox(height: 10), + SizedBox(height: 10), - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, // Enable horizontal scrolling - padding: const EdgeInsets.only(right: 40, top: 10), - child: SizedBox( - width: (uniqueXValues.length * 50) + - 50, // Adjust width dynamically - child: LineChart(LineChartData( - lineTouchData: lineTouchData1(), - gridData: gridData(), - titlesData: titlesData1(uniqueXValues), - borderData: borderData(), - lineBarsData: lineBars, - minX: uniqueXValues.reduce((a, b) => a < b ? a : b), - maxX: uniqueXValues.reduce((a, b) => a > b ? a : b), - )), + Expanded( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, // Enable horizontal scrolling + padding: const EdgeInsets.only(right: 40, top: 10), + child: SizedBox( + width: + (uniqueXValues.length * 50) + + 50, // Adjust width dynamically + child: LineChart( + LineChartData( + lineTouchData: lineTouchData1(), + gridData: gridData(), + titlesData: titlesData1(uniqueXValues), + borderData: borderData(), + lineBarsData: lineBars, + minX: uniqueXValues.reduce((a, b) => a < b ? a : b), + maxX: uniqueXValues.reduce((a, b) => a > b ? a : b), + ), + ), + ), ), ), - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Wrap( - spacing: 12, - runSpacing: 8, - children: groupByValues.map((group) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - width: 12, - height: 12, - color: groupColorMap[group], - ), - SizedBox(width: 6), - Text( - group, - style: TextStyle(fontSize: 14), - ), - ], - ); - }).toList(), + Padding( + padding: const EdgeInsets.all(8.0), + child: Wrap( + spacing: 12, + runSpacing: 8, + children: + groupByValues.map((group) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: 12, + height: 12, + color: groupColorMap[group], + ), + SizedBox(width: 6), + Text(group, style: TextStyle(fontSize: 14)), + ], + ); + }).toList(), + ), ), - ) - // Chart - ]); + // Chart + ], + ); case 'line_trend_2': // final List uniqueColorsLine_trend_2 = [ // Color(0xFF6097CD), @@ -1341,10 +1359,13 @@ class ChartWidget extends StatelessWidget { // } // Extract all years from the chart data - List years = (chartData['response'] as List) - .map((entry) => - int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0) - .toList(); + List years = + (chartData['response'] as List) + .map( + (entry) => + int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0, + ) + .toList(); if (years.isEmpty) { // Return an empty chart if no data @@ -1362,17 +1383,20 @@ class ChartWidget extends StatelessWidget { selectedYears.add(latestYear); // Include the latest year in selection } -// Filter chart data to include only the selected years + // Filter chart data to include only the selected years List filteredData = (chartData['response'] as List).where((entry) { - int year = int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0; - return selectedYears.contains(year); - }).toList(); + int year = + int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0; + return selectedYears.contains(year); + }).toList(); - Set uniqueXValues = filteredData - .map( - (entry) => double.parse(entry['ObsKey']['TIME_PERIOD'])) - .toSet(); + Set uniqueXValues = + filteredData + .map( + (entry) => double.parse(entry['ObsKey']['TIME_PERIOD']), + ) + .toSet(); print('uniqueXValuesLineTrend2- $uniqueXValues'); @@ -1386,12 +1410,15 @@ class ChartWidget extends StatelessWidget { var chartBarColorsRaw = chartData['chart_bar_color'] ?? {}; // Convert LinkedMap to Map - Map chartBarColrs = - Map.from(chartBarColorsRaw); + Map chartBarColrs = Map.from( + chartBarColorsRaw, + ); // Now map to Color - Map parsedChartBarColors = - chartBarColrs.map((key, value) { + Map parsedChartBarColors = chartBarColrs.map(( + key, + value, + ) { return MapEntry(key, _hexToColor(value)); }); @@ -1409,49 +1436,46 @@ class ChartWidget extends StatelessWidget { // Generate line bars for the chart List lineBars = lineBarsData2(filteredData); - return Column(children: [ - Text( - chartData['chart_heading'] ?? '', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w400, + return Column( + children: [ + Text( + chartData['chart_heading'] ?? '', + style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400), + textAlign: TextAlign.center, ), - textAlign: TextAlign.center, - ), - SizedBox(height: 5), - Text( - '', - style: TextStyle( - fontSize: 13, - fontWeight: FontWeight.w300, + SizedBox(height: 5), + Text( + '', + style: TextStyle(fontSize: 13, fontWeight: FontWeight.w300), + textAlign: TextAlign.center, ), - textAlign: TextAlign.center, - ), - SizedBox(height: 10), - // Chart - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, // Enable horizontal scrolling - padding: const EdgeInsets.only(right: 40, top: 20), - child: SizedBox( - width: (uniqueXValues.length * 50) + - 50, // Adjust width dynamically - child: LineChart( - LineChartData( - lineTouchData: lineTouchData1(), - gridData: gridData(), - titlesData: titlesData1(uniqueXValues), - borderData: borderData(), - lineBarsData: lineBars, - minX: uniqueXValues.reduce((a, b) => a < b ? a : b), - maxX: uniqueXValues.reduce((a, b) => a > b ? a : b), - minY: 0, + SizedBox(height: 10), + // Chart + Expanded( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, // Enable horizontal scrolling + padding: const EdgeInsets.only(right: 40, top: 20), + child: SizedBox( + width: + (uniqueXValues.length * 50) + + 50, // Adjust width dynamically + child: LineChart( + LineChartData( + lineTouchData: lineTouchData1(), + gridData: gridData(), + titlesData: titlesData1(uniqueXValues), + borderData: borderData(), + lineBarsData: lineBars, + minX: uniqueXValues.reduce((a, b) => a < b ? a : b), + maxX: uniqueXValues.reduce((a, b) => a > b ? a : b), + minY: 0, + ), ), ), ), ), - ), - ]); + ], + ); case 'bar_chart': // Extract groupBy values and their corresponding y-axis values List xAxisData = []; @@ -1492,11 +1516,15 @@ class ChartWidget extends StatelessWidget { int.tryParse(b['ObsKey']['TIME_PERIOD'].toString()) ?? 0; // Extract QUARTER and convert "Q1", "Q2", etc. to numeric values - int quarterA = int.tryParse( - a['ObsKey']['QUARTER'].toString().replaceAll('Q', '')) ?? + int quarterA = + int.tryParse( + a['ObsKey']['QUARTER'].toString().replaceAll('Q', ''), + ) ?? 0; - int quarterB = int.tryParse( - b['ObsKey']['QUARTER'].toString().replaceAll('Q', '')) ?? + int quarterB = + int.tryParse( + b['ObsKey']['QUARTER'].toString().replaceAll('Q', ''), + ) ?? 0; // First, sort by TIME_PERIOD. If equal, sort by QUARTER @@ -1524,248 +1552,265 @@ class ChartWidget extends StatelessWidget { // yAxisLabels.add(unitMsr ?? ''); } } - return Column(children: [ - Text( - chartData['chart_heading'] ?? '', // Chart title from data - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w400, + return Column( + children: [ + Text( + chartData['chart_heading'] ?? '', // Chart title from data + style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400), + textAlign: TextAlign.center, ), - textAlign: TextAlign.center, - ), - SizedBox(height: 5), - Text( - chartData['chart_sub_heading'] ?? '', - style: TextStyle( - fontSize: 13, - fontWeight: FontWeight.w300, + SizedBox(height: 5), + Text( + chartData['chart_sub_heading'] ?? '', + style: TextStyle(fontSize: 13, fontWeight: FontWeight.w300), + textAlign: TextAlign.center, ), - textAlign: TextAlign.center, - ), - SizedBox(height: 10), - // Chart - Expanded(child: LayoutBuilder( - builder: (context, constraints) { - double chartWidth = - xAxisData.length * (40 + 10); // Compute chart width - double screenWidth = constraints.maxWidth; + SizedBox(height: 10), + // Chart + Expanded( + child: LayoutBuilder( + builder: (context, constraints) { + double chartWidth = + xAxisData.length * (40 + 10); // Compute chart width + double screenWidth = constraints.maxWidth; - return SingleChildScrollView( - scrollDirection: Axis.horizontal, - padding: const EdgeInsets.only(top: 10, left: 5), - child: ConstrainedBox( + return SingleChildScrollView( + scrollDirection: Axis.horizontal, + padding: const EdgeInsets.only(top: 10, left: 5), + child: ConstrainedBox( constraints: BoxConstraints( minWidth: screenWidth, // Ensure it at least fills available width - maxWidth: chartWidth > screenWidth - ? chartWidth - : screenWidth, // Prevent non-normalized constraints + maxWidth: + chartWidth > screenWidth + ? chartWidth + : screenWidth, // Prevent non-normalized constraints ), child: Center( child: SizedBox( - width: xAxisData.length * - (40 + 10), // Bar width + manual spacing - child: BarChart( - BarChartData( - alignment: BarChartAlignment.spaceAround, - maxY: yAxisData.isNotEmpty - ? yAxisData - .reduce((a, b) => a > b ? a : b) * - 1.2 - : 10, - // barTouchData: BarTouchData( - // enabled: true, - // touchCallback: (FlTouchEvent event, barTouchResponse) { - // if (!event.isInterestedForInteractions || barTouchResponse == null || barTouchResponse.spot == null) { - // return; - // } - // }, - // touchTooltipData: BarTouchTooltipData( - // getTooltipColor: (group) => Colors.transparent, - // getTooltipItem: (group, groupIndex, rod, rodIndex) { - // if (rod.toY == 0) return null; // Hide for zero values - // return BarTooltipItem( - // formatNumber(rod.toY), - // TextStyle(color: Colors.black), - // ); - // }, - // ), - // ), + width: + xAxisData.length * + (40 + 10), // Bar width + manual spacing + child: BarChart( + BarChartData( + alignment: BarChartAlignment.spaceAround, + maxY: + yAxisData.isNotEmpty + ? yAxisData.reduce( + (a, b) => a > b ? a : b, + ) * + 1.2 + : 10, + // barTouchData: BarTouchData( + // enabled: true, + // touchCallback: (FlTouchEvent event, barTouchResponse) { + // if (!event.isInterestedForInteractions || barTouchResponse == null || barTouchResponse.spot == null) { + // return; + // } + // }, + // touchTooltipData: BarTouchTooltipData( + // getTooltipColor: (group) => Colors.transparent, + // getTooltipItem: (group, groupIndex, rod, rodIndex) { + // if (rod.toY == 0) return null; // Hide for zero values + // return BarTooltipItem( + // formatNumber(rod.toY), + // TextStyle(color: Colors.black), + // ); + // }, + // ), + // ), - // barTouchData: BarTouchData(enabled: true), - barTouchData: BarTouchData( - enabled: false, - handleBuiltInTouches: false, - touchTooltipData: BarTouchTooltipData( - getTooltipColor: (group) => - Colors.transparent, - // fitInsideHorizontally: true, - // fitInsideVertically: true, - // tooltipPadding: const EdgeInsets.all(8), - tooltipMargin: 1, - getTooltipItem: - (group, groupIndex, rod, rodIndex) { - // String unitMsrLabel = yAxisLabels.isNotEmpty && groupIndex < yAxisLabels.length - // ? yAxisLabels[groupIndex] - // : ''; - if (rod.toY == 0) return null; + // barTouchData: BarTouchData(enabled: true), + barTouchData: BarTouchData( + enabled: false, + handleBuiltInTouches: false, + touchTooltipData: BarTouchTooltipData( + getTooltipColor: + (group) => Colors.transparent, + // fitInsideHorizontally: true, + // fitInsideVertically: true, + // tooltipPadding: const EdgeInsets.all(8), + tooltipMargin: 1, + getTooltipItem: ( + group, + groupIndex, + rod, + rodIndex, + ) { + // String unitMsrLabel = yAxisLabels.isNotEmpty && groupIndex < yAxisLabels.length + // ? yAxisLabels[groupIndex] + // : ''; + if (rod.toY == 0) return null; - return BarTooltipItem( - (chartConversion != null && - chartConversion.isNotEmpty && - number_format != null && - chartConversion.isNotEmpty) - ? formatNumberConversion( - rod.toY, - chartConversion, - number_format) // If condition is true - : formatNumber(rod.toY), - const TextStyle( - color: Colors.black, - fontSize: 12, - fontWeight: FontWeight.w400, - ), - ); - }, - ), - ), - titlesData: FlTitlesData( - leftTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: false, - interval: (yAxisData.isNotEmpty - ? yAxisData.reduce( - (a, b) => a > b ? a : b) / - 5 - : 1), - getTitlesWidget: (value, meta) { - return Padding( - padding: - const EdgeInsets.only(right: 8.0), - child: Text('${value.toInt()}'), - ); - }, - reservedSize: 60, - ), - ), - bottomTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: true, - interval: 1, - getTitlesWidget: (value, meta) { - if (value.toInt() < xAxisData.length) { - String title = - xAxisData[value.toInt()]; - String displayTitle = title.length > - 10 - ? title.substring(0, 10) + '...' - : title; - - return Padding( - padding: const EdgeInsets.only( - top: 8.0, left: 75.0), - child: SizedBox( - width: - 60, // Limit width to force wrapping - child: Transform.rotate( - // angle: -0.5, - angle: -1.5, - - child: TooltipTheme( - data: TooltipThemeData( - decoration: - BoxDecoration( - color: Colors - .blueGrey[ - 800], // Change background color - borderRadius: - BorderRadius.circular( - 8), // Optional: rounded corners - ), - textStyle: TextStyle( - color: Colors - .white), // Change text color - ), - child: TooltipTheme( - data: TooltipThemeData( - decoration: - BoxDecoration( - color: Colors - .black, // Change background color - // color: Colors.blueGrey[800], // Change background color - borderRadius: - BorderRadius - .circular( - 8), // Optional: rounded corners - ), - textStyle: TextStyle( - color: Colors - .white), // Change text color - ), - child: Tooltip( - message: title, - child: Text( - // title, - displayTitle, - softWrap: true, - textAlign: - TextAlign.right, - style: TextStyle( - fontSize: 10, - ), - overflow: - TextOverflow - .ellipsis, - ), - ), - ), - ), - ))); - } - return Container(); - }, - reservedSize: 110, - ), - ), - topTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: false), // Hide top titles - ), - rightTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: false), // Hide right titles - ), - ), - gridData: FlGridData(show: false), - borderData: FlBorderData( - show: true, - border: const Border( - // left: BorderSide(color: Colors.grey), - bottom: BorderSide(color: Colors.grey), - ), - ), - barGroups: List.generate( - xAxisData.length, - (index) => BarChartGroupData( - x: index, - barsSpace: 10, - barRods: [ - BarChartRodData( - toY: yAxisData[index], - color: bodyColor, - borderRadius: BorderRadius.circular(4), - width: 20, + return BarTooltipItem( + (chartConversion != null && + chartConversion.isNotEmpty && + number_format != null && + chartConversion.isNotEmpty) + ? formatNumberConversion( + rod.toY, + chartConversion, + number_format, + ) // If condition is true + : formatNumber(rod.toY), + const TextStyle( + color: Colors.black, + fontSize: 12, + fontWeight: FontWeight.w400, ), - ], - showingTooltipIndicators: [0], - ), + ); + }, ), ), - )), - ))); - }, - )) - ]); + titlesData: FlTitlesData( + leftTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: false, + interval: + (yAxisData.isNotEmpty + ? yAxisData.reduce( + (a, b) => a > b ? a : b, + ) / + 5 + : 1), + getTitlesWidget: (value, meta) { + return Padding( + padding: const EdgeInsets.only( + right: 8.0, + ), + child: Text('${value.toInt()}'), + ); + }, + reservedSize: 60, + ), + ), + bottomTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + interval: 1, + getTitlesWidget: (value, meta) { + if (value.toInt() < xAxisData.length) { + String title = xAxisData[value.toInt()]; + String displayTitle = + title.length > 10 + ? title.substring(0, 10) + '...' + : title; + + return Padding( + padding: const EdgeInsets.only( + top: 8.0, + left: 75.0, + ), + child: SizedBox( + width: + 60, // Limit width to force wrapping + child: Transform.rotate( + // angle: -0.5, + angle: -1.5, + + child: TooltipTheme( + data: TooltipThemeData( + decoration: BoxDecoration( + color: + Colors + .blueGrey[800], // Change background color + borderRadius: + BorderRadius.circular( + 8, + ), // Optional: rounded corners + ), + textStyle: TextStyle( + color: Colors.white, + ), // Change text color + ), + child: TooltipTheme( + data: TooltipThemeData( + decoration: BoxDecoration( + color: + Colors + .black, // Change background color + // color: Colors.blueGrey[800], // Change background color + borderRadius: + BorderRadius.circular( + 8, + ), // Optional: rounded corners + ), + textStyle: TextStyle( + color: Colors.white, + ), // Change text color + ), + child: Tooltip( + message: title, + child: Text( + // title, + displayTitle, + softWrap: true, + textAlign: + TextAlign.right, + style: TextStyle( + fontSize: 10, + ), + overflow: + TextOverflow.ellipsis, + ), + ), + ), + ), + ), + ), + ); + } + return Container(); + }, + reservedSize: 110, + ), + ), + topTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: false, + ), // Hide top titles + ), + rightTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: false, + ), // Hide right titles + ), + ), + gridData: FlGridData(show: false), + borderData: FlBorderData( + show: true, + border: const Border( + // left: BorderSide(color: Colors.grey), + bottom: BorderSide(color: Colors.grey), + ), + ), + barGroups: List.generate( + xAxisData.length, + (index) => BarChartGroupData( + x: index, + barsSpace: 10, + barRods: [ + BarChartRodData( + toY: yAxisData[index], + color: bodyColor, + borderRadius: BorderRadius.circular(4), + width: 20, + ), + ], + showingTooltipIndicators: [0], + ), + ), + ), + ), + ), + ), + ), + ); + }, + ), + ), + ], + ); case 'bar_chart_horizontal': // Extract groupBy values and their corresponding y-axis values List xAxisData = []; @@ -1793,14 +1838,16 @@ class ChartWidget extends StatelessWidget { String timeA = a['ObsKey']['TIME_PERIOD']; String timeB = b['ObsKey']['TIME_PERIOD']; - return timeA - .compareTo(timeB); // Lexicographical sorting works for YYYY-MM + return timeA.compareTo( + timeB, + ); // Lexicographical sorting works for YYYY-MM }); // If no valid TIME_PERIOD with a month is found, return original response - List> finalData = sortedData.isNotEmpty - ? sortedData - : List.from(chartData['response']); + List> finalData = + sortedData.isNotEmpty + ? sortedData + : List.from(chartData['response']); for (var entry in finalData) { var xValue = entry['ObsKey'][groupByKey]; @@ -1816,151 +1863,155 @@ class ChartWidget extends StatelessWidget { print(chartData['response']); int rotationTurns = 1; - return Column(children: [ - Text( - chartData['chart_heading'] ?? '', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w400, + return Column( + children: [ + Text( + chartData['chart_heading'] ?? '', + style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400), + textAlign: TextAlign.center, ), - textAlign: TextAlign.center, - ), - // SizedBox(height: 5), - // Text( - // chartData['chart_sub_heading'] ?? '', - // style: TextStyle( - // fontSize: 13, - // fontWeight: FontWeight.w300, - // ), - // textAlign: TextAlign.center, - // ), - // SizedBox(height: 5), - // Chart - Flexible( - child: BarChart( - BarChartData( - // alignment: BarChartAlignment.spaceAround, - // maxY: yAxisData.isNotEmpty - // ? yAxisData.reduce((a, b) => a > b ? a : b) * 1.2 - // : 10, - maxY: _calculateMaxY(chartData), - rotationQuarterTurns: rotationTurns, - barTouchData: BarTouchData( - enabled: false, - handleBuiltInTouches: false, - touchTooltipData: BarTouchTooltipData( - fitInsideHorizontally: true, - fitInsideVertically: true, - tooltipPadding: const EdgeInsets.all(5), - tooltipMargin: 12, - getTooltipColor: (group) => Colors.transparent, - getTooltipItem: (group, groupIndex, rod, rodIndex) { - if (rod.toY == 0) return null; + // SizedBox(height: 5), + // Text( + // chartData['chart_sub_heading'] ?? '', + // style: TextStyle( + // fontSize: 13, + // fontWeight: FontWeight.w300, + // ), + // textAlign: TextAlign.center, + // ), + // SizedBox(height: 5), + // Chart + Flexible( + child: BarChart( + BarChartData( + // alignment: BarChartAlignment.spaceAround, + // maxY: yAxisData.isNotEmpty + // ? yAxisData.reduce((a, b) => a > b ? a : b) * 1.2 + // : 10, + maxY: _calculateMaxY(chartData), + rotationQuarterTurns: rotationTurns, + barTouchData: BarTouchData( + enabled: false, + handleBuiltInTouches: false, + touchTooltipData: BarTouchTooltipData( + fitInsideHorizontally: true, + fitInsideVertically: true, + tooltipPadding: const EdgeInsets.all(5), + tooltipMargin: 12, + getTooltipColor: (group) => Colors.transparent, + getTooltipItem: (group, groupIndex, rod, rodIndex) { + if (rod.toY == 0) return null; - return BarTooltipItem( - // formatNumber(rod.toY), - (chartConversion != null && - chartConversion.isNotEmpty && - number_format != null) - ? formatNumberConversion( - rod.toY, chartConversion, number_format) - : formatNumber(rod.toY), - TextStyle( - color: Colors.black, - fontSize: 12, - fontWeight: FontWeight.w400, - ), - ); - }, - ), - ), - titlesData: FlTitlesData( - leftTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: false, - interval: (yAxisData.isNotEmpty - ? yAxisData.reduce((a, b) => a > b ? a : b) / 5 - : 1), - getTitlesWidget: (value, meta) { - return Padding( - padding: const EdgeInsets.only(right: 8.0), - child: Text('${value.toInt()}'), + return BarTooltipItem( + // formatNumber(rod.toY), + (chartConversion != null && + chartConversion.isNotEmpty && + number_format != null) + ? formatNumberConversion( + rod.toY, + chartConversion, + number_format, + ) + : formatNumber(rod.toY), + TextStyle( + color: Colors.black, + fontSize: 12, + fontWeight: FontWeight.w400, + ), ); }, - reservedSize: 60, ), ), - bottomTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: true, - getTitlesWidget: (value, meta) { - if (value.toInt() < xAxisData.length) { + titlesData: FlTitlesData( + leftTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: false, + interval: + (yAxisData.isNotEmpty + ? yAxisData.reduce((a, b) => a > b ? a : b) / 5 + : 1), + getTitlesWidget: (value, meta) { return Padding( - padding: const EdgeInsets.only(top: 8.0), - child: Transform.rotate( - angle: -1.58, - // angle: -45 * - // (3.1415927 / 180), // Rotating by -45 degrees - alignment: Alignment.center, - child: Center( - child: SizedBox( - width: 100, - child: Text( - xAxisData[value.toInt()], - textAlign: TextAlign.right, - style: const TextStyle( - fontSize: 10, + padding: const EdgeInsets.only(right: 8.0), + child: Text('${value.toInt()}'), + ); + }, + reservedSize: 60, + ), + ), + bottomTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + getTitlesWidget: (value, meta) { + if (value.toInt() < xAxisData.length) { + return Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Transform.rotate( + angle: -1.58, + // angle: -45 * + // (3.1415927 / 180), // Rotating by -45 degrees + alignment: Alignment.center, + child: Center( + child: SizedBox( + width: 100, + child: Text( + xAxisData[value.toInt()], + textAlign: TextAlign.right, + style: const TextStyle(fontSize: 10), + softWrap: true, + maxLines: 2, ), - softWrap: true, - maxLines: 2, ), ), ), - ), - ); - } - return Container(); - }, - reservedSize: 125, + ); + } + return Container(); + }, + reservedSize: 125, + ), + ), + topTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: false, + ), // Hide top titles + ), + rightTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: false, + ), // Hide right titles ), ), - topTitles: AxisTitles( - sideTitles: - SideTitles(showTitles: false), // Hide top titles - ), - rightTitles: AxisTitles( - sideTitles: - SideTitles(showTitles: false), // Hide right titles - ), - ), - gridData: FlGridData(show: false), - // borderData: FlBorderData(show: false), + gridData: FlGridData(show: false), - borderData: FlBorderData( - show: false, - ), - // groupsSpace: 5, - barGroups: List.generate( - xAxisData.length, - (index) => BarChartGroupData( - x: index, - barsSpace: 20, - barRods: [ - BarChartRodData( - toY: yAxisData[index], - // color: Colors.blueAccent, - color: uniqueColors[1], - borderRadius: BorderRadius.circular(4), - width: 20, - ), - ], - showingTooltipIndicators: [0], + // borderData: FlBorderData(show: false), + borderData: FlBorderData(show: false), + // groupsSpace: 5, + barGroups: List.generate( + xAxisData.length, + (index) => BarChartGroupData( + x: index, + barsSpace: 20, + barRods: [ + BarChartRodData( + toY: + (yAxisData[index] == 0) + ? 0.0001 + : yAxisData[index], + // color: Colors.blueAccent, + color: uniqueColors[1], + borderRadius: BorderRadius.circular(4), + width: 20, + ), + ], + showingTooltipIndicators: [0], + ), ), ), ), ), - ), - ]); + ], + ); case 'fl_multi_bar': double _calculateChartWidth(dynamic chartData) { int totalBars = chartData['response']?.length ?? 0; @@ -1979,12 +2030,15 @@ class ChartWidget extends StatelessWidget { var chartBarColorsRaw = chartData['chart_bar_color'] ?? {}; // Convert LinkedMap to Map - Map chartBarColrs = - Map.from(chartBarColorsRaw); + Map chartBarColrs = Map.from( + chartBarColorsRaw, + ); // Now map to Color - Map parsedChartBarColors = - chartBarColrs.map((key, value) { + Map parsedChartBarColors = chartBarColrs.map(( + key, + value, + ) { return MapEntry(key, _hexToColor(value)); }); @@ -2046,67 +2100,76 @@ class ChartWidget extends StatelessWidget { print('hormulti_bar'); return Center( - child: Column(children: [ - Text( - chartData['chart_heading'] ?? '', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w400, + child: Column( + children: [ + Text( + chartData['chart_heading'] ?? '', + style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400), + textAlign: TextAlign.center, ), - textAlign: TextAlign.center, - ), - SizedBox(height: 5), - Text( - '', - style: TextStyle( - fontSize: 13, - fontWeight: FontWeight.w300, + SizedBox(height: 5), + Text( + '', + style: TextStyle(fontSize: 13, fontWeight: FontWeight.w300), + textAlign: TextAlign.center, ), - textAlign: TextAlign.center, - ), - SizedBox(height: 10), - // Chart - Expanded( + SizedBox(height: 10), + // Chart + Expanded( child: SingleChildScrollView( - scrollDirection: Axis.horizontal, // Enable horizontal scrolling - child: SizedBox( - width: _calculateChartWidth( - chartData), // Dynamically calculate the chart width + scrollDirection: + Axis.horizontal, // Enable horizontal scrolling + child: SizedBox( + width: _calculateChartWidth( + chartData, + ), // Dynamically calculate the chart width - child: BarChart( - BarChartData( - alignment: BarChartAlignment.spaceAround, - maxY: _calculateMaxY( - chartData), // Dynamically calculate max Y - // barGroups: _buildHorizontalRotateBarGroups( - // chartData, groupByValues), // Build bar groups - barGroups: hasBarColors - ? _buildHorizontalRotateBarGroupsBarColors( - chartData, groupByValues, parsedChartBarColors) - : _buildHorizontalRotateBarGroups( - chartData, groupByValues), + child: BarChart( + BarChartData( + alignment: BarChartAlignment.spaceAround, + maxY: _calculateMaxY( + chartData, + ), // Dynamically calculate max Y + // barGroups: _buildHorizontalRotateBarGroups( + // chartData, groupByValues), // Build bar groups + barGroups: + hasBarColors + ? _buildHorizontalRotateBarGroupsBarColors( + chartData, + groupByValues, + parsedChartBarColors, + ) + : _buildHorizontalRotateBarGroups( + chartData, + groupByValues, + ), - titlesData: FlTitlesData( - leftTitles: AxisTitles( - sideTitles: SideTitles(showTitles: false), - ), - bottomTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: true, - reservedSize: 130, // Added space for rotated titles - getTitlesWidget: (value, meta) { - if (value < groupByValues.length) { - String title = - groupByValues.elementAt(value.toInt()); + titlesData: FlTitlesData( + leftTitles: AxisTitles( + sideTitles: SideTitles(showTitles: false), + ), + bottomTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + reservedSize: + 130, // Added space for rotated titles + getTitlesWidget: (value, meta) { + if (value < groupByValues.length) { + String title = groupByValues.elementAt( + value.toInt(), + ); - String displayTitle = title.length > 10 - ? title.substring(0, 10) + '...' - : title; + String displayTitle = + title.length > 10 + ? title.substring(0, 10) + '...' + : title; - return Padding( - padding: const EdgeInsets.only( - top: 8.0, left: 95.0), - child: SizedBox( + return Padding( + padding: const EdgeInsets.only( + top: 8.0, + left: 95.0, + ), + child: SizedBox( width: 80, // Limit width to force wrapping child: Transform.rotate( @@ -2114,148 +2177,162 @@ class ChartWidget extends StatelessWidget { child: TooltipTheme( data: TooltipThemeData( decoration: BoxDecoration( - color: Colors - .black, // Change background color + color: + Colors + .black, // Change background color // color: Colors.blueGrey[800], // Change background color - borderRadius: BorderRadius.circular( - 8), // Optional: rounded corners + borderRadius: + BorderRadius.circular( + 8, + ), // Optional: rounded corners ), textStyle: TextStyle( - color: Colors - .white), // Change text color + color: Colors.white, + ), // Change text color ), child: Tooltip( - message: title, - child: Text( - title, - softWrap: true, - maxLines: 2, - textAlign: TextAlign.right, - style: TextStyle(fontSize: 10), - // overflow: TextOverflow.ellipsis, - )), + message: title, + child: Text( + title, + softWrap: true, + maxLines: 2, + textAlign: TextAlign.right, + style: TextStyle(fontSize: 10), + // overflow: TextOverflow.ellipsis, + ), + ), ), - ))); - // return Transform.rotate( - // angle: - // -0.5, // Rotation in radians (~ -30 degrees) - // child: Text( - // title, - // style: const TextStyle(fontSize: 12), - // ), - // ); - } + ), + ), + ); + // return Transform.rotate( + // angle: + // -0.5, // Rotation in radians (~ -30 degrees) + // child: Text( + // title, + // style: const TextStyle(fontSize: 12), + // ), + // ); + } - return const SizedBox.shrink(); + return const SizedBox.shrink(); + }, + ), + ), + topTitles: AxisTitles( + sideTitles: SideTitles(showTitles: false), + ), + rightTitles: AxisTitles( + sideTitles: SideTitles(showTitles: false), + ), + ), + borderData: FlBorderData(show: false), + + barTouchData: BarTouchData( + enabled: true, + touchTooltipData: BarTouchTooltipData( + getTooltipColor: (group) => Colors.black, + tooltipHorizontalAlignment: + FLHorizontalAlignment.center, + tooltipRoundedRadius: 8, + fitInsideHorizontally: + true, // Ensure it fits within the screen + fitInsideVertically: true, + tooltipPadding: EdgeInsets.all(8), + tooltipMargin: 16, + + // Only show tooltip when touched + getTooltipItem: (group, groupIndex, rod, rodIndex) { + // if (rod.toY == 0 || touchedGroupIndex == -1) { + // return null; // Don't show the tooltip if the value is 0 or there's no touch + // } + if (rod.toY == 0) { + return null; // Don't show for zero values + } + + if (groupIndex == touchedGroupIndex) { + // Get the group label dynamically + String groupLabel = groupByValues.elementAt( + groupIndex, + ); + + // Fetch the crop for the current group from groupedCrops + String cropType = groupByValues.elementAt( + groupIndex, + ); + print('GrpcropType: $cropType'); + // String crop = groupedCrops[cropType]![rodIndex]; + + // Safely fetch crop with null check + List? crops = groupedCrops[cropType]; + String crop; + if (crops != null && rodIndex < crops.length) { + crop = crops[rodIndex]; + } else { + print( + 'Crop is null or index out of bounds for cropType: $cropType and rodIndex: $rodIndex', + ); + // crop = cropType; // Fallback to cropType + crop = + (crops != null && crops.isNotEmpty) + ? crops.first + : cropType; + } + + // print('groupedCrops1: $groupedCrops - $rodIndex'); + // print( + // 'Groupcrop: $crop'); + double value = rod.toY; + + return BarTooltipItem( + '$groupLabel\n$crop', + const TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + ), + children: [ + TextSpan( + text: + '- ${(chartConversion != null && chartConversion.isNotEmpty && number_format != null) ? formatNumberConversion(rod.toY, chartConversion, number_format) : formatNumber(rod.toY)}', + style: const TextStyle( + color: Colors.white, + fontWeight: FontWeight.w500, + ), + ), + ], + ); + } + return null; + }, + ), + touchCallback: (event, response) { + if (event.isInterestedForInteractions && + response != null && + response.spot != null) { + // setState(() { + touchedGroupIndex = + response.spot!.touchedBarGroupIndex; + // }); + } else { + // setState(() { + touchedGroupIndex = -1; // Reset if no interaction + // }); + } }, ), + gridData: FlGridData(show: false), ), - topTitles: - AxisTitles(sideTitles: SideTitles(showTitles: false)), - rightTitles: - AxisTitles(sideTitles: SideTitles(showTitles: false)), ), - borderData: FlBorderData(show: false), - - barTouchData: BarTouchData( - enabled: true, - touchTooltipData: BarTouchTooltipData( - getTooltipColor: (group) => Colors.black, - tooltipHorizontalAlignment: - FLHorizontalAlignment.center, - tooltipRoundedRadius: 8, - fitInsideHorizontally: - true, // Ensure it fits within the screen - fitInsideVertically: true, - tooltipPadding: EdgeInsets.all(8), - tooltipMargin: 16, - - // Only show tooltip when touched - getTooltipItem: (group, groupIndex, rod, rodIndex) { - // if (rod.toY == 0 || touchedGroupIndex == -1) { - // return null; // Don't show the tooltip if the value is 0 or there's no touch - // } - if (rod.toY == 0) { - return null; // Don't show for zero values - } - - if (groupIndex == touchedGroupIndex) { - // Get the group label dynamically - String groupLabel = - groupByValues.elementAt(groupIndex); - - // Fetch the crop for the current group from groupedCrops - String cropType = - groupByValues.elementAt(groupIndex); - print('GrpcropType: $cropType'); - // String crop = groupedCrops[cropType]![rodIndex]; - - // Safely fetch crop with null check - List? crops = groupedCrops[cropType]; - String crop; - if (crops != null && rodIndex < crops.length) { - crop = crops[rodIndex]; - } else { - print( - 'Crop is null or index out of bounds for cropType: $cropType and rodIndex: $rodIndex'); - // crop = cropType; // Fallback to cropType - crop = (crops != null && crops.isNotEmpty) - ? crops.first - : cropType; - } - - // print('groupedCrops1: $groupedCrops - $rodIndex'); - // print( - // 'Groupcrop: $crop'); - double value = rod.toY; - - return BarTooltipItem( - '$groupLabel\n$crop', - const TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - ), - children: [ - TextSpan( - text: - '- ${(chartConversion != null && chartConversion.isNotEmpty && number_format != null) ? formatNumberConversion(rod.toY, chartConversion, number_format) : formatNumber(rod.toY)}', - style: const TextStyle( - color: Colors.white, - fontWeight: FontWeight.w500, - ), - ), - ], - ); - } - return null; - }, - ), - touchCallback: (event, response) { - if (event.isInterestedForInteractions && - response != null && - response.spot != null) { - // setState(() { - touchedGroupIndex = - response.spot!.touchedBarGroupIndex; - // }); - } else { - // setState(() { - touchedGroupIndex = -1; // Reset if no interaction - // }); - } - }, - ), - gridData: FlGridData(show: false), ), ), ), - )) - ]), + ], + ), ); case 'horizontal_rotate': - String cropKey = chartData['chart_type_json'] - ['y_sub_group']; // Dynamically get crop key + String cropKey = + chartData['chart_type_json']['y_sub_group']; // Dynamically get crop key // Group crops by CROP_TYPE Map> groupedCrops = {}; @@ -2318,271 +2395,334 @@ class ChartWidget extends StatelessWidget { // Convert to a map for easy lookup Map parsedChartBarColors = {}; for (int i = 0; i < keys.length; i++) { - parsedChartBarColors[keys[i].toString()] = - _hexToColor(colors[i].toString()); + parsedChartBarColors[keys[i].toString()] = _hexToColor( + colors[i].toString(), + ); } print('RT1 - $parsedChartBarColors'); bool hasBarColors = parsedChartBarColors.isNotEmpty; - return Column(children: [ - Text( - chartData['chart_heading'] ?? '', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w400, + return Column( + children: [ + Text( + chartData['chart_heading'] ?? '', + style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400), + textAlign: TextAlign.center, ), - textAlign: TextAlign.center, - ), - SizedBox(height: 5), - Text( - chartData['chart_sub_heading'] ?? '', - style: TextStyle( - fontSize: 13, - fontWeight: FontWeight.w300, + SizedBox(height: 5), + Text( + chartData['chart_sub_heading'] ?? '', + style: TextStyle(fontSize: 13, fontWeight: FontWeight.w300), + textAlign: TextAlign.center, ), - textAlign: TextAlign.center, - ), - SizedBox(height: 5), - // Chart - Flexible( - // child: SingleChildScrollView( - // scrollDirection: Axis.vertical, - // child: SingleChildScrollView( - // scrollDirection: Axis.horizontal, - - child: SizedBox( + SizedBox(height: 5), + // Chart + Flexible( + // child: SingleChildScrollView( + // scrollDirection: Axis.vertical, + // child: SingleChildScrollView( + // scrollDirection: Axis.horizontal, + child: SizedBox( // width: 500, // width: 1000, // height: chartHeight, - child: Stack(children: [ - BarChart( - BarChartData( - // maxY: 400000, - maxY: _calculateMaxY(chartData), - rotationQuarterTurns: rotationTurns, - barTouchData: BarTouchData( - // enabled: true, - enabled: false, - touchTooltipData: BarTouchTooltipData( - // getTooltipColor: (group) => Colors.black12, - getTooltipColor: (group) => Colors.transparent, - tooltipHorizontalAlignment: FLHorizontalAlignment.center, + child: Stack( + children: [ + BarChart( + BarChartData( + // maxY: 400000, + maxY: _calculateMaxY(chartData), + rotationQuarterTurns: rotationTurns, - tooltipRoundedRadius: 8, - fitInsideHorizontally: - true, // Ensure it fits within the screen - fitInsideVertically: true, - tooltipPadding: EdgeInsets.only( - left: 5, right: 3, top: 0.5, bottom: 1), - - tooltipMargin: 20, - - // Only show tooltip when touched - getTooltipItem: (group, groupIndex, rod, rodIndex) { - // if (rod.toY == 0 || touchedGroupIndex == -1) { - // return null; // Don't show the tooltip if the value is 0 or there's no touch - // } - // Hide tooltips for 0 values - if (rod.toY == 0) return null; // Hide for zero values - - // if (groupIndex == touchedGroupIndex) { - // print('Group Index: $groupIndex, Group : $group'); - - // Get the group label dynamically - String groupLabel = groupByValues.elementAt(groupIndex); - - // Fetch the crop for the current group from groupedCrops - String cropType = groupByValues.elementAt(groupIndex); - String crop = groupedCrops[cropType]![rodIndex]; - double value = rod.toY; - - String formattedValue; - if (value >= 1000000) { - formattedValue = - (value / 1000000).toStringAsFixed(1) + 'M'; - } else if (value >= 1000) { - formattedValue = - (value / 1000).toStringAsFixed(1) + 'K'; - } else { - formattedValue = value.toStringAsFixed( - 0); // for values smaller than 1000 - } - - // return BarTooltipItem( - // // '$groupLabel\n$crop', - // '$formattedValue', - // const TextStyle( - // color: Colors.black, - // fontWeight: FontWeight.w400, - // fontSize: 12, + // barTouchData: BarTouchData( + // // enabled: true, + // enabled: false, + // touchTooltipData: BarTouchTooltipData( + // // getTooltipColor: (group) => Colors.black12, + // getTooltipColor: (group) => Colors.transparent, + // tooltipHorizontalAlignment: FLHorizontalAlignment.center, + // tooltipRoundedRadius: 8, + // fitInsideHorizontally: + // true, // Ensure it fits within the screen + // fitInsideVertically: true, + // tooltipPadding: const EdgeInsets.all(5), + // tooltipMargin: 10, + // + // // Only show tooltip when touched + // getTooltipItem: (group, groupIndex, rod, rodIndex) { + // // if (rod.toY == 0 || touchedGroupIndex == -1) { + // // return null; // Don't show the tooltip if the value is 0 or there's no touch + // // } + // // Hide tooltips for 0 values + // if (rod.toY == 0) return null; // Hide for zero values + // + // // if (groupIndex == touchedGroupIndex) { + // // print('Group Index: $groupIndex, Group : $group'); + // + // // Get the group label dynamically + // String groupLabel = groupByValues.elementAt(groupIndex); + // + // // Fetch the crop for the current group from groupedCrops + // String cropType = groupByValues.elementAt(groupIndex); + // String crop = groupedCrops[cropType]![rodIndex]; + // double value = rod.toY; + // + // String formattedValue; + // if (value >= 1000000) { + // formattedValue = + // (value / 1000000).toStringAsFixed(1) + 'M'; + // } else if (value >= 1000) { + // formattedValue = + // (value / 1000).toStringAsFixed(1) + 'K'; + // } else { + // formattedValue = value.toStringAsFixed( + // 0); // for values smaller than 1000 + // } + // + // // return BarTooltipItem( + // // // '$groupLabel\n$crop', + // // '$formattedValue', + // // const TextStyle( + // // color: Colors.black, + // // fontWeight: FontWeight.w400, + // // fontSize: 12, + // // ), + // // ); + // + // return BarTooltipItem( + // ' $formattedValue', // This is your main tooltip text + // // textAlign: TextAlign.center, + // const TextStyle( + // color: Colors.black, + // fontWeight: FontWeight.w400, + // fontSize: 12, + // ), + // children: [ + // TextSpan( + // text: '', // Add extra information here + // // text: '\n$crop', // Add extra information here + // + // style: TextStyle( + // color: Colors.grey[ + // 700], // Optional: Different color for extra text + // fontSize: 8, + // ), + // ), + // ], + // ); + // + // // return BarTooltipItem( + // // '$groupLabel\n$crop', + // // const TextStyle( + // // color: Colors.white, + // // fontWeight: FontWeight.bold, + // // ), + // // children: [ + // // TextSpan( + // // text: ' Value: $formattedValue', + // // style: const TextStyle( + // // color: Colors.yellow, + // // fontWeight: FontWeight.w500, + // // ), + // // ), + // // ], + // // ); + // + // // } + // // return null; + // }, // ), - // ); + // // touchCallback: (event, response) { + // // if (event.isInterestedForInteractions && + // // response != null && + // // response.spot != null) { + // // // setState(() { + // // touchedGroupIndex = + // // response.spot!.touchedBarGroupIndex; + // // // }); + // // } else { + // // // setState(() { + // // touchedGroupIndex = -1; // Reset if no interaction + // // // }); + // // } + // // }, + // ), + barTouchData: BarTouchData( + enabled: false, // Enable touch to show tooltip + handleBuiltInTouches: false, + touchTooltipData: BarTouchTooltipData( + getTooltipColor: + (group) => + Colors + .transparent, // Light background for visibility + tooltipHorizontalAlignment: + FLHorizontalAlignment.center, + tooltipRoundedRadius: + 6, // Softer roundness for tooltips + fitInsideHorizontally: true, + fitInsideVertically: true, + tooltipPadding: const EdgeInsets.all(5), + tooltipMargin: + 20, // Reduce margin for better alignment - return BarTooltipItem( - ' $formattedValue', // This is your main tooltip text - // textAlign: TextAlign.center, - const TextStyle( - color: Colors.black, - fontWeight: FontWeight.w400, - fontSize: 12, - ), - children: [ - TextSpan( - text: '', // Add extra information here - // text: '\n$crop', // Add extra information here + getTooltipItem: (group, groupIndex, rod, rodIndex) { + // if (rod.toY == 0) return null; // Hide for zero values - style: TextStyle( - color: Colors.grey[ - 700], // Optional: Different color for extra text - fontSize: 8, - ), - ), - ], - ); + String cropType = groupByValues.elementAt( + groupIndex, + ); + String crop = groupedCrops[cropType]![rodIndex]; + double value = rod.toY; - // return BarTooltipItem( - // '$groupLabel\n$crop', - // const TextStyle( - // color: Colors.white, - // fontWeight: FontWeight.bold, - // ), - // children: [ - // TextSpan( - // text: ' Value: $formattedValue', - // style: const TextStyle( - // color: Colors.yellow, - // fontWeight: FontWeight.w500, - // ), - // ), - // ], - // ); + // Format values dynamically + // String formattedValue = value >= 1e6 + // ? '${(value / 1e6).toStringAsFixed(1)}M' + // : value >= 1e3 + // ? '${(value / 1e3).toStringAsFixed(1)}K' + // : value.toStringAsFixed(0); - // } - // return null; - }, - ), - // touchCallback: (event, response) { - // if (event.isInterestedForInteractions && - // response != null && - // response.spot != null) { - // // setState(() { - // touchedGroupIndex = - // response.spot!.touchedBarGroupIndex; - // // }); - // } else { - // // setState(() { - // touchedGroupIndex = -1; // Reset if no interaction - // // }); - // } - // }, - ), - titlesData: FlTitlesData( - leftTitles: AxisTitles( - sideTitles: SideTitles( - // showTitles: false, - reservedSize: 40, - interval: 100000, - getTitlesWidget: (value, meta) { - return SizedBox( - width: 50, - child: Text( - value.toInt().toString(), - textAlign: TextAlign.justify, - style: const TextStyle( - fontSize: 12, - ), - ), - ); - }, - ), - ), - bottomTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: true, - reservedSize: 150, // Added space for rotated titles - getTitlesWidget: (value, meta) { - if (value < groupByValues.length) { - String title = - groupByValues.elementAt(value.toInt()); - return Transform.rotate( - angle: - -1.58, // Rotation in radians (~ -30 degrees) - child: Center( - child: SizedBox( - width: 120, - child: Text( - title, - textAlign: TextAlign.right, - style: const TextStyle(fontSize: 12), - softWrap: true, - maxLines: 2, - ), + String formattedValue; + if (value >= 1000000) { + formattedValue = + (value / 1000000).toStringAsFixed(1) + 'M'; + } else if (value >= 1000) { + formattedValue = + (value / 1000).toStringAsFixed(1) + 'K'; + } else { + formattedValue = value.toStringAsFixed( + 0, + ); // for values smaller than 1000 + } + + return BarTooltipItem( + formattedValue, + textAlign: TextAlign.right, + const TextStyle( + color: Colors.black, + fontSize: 12, ), - ), + ); + }, + ), + ), + + titlesData: FlTitlesData( + leftTitles: AxisTitles( + sideTitles: SideTitles( + // showTitles: false, + reservedSize: 40, + interval: 100000, + getTitlesWidget: (value, meta) { + return SizedBox( + width: 50, + child: Text( + value.toInt().toString(), + textAlign: TextAlign.center, + style: const TextStyle(fontSize: 12), + ), + ); + }, + ), + ), + bottomTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + reservedSize: + 150, // Added space for rotated titles + getTitlesWidget: (value, meta) { + if (value < groupByValues.length) { + String title = groupByValues.elementAt( + value.toInt(), + ); + return Transform.rotate( + angle: + -1.58, // Rotation in radians (~ -30 degrees) + child: Center( + child: SizedBox( + width: 120, + child: Text( + title, + textAlign: TextAlign.right, + style: const TextStyle(fontSize: 12), + softWrap: true, + maxLines: 2, + ), + ), + ), + ); + } + return const SizedBox.shrink(); + }, + ), + ), + rightTitles: AxisTitles( + sideTitles: SideTitles(showTitles: false), + ), + topTitles: AxisTitles( + sideTitles: SideTitles(showTitles: false), + ), + ), + borderData: FlBorderData( + show: true, + border: const Border( + // left: BorderSide(color: Colors.grey), + bottom: BorderSide(color: Colors.white), + ), + ), + gridData: FlGridData( + show: false, + drawVerticalLine: true, + verticalInterval: 1, + horizontalInterval: 100000, + getDrawingHorizontalLine: (value) { + return FlLine( + color: Colors.grey.withOpacity(0.5), + strokeWidth: 1, ); - } - return const SizedBox.shrink(); - }, + }, + getDrawingVerticalLine: (value) { + return FlLine( + color: Colors.grey.withOpacity(0.5), + strokeWidth: 1, + ); + }, + ), + + // barGroups: _buildHorizontalRotateBarGroups( + // chartData, groupByValues), + barGroups: + hasBarColors + ? _buildHorizontalRotateBarGroupsBarColors( + chartData, + groupByValues, + parsedChartBarColors, + ) + : _buildHorizontalRotateBarGroups( + chartData, + groupByValues, + ), + + alignment: BarChartAlignment.spaceAround, ), ), - rightTitles: - AxisTitles(sideTitles: SideTitles(showTitles: false)), - topTitles: - AxisTitles(sideTitles: SideTitles(showTitles: false)), - ), - borderData: FlBorderData( - show: true, - border: const Border( - // left: BorderSide(color: Colors.grey), - bottom: BorderSide(color: Colors.white), - ), - ), - gridData: FlGridData( - show: false, - drawVerticalLine: true, - verticalInterval: 1, - horizontalInterval: 100000, - getDrawingHorizontalLine: (value) { - return FlLine( - color: Colors.grey.withOpacity(0.5), - strokeWidth: 1, - ); - }, - getDrawingVerticalLine: (value) { - return FlLine( - color: Colors.grey.withOpacity(0.5), - strokeWidth: 1, - ); - }, - ), - // barGroups: _buildHorizontalRotateBarGroups( - // chartData, groupByValues), - - barGroups: hasBarColors - ? _buildHorizontalRotateBarGroupsBarColors( - chartData, groupByValues, parsedChartBarColors) - : _buildHorizontalRotateBarGroups( - chartData, groupByValues), - - alignment: BarChartAlignment.spaceAround, + ], ), ), - ])), - ), + ), - // ), - // ) - - const SizedBox(height: 10), // Space between chart and legend - _buildChartLegend(groupedCrops, parsedChartBarColors, uniqueColors), - ]); + // ), + // ) + const SizedBox(height: 10), // Space between chart and legend + _buildChartLegend(groupedCrops, parsedChartBarColors, uniqueColors), + ], + ); default: return Center(child: Text('Unknown chart type')); } } -// Start Of line trend chart + // Start Of line trend chart FlTitlesData titlesData2(Set xValues) { return FlTitlesData( leftTitles: AxisTitles( @@ -2687,7 +2827,8 @@ class ChartWidget extends StatelessWidget { } else if (RegExp(r'^\d{4}-\d{2}$').hasMatch(timePeriod)) { // Format: Year-Month (e.g., "2020-10") return double.parse( - timePeriod.replaceAll('-', '.')); // Convert "2020-10" → 2020.10 + timePeriod.replaceAll('-', '.'), + ); // Convert "2020-10" → 2020.10 } else if (RegExp(r'^\d{4}-[A-Za-z]{3}$').hasMatch(timePeriod)) { // Format: Year-MonthAbbr (e.g., "2020-Oct") Map monthMap = { @@ -2702,7 +2843,7 @@ class ChartWidget extends StatelessWidget { 'Sep': 9, 'Oct': 10, 'Nov': 11, - 'Dec': 12 + 'Dec': 12, }; List parts = timePeriod.split('-'); @@ -2715,10 +2856,11 @@ class ChartWidget extends StatelessWidget { } List lineBarsData( - List filteredData, - Set groupByValues, - String groupByKey, - Map chartBarColors) { + List filteredData, + Set groupByValues, + String groupByKey, + Map chartBarColors, + ) { List lineBars = []; print('LineParsedChartBarColors $chartBarColors'); @@ -2781,37 +2923,42 @@ class ChartWidget extends StatelessWidget { // return FlSpot(xValue, yValue); // }).toList(); - List spots = filteredData - .where((entry) => entry['ObsKey'][groupByKey] == group) - .map((entry) { - String timePeriod = entry['ObsKey']['TIME_PERIOD']; - print("FindTimePeriod: $timePeriod"); + List spots = + filteredData + .where((entry) => entry['ObsKey'][groupByKey] == group) + .map((entry) { + String timePeriod = entry['ObsKey']['TIME_PERIOD']; + print("FindTimePeriod: $timePeriod"); - // Use the timePeriod directly as a string for x-axis - double xValue = parseTimePeriod(timePeriod); - print('spotss $xValue'); + // Use the timePeriod directly as a string for x-axis + double xValue = parseTimePeriod(timePeriod); + print('spotss $xValue'); - // double yValue = double.parse(entry['ObsValue']['Value']); - double yValue; - var value = entry['ObsValue']['Value']; + // double yValue = double.parse(entry['ObsValue']['Value']); + double yValue; + var value = entry['ObsValue']['Value']; - print('LineTrend $value'); + print('LineTrend $value'); - if (value is int) { - yValue = value.toDouble(); - } else if (value is double) { - yValue = value; - } else if (value is String) { - yValue = - double.tryParse(value) ?? 0.0; // Handle invalid strings safely - } else { - throw Exception("Unexpected value type: ${value.runtimeType}"); - } - print('LineTrendX $xValue'); - print('LineTrendY $yValue'); - return FlSpot(xValue, yValue); - }).toList() - ..sort((a, b) => a.x.compareTo(b.x)); + if (value is int) { + yValue = value.toDouble(); + } else if (value is double) { + yValue = value; + } else if (value is String) { + yValue = + double.tryParse(value) ?? + 0.0; // Handle invalid strings safely + } else { + throw Exception( + "Unexpected value type: ${value.runtimeType}", + ); + } + print('LineTrendX $xValue'); + print('LineTrendY $yValue'); + return FlSpot(xValue, yValue); + }) + .toList() + ..sort((a, b) => a.x.compareTo(b.x)); print('spots - $spots'); @@ -2851,7 +2998,7 @@ class ChartWidget extends StatelessWidget { return lineBars; } -// Helper functions for chart styles + // Helper functions for chart styles LineTouchData lineTouchData1() { var chartConversion = chartData['chart_type_json']['conversion']; var number_format = chartData['chart_type_json']['number_format']; @@ -2867,9 +3014,10 @@ class ChartWidget extends StatelessWidget { getTooltipColor: (spot) => Colors.black, getTooltipItems: (List lineBarsSpot) { return lineBarsSpot.map((lineBarSpot) { - Color lineColor = lineBarSpot.bar is LineChartBarData - ? (lineBarSpot.bar).color ?? Colors.white - : Colors.white; // Extract bar color safely + Color lineColor = + lineBarSpot.bar is LineChartBarData + ? (lineBarSpot.bar).color ?? Colors.white + : Colors.white; // Extract bar color safely return LineTooltipItem( '', const TextStyle(), @@ -2877,16 +3025,21 @@ class ChartWidget extends StatelessWidget { TextSpan( text: '● ', // Unicode circle style: TextStyle( - color: lineColor), // Set circle color to match bar + color: lineColor, + ), // Set circle color to match bar ), TextSpan( // text: formatNumber(lineBarSpot.y), - text: (chartConversion != null && - chartConversion.isNotEmpty && - number_format != null) - ? formatNumberConversion( - lineBarSpot.y, chartConversion, number_format) - : formatNumber(lineBarSpot.y), + text: + (chartConversion != null && + chartConversion.isNotEmpty && + number_format != null) + ? formatNumberConversion( + lineBarSpot.y, + chartConversion, + number_format, + ) + : formatNumber(lineBarSpot.y), // text: ' ${lineBarSpot.y}', // Keep the value white style: const TextStyle(color: Colors.white), ), @@ -2975,10 +3128,10 @@ class ChartWidget extends StatelessWidget { return FlGridData( show: false, drawVerticalLine: true, - getDrawingHorizontalLine: (value) => - FlLine(color: Colors.grey, strokeWidth: 1), - getDrawingVerticalLine: (value) => - FlLine(color: Colors.grey, strokeWidth: 1), + getDrawingHorizontalLine: + (value) => FlLine(color: Colors.grey, strokeWidth: 1), + getDrawingVerticalLine: + (value) => FlLine(color: Colors.grey, strokeWidth: 1), ); } @@ -2986,8 +3139,9 @@ class ChartWidget extends StatelessWidget { print('tileDATa1xvalueline2 - $xValues'); double findClosest(double value, Set values) { - return values - .reduce((a, b) => (value - a).abs() < (value - b).abs() ? a : b); + return values.reduce( + (a, b) => (value - a).abs() < (value - b).abs() ? a : b, + ); } return FlTitlesData( @@ -3072,7 +3226,8 @@ class ChartWidget extends StatelessWidget { } print( - 'Value: $value | Formatted: ${formattedValue ?? "Hidden"}'); // Debugging + 'Value: $value | Formatted: ${formattedValue ?? "Hidden"}', + ); // Debugging if (formattedValue != null) { return Text( @@ -3088,37 +3243,38 @@ class ChartWidget extends StatelessWidget { ), bottomTitles: AxisTitles( sideTitles: SideTitles( - showTitles: true, - interval: null, - // interval: 10, // Ensure each year is shown only once - getTitlesWidget: (value, meta) { - // print('BtmTiles :-$value'); - // print('BtmTilesmeta :-$meta'); - // if (xValues.contains(value)) - double closestValue = findClosest(value, xValues); - if ((closestValue - value).abs() < 0.15) { - // print("Bottomtiles"); - // print(value); - return Padding( - padding: const EdgeInsets.only(top: 5, left: 20.0), - child: SizedBox( - width: 40, - child: Transform.rotate( - // angle: 0.0, - angle: -1.5, // Slight rotation to improve readability - child: Text( - value.toInt().toString(), - textAlign: TextAlign.center, - style: TextStyle(color: Colors.black, fontSize: 12), - ), + showTitles: true, + interval: null, + // interval: 10, // Ensure each year is shown only once + getTitlesWidget: (value, meta) { + // print('BtmTiles :-$value'); + // print('BtmTilesmeta :-$meta'); + // if (xValues.contains(value)) + double closestValue = findClosest(value, xValues); + if ((closestValue - value).abs() < 0.15) { + // print("Bottomtiles"); + // print(value); + return Padding( + padding: const EdgeInsets.only(top: 5, left: 20.0), + child: SizedBox( + width: 40, + child: Transform.rotate( + // angle: 0.0, + angle: -1.5, // Slight rotation to improve readability + child: Text( + value.toInt().toString(), + textAlign: TextAlign.center, + style: TextStyle(color: Colors.black, fontSize: 12), ), ), - ); - } else { - return SizedBox.shrink(); // Hide non-relevant labels - } - }, - reservedSize: 40), + ), + ); + } else { + return SizedBox.shrink(); // Hide non-relevant labels + } + }, + reservedSize: 40, + ), ), topTitles: AxisTitles( sideTitles: SideTitles(showTitles: false), // Hide top titles @@ -3176,7 +3332,10 @@ class ChartWidget extends StatelessWidget { } List _generateBarGroups( - BuildContext context, dynamic chartData, String groupByKey) { + BuildContext context, + dynamic chartData, + String groupByKey, + ) { Map> groupedData = {}; print('flStackedBar3'); // Group data by `group_by` and `TIME_PERIOD`, accumulating the values for each group and year @@ -3251,14 +3410,14 @@ class ChartWidget extends StatelessWidget { x: i, // Index for the x-axis based on the time period barRods: [ BarChartRodData( - toY: currentToY, // Use the accumulated `currentToY` value - rodStackItems: rodStackItems, // Add the stacked items - width: 20, - // width: barWidth, - borderRadius: BorderRadius.zero, - color: - Colors.black // This will act as a container for stacked items - ), + toY: currentToY, // Use the accumulated `currentToY` value + rodStackItems: rodStackItems, // Add the stacked items + width: 20, + // width: barWidth, + borderRadius: BorderRadius.zero, + color: + Colors.black, // This will act as a container for stacked items + ), ], ); @@ -3275,27 +3434,25 @@ class ChartWidget extends StatelessWidget { timePeriods.add(entry['ObsKey']['TIME_PERIOD']); } return timePeriods.map((period) { - return Text( - period, - style: TextStyle(fontSize: 12), - ); + return Text(period, style: TextStyle(fontSize: 12)); }).toList(); } -// Function to dynamically set left axis titles (values) + // Function to dynamically set left axis titles (values) String? _lastFormattedValue; Widget _generateLeftTitles(double value, TitleMeta meta) { String formattedValue; if (value % 1000 == 0) { -// Check if the value is in the millions or thousands range + // Check if the value is in the millions or thousands range if (value >= 1000000) { formattedValue = '${(value / 1000000).toStringAsFixed(0)}M'; } else if (value >= 1000) { formattedValue = '${(value / 1000).toStringAsFixed(0)}k'; } else { - formattedValue = - value.toStringAsFixed(0); // No decimals for values less than 1000 + formattedValue = value.toStringAsFixed( + 0, + ); // No decimals for values less than 1000 } // Skip rendering if the formatted value is the same as the last one @@ -3388,7 +3545,9 @@ class ChartWidget extends StatelessWidget { } List _buildHorizontalRotateBarGroups( - dynamic chartData, Set groupByValues) { + dynamic chartData, + Set groupByValues, + ) { String groupByKeyValueData; if (chartData['chart_type_json']['chart_type'] == 'bar_chart_horizontal' || @@ -3409,68 +3568,75 @@ class ChartWidget extends StatelessWidget { String groupValue = groupByValues.elementAt(i); // Filter data for the current group (grouping by CROP_TYPE) - List groupData = responseData.where((entry) { - return entry['ObsKey'][groupByKeyValueData] == groupValue; - }).toList(); + List groupData = + responseData.where((entry) { + return entry['ObsKey'][groupByKeyValueData] == groupValue; + }).toList(); // Create BarChartRodData for each bar in the group - List barRods = groupData.map((data) { - // Ensure to retrieve and parse 'ObsValue' value (which should be a double) - double value = - double.tryParse(data['ObsValue']['Value'].toString()) ?? 0.0; - print('multi_bar1.1'); - // final List uniqueColorsForTwo = [ - // Color(0xFF648CBA), - // Color(0xFF90B0D5), - // ]; + List barRods = + groupData.map((data) { + // Ensure to retrieve and parse 'ObsValue' value (which should be a double) + double value = + double.tryParse(data['ObsValue']['Value'].toString()) ?? 0.0; + // double minBarHeight = 0.5; + print('multi_bar1.1'); + // final List uniqueColorsForTwo = [ + // Color(0xFF648CBA), + // Color(0xFF90B0D5), + // ]; - // Use bodyColor instead of hardcoded colors + // Use bodyColor instead of hardcoded colors - final barColor; - if (chartData['dataset'] == 'general_education' || - chartData['dataset'] == 'higher_education' || - chartData['dataset'] == 'air_transport' || - chartData['dataset'] == 'labour_force' || - chartData['dataset'] == 'gdp' || - chartData['dataset'] == 'hotels' || - chartData['dataset'] == 'hotel_guests' || - chartData['dataset'] == 'health_services' || - chartData['dataset'] == 'clinics') { - barColor = uniqueColorsForTwo[colorIndex % uniqueColorsForTwo.length]; - colorIndex++; - } else if (chartData['dataset'] == 'cropsk') { - barColor = - uniqueColorsForThree[colorIndex % uniqueColorsForThree.length]; - colorIndex++; - } else if (chartData['dataset'] == 'oil_and_gas') { - barColor = - uniqueColorsForFour[colorIndex % uniqueColorsForFour.length]; - colorIndex++; - } else { - barColor = uniqueColors[colorIndex % uniqueColors.length]; - colorIndex++; - } + final barColor; + if (chartData['dataset'] == 'general_education' || + chartData['dataset'] == 'higher_education' || + chartData['dataset'] == 'air_transport' || + chartData['dataset'] == 'labour_force' || + chartData['dataset'] == 'gdp' || + chartData['dataset'] == 'hotels' || + chartData['dataset'] == 'hotel_guests' || + chartData['dataset'] == 'health_services' || + chartData['dataset'] == 'clinics') { + barColor = + uniqueColorsForTwo[colorIndex % uniqueColorsForTwo.length]; + colorIndex++; + } else if (chartData['dataset'] == 'cropsk') { + barColor = + uniqueColorsForThree[colorIndex % + uniqueColorsForThree.length]; + colorIndex++; + } else if (chartData['dataset'] == 'oil_and_gas') { + barColor = + uniqueColorsForFour[colorIndex % uniqueColorsForFour.length]; + colorIndex++; + } else { + barColor = uniqueColors[colorIndex % uniqueColors.length]; + colorIndex++; + } - return BarChartRodData( - toY: value, // Use the parsed value - color: barColor, // Dynamic color - width: 20, + return BarChartRodData( + toY: value, // Use the parsed value + color: barColor, // Dynamic color + width: 20, - // backDrawRodData: BackgroundBarChartRodData( - // show: true, - // toY: 400000, - // color: Colors.grey.shade300, - // ), - ); - }).toList(); + // backDrawRodData: BackgroundBarChartRodData( + // show: true, + // toY: 400000, + // color: Colors.grey.shade300, + // ), + ); + }).toList(); // Add BarChartGroupData for the group barGroups.add( BarChartGroupData( x: i, barRods: barRods, - showingTooltipIndicators: - List.generate(barRods.length, (index) => index), + showingTooltipIndicators: List.generate( + barRods.length, + (index) => index, + ), ), ); } @@ -3479,9 +3645,10 @@ class ChartWidget extends StatelessWidget { } List _buildHorizontalRotateBarGroupsBarColors( - dynamic chartData, - Set groupByValues, - Map chartBarColors) { + dynamic chartData, + Set groupByValues, + Map chartBarColors, + ) { String groupByKeyValueData1; if (chartData['chart_type_json']['chart_type'] == 'bar_chart_horizontal' || @@ -3499,8 +3666,9 @@ class ChartWidget extends StatelessWidget { // Define two shades for alternating colors List uniqueColorsForTwo = [ chartBarColors['default'] ?? Colors.blue, // Original color - (chartBarColors['default'] ?? Colors.blue) - .withAlpha(180) // Slightly modified shade + (chartBarColors['default'] ?? Colors.blue).withAlpha( + 180, + ), // Slightly modified shade ]; int colorIndex = 0; @@ -3509,13 +3677,14 @@ class ChartWidget extends StatelessWidget { String groupValue = groupByValues.elementAt(i); // Filter data for the current group - List groupData = responseData.where((entry) { - return entry['ObsKey'][groupByKeyValueData1] == groupValue; - }).toList(); + List groupData = + responseData.where((entry) { + return entry['ObsKey'][groupByKeyValueData1] == groupValue; + }).toList(); Map genderMapping = { 'ذكر': 'Male', // Arabic for Male - 'أنثى': 'Female' // Arabic for Female + 'أنثى': 'Female', // Arabic for Female }; // Sort data so "Male" appears first, "Female" second @@ -3529,45 +3698,49 @@ class ChartWidget extends StatelessWidget { }); // Create BarChartRodData for each bar in the group - List barRods = groupData.map((data) { - double value = - double.tryParse(data['ObsValue']['Value'].toString()) ?? 0.0; + List barRods = + groupData.map((data) { + double value = + double.tryParse(data['ObsValue']['Value'].toString()) ?? 0.0; - // Get gender-based color - String gender = data['ObsKey']['GENDER'] ?? ""; - // Convert Arabic gender to English if necessary - String normalizedGender = genderMapping[gender] ?? gender; + // Get gender-based color + String gender = data['ObsKey']['GENDER'] ?? ""; + // Convert Arabic gender to English if necessary + String normalizedGender = genderMapping[gender] ?? gender; - print('horizontalRotateGender - $gender'); - // Map Arabic gender values to English equivalents + print('horizontalRotateGender - $gender'); + // Map Arabic gender values to English equivalents - // Determine color dynamically - Color barColor; - if (chartData['dataset'] == 'health_services') { - barColor = uniqueColorsForTwo[ - colorIndex % 2]; // Alternate between two colors - colorIndex++; // Update index for next bar - } else { - // barColor = chartBarColors[gender] ?? Colors.grey; // Default gender-based color - barColor = chartBarColors[normalizedGender] ?? Colors.grey; - } + // Determine color dynamically + Color barColor; + if (chartData['dataset'] == 'health_services') { + barColor = + uniqueColorsForTwo[colorIndex % + 2]; // Alternate between two colors + colorIndex++; // Update index for next bar + } else { + // barColor = chartBarColors[gender] ?? Colors.grey; // Default gender-based color + barColor = chartBarColors[normalizedGender] ?? Colors.grey; + } - print('GEG- $gender'); + print('GEG- $gender'); - return BarChartRodData( - toY: value, // Use the parsed value - color: barColor, // Gender-based dynamic color - width: 20, - ); - }).toList(); + return BarChartRodData( + toY: value, // Use the parsed value + color: barColor, // Gender-based dynamic color + width: 20, + ); + }).toList(); // Add BarChartGroupData for the group barGroups.add( BarChartGroupData( x: i, barRods: barRods, - showingTooltipIndicators: - List.generate(barRods.length, (index) => index), + showingTooltipIndicators: List.generate( + barRods.length, + (index) => index, + ), ), ); } @@ -3599,31 +3772,27 @@ Widget _buildChartLegend( alignment: WrapAlignment.center, spacing: 12, runSpacing: 6, - children: uniqueCropTypes.map((cropType) { - // Color cropColor = parsedChartBarColors[cropType] ?? Colors.grey; // Fetch color for each crop type - int index = uniqueCropTypes - .toList() - .indexOf(cropType); // Get index for cycling colors - Color cropColor = parsedChartBarColors.isNotEmpty && - parsedChartBarColors.containsKey(cropType) - ? parsedChartBarColors[cropType]! - : uniqueColors[index % uniqueColors.length]; - - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - CircleAvatar( - radius: 6, - backgroundColor: cropColor, - ), - const SizedBox(width: 4), - Text( + children: + uniqueCropTypes.map((cropType) { + // Color cropColor = parsedChartBarColors[cropType] ?? Colors.grey; // Fetch color for each crop type + int index = uniqueCropTypes.toList().indexOf( cropType, - style: const TextStyle(fontSize: 12), - ), - ], - ); - }).toList(), + ); // Get index for cycling colors + Color cropColor = + parsedChartBarColors.isNotEmpty && + parsedChartBarColors.containsKey(cropType) + ? parsedChartBarColors[cropType]! + : uniqueColors[index % uniqueColors.length]; + + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + CircleAvatar(radius: 6, backgroundColor: cropColor), + const SizedBox(width: 4), + Text(cropType, style: const TextStyle(fontSize: 12)), + ], + ); + }).toList(), ); } diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/feedback.dart b/lib/presentation/routes/drawer_routes/Drawer Items/feedback.dart index 3f8ca589..9566ae67 100644 --- a/lib/presentation/routes/drawer_routes/Drawer Items/feedback.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/feedback.dart @@ -777,9 +777,6 @@ class _FeedbackFormState extends ConsumerState } Future _submitFeedback() async { - setState(() { - isLoading = true; - }); if (_selectedEmojiIndex == null) { setState(() { _isSmileySelected = false; @@ -802,6 +799,10 @@ class _FeedbackFormState extends ConsumerState return; } + setState(() { + isLoading = true; + }); + final feedbackData = { "userId": userId, "ease_of_use": _easeOfUseRating, diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/notification/notification.dart b/lib/presentation/routes/drawer_routes/Drawer Items/notification/notification.dart index 6f5411d9..6fb39abb 100644 --- a/lib/presentation/routes/drawer_routes/Drawer Items/notification/notification.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/notification/notification.dart @@ -357,20 +357,18 @@ class NotificationTile extends StatelessWidget { print('isPushed $isPushed , $id'); return GestureDetector( - onTap: isPushed - ? () { - readedNotification(userID, id); - final encodedKey = Uri.encodeQueryComponent('notification'); - context.go('/notification_details', extra: { - 'title': title, - 'message': message, - 'date': date, - 'category': category, - 'id': id, - 'backNavigation': encodedKey - }); - } - : null, + onTap: () { + readedNotification(userID, id); + final encodedKey = Uri.encodeQueryComponent('notification'); + context.go('/notification_details', extra: { + 'title': title, + 'message': message, + 'date': date, + 'category': category, + 'id': id, + 'backNavigation': encodedKey + }); + }, child: ListTile( leading: isPushed ? const Icon(Icons.circle, size: 12, color: Color(0xFFFF274E)) @@ -390,10 +388,8 @@ class NotificationTile extends StatelessWidget { fontWeight: FontWeight.w400, ), ), - trailing: isPushed - ? const Icon(Icons.arrow_forward_ios, - size: 16, color: Color(0xFF898C81)) - : null, + trailing: const Icon(Icons.arrow_forward_ios, + size: 16, color: Color(0xFF898C81)), ), ); } diff --git a/pubspec.yaml b/pubspec.yaml index 7d133b2a..4b965ae1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: uae_stat description: "View statistics about the UAE from the Federal Center for Statistics and Competitiveness." publish_to: "none" -version: 1.0.41+40 +version: 1.0.42+43 environment: sdk: ">=3.2.3 <4.0.0"