chart and card changes
This commit is contained in:
parent
dafc089ae9
commit
140ea2405a
@ -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")
|
||||||
|
|||||||
@ -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),
|
||||||
@ -1959,7 +1992,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
|
|||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontSize: 26,
|
fontSize: 26,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
fontFamily: 'Roboto'
|
fontFamily: 'Roboto'
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
@ -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),
|
||||||
),
|
),
|
||||||
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');
|
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,354 +2260,241 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
|
|||||||
? 180.0
|
? 180.0
|
||||||
: 130.0;
|
: 130.0;
|
||||||
|
|
||||||
if (chart_type == 'total') {
|
if (response.isEmpty) {
|
||||||
return
|
return const SizedBox.shrink();
|
||||||
Container(
|
// return Container(
|
||||||
margin: const EdgeInsets.all(10),
|
// color: Colors.redAccent,
|
||||||
decoration: BoxDecoration(
|
// );
|
||||||
borderRadius: BorderRadius.circular(12),
|
}
|
||||||
border: Border.all(
|
if (response.length == 1) {
|
||||||
color: Color(int.parse(chartScreenData['border_color'].replaceFirst('#', '0xff'))), // Dynamic border color
|
return Container(
|
||||||
width: 1, // Adjust border thickness
|
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),
|
child: Card(
|
||||||
shape: RoundedRectangleBorder(
|
margin: const EdgeInsets.all(0),
|
||||||
borderRadius: BorderRadius.circular(12),
|
shape: RoundedRectangleBorder(
|
||||||
),
|
borderRadius: BorderRadius.circular(12),
|
||||||
elevation: 0, // Remove shadow to keep only the outli
|
),
|
||||||
|
elevation: 2,
|
||||||
child: Container(
|
child: Container(
|
||||||
height: cardHeight,
|
height: cardHeight,
|
||||||
padding: const EdgeInsets.all(10.0),
|
padding: const EdgeInsets.only(left:16.0, right: 16.0, bottom: 1.0 , top: 1.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize
|
mainAxisSize: MainAxisSize.min,
|
||||||
.min, // Adjust card height based on content
|
mainAxisAlignment: MainAxisAlignment
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
.center,
|
||||||
children: [
|
children: [
|
||||||
// const Icon(Icons.public,
|
Image.network(
|
||||||
// color: Color(0xFF90B0D5), size: 30),
|
card_logo ?? '',
|
||||||
Image.network(
|
width: 30,
|
||||||
card_logo ?? '',
|
height: 30,
|
||||||
width: 30,
|
errorBuilder:
|
||||||
height: 30,
|
(context, error, stackTrace) {
|
||||||
errorBuilder:
|
return Icon(Icons.public,
|
||||||
(context, error, stackTrace) {
|
color: Color(0xFF90B0D5),
|
||||||
return Icon(Icons.public,
|
size: 30); // Fallback icon
|
||||||
color: Color(0xFF90B0D5),
|
},
|
||||||
size: 30); // Fallback icon
|
),
|
||||||
},
|
const SizedBox(height: 1),
|
||||||
),
|
Flexible(
|
||||||
const SizedBox(height: 3),
|
fit: FlexFit.loose,
|
||||||
Flexible(
|
// child: FittedBox(
|
||||||
fit: FlexFit.loose,
|
|
||||||
child: FittedBox(
|
|
||||||
child: SizedBox(
|
|
||||||
// height: 70.0,
|
|
||||||
child: Text(
|
child: Text(
|
||||||
|
|
||||||
'${chart_heading ?? 'NA'}',
|
'${chart_heading ?? 'NA'}',
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
maxLines: 2, // Limit to 2 lines
|
maxLines: 2,
|
||||||
|
// Limit to 2 lines
|
||||||
softWrap:
|
softWrap:
|
||||||
true, // Enable soft wrapping
|
true,
|
||||||
|
// Enable soft wrapping
|
||||||
// overflow: TextOverflow.ellipsis, // Handle overflow gracefully
|
// overflow: TextOverflow.ellipsis, // Handle overflow gracefully
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 8,
|
fontSize: 9,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
color: Colors.black87,
|
color: Colors.black87,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
// ),
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(height: 5),
|
||||||
),
|
Flexible(
|
||||||
const SizedBox(height: 1),
|
fit: FlexFit.loose,
|
||||||
Text(
|
child: FittedBox(
|
||||||
'(${data['lastYear'] ?? 'NA'})',
|
child: Text(
|
||||||
style: const TextStyle(
|
'(${ response[0]['display_value'] ?? 'NA'})',
|
||||||
fontSize: 10, color: Colors.grey),
|
// '(${data['firstYear'] ??
|
||||||
),
|
// 'NA'} - ${data['lastYear'] ??
|
||||||
const SizedBox(height: 1),
|
// 'NA'})',
|
||||||
Flexible(
|
style: const TextStyle(
|
||||||
fit: FlexFit.loose,
|
fontSize: 10,
|
||||||
child: FittedBox(
|
color: Colors.grey),
|
||||||
fit: BoxFit.contain,
|
),),),
|
||||||
child: Text(
|
const SizedBox(height: 1),
|
||||||
apiService.formatAmount(
|
Flexible(
|
||||||
data['lastYearValue']),
|
fit: FlexFit.loose,
|
||||||
style: const TextStyle(
|
child: SizedBox(
|
||||||
fontSize: 18,
|
height: 50.0,
|
||||||
fontWeight: FontWeight.w900,
|
child: FittedBox(
|
||||||
color: Color(0xFF90B0D5),
|
fit: BoxFit.contain,
|
||||||
),
|
child: Text(
|
||||||
),
|
response[0]['value'] ?? 'NA',
|
||||||
),
|
// '${data['roundedAverage'] ??
|
||||||
),
|
// 'NA'}',
|
||||||
SizedBox(
|
style: const TextStyle(
|
||||||
height: 2, // Height of the divider
|
fontSize: 20,
|
||||||
child: Divider(
|
fontWeight: FontWeight
|
||||||
color: Colors.grey,
|
.w900,
|
||||||
thickness:
|
color: Color(0xFF90B0D5),
|
||||||
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),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
));
|
|
||||||
} 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,
|
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])),
|
||||||
|
|||||||
@ -261,21 +261,23 @@ 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(
|
||||||
child: Wrap(
|
left: 8.0, right: 8.0, bottom: 8.0, top: 20.0),
|
||||||
spacing: 12,
|
child: Wrap(
|
||||||
runSpacing: 8,
|
spacing: 12,
|
||||||
children: generateIndicators(chartData, chartData['group_by']),
|
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
|
? 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(
|
||||||
@ -925,11 +942,11 @@ class ChartWidget extends StatelessWidget {
|
|||||||
// angle: -45 *
|
// angle: -45 *
|
||||||
// (3.1415927 / 180), // Rotating by -45 degrees
|
// (3.1415927 / 180), // Rotating by -45 degrees
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: 100,
|
width: 100,
|
||||||
child: Text(
|
child: Text(
|
||||||
xAxisData[value.toInt()],
|
xAxisData[value.toInt()],
|
||||||
style: const TextStyle(fontSize: 12),
|
style: const TextStyle(fontSize: 12),
|
||||||
softWrap: true,
|
softWrap: true,
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
@ -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,16 +1203,17 @@ 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 =
|
||||||
.clamp(minHeight, maxHeight);
|
((numberOfBars * barHeight) + ((numberOfBars - 1) * barSpacing))
|
||||||
|
.clamp(minHeight, maxHeight);
|
||||||
|
|
||||||
return Column(children: [
|
return Column(children: [
|
||||||
Text(
|
Text(
|
||||||
@ -1280,166 +1227,172 @@ class ChartWidget extends StatelessWidget {
|
|||||||
SizedBox(height: 10),
|
SizedBox(height: 10),
|
||||||
// Chart
|
// Chart
|
||||||
Expanded(
|
Expanded(
|
||||||
child: SingleChildScrollView(
|
|
||||||
scrollDirection: Axis.vertical,
|
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.vertical,
|
||||||
child:SizedBox(
|
child: SingleChildScrollView(
|
||||||
width: 1000,
|
scrollDirection: Axis.horizontal,
|
||||||
height: chartHeight,
|
child: SizedBox(
|
||||||
child: BarChart(
|
width: 1000,
|
||||||
BarChartData(
|
height: chartHeight,
|
||||||
maxY: 400000,
|
child: BarChart(
|
||||||
rotationQuarterTurns: rotationTurns,
|
BarChartData(
|
||||||
barTouchData: BarTouchData(
|
maxY: 400000,
|
||||||
touchTooltipData: BarTouchTooltipData(
|
rotationQuarterTurns: rotationTurns,
|
||||||
tooltipHorizontalAlignment: FLHorizontalAlignment.center,
|
barTouchData: BarTouchData(
|
||||||
tooltipRoundedRadius: 8,
|
touchTooltipData: BarTouchTooltipData(
|
||||||
fitInsideHorizontally:
|
tooltipHorizontalAlignment:
|
||||||
true, // Ensure it fits within the screen
|
FLHorizontalAlignment.center,
|
||||||
fitInsideVertically: true,
|
tooltipRoundedRadius: 8,
|
||||||
tooltipPadding: EdgeInsets.all(8),
|
fitInsideHorizontally:
|
||||||
tooltipMargin: 16,
|
true, // Ensure it fits within the screen
|
||||||
// Only show tooltip when touched
|
fitInsideVertically: true,
|
||||||
getTooltipItem: (group, groupIndex, rod, rodIndex) {
|
tooltipPadding: EdgeInsets.all(8),
|
||||||
if (rod.toY == 0 || touchedGroupIndex == -1) {
|
tooltipMargin: 16,
|
||||||
return null; // Don't show the tooltip if the value is 0 or there's no touch
|
// 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) {
|
if (groupIndex == touchedGroupIndex) {
|
||||||
// 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 =
|
||||||
String crop = groupedCrops[cropType]![rodIndex];
|
groupByValues.elementAt(groupIndex);
|
||||||
double value = rod.toY;
|
String crop = groupedCrops[cropType]![rodIndex];
|
||||||
|
double value = rod.toY;
|
||||||
|
|
||||||
String formattedValue;
|
String formattedValue;
|
||||||
if (value >= 1000000) {
|
if (value >= 1000000) {
|
||||||
formattedValue =
|
formattedValue =
|
||||||
(value / 1000000).toStringAsFixed(1) + 'M';
|
(value / 1000000).toStringAsFixed(1) + 'M';
|
||||||
} else if (value >= 1000) {
|
} else if (value >= 1000) {
|
||||||
formattedValue =
|
formattedValue =
|
||||||
(value / 1000).toStringAsFixed(1) + 'K';
|
(value / 1000).toStringAsFixed(1) + 'K';
|
||||||
} else {
|
} else {
|
||||||
formattedValue = value.toStringAsFixed(
|
formattedValue = value.toStringAsFixed(
|
||||||
0); // for values smaller than 1000
|
0); // for values smaller than 1000
|
||||||
}
|
}
|
||||||
|
|
||||||
return BarTooltipItem(
|
return BarTooltipItem(
|
||||||
'$groupLabel\n$crop',
|
'$groupLabel\n$crop',
|
||||||
const TextStyle(
|
const TextStyle(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
|
||||||
children: [
|
|
||||||
TextSpan(
|
|
||||||
text: ' Value: $formattedValue',
|
|
||||||
style: const TextStyle(
|
|
||||||
color: Colors.yellow,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
),
|
),
|
||||||
),
|
children: [
|
||||||
],
|
TextSpan(
|
||||||
);
|
text: ' Value: $formattedValue',
|
||||||
}
|
style: const TextStyle(
|
||||||
return null;
|
color: Colors.yellow,
|
||||||
},
|
fontWeight: FontWeight.w500,
|
||||||
),
|
),
|
||||||
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,
|
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
),
|
);
|
||||||
);
|
}
|
||||||
|
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();
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
titlesData: FlTitlesData(
|
||||||
rightTitles:
|
leftTitles: AxisTitles(
|
||||||
AxisTitles(sideTitles: SideTitles(showTitles: false)),
|
sideTitles: SideTitles(
|
||||||
topTitles:
|
showTitles: false,
|
||||||
AxisTitles(sideTitles: SideTitles(showTitles: false)),
|
reservedSize: 20,
|
||||||
),
|
interval: 100000,
|
||||||
borderData: FlBorderData(
|
getTitlesWidget: (value, meta) {
|
||||||
show: true,
|
return Text(
|
||||||
border: const Border(
|
value.toInt().toString(),
|
||||||
// left: BorderSide(color: Colors.grey),
|
style: const TextStyle(fontSize: 12),
|
||||||
bottom: BorderSide(color: Colors.white),
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
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(
|
// Expanded(
|
||||||
// child: Stack(
|
// child: Stack(
|
||||||
@ -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 {
|
||||||
|
|||||||
@ -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"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user