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")
if (flutterVersionCode == null) {
flutterVersionCode = "16"
flutterVersionCode = "17"
}
def flutterVersionName = localProperties.getProperty("flutter.versionName")
if (flutterVersionName == null) {
flutterVersionName = "1.0.15"
flutterVersionName = "1.0.16"
}
def keystorePropertiesFile = rootProject.file("key.properties")

View File

@ -51,6 +51,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
List<dynamic> tabFilteredChartData = [];
List<dynamic> tabFilteredCardData = [];
List<dynamic> cardData = [];
List<Map<String, dynamic>> filteredAndSortedData = [];
List<dynamic> originalChartsData = [];
List<dynamic> originalCardData = [];
List<dynamic> originalTabCardData = [];
@ -60,6 +61,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
int _activeTabIndex = 0;
dynamic _tabsData = [];
// List<Map<String, dynamic>> _tabsData = [];
late List<TargetFocus> marriageTargets;
late List<TargetFocus> previousMarriageTargets;
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) {
// Group data by 'kpi'
Map<String, List<Map<String, dynamic>>> groupedData = {};
@ -1201,12 +1216,15 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
// Format 'kpi' values for _tabs with tab_heading
List<Map<String, String>> _tabs = groupedData.entries.map((entry) {
String kpi = entry.key;
var firstChart = entry.value.first;
// Extract tab_heading from the first chart in the grouped list
String tabHeading = entry.value.isNotEmpty
? entry.value.first['tab_heading'] ?? 'Unknown'
: 'Unknown';
int tabOrder = int.tryParse(firstChart['tab_order'] ?? '0') ?? 0;
String formattedKpi = kpi
.split('_') // Split by underscore
.map((word) => word.isNotEmpty
@ -1214,9 +1232,20 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
: '') // Capitalize
.join(' '); // Join words with space
return {'id': kpi, 'name': tabHeading};
return {'id': kpi, 'name': tabHeading, 'order': tabOrder.toString()};
}).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('Tabs: $_tabs');
@ -1252,8 +1281,10 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
cardData = nonChartData;
chartScreenData = data['chartScreenData'] ?? {};
processCardData(cardData);
processChartData(chartsData);
print('chartsData :- $chartsData');
print('cardData :- $cardData');
print('chartScreenData :- $chartScreenData');
@ -1274,7 +1305,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
setState(() {
chartsData =
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');
Navigator.pop(context);
@ -1326,47 +1357,47 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
}
}
List filteredCardData = [];
for (var chart in dataCard) {
Map<String, dynamic> chartData = Map<String, dynamic>.from(chart);
// Extract response data for filtering
List response = chartData['response'] ?? [];
// List filteredCardData = [];
// for (var chart in dataCard) {
// Map<String, dynamic> chartData = Map<String, dynamic>.from(chart);
// // Extract response data for filtering
// List response = chartData['response'] ?? [];
// Filter the response based on selected filters
var cardFilteredData = response.where((responseItem) {
final obsKey = responseItem['ObsKey'];
// // Filter the response based on selected filters
// var cardFilteredData = response.where((responseItem) {
// final obsKey = responseItem['ObsKey'];
// Check if each selected filter's `filter_data` matches `ObsKey` values
return selectedFilters.every((filter) {
final filterKey = filter['filter_key'];
final filterValues = filter['filter_data'];
// // Check if each selected filter's `filter_data` matches `ObsKey` values
// return selectedFilters.every((filter) {
// final filterKey = filter['filter_key'];
// final filterValues = filter['filter_data'];
// Ensure the filter_key exists in the `ObsKey` and check if it matches any of the `filter_data`
if (obsKey.containsKey(filterKey)) {
final obsKeyValue = obsKey[filterKey]?.toString();
return filterValues.isEmpty || filterValues.contains(obsKeyValue);
}
return false;
});
}).toList();
// If any data matches the filter, add the whole chart data object
if (cardFilteredData.isNotEmpty) {
filteredCardData.add({
...chart, // Include all other properties of the chart object
'response': cardFilteredData, // Only include filtered response data
});
}
}
// // Ensure the filter_key exists in the `ObsKey` and check if it matches any of the `filter_data`
// if (obsKey.containsKey(filterKey)) {
// final obsKeyValue = obsKey[filterKey]?.toString();
// return filterValues.isEmpty || filterValues.contains(obsKeyValue);
// }
// return false;
// });
// }).toList();
//
// // If any data matches the filter, add the whole chart data object
// if (cardFilteredData.isNotEmpty) {
// filteredCardData.add({
// ...chart, // Include all other properties of the chart object
// 'response': cardFilteredData, // Only include filtered response data
// });
// }
// }
// Update the chartsData with the filtered data
setState(() {
chartsData = filteredData;
cardData = filteredCardData; // Adjust this part as needed
// cardData = filteredCardData; // Adjust this part as needed
});
print("Filtered Data: $filteredData");
print("Filtered Card: $filteredCardData");
// print("Filtered Card: $filteredCardData");
// Go back after applying filters
Navigator.pop(context);
@ -1856,6 +1887,8 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
// return 1.0; // Default fallback (should never be reached)
// }
@override
Widget build(BuildContext context) {
final locale = ref.watch(localeProvider);
@ -1945,7 +1978,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
// height: myheight / 5,
width: double.infinity,
// color: color,
color: Color(int.parse(chartScreenData['header_color'].replaceFirst('#', '0xff'))),
color: Color(int.parse((chartScreenData['header_color']?? '#898C81').replaceFirst('#', '0xff'))),
child: Padding(
padding: EdgeInsets.only(
left: 30, right: 30, top: 8, bottom: 5),
@ -1959,7 +1992,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
color: Colors.white,
fontSize: 26,
fontWeight: FontWeight.w400,
fontFamily: 'Roboto'
fontFamily: 'Roboto'
),
),
Container(
@ -1999,7 +2032,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
),
)),
Container(
color: Color(int.parse(chartScreenData['header_color'].replaceFirst('#', '0xff'))),
color: Color(int.parse((chartScreenData['header_color']?? '#898C81').replaceFirst('#', '0xff'))),
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
@ -2099,15 +2132,25 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
color: Colors.white,
),
),
IconButton(
icon: Icon(Icons.filter_alt_outlined,
color: Colors.white, size: 24),
onPressed: () {
showRightSideModal(
context, filterData, chartsData);
GestureDetector(
onTap: () {
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(
child: Container(
color: Color(int.parse(chartScreenData['body_color'].replaceFirst('#', '0xff'))),
color: Color(int.parse((chartScreenData['body_color']?? '#898C81').replaceFirst('#', '0xff'))),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: ListView(
child: ListView(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
@ -2181,23 +2223,34 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
physics: const NeverScrollableScrollPhysics(),
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: cardData.length == 2
? 2
: cardData.length == 3
? 3
: cardData.length == 4
? 2
: 3, // Default to 3 if more than 4 items // 2 cards per row
// crossAxisCount:2,
crossAxisCount: cardData.length % 2 == 0 ? 2 : 3,
// crossAxisCount: cardData.length == 2
// ? 2
// : cardData.length == 3
// ? 3
// : cardData.length == 4
// ? 2
// : 3, // Default to 3 if more than 4 items // 2 cards per row
crossAxisSpacing: 2,
mainAxisSpacing: 5,
childAspectRatio:
calculateAspectRatio(cardData.length, cardData),
childAspectRatio: MediaQuery.of(context).size.width /
(MediaQuery.of(context).size.height / (cardData.length % 2 == 0 ? 2 : 1.3)),
// childAspectRatio:
// calculateAspectRatio(cardData.length, cardData),
),
itemBuilder: (context, index) {
final item = cardData[index];
// Sort and filter the cardData
itemBuilder: (context, index) {
final item = filteredAndSortedData[index];
// print('item');
// final item = cardData[index];
print('item item item $item');
final chart_type = item['chart_type'];
final chart_heading = item['chart_heading'];
final response = item['response'] as List<dynamic>? ?? [];
final card_logo = item['card_logo'];
final data = apiService.processNonChartData(item);
print('processNonChartData');
@ -2207,354 +2260,241 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
? 180.0
: 130.0;
if (chart_type == 'total') {
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
),
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: 0, // Remove shadow to keep only the outli
child: Container(
height: cardHeight,
padding: const EdgeInsets.all(10.0),
child: Column(
mainAxisSize: MainAxisSize
.min, // Adjust card height based on content
mainAxisAlignment: MainAxisAlignment.center,
children: [
// const Icon(Icons.public,
// color: Color(0xFF90B0D5), size: 30),
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: 3),
Flexible(
fit: FlexFit.loose,
child: FittedBox(
child: SizedBox(
// height: 70.0,
),
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
maxLines: 2,
// Limit to 2 lines
softWrap:
true, // Enable soft wrapping
true,
// Enable soft wrapping
// overflow: TextOverflow.ellipsis, // Handle overflow gracefully
style: TextStyle(
fontSize: 8,
fontSize: 9,
fontWeight: FontWeight.w400,
color: Colors.black87,
),
),
// ),
),
),
),
const SizedBox(height: 1),
Text(
'(${data['lastYear'] ?? 'NA'})',
style: const TextStyle(
fontSize: 10, color: Colors.grey),
),
const SizedBox(height: 1),
Flexible(
fit: FlexFit.loose,
child: FittedBox(
fit: BoxFit.contain,
child: Text(
apiService.formatAmount(
data['lastYearValue']),
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w900,
color: Color(0xFF90B0D5),
),
),
),
),
SizedBox(
height: 2, // Height of the divider
child: Divider(
color: Colors.grey,
thickness:
1, // Divider line thickness
),
),
Flexible(
fit: FlexFit.loose,
child: FittedBox(
fit: BoxFit.contain,
child: Text(
apiService.formatAmount(
data['secondLastYearValue']),
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Color(0xFFD83731),
),
),
),
),
Text(
'(${data['secondLastYear'] ?? 'NA'})',
style: const TextStyle(
fontSize: 9,
fontWeight: FontWeight.w500,
color: Colors.grey),
),
],
),
),
),);
} 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),
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 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
));
}
else{
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: 0, // Remove shadow to keep only the outli
child: Container(
height: cardHeight,
padding: const EdgeInsets.all(10.0),
child: Column(
mainAxisSize: MainAxisSize
.min, // Adjust card height based on content
mainAxisAlignment: MainAxisAlignment.center,
children: [
// const Icon(Icons.public,
// color: Color(0xFF90B0D5), size: 30),
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: 3),
Flexible(
fit: FlexFit.loose,
child: FittedBox(
child: SizedBox(
// height: 70.0,
child: Text(
'${chart_heading ?? 'NA'}',
// "TOTAL",
textAlign: TextAlign.center,
maxLines: 2, // Limit to 2 lines
softWrap:
true, // Enable soft wrapping
// overflow: TextOverflow.ellipsis, // Handle overflow gracefully
style: TextStyle(
fontSize: 8,
fontWeight: FontWeight.w400,
color: Colors.black87,
),
),
),
),
),
const SizedBox(height: 1),
Text(
'(${response[0]['display_value'] ?? 'NA'})',
// '(${data['lastYear'] ?? 'NA'})',
style: const TextStyle(
fontSize: 10, color: Colors.grey),
),
const SizedBox(height: 1),
Flexible(
fit: FlexFit.loose,
child: FittedBox(
fit: BoxFit.contain,
child: Text(
response[0]['value'] ?? 'NA',
// apiService.formatAmount(
// data['lastYearValue']),
// apiService.formatAmount(
// data['lastYearValue']),
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w900,
color: Color(0xFF90B0D5),
),
),
),
),
SizedBox(
height: 2, // Height of the divider
child: Divider(
color: Color(0xFFBBBCBD),
thickness:
1, // Divider line thickness
),
),
Flexible(
fit: FlexFit.loose,
child: FittedBox(
fit: BoxFit.contain,
child: Text(
response[1]['value'] ?? 'NA',
// apiService.formatAmount(
// data['secondLastYearValue']),
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Color(0xFFD83731),
),
),
),
),
Text(
'(${response[1]['display_value'] ?? 'NA'})',
// '(${data['secondLastYear'] ?? 'NA'})',
style: const TextStyle(
fontSize: 9,
fontWeight: FontWeight.w500,
color: Colors.grey),
),
],
),
),
),);
}
},
),
),
@ -2572,8 +2512,11 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 10),
Container(
height: 300,
ConstrainedBox(
constraints: const BoxConstraints(
minHeight: 200, // Minimum height
maxHeight: 400, // Maximum height
),
// child: buildChart(chartsData[index]),
child: ChartWidget(
chartData: chartsData[index])),

View File

@ -261,21 +261,23 @@ class ChartWidget extends StatelessWidget {
),
),
SizedBox(height: 25),
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),
child: Wrap(
spacing: 12,
runSpacing: 8,
children: generateIndicators(chartData, chartData['group_by']),
),
),
),
padding: const EdgeInsets.only(
left: 8.0, right: 8.0, bottom: 8.0, top: 20.0),
child: Wrap(
spacing: 12,
runSpacing: 8,
children:
generateIndicators(chartData, chartData['group_by']),
),
),
),
),
),
],
@ -896,7 +898,22 @@ class ChartWidget extends StatelessWidget {
? yAxisData.reduce((a, b) => a > b ? a : b) * 1.2
: 10,
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(
leftTitles: AxisTitles(
sideTitles: SideTitles(
@ -925,11 +942,11 @@ class ChartWidget extends StatelessWidget {
// angle: -45 *
// (3.1415927 / 180), // Rotating by -45 degrees
alignment: Alignment.center,
child: Center(
child: Center(
child: SizedBox(
width: 100,
child: Text(
xAxisData[value.toInt()],
xAxisData[value.toInt()],
style: const TextStyle(fontSize: 12),
softWrap: true,
maxLines: 2,
@ -977,39 +994,15 @@ class ChartWidget extends StatelessWidget {
const double barWidth = 30; // Width for each bar, including spacing
return totalBars * barWidth; // Calculate total chart width
}
String cropKey = chartData['chart_type_json']['x_sub_group'];
// Group crops by CROP_TYPE
Map<String, List<String>> groupedCrops = {};
int touchedGroupIndex = -1;
// Iterate over the chartData to group crops by CROP_TYPE
for (var item in chartData['response']) {
String crop, cropType;
if (chartData['dataset'] == 'health_services') {
crop = item['ObsKey']['SECTOR'];
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];
}
crop = item['ObsKey'][cropKey];
cropType = item['ObsKey'][groupByKey];
if (groupedCrops.containsKey(cropType)) {
groupedCrops[cropType]!.add(crop);
@ -1187,64 +1180,17 @@ class ChartWidget extends StatelessWidget {
]);
case 'horizontal_rotate':
String cropKey = chartData['chart_type_json']
['y_sub_group']; // Dynamically get crop key
// Group crops by CROP_TYPE
Map<String, List<String>> groupedCrops = {};
// Iterate over the chartData to group crops by CROP_TYPE
for (var item in chartData['response']) {
String crop, cropType;
if (chartData['dataset'] == 'natural_reserves') {
crop = item['ObsKey']['NR_TYPE'];
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];
}
// crop = item['ObsKey']['CROP'];
crop = item['ObsKey'][cropKey];
cropType = item['ObsKey'][groupByKey];
if (groupedCrops.containsKey(cropType)) {
groupedCrops[cropType]!.add(crop);
@ -1257,16 +1203,17 @@ class ChartWidget extends StatelessWidget {
int rotationTurns = 1;
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 barSpacing = 30.0; // Space between bar sets
double minHeight = 300.0; // Minimum chart height
double maxHeight = 1000.0; // Maximum chart height
// Calculate total height dynamically
double chartHeight = ((numberOfBars * barHeight) + ((numberOfBars - 1) * barSpacing))
.clamp(minHeight, maxHeight);
double chartHeight =
((numberOfBars * barHeight) + ((numberOfBars - 1) * barSpacing))
.clamp(minHeight, maxHeight);
return Column(children: [
Text(
@ -1280,166 +1227,172 @@ class ChartWidget extends StatelessWidget {
SizedBox(height: 10),
// Chart
Expanded(
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child:SizedBox(
width: 1000,
height: chartHeight,
child: BarChart(
BarChartData(
maxY: 400000,
rotationQuarterTurns: rotationTurns,
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
}
scrollDirection: Axis.vertical,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: SizedBox(
width: 1000,
height: chartHeight,
child: BarChart(
BarChartData(
maxY: 400000,
rotationQuarterTurns: rotationTurns,
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
}
if (groupIndex == touchedGroupIndex) {
// print('Group Index: $groupIndex, Group : $group');
if (groupIndex == touchedGroupIndex) {
// print('Group Index: $groupIndex, Group : $group');
// Get the group label dynamically
String groupLabel = groupByValues.elementAt(groupIndex);
// 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;
// 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
}
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',
const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
children: [
TextSpan(
text: ' Value: $formattedValue',
style: const TextStyle(
color: Colors.yellow,
fontWeight: FontWeight.w500,
return BarTooltipItem(
'$groupLabel\n$crop',
const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
],
);
}
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: 20,
interval: 100000,
getTitlesWidget: (value, meta) {
return Text(
value.toInt().toString(),
style: const TextStyle(fontSize: 12),
);
},
),
),
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
reservedSize: 80, // 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: 80,
child: Text(
title,
style: const TextStyle(fontSize: 12),
softWrap: true,
maxLines: 2,
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
// });
}
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),
titlesData: FlTitlesData(
leftTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: false,
reservedSize: 20,
interval: 100000,
getTitlesWidget: (value, meta) {
return Text(
value.toInt().toString(),
style: const TextStyle(fontSize: 12),
);
},
),
),
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
reservedSize: 80, // 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: 80,
child: Text(
title,
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,
);
},
getDrawingVerticalLine: (value) {
return FlLine(
color: Colors.grey.withOpacity(0.5),
strokeWidth: 1,
);
},
),
barGroups: _buildHorizontalRotateBarGroups(
chartData, groupByValues),
alignment: BarChartAlignment.spaceAround,
),
),
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),
alignment: BarChartAlignment.spaceAround,
),
),
),
),
)),
// Expanded(
// child: Stack(
@ -2109,9 +2062,8 @@ class ChartWidget extends StatelessWidget {
chartData['dataset'] == 'higher_education' ||
chartData['dataset'] == 'air_transport' ||
chartData['dataset'] == 'labour_force' ||
chartData['dataset'] == 'gdp'
) {
chartData['dataset'] == 'gdp' ||
chartData['dataset'] == 'clinics') {
barColor = uniqueColorsForTwo[colorIndex % uniqueColorsForTwo.length];
colorIndex++;
} else {

View File

@ -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.15+16
version: 1.0.16+17
environment:
sdk: ">=3.2.3 <4.0.0"