From 80fc023b4aef008cb10cd3f2058e0f5647098bf3 Mon Sep 17 00:00:00 2001 From: venbaittech Date: Tue, 18 Feb 2025 18:26:12 +0530 Subject: [PATCH] charts bug fix --- android/app/build.gradle | 4 +- .../Screens/charts/screens/chart_screen.dart | 53 +- .../Screens/charts/widgets/chart_widget.dart | 483 +++++++++++------- pubspec.yaml | 2 +- 4 files changed, 333 insertions(+), 209 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index c1188579..c8d2d5d2 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -15,12 +15,12 @@ if (localPropertiesFile.exists()) { def flutterVersionCode = localProperties.getProperty("flutter.versionCode") if (flutterVersionCode == null) { - flutterVersionCode = "20" + flutterVersionCode = "21" } def flutterVersionName = localProperties.getProperty("flutter.versionName") if (flutterVersionName == null) { - flutterVersionName = "1.0.19" + flutterVersionName = "1.0.20" } def keystorePropertiesFile = rootProject.file("key.properties") diff --git a/lib/presentation/Screens/charts/screens/chart_screen.dart b/lib/presentation/Screens/charts/screens/chart_screen.dart index 22f1e054..5ee3e428 100644 --- a/lib/presentation/Screens/charts/screens/chart_screen.dart +++ b/lib/presentation/Screens/charts/screens/chart_screen.dart @@ -2330,6 +2330,10 @@ class _ChartScreen1State extends ConsumerState { right: 16.0, bottom: 1.0, top: 1.0), + decoration: BoxDecoration( + color: Colors.white, // Move color inside BoxDecoration + borderRadius: BorderRadius.circular(12), // Ensure border radius is applied + ), child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: @@ -2373,6 +2377,8 @@ class _ChartScreen1State extends ConsumerState { const SizedBox(height: 5), Flexible( fit: FlexFit.loose, + child: SizedBox( + height: 20.0, child: FittedBox( child: Text( '(${response[0]['display_value'] ?? 'NA'})', @@ -2384,6 +2390,7 @@ class _ChartScreen1State extends ConsumerState { color: Colors.grey), ), ), + ), ), const SizedBox(height: 1), Flexible( @@ -2441,6 +2448,10 @@ class _ChartScreen1State extends ConsumerState { child: Container( height: cardHeight, padding: const EdgeInsets.all(10.0), + decoration: BoxDecoration( + color: Colors.white, // Move color inside BoxDecoration + borderRadius: BorderRadius.circular(12), // Ensure border radius is applied + ), child: Column( mainAxisSize: MainAxisSize .min, // Adjust card height based on content @@ -2574,24 +2585,42 @@ class _ChartScreen1State extends ConsumerState { itemBuilder: (context, index) { return Card( margin: const EdgeInsets.all(10), + child: Container( + + + decoration: BoxDecoration( + border: Border.all( + color: Color(int.parse((chartScreenData[ + 'border_color'] ?? '#898C81') + .replaceFirst('#', '0xff'),),), // Border color + width: 1, // Border width + ), + color: Colors.white, + borderRadius: BorderRadius.circular(8), // Optional: Rounded corners + ), child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const SizedBox(height: 10), - ConstrainedBox( - constraints: const BoxConstraints( - minHeight: - 200, // Minimum height - maxHeight: - 400, // Maximum height - ), - // child: buildChart(chartsData[index]), - child: ChartWidget( - chartData: - chartsData[index])), + + + // ConstrainedBox + Container + ( + // constraints: const BoxConstraints( + // minHeight: + // 200, // Minimum height + // maxHeight: + // 400, // Maximum height + // ), + height: 320, + + // child: buildChart(chartsData[index]), + child: ChartWidget( + chartData: + chartsData[index])) ], ), ), diff --git a/lib/presentation/Screens/charts/widgets/chart_widget.dart b/lib/presentation/Screens/charts/widgets/chart_widget.dart index 3cf031dd..7fe541dc 100644 --- a/lib/presentation/Screens/charts/widgets/chart_widget.dart +++ b/lib/presentation/Screens/charts/widgets/chart_widget.dart @@ -55,9 +55,30 @@ class ChartWidget extends StatelessWidget { .entries .map((entry) { int index = entry.key; + + print('piePArse'); + var data = entry.value; - double value = double.tryParse(data['ObsValue']['Value']) ?? 0.0; - double percentage = (value / totalValue) * 100; + // double value = double.tryParse(data['ObsValue']['Value']) ?? 0.0; + // double value = (data['ObsValue']['Value'] is double) + // ? data['ObsValue']['Value'] + // : (data['ObsValue']['Value'] is int) + // ? (data['ObsValue']['Value'] as int).toDouble() + // : 0.0; + + // Handle different types: int, double, and String + double value = 0.0; + + if (data['ObsValue']['Value'] is String) { + value = double.tryParse(data['ObsValue']['Value']) ?? 0.0; // Parse string to double + } else if (data['ObsValue']['Value'] is int) { + value = (data['ObsValue']['Value'] as int).toDouble(); // Convert int to double + } else if (data['ObsValue']['Value'] is double) { + value = data['ObsValue']['Value']; // Already a double + } + + print('piePArse1 - $value'); + double percentage = (value / totalValue) * 100; bool isTouched = index == touchedIndex; return PieChartSectionData( value: value, @@ -94,14 +115,22 @@ class ChartWidget extends StatelessWidget { ), ), SizedBox(width: 8), - Tooltip( + 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: Tooltip( message: title, // Full text on hover child: Text( shortTitle, style: TextStyle(fontSize: 12), overflow: TextOverflow.ellipsis, // Ensures text doesn't overflow ), - ), + ),), ], ); }).toList(); @@ -214,8 +243,11 @@ class ChartWidget extends StatelessWidget { ); case 'pie_chart': double totalValue = chartData['response'] - .map( - (entry) => double.tryParse(entry['ObsValue']['Value']) ?? 0.0) + .map((entry) { + var value = entry['ObsValue']['Value']; + print('Processing value: $value, type: ${value.runtimeType}'); // Debug each value + return value is int ? value.toDouble() : value is String ? double.tryParse(value) ?? 0.0 : 0.0; + }) .fold(0.0, (prev, element) => prev + element); ValueNotifier touchedIndex = ValueNotifier(null); @@ -240,7 +272,8 @@ class ChartWidget extends StatelessWidget { ), textAlign: TextAlign.center, ), - SizedBox(height: 20), + SizedBox(height: 40), + Expanded( child: ValueListenableBuilder( valueListenable: touchedIndex, @@ -266,22 +299,24 @@ class ChartWidget extends StatelessWidget { ), ), ); + }, + ), ), - SizedBox(height: 25), + SizedBox(height:60), Flexible( child: SingleChildScrollView( scrollDirection: Axis.vertical, child: Container( - constraints: - BoxConstraints(minHeight: 5), // Allow dynamic height + // constraints: + // BoxConstraints(minHeight: 5), // Allow dynamic height child: Padding( padding: const EdgeInsets.only( - left: 8.0, right: 8.0, bottom: 8.0, top: 20.0), + left: 0.0, right: 0.0, bottom: 8.0, top: 20.0), child: Wrap( - spacing: 12, - runSpacing: 8, + // spacing: 12, + // runSpacing: 8, children: generateIndicators(chartData, chartData['group_by']), ), @@ -325,7 +360,7 @@ class ChartWidget extends StatelessWidget { ), textAlign: TextAlign.center, ), - SizedBox(height: 10), + SizedBox(height: 15), AspectRatio( aspectRatio: 1.5, child: BarChart( @@ -336,8 +371,12 @@ class ChartWidget extends StatelessWidget { // tooltipBgColor: Colors.black.withOpacity(0.8), fitInsideHorizontally: true, fitInsideVertically: true, - tooltipPadding: const EdgeInsets.all(8), + // tooltipPadding: const EdgeInsets.all(8), + tooltipPadding: const EdgeInsets.symmetric(horizontal: 4, vertical: 8), // Optional + tooltipHorizontalAlignment: FLHorizontalAlignment.left, tooltipMargin: 16, + + getTooltipItem: (groupData, groupIndex, rodData, rodIndex) { // Get the list of group names dynamically @@ -395,6 +434,7 @@ class ChartWidget extends StatelessWidget { '', TextStyle(color: Colors.white, fontSize: 12), children: tooltipTextSpans, + textAlign: TextAlign.left, ); }, ), @@ -458,7 +498,7 @@ class ChartWidget extends StatelessWidget { 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), @@ -535,7 +575,7 @@ class ChartWidget extends StatelessWidget { Set uniqueXValues = filteredData .map((entry) { String? timePeriod = entry['ObsKey']['TIME_PERIOD']; // Nullable String - // print('TIME_PERIOD- $timePeriod'); + print('TIME_PERIOD- $timePeriod'); if (timePeriod == null) { print('TIME_PERIOD is null'); @@ -715,7 +755,7 @@ class ChartWidget extends StatelessWidget { // Generate line bars for the chart List lineBars = lineBarsData(filteredData, groupByValues, groupByKey); - + return Column(children: [ Text( chartData['chart_heading'] ?? '', // Chart title from data @@ -859,7 +899,7 @@ class ChartWidget extends StatelessWidget { Expanded( child: SingleChildScrollView( scrollDirection: Axis.horizontal, // Enable horizontal scrolling - padding: const EdgeInsets.only(right: 40), + padding: const EdgeInsets.only(right: 40, top: 20), child: SizedBox( width: (uniqueXValues.length * 50) + 50, // Adjust width dynamically @@ -919,7 +959,23 @@ class ChartWidget extends StatelessWidget { maxY: yAxisData.isNotEmpty ? yAxisData.reduce((a, b) => a > b ? a : b) * 1.2 : 10, - barTouchData: BarTouchData(enabled: true), + // barTouchData: BarTouchData(enabled: true), + barTouchData: BarTouchData( + enabled: true, + handleBuiltInTouches: true, + touchTooltipData: BarTouchTooltipData( + // fitInsideHorizontally: true, + // fitInsideVertically: true, + // tooltipPadding: const EdgeInsets.all(8), + // tooltipMargin: 16, + getTooltipItem: (group, groupIndex, rod, rodIndex) { + return BarTooltipItem( + rod.toY.toStringAsFixed(1), + const TextStyle(color: Colors.white), + ); + }, + ), + ), titlesData: FlTitlesData( leftTitles: AxisTitles( sideTitles: SideTitles( @@ -948,23 +1004,49 @@ class ChartWidget extends StatelessWidget { : title; return Padding( - padding: const EdgeInsets.only(top: 8.0), + padding: const EdgeInsets.only(top: 8.0,left: 25.0), child: SizedBox( width: 60, // Limit width to force wrapping child: Transform.rotate( - angle: -0.5, - child: Tooltip( + // 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.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, + style: TextStyle(fontSize: 10,), overflow: TextOverflow.ellipsis, - )), + ),), + ), + + ), + ))); } return Container(); }, - reservedSize: 40, + reservedSize: 80, ), ), topTitles: AxisTitles( @@ -1087,7 +1169,7 @@ class ChartWidget extends StatelessWidget { xAxisData[value.toInt()], style: const TextStyle(fontSize: 12), softWrap: true, - maxLines: 2, + maxLines: 3, ), ), ), @@ -1144,7 +1226,7 @@ class ChartWidget extends StatelessWidget { for (var item in chartData['response']) { - // print("MultiBArRaw item: $item"); + print("MultiBArRaw item: $item"); String crop = item['ObsKey'][cropKey]; String cropType = item['ObsKey'][groupByKey]; @@ -1174,184 +1256,197 @@ class ChartWidget extends StatelessWidget { // print('groupedCropsflmutli- $groupedCrops'); - return Column(children: [ - Text( - chartData['chart_heading'] ?? '', // Chart title from data - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w400, + return Center( + child: 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: SingleChildScrollView( - 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 - titlesData: FlTitlesData( - leftTitles: AxisTitles( - sideTitles: SideTitles(showTitles: false), + SizedBox(height: 10), + // Chart + Expanded( + child: SingleChildScrollView( + 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 + titlesData: FlTitlesData( + leftTitles: AxisTitles( + sideTitles: SideTitles(showTitles: false), + ), + bottomTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + reservedSize: 40, // 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; + + return Padding( + padding: const EdgeInsets.only(top: 8.0), + child: SizedBox( + width: 60, // Limit width to force wrapping + child: Transform.rotate( + angle: -0.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: Tooltip( + message: title, + child: Text( + displayTitle, + softWrap: true, + // style: TextStyle(backgroundColor: Colors.blueGrey[800]), + overflow: TextOverflow.ellipsis, + )), + + ), + ))); + // return Transform.rotate( + // angle: + // -0.5, // Rotation in radians (~ -30 degrees) + // child: Text( + // title, + // style: const TextStyle(fontSize: 12), + // ), + // ); + } + return const SizedBox.shrink(); + }, + ), + ), + topTitles: + AxisTitles(sideTitles: SideTitles(showTitles: false)), + rightTitles: + AxisTitles(sideTitles: SideTitles(showTitles: false)), ), - bottomTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: true, - reservedSize: 40, // 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; - - return Padding( - padding: const EdgeInsets.only(top: 8.0), - child: SizedBox( - width: 60, // Limit width to force wrapping - child: Transform.rotate( - angle: -0.5, - child: Tooltip( - message: title, - child: Text( - displayTitle, - softWrap: true, - overflow: TextOverflow.ellipsis, - )), - ))); - // return Transform.rotate( - // angle: - // -0.5, // Rotation in radians (~ -30 degrees) - // child: Text( - // title, - // style: const TextStyle(fontSize: 12), - // ), - // ); + borderData: FlBorderData(show: false), + barTouchData: BarTouchData( + touchTooltipData: BarTouchTooltipData( + 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 } - return const SizedBox.shrink(); + 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; + + 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 + } + // print('Cropvaluevalue: $groupLabel\n$crop $value $formattedValue'); + + return BarTooltipItem( + '$groupLabel\n$crop', + const TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + ), + children: [ + TextSpan( + // text: ' Value: ${rod.toY}', + text: ' Value: $formattedValue', + style: const TextStyle( + color: Colors.yellow, + fontWeight: FontWeight.w500, + ), + ), + ], + ); + } + return null; }, ), - ), - topTitles: - AxisTitles(sideTitles: SideTitles(showTitles: false)), - rightTitles: - AxisTitles(sideTitles: SideTitles(showTitles: false)), - ), - borderData: FlBorderData(show: false), - barTouchData: BarTouchData( - touchTooltipData: BarTouchTooltipData( - 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 + touchCallback: (event, response) { + if (event.isInterestedForInteractions && + response != null && + response.spot != null) { + // setState(() { + touchedGroupIndex = response.spot!.touchedBarGroupIndex; + // }); + } else { + // setState(() { + touchedGroupIndex = -1; // Reset if no interaction + // }); } - 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; - - 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 - } - // print('Cropvaluevalue: $groupLabel\n$crop $value $formattedValue'); - - return BarTooltipItem( - '$groupLabel\n$crop', - const TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - ), - children: [ - TextSpan( - // text: ' Value: ${rod.toY}', - 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 - // }); - } - }, + gridData: FlGridData(show: false), ), - gridData: FlGridData(show: false), ), ), - ), - )) - ]); + )) + ]), + ); case 'horizontal_rotate': String cropKey = chartData['chart_type_json'] @@ -2405,7 +2500,7 @@ double calculateBarWidth(BuildContext context, int totalBars) { barWidth = availableWidth; } - // Optional: Add a minimum width constraint if needed + // Optional: Add a minimum width constraint if needed double minWidth = 10.0; // Example minimum width if (barWidth < minWidth) { barWidth = minWidth; diff --git a/pubspec.yaml b/pubspec.yaml index b9904725..164da211 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.19+20 +version: 1.0.20+21 environment: sdk: ">=3.2.3 <4.0.0"