chart and card changes

This commit is contained in:
venbaittech 2025-02-14 18:25:18 +05:30
parent dafc089ae9
commit 140ea2405a
4 changed files with 532 additions and 637 deletions

View File

@ -15,12 +15,12 @@ if (localPropertiesFile.exists()) {
def flutterVersionCode = localProperties.getProperty("flutter.versionCode") def flutterVersionCode = localProperties.getProperty("flutter.versionCode")
if (flutterVersionCode == null) { if (flutterVersionCode == null) {
flutterVersionCode = "16" flutterVersionCode = "17"
} }
def flutterVersionName = localProperties.getProperty("flutter.versionName") def flutterVersionName = localProperties.getProperty("flutter.versionName")
if (flutterVersionName == null) { if (flutterVersionName == null) {
flutterVersionName = "1.0.15" flutterVersionName = "1.0.16"
} }
def keystorePropertiesFile = rootProject.file("key.properties") def keystorePropertiesFile = rootProject.file("key.properties")

View File

@ -51,6 +51,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
List<dynamic> tabFilteredChartData = []; List<dynamic> tabFilteredChartData = [];
List<dynamic> tabFilteredCardData = []; List<dynamic> tabFilteredCardData = [];
List<dynamic> cardData = []; List<dynamic> cardData = [];
List<Map<String, dynamic>> filteredAndSortedData = [];
List<dynamic> originalChartsData = []; List<dynamic> originalChartsData = [];
List<dynamic> originalCardData = []; List<dynamic> originalCardData = [];
List<dynamic> originalTabCardData = []; List<dynamic> originalTabCardData = [];
@ -60,6 +61,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
int _activeTabIndex = 0; int _activeTabIndex = 0;
dynamic _tabsData = []; dynamic _tabsData = [];
// List<Map<String, dynamic>> _tabsData = [];
late List<TargetFocus> marriageTargets; late List<TargetFocus> marriageTargets;
late List<TargetFocus> previousMarriageTargets; late List<TargetFocus> previousMarriageTargets;
late TutorialCoachMark tutorialCoachMark; late TutorialCoachMark tutorialCoachMark;
@ -1186,6 +1188,19 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
// }); // });
// } // }
void processCardData(cardData){
print('PRocessCardData');
setState(() {
filteredAndSortedData = (cardData as List)
.where((card) => (card as Map<String, dynamic>)['is_chart'] == 'false')
.map((card) => card as Map<String, dynamic>)
.toList()
..sort((a, b) => (a['order_id'] as int).compareTo(b['order_id'] as int));
});
}
void processChartData(chartsData) { void processChartData(chartsData) {
// Group data by 'kpi' // Group data by 'kpi'
Map<String, List<Map<String, dynamic>>> groupedData = {}; Map<String, List<Map<String, dynamic>>> groupedData = {};
@ -1201,12 +1216,15 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
// Format 'kpi' values for _tabs with tab_heading // Format 'kpi' values for _tabs with tab_heading
List<Map<String, String>> _tabs = groupedData.entries.map((entry) { List<Map<String, String>> _tabs = groupedData.entries.map((entry) {
String kpi = entry.key; String kpi = entry.key;
var firstChart = entry.value.first;
// Extract tab_heading from the first chart in the grouped list // Extract tab_heading from the first chart in the grouped list
String tabHeading = entry.value.isNotEmpty String tabHeading = entry.value.isNotEmpty
? entry.value.first['tab_heading'] ?? 'Unknown' ? entry.value.first['tab_heading'] ?? 'Unknown'
: 'Unknown'; : 'Unknown';
int tabOrder = int.tryParse(firstChart['tab_order'] ?? '0') ?? 0;
String formattedKpi = kpi String formattedKpi = kpi
.split('_') // Split by underscore .split('_') // Split by underscore
.map((word) => word.isNotEmpty .map((word) => word.isNotEmpty
@ -1214,9 +1232,20 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
: '') // Capitalize : '') // Capitalize
.join(' '); // Join words with space .join(' '); // Join words with space
return {'id': kpi, 'name': tabHeading}; return {'id': kpi, 'name': tabHeading, 'order': tabOrder.toString()};
}).toList(); }).toList();
// Sort tabs by tab_order
_tabs.sort((a, b) {
int orderA = int.tryParse(a['order'] ?? '0') ?? 0;
int orderB = int.tryParse(b['order'] ?? '0') ?? 0;
return orderA.compareTo(orderB);
});
print('Sorted Tabs: $_tabs');
print('Grouped Data: $groupedData'); print('Grouped Data: $groupedData');
print('Tabs: $_tabs'); print('Tabs: $_tabs');
@ -1252,8 +1281,10 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
cardData = nonChartData; cardData = nonChartData;
chartScreenData = data['chartScreenData'] ?? {}; chartScreenData = data['chartScreenData'] ?? {};
processCardData(cardData);
processChartData(chartsData); processChartData(chartsData);
print('chartsData :- $chartsData'); print('chartsData :- $chartsData');
print('cardData :- $cardData'); print('cardData :- $cardData');
print('chartScreenData :- $chartScreenData'); print('chartScreenData :- $chartScreenData');
@ -1274,7 +1305,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
setState(() { setState(() {
chartsData = chartsData =
List.from(originalTabChartsData); // Restore the original data List.from(originalTabChartsData); // Restore the original data
cardData = List.from(originalTabCardData); // Restore the original data // cardData = List.from(originalTabCardData); // Restore the original data
}); });
print('Returning as no filters are selected'); print('Returning as no filters are selected');
Navigator.pop(context); Navigator.pop(context);
@ -1326,47 +1357,47 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
} }
} }
List filteredCardData = []; // List filteredCardData = [];
for (var chart in dataCard) { // for (var chart in dataCard) {
Map<String, dynamic> chartData = Map<String, dynamic>.from(chart); // Map<String, dynamic> chartData = Map<String, dynamic>.from(chart);
// Extract response data for filtering // // Extract response data for filtering
List response = chartData['response'] ?? []; // List response = chartData['response'] ?? [];
// Filter the response based on selected filters // // Filter the response based on selected filters
var cardFilteredData = response.where((responseItem) { // var cardFilteredData = response.where((responseItem) {
final obsKey = responseItem['ObsKey']; // final obsKey = responseItem['ObsKey'];
// Check if each selected filter's `filter_data` matches `ObsKey` values // // Check if each selected filter's `filter_data` matches `ObsKey` values
return selectedFilters.every((filter) { // return selectedFilters.every((filter) {
final filterKey = filter['filter_key']; // final filterKey = filter['filter_key'];
final filterValues = filter['filter_data']; // final filterValues = filter['filter_data'];
// Ensure the filter_key exists in the `ObsKey` and check if it matches any of the `filter_data` // // Ensure the filter_key exists in the `ObsKey` and check if it matches any of the `filter_data`
if (obsKey.containsKey(filterKey)) { // if (obsKey.containsKey(filterKey)) {
final obsKeyValue = obsKey[filterKey]?.toString(); // final obsKeyValue = obsKey[filterKey]?.toString();
return filterValues.isEmpty || filterValues.contains(obsKeyValue); // return filterValues.isEmpty || filterValues.contains(obsKeyValue);
} // }
return false; // return false;
}); // });
}).toList(); // }).toList();
//
// If any data matches the filter, add the whole chart data object // // If any data matches the filter, add the whole chart data object
if (cardFilteredData.isNotEmpty) { // if (cardFilteredData.isNotEmpty) {
filteredCardData.add({ // filteredCardData.add({
...chart, // Include all other properties of the chart object // ...chart, // Include all other properties of the chart object
'response': cardFilteredData, // Only include filtered response data // 'response': cardFilteredData, // Only include filtered response data
}); // });
} // }
} // }
// Update the chartsData with the filtered data // Update the chartsData with the filtered data
setState(() { setState(() {
chartsData = filteredData; chartsData = filteredData;
cardData = filteredCardData; // Adjust this part as needed // cardData = filteredCardData; // Adjust this part as needed
}); });
print("Filtered Data: $filteredData"); print("Filtered Data: $filteredData");
print("Filtered Card: $filteredCardData"); // print("Filtered Card: $filteredCardData");
// Go back after applying filters // Go back after applying filters
Navigator.pop(context); Navigator.pop(context);
@ -1856,6 +1887,8 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
// return 1.0; // Default fallback (should never be reached) // return 1.0; // Default fallback (should never be reached)
// } // }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final locale = ref.watch(localeProvider); final locale = ref.watch(localeProvider);
@ -1945,7 +1978,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
// height: myheight / 5, // height: myheight / 5,
width: double.infinity, width: double.infinity,
// color: color, // color: color,
color: Color(int.parse(chartScreenData['header_color'].replaceFirst('#', '0xff'))), color: Color(int.parse((chartScreenData['header_color']?? '#898C81').replaceFirst('#', '0xff'))),
child: Padding( child: Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(
left: 30, right: 30, top: 8, bottom: 5), left: 30, right: 30, top: 8, bottom: 5),
@ -1999,7 +2032,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
), ),
)), )),
Container( Container(
color: Color(int.parse(chartScreenData['header_color'].replaceFirst('#', '0xff'))), color: Color(int.parse((chartScreenData['header_color']?? '#898C81').replaceFirst('#', '0xff'))),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
@ -2099,15 +2132,25 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
color: Colors.white, color: Colors.white,
), ),
), ),
GestureDetector(
IconButton( onTap: () {
icon: Icon(Icons.filter_alt_outlined, showRightSideModal(context, filterData, chartsData);
color: Colors.white, size: 24),
onPressed: () {
showRightSideModal(
context, filterData, chartsData);
}, },
child: Image.asset(
UaeNumbersAssetPath.filterUae,
color: Colors.white, // Set color to white
width: 21,
height: 21,
), ),
)
// IconButton(
// icon: Icon(Icons.filter_alt_outlined,
// color: Colors.white, size: 24),
// onPressed: () {
// showRightSideModal(
// context, filterData, chartsData);
// },
// ),
], ],
), ),
@ -2120,12 +2163,11 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
), ),
Expanded( Expanded(
child: Container( child: Container(
color: Color(int.parse(chartScreenData['body_color'].replaceFirst('#', '0xff'))), color: Color(int.parse((chartScreenData['body_color']?? '#898C81').replaceFirst('#', '0xff'))),
child: Padding( child: Padding(
padding: const EdgeInsets.all(10.0), padding: const EdgeInsets.all(10.0),
child: ListView( child: ListView(
children: [ children: [
Row( Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
@ -2181,23 +2223,34 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
gridDelegate: gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount( SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: cardData.length == 2 // crossAxisCount:2,
? 2 crossAxisCount: cardData.length % 2 == 0 ? 2 : 3,
: cardData.length == 3 // crossAxisCount: cardData.length == 2
? 3 // ? 2
: cardData.length == 4 // : cardData.length == 3
? 2 // ? 3
: 3, // Default to 3 if more than 4 items // 2 cards per row // : cardData.length == 4
// ? 2
// : 3, // Default to 3 if more than 4 items // 2 cards per row
crossAxisSpacing: 2, crossAxisSpacing: 2,
mainAxisSpacing: 5, mainAxisSpacing: 5,
childAspectRatio: childAspectRatio: MediaQuery.of(context).size.width /
calculateAspectRatio(cardData.length, cardData), (MediaQuery.of(context).size.height / (cardData.length % 2 == 0 ? 2 : 1.3)),
// childAspectRatio:
// calculateAspectRatio(cardData.length, cardData),
), ),
// Sort and filter the cardData
itemBuilder: (context, index) { itemBuilder: (context, index) {
final item = cardData[index]; final item = filteredAndSortedData[index];
// print('item');
// final item = cardData[index];
print('item item item $item'); print('item item item $item');
final chart_type = item['chart_type']; final chart_type = item['chart_type'];
final chart_heading = item['chart_heading']; final chart_heading = item['chart_heading'];
final response = item['response'] as List<dynamic>? ?? [];
final card_logo = item['card_logo']; final card_logo = item['card_logo'];
final data = apiService.processNonChartData(item); final data = apiService.processNonChartData(item);
print('processNonChartData'); print('processNonChartData');
@ -2207,14 +2260,119 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
? 180.0 ? 180.0
: 130.0; : 130.0;
if (chart_type == 'total') { if (response.isEmpty) {
return const SizedBox.shrink();
// return Container(
// color: Colors.redAccent,
// );
}
if (response.length == 1) {
return Container(
margin: const EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: Color(int.parse(
(chartScreenData['border_color']?? '#898C81')
.replaceFirst('#', '0xff'))),
// Dynamic border color
width: 1, // Adjust border thickness
),
),
child: Card(
margin: const EdgeInsets.all(0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 2,
child: Container(
height: cardHeight,
padding: const EdgeInsets.only(left:16.0, right: 16.0, bottom: 1.0 , top: 1.0),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment
.center,
children: [
Image.network(
card_logo ?? '',
width: 30,
height: 30,
errorBuilder:
(context, error, stackTrace) {
return Icon(Icons.public,
color: Color(0xFF90B0D5),
size: 30); // Fallback icon
},
),
const SizedBox(height: 1),
Flexible(
fit: FlexFit.loose,
// child: FittedBox(
child: Text(
'${chart_heading ?? 'NA'}',
textAlign: TextAlign.center,
maxLines: 2,
// Limit to 2 lines
softWrap:
true,
// Enable soft wrapping
// overflow: TextOverflow.ellipsis, // Handle overflow gracefully
style: TextStyle(
fontSize: 9,
fontWeight: FontWeight.w400,
color: Colors.black87,
),
),
// ),
),
const SizedBox(height: 5),
Flexible(
fit: FlexFit.loose,
child: FittedBox(
child: Text(
'(${ response[0]['display_value'] ?? 'NA'})',
// '(${data['firstYear'] ??
// 'NA'} - ${data['lastYear'] ??
// 'NA'})',
style: const TextStyle(
fontSize: 10,
color: Colors.grey),
),),),
const SizedBox(height: 1),
Flexible(
fit: FlexFit.loose,
child: SizedBox(
height: 50.0,
child: FittedBox(
fit: BoxFit.contain,
child: Text(
response[0]['value'] ?? 'NA',
// '${data['roundedAverage'] ??
// 'NA'}',
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight
.w900,
color: Color(0xFF90B0D5),
),
),
),
),
),
],
),
),
));
}
else{
return return
Container( Container(
margin: const EdgeInsets.all(10), margin: const EdgeInsets.all(10),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
border: Border.all( border: Border.all(
color: Color(int.parse(chartScreenData['border_color'].replaceFirst('#', '0xff'))), // Dynamic border color color: Color(int.parse((chartScreenData['border_color']?? '#898C81').replaceFirst('#', '0xff'))), // Dynamic border color
width: 1, // Adjust border thickness width: 1, // Adjust border thickness
), ),
), ),
@ -2254,6 +2412,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
// height: 70.0, // height: 70.0,
child: Text( child: Text(
'${chart_heading ?? 'NA'}', '${chart_heading ?? 'NA'}',
// "TOTAL",
textAlign: TextAlign.center, textAlign: TextAlign.center,
maxLines: 2, // Limit to 2 lines maxLines: 2, // Limit to 2 lines
softWrap: softWrap:
@ -2270,7 +2429,9 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
), ),
const SizedBox(height: 1), const SizedBox(height: 1),
Text( Text(
'(${data['lastYear'] ?? 'NA'})', '(${response[0]['display_value'] ?? 'NA'})',
// '(${data['lastYear'] ?? 'NA'})',
style: const TextStyle( style: const TextStyle(
fontSize: 10, color: Colors.grey), fontSize: 10, color: Colors.grey),
), ),
@ -2280,8 +2441,12 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
child: FittedBox( child: FittedBox(
fit: BoxFit.contain, fit: BoxFit.contain,
child: Text( child: Text(
apiService.formatAmount( response[0]['value'] ?? 'NA',
data['lastYearValue']),
// apiService.formatAmount(
// data['lastYearValue']),
// apiService.formatAmount(
// data['lastYearValue']),
style: const TextStyle( style: const TextStyle(
fontSize: 18, fontSize: 18,
fontWeight: FontWeight.w900, fontWeight: FontWeight.w900,
@ -2293,7 +2458,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
SizedBox( SizedBox(
height: 2, // Height of the divider height: 2, // Height of the divider
child: Divider( child: Divider(
color: Colors.grey, color: Color(0xFFBBBCBD),
thickness: thickness:
1, // Divider line thickness 1, // Divider line thickness
), ),
@ -2303,8 +2468,9 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
child: FittedBox( child: FittedBox(
fit: BoxFit.contain, fit: BoxFit.contain,
child: Text( child: Text(
apiService.formatAmount( response[1]['value'] ?? 'NA',
data['secondLastYearValue']), // apiService.formatAmount(
// data['secondLastYearValue']),
style: const TextStyle( style: const TextStyle(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -2314,7 +2480,9 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
), ),
), ),
Text( Text(
'(${data['secondLastYear'] ?? 'NA'})',
'(${response[1]['display_value'] ?? 'NA'})',
// '(${data['secondLastYear'] ?? 'NA'})',
style: const TextStyle( style: const TextStyle(
fontSize: 9, fontSize: 9,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
@ -2324,237 +2492,9 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
), ),
), ),
),); ),);
} else if (chart_type == 'average') {
return Container(
margin: const EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: Color(int.parse(chartScreenData['border_color'].replaceFirst('#', '0xff'))), // Dynamic border color
width: 1, // Adjust border thickness
),
),
child: Card(
margin: const EdgeInsets.all(0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 4,
child: Container(
height: cardHeight,
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.network(
card_logo ?? '',
width: 30,
height: 30,
errorBuilder:
(context, error, stackTrace) {
return Icon(Icons.public,
color: Color(0xFF90B0D5),
size: 30); // Fallback icon
},
),
const SizedBox(height: 1),
Flexible(
fit: FlexFit.loose,
// child: FittedBox(
child: Text(
'${chart_heading ?? 'NA'}',
textAlign: TextAlign.center,
maxLines: 2, // Limit to 2 lines
softWrap:
true, // Enable soft wrapping
// overflow: TextOverflow.ellipsis, // Handle overflow gracefully
style: TextStyle(
fontSize: 9,
fontWeight: FontWeight.w400,
color: Colors.black87,
),
),
// ),
),
const SizedBox(height: 5),
Flexible(
fit: FlexFit.loose,
child: FittedBox(
child:Text(
'(${data['firstYear'] ?? 'NA'} - ${data['lastYear'] ?? 'NA'})',
style: const TextStyle(
fontSize: 10, color: Colors.grey),
),),),
const SizedBox(height: 1),
Flexible(
fit: FlexFit.loose,
child: SizedBox(
height: 50.0,
child: FittedBox(
fit: BoxFit.contain,
child: Text(
'${data['roundedAverage'] ?? 'NA'}',
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w900,
color: Color(0xFF90B0D5),
),
),
),
),
),
],
),
),
));
} else if (chart_type == 'totals') {
return Container(
margin: const EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: Color(int.parse(chartScreenData['border_color'].replaceFirst('#', '0xff'))), // Dynamic border color
width: 1, // Adjust border thickness
),
),
child: Card(
margin: const EdgeInsets.all(0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 4,
child: Container(
height: cardHeight,
// height: maxHeight,
// padding: const EdgeInsets.all(10.0),
padding: const EdgeInsets.symmetric(
vertical: 0, horizontal: 10),
child: Column(
// mainAxisSize: MainAxisSize.min, // Adjust card height based on content
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.public,
color: Color(0xFF90B0D5), size: 30),
const SizedBox(height: 3),
Flexible(
fit: FlexFit.loose,
child: FittedBox(
child: Text(
'${chart_heading ?? 'NA'}',
textAlign: TextAlign.center,
maxLines: 2, // Limit to 2 lines
softWrap:
true, // Enable soft wrapping
// overflow: TextOverflow.ellipsis, // Handle overflow gracefully
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.w400,
color: Colors.black87,
),
),
),
),
Text(
'(${data['lastYear'] ?? 'NA'})',
style: const TextStyle(
fontSize: 11, color: Colors.grey),
),
Flexible(
fit: FlexFit.loose,
child: FittedBox(
fit: BoxFit.contain,
child: Text(
apiService.formatAmount(
data['lastYearValue']),
style: const TextStyle(
fontSize: 22,
fontWeight: FontWeight.w900,
color: Color(0xFF90B0D5),
),
),
),
),
],
),
),
));
} else if (chart_type == 'averages') {
return Container(
margin: const EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: Color(int.parse(chartScreenData['border_color'].replaceFirst('#', '0xff'))), // Dynamic border color
width: 1, // Adjust border thickness
),
),
child: Card(
margin: const EdgeInsets.all(0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 4,
child: Container(
// height: maxHeight,
// height: 200,
height: cardHeight,
padding: const EdgeInsets.all(5.0),
// padding: const EdgeInsets.symmetric(vertical: 0, horizontal: 10),
child: Column(
// mainAxisSize: MainAxisSize.min, // Adjust card height based on content
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.public,
color: Color(0xFF90B0D5), size: 30),
const SizedBox(height: 5),
Text(
'${chart_heading ?? 'NA'}',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.w400,
color: Colors.black87,
),
),
Text(
'(${data['lastYear'] ?? 'NA'})',
style: const TextStyle(
fontSize: 11, color: Colors.grey),
),
const SizedBox(height: 5),
Flexible(
fit: FlexFit.loose,
child: FittedBox(
child: Text(
'${chart_heading ?? 'NA'}',
textAlign: TextAlign.center,
maxLines: 2, // Limit to 2 lines
softWrap:
true, // Enable soft wrapping
// overflow: TextOverflow.ellipsis, // Handle overflow gracefully
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.w400,
color: Colors.black87,
),
),
),
),
],
),
),
));
} else {
return const SizedBox
.shrink(); // Ignore unknown KPIs
} }
}, },
), ),
), ),
@ -2572,8 +2512,11 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
const SizedBox(height: 10), const SizedBox(height: 10),
Container( ConstrainedBox(
height: 300, constraints: const BoxConstraints(
minHeight: 200, // Minimum height
maxHeight: 400, // Maximum height
),
// child: buildChart(chartsData[index]), // child: buildChart(chartsData[index]),
child: ChartWidget( child: ChartWidget(
chartData: chartsData[index])), chartData: chartsData[index])),

View File

@ -261,18 +261,20 @@ class ChartWidget extends StatelessWidget {
), ),
), ),
SizedBox(height: 25), SizedBox(height: 25),
Flexible( Flexible(
child: SingleChildScrollView( child: SingleChildScrollView(
scrollDirection: Axis.vertical, scrollDirection: Axis.vertical,
child: Container( child: Container(
constraints: BoxConstraints(minHeight: 5), // Allow dynamic height constraints:
BoxConstraints(minHeight: 5), // Allow dynamic height
child: Padding( child: Padding(
padding: const EdgeInsets.only(left: 8.0 ,right: 8.0,bottom: 8.0,top:20.0), padding: const EdgeInsets.only(
left: 8.0, right: 8.0, bottom: 8.0, top: 20.0),
child: Wrap( child: Wrap(
spacing: 12, spacing: 12,
runSpacing: 8, runSpacing: 8,
children: generateIndicators(chartData, chartData['group_by']), children:
generateIndicators(chartData, chartData['group_by']),
), ),
), ),
), ),
@ -896,7 +898,22 @@ class ChartWidget extends StatelessWidget {
? yAxisData.reduce((a, b) => a > b ? a : b) * 1.2 ? yAxisData.reduce((a, b) => a > b ? a : b) * 1.2
: 10, : 10,
rotationQuarterTurns: rotationTurns, rotationQuarterTurns: rotationTurns,
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( titlesData: FlTitlesData(
leftTitles: AxisTitles( leftTitles: AxisTitles(
sideTitles: SideTitles( sideTitles: SideTitles(
@ -977,39 +994,15 @@ class ChartWidget extends StatelessWidget {
const double barWidth = 30; // Width for each bar, including spacing const double barWidth = 30; // Width for each bar, including spacing
return totalBars * barWidth; // Calculate total chart width return totalBars * barWidth; // Calculate total chart width
} }
String cropKey = chartData['chart_type_json']['x_sub_group'];
// Group crops by CROP_TYPE // Group crops by CROP_TYPE
Map<String, List<String>> groupedCrops = {}; Map<String, List<String>> groupedCrops = {};
int touchedGroupIndex = -1; int touchedGroupIndex = -1;
// Iterate over the chartData to group crops by CROP_TYPE // Iterate over the chartData to group crops by CROP_TYPE
for (var item in chartData['response']) { for (var item in chartData['response']) {
String crop, cropType; String crop, cropType;
if (chartData['dataset'] == 'health_services') { crop = item['ObsKey'][cropKey];
crop = item['ObsKey']['SECTOR'];
cropType = item['ObsKey'][groupByKey]; cropType = item['ObsKey'][groupByKey];
} else if (chartData['dataset'] == 'general_education') {
print(chartData['dataset'] == 'general_education');
crop = item['ObsKey']['GENDER'];
cropType = item['ObsKey'][groupByKey];
} else if (chartData['dataset'] == 'higher_education') {
crop = item['ObsKey']['GENDER'];
cropType = item['ObsKey'][groupByKey];
} else if (chartData['dataset'] == 'labour_force') {
crop = item['ObsKey']['GENDER'];
cropType = item['ObsKey'][groupByKey];
} else if (chartData['dataset'] == 'clinics') {
if (kDebugMode) {
print('forclinics');
print('ObsKey: ${item['ObsKey']}');
// print('NR_TYPE: ${item['ObsKey']?['NR_TYPE']}');
}
crop = item['ObsKey']['MEASURE'];
cropType = item['ObsKey'][groupByKey];
} else {
crop = item['ObsKey']['CROP'];
cropType = item['ObsKey'][groupByKey];
}
if (groupedCrops.containsKey(cropType)) { if (groupedCrops.containsKey(cropType)) {
groupedCrops[cropType]!.add(crop); groupedCrops[cropType]!.add(crop);
@ -1187,64 +1180,17 @@ class ChartWidget extends StatelessWidget {
]); ]);
case 'horizontal_rotate': case 'horizontal_rotate':
String cropKey = chartData['chart_type_json']
['y_sub_group']; // Dynamically get crop key
// Group crops by CROP_TYPE // Group crops by CROP_TYPE
Map<String, List<String>> groupedCrops = {}; Map<String, List<String>> groupedCrops = {};
// Iterate over the chartData to group crops by CROP_TYPE // Iterate over the chartData to group crops by CROP_TYPE
for (var item in chartData['response']) { for (var item in chartData['response']) {
String crop, cropType; String crop, cropType;
if (chartData['dataset'] == 'natural_reserves') { // crop = item['ObsKey']['CROP'];
crop = item['ObsKey']['NR_TYPE']; crop = item['ObsKey'][cropKey];
cropType = item['ObsKey'][groupByKey]; cropType = item['ObsKey'][groupByKey];
}
else if(chartData['dataset'] == 'gdp')
{
print("ForGDP");
if (kDebugMode) {
print('ObsKey: ${item['ObsKey']}');
// print('NR_TYPE: ${item['ObsKey']?['NR_TYPE']}');
}
crop = item['ObsKey']['BOP_ITEM'];
cropType = item['ObsKey'][groupByKey];
} else if(chartData['dataset'] == 'air_transport')
{
print("Forair_transport");
if (kDebugMode) {
print('ObsKey: ${item['ObsKey']}');
// print('NR_TYPE: ${item['ObsKey']?['NR_TYPE']}');
}
crop = item['ObsKey']['MEASURE'];
cropType = item['ObsKey'][groupByKey];
} else if(chartData['dataset'] == 'import')
{
print("Forimport");
if (kDebugMode) {
print('ObsKey: ${item['ObsKey']}');
// print('NR_TYPE: ${item['ObsKey']?['NR_TYPE']}');
}
crop = item['ObsKey']['COUNTRY'];
cropType = item['ObsKey'][groupByKey];
}
else if(chartData['dataset'] == 'gdpq')
{
print("ForGDPq");
if (kDebugMode) {
print('ObsKey: ${item['ObsKey']}');
}
crop = item['ObsKey']['MEASURE'];
// crop = item['ObsKey']['TIME_PERIOD'];
cropType = item['ObsKey'][groupByKey];
}
else {
crop = item['ObsKey']['CROP'];
cropType = item['ObsKey'][groupByKey];
}
if (groupedCrops.containsKey(cropType)) { if (groupedCrops.containsKey(cropType)) {
groupedCrops[cropType]!.add(crop); groupedCrops[cropType]!.add(crop);
@ -1257,17 +1203,18 @@ class ChartWidget extends StatelessWidget {
int rotationTurns = 1; int rotationTurns = 1;
print('Grouped Crops: $groupedCrops'); print('Grouped Crops: $groupedCrops');
int numberOfBars = groupedCrops.length; // Number of grouped sets (bar groups) int numberOfBars =
groupedCrops.length; // Number of grouped sets (bar groups)
double barHeight = 40.0; // Height per individual bar double barHeight = 40.0; // Height per individual bar
double barSpacing = 30.0; // Space between bar sets double barSpacing = 30.0; // Space between bar sets
double minHeight = 300.0; // Minimum chart height double minHeight = 300.0; // Minimum chart height
double maxHeight = 1000.0; // Maximum chart height double maxHeight = 1000.0; // Maximum chart height
// Calculate total height dynamically // Calculate total height dynamically
double chartHeight = ((numberOfBars * barHeight) + ((numberOfBars - 1) * barSpacing)) double chartHeight =
((numberOfBars * barHeight) + ((numberOfBars - 1) * barSpacing))
.clamp(minHeight, maxHeight); .clamp(minHeight, maxHeight);
return Column(children: [ return Column(children: [
Text( Text(
chartData['chart_heading'] ?? '', // Chart title from data chartData['chart_heading'] ?? '', // Chart title from data
@ -1293,7 +1240,8 @@ class ChartWidget extends StatelessWidget {
rotationQuarterTurns: rotationTurns, rotationQuarterTurns: rotationTurns,
barTouchData: BarTouchData( barTouchData: BarTouchData(
touchTooltipData: BarTouchTooltipData( touchTooltipData: BarTouchTooltipData(
tooltipHorizontalAlignment: FLHorizontalAlignment.center, tooltipHorizontalAlignment:
FLHorizontalAlignment.center,
tooltipRoundedRadius: 8, tooltipRoundedRadius: 8,
fitInsideHorizontally: fitInsideHorizontally:
true, // Ensure it fits within the screen true, // Ensure it fits within the screen
@ -1310,10 +1258,12 @@ class ChartWidget extends StatelessWidget {
// print('Group Index: $groupIndex, Group : $group'); // print('Group Index: $groupIndex, Group : $group');
// Get the group label dynamically // Get the group label dynamically
String groupLabel = groupByValues.elementAt(groupIndex); String groupLabel =
groupByValues.elementAt(groupIndex);
// Fetch the crop for the current group from groupedCrops // Fetch the crop for the current group from groupedCrops
String cropType = groupByValues.elementAt(groupIndex); String cropType =
groupByValues.elementAt(groupIndex);
String crop = groupedCrops[cropType]![rodIndex]; String crop = groupedCrops[cropType]![rodIndex];
double value = rod.toY; double value = rod.toY;
@ -1354,7 +1304,8 @@ class ChartWidget extends StatelessWidget {
response != null && response != null &&
response.spot != null) { response.spot != null) {
// setState(() { // setState(() {
touchedGroupIndex = response.spot!.touchedBarGroupIndex; touchedGroupIndex =
response.spot!.touchedBarGroupIndex;
// }); // });
} else { } else {
// setState(() { // setState(() {
@ -1383,9 +1334,11 @@ class ChartWidget extends StatelessWidget {
reservedSize: 80, // Added space for rotated titles reservedSize: 80, // Added space for rotated titles
getTitlesWidget: (value, meta) { getTitlesWidget: (value, meta) {
if (value < groupByValues.length) { if (value < groupByValues.length) {
String title = groupByValues.elementAt(value.toInt()); String title =
groupByValues.elementAt(value.toInt());
return Transform.rotate( return Transform.rotate(
angle: -1.58, // Rotation in radians (~ -30 degrees) angle:
-1.58, // Rotation in radians (~ -30 degrees)
child: Center( child: Center(
child: SizedBox( child: SizedBox(
width: 80, width: 80,
@ -1433,8 +1386,8 @@ class ChartWidget extends StatelessWidget {
); );
}, },
), ),
barGroups: barGroups: _buildHorizontalRotateBarGroups(
_buildHorizontalRotateBarGroups(chartData, groupByValues), chartData, groupByValues),
alignment: BarChartAlignment.spaceAround, alignment: BarChartAlignment.spaceAround,
), ),
), ),
@ -2109,9 +2062,8 @@ class ChartWidget extends StatelessWidget {
chartData['dataset'] == 'higher_education' || chartData['dataset'] == 'higher_education' ||
chartData['dataset'] == 'air_transport' || chartData['dataset'] == 'air_transport' ||
chartData['dataset'] == 'labour_force' || chartData['dataset'] == 'labour_force' ||
chartData['dataset'] == 'gdp' chartData['dataset'] == 'gdp' ||
) { chartData['dataset'] == 'clinics') {
barColor = uniqueColorsForTwo[colorIndex % uniqueColorsForTwo.length]; barColor = uniqueColorsForTwo[colorIndex % uniqueColorsForTwo.length];
colorIndex++; colorIndex++;
} else { } else {

View File

@ -1,7 +1,7 @@
name: uae_stat name: uae_stat
description: "View statistics about the UAE from the Federal Center for Statistics and Competitiveness." description: "View statistics about the UAE from the Federal Center for Statistics and Competitiveness."
publish_to: "none" publish_to: "none"
version: 1.0.15+16 version: 1.0.16+17
environment: environment:
sdk: ">=3.2.3 <4.0.0" sdk: ">=3.2.3 <4.0.0"