diff --git a/lib/config/my_router.dart b/lib/config/my_router.dart index 96d64083..70b4fa22 100644 --- a/lib/config/my_router.dart +++ b/lib/config/my_router.dart @@ -328,7 +328,7 @@ final GoRouter router = GoRouter( GoRoute( path: '/', //builder: (context, state) => LoginRoute(), - builder: (context, state) => MyHomePage(), + builder: (context, state) => LoginRoute(), ), GoRoute( path: '/internetcheck', @@ -348,29 +348,39 @@ final GoRouter router = GoRouter( path: '/register', builder: (context, state) => RegisterScreen(), ), - GoRoute( - path: '/DemoHome/:dataSets', - builder: (context, state) { - final dataSets = state.pathParameters['dataSets']!; - print('Router $dataSets'); - return ChartPage(dataSets: dataSets); - }, - ), - GoRoute( - path: '/Chart/:dataSets', - builder: (context, state) { - final dataSets = state.pathParameters['dataSets']!; - print('Router $dataSets'); - return ChartScreen(dataSets: dataSets); - }, - ), + // GoRoute( + // path: '/DemoHome/:dataSets', + // builder: (context, state) { + // final dataSets = state.pathParameters['dataSets']!; + // print('Router $dataSets'); + // return ChartPage(dataSets: dataSets); + // }, + // ), + // GoRoute( + // path: '/Chart/:dataSets', + // builder: (context, state) { + // final dataSets = state.pathParameters['dataSets']!; + // print('Router $dataSets'); + // return ChartScreen(dataSets: dataSets); + // }, + // ), GoRoute( path: '/chartScreen/:dataSets', builder: (context, state) { + // Retrieve path parameter final dataSets = state.pathParameters['dataSets']!; - print('Router $dataSets'); - // return ChartScreen(dataSets: dataSets); - return ChartScreen1(dataSets: dataSets); + // Retrieve query parameter + final bgColor = state.uri.queryParameters['bgColor'] ?? + '0xFFFFFFFF'; // Default white + + print('Router dataSets: $dataSets'); + print('Router bgColor: $bgColor'); + + // Pass both values to the screen + return ChartScreen1( + dataSets: dataSets, + bgColor: bgColor, + ); }, ), GoRoute( @@ -423,19 +433,20 @@ final GoRouter router = GoRouter( path: '/user-guide', builder: (context, state) => UserGuide(), routes: [ - GoRoute(path: '/features', - name: 'features', - builder: (context, state) => UsingFeatures(), + GoRoute( + path: '/features', + name: 'features', + builder: (context, state) => UsingFeatures(), ), - - GoRoute(path: '/faq', - name: 'faq', - builder: (context, state) => FAQPage(), + GoRoute( + path: '/faq', + name: 'faq', + builder: (context, state) => FAQPage(), ), - - GoRoute(path: '/gettingStarted', - name: 'gettingStarted', - builder: (context, state) => GettingStarted(), + GoRoute( + path: '/gettingStarted', + name: 'gettingStarted', + builder: (context, state) => GettingStarted(), ), ], ), @@ -461,10 +472,7 @@ final GoRouter router = GoRouter( // path: '/uaenumbers', // builder: (context, state) => UaeNumbers(), // ), - GoRoute( - path: '/uaenumbers', - builder: (context,state) => UaeNumbers() - ), + GoRoute(path: '/uaenumbers', builder: (context, state) => UaeNumbers()), GoRoute( path: '/competitiveness', diff --git a/lib/presentation/Screens/Bottom Navigation Pages/UAE_Numbers/uae_numbers.dart b/lib/presentation/Screens/Bottom Navigation Pages/UAE_Numbers/uae_numbers.dart index 51c0e2aa..258caedc 100644 --- a/lib/presentation/Screens/Bottom Navigation Pages/UAE_Numbers/uae_numbers.dart +++ b/lib/presentation/Screens/Bottom Navigation Pages/UAE_Numbers/uae_numbers.dart @@ -1,8 +1,11 @@ +import 'dart:convert'; + import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:uae_stat/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart'; import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart'; import 'package:uae_stat/presentation/components/constant/constant.dart'; +import 'package:http/http.dart' as http; class UaeNumbers extends StatelessWidget { const UaeNumbers({super.key}); @@ -20,13 +23,49 @@ class UaeNumbers extends StatelessWidget { } } -class uaenumberWidget extends StatelessWidget { +class uaenumberWidget extends StatefulWidget { const uaenumberWidget({super.key}); @override + _UaenumberWidgetState createState() => _UaenumberWidgetState(); +} + +class _UaenumberWidgetState extends State { + @override + List homePageData = []; + bool isLoading = true; + + @override + void initState() { + fetchData(); + } + + Future fetchData() async { + // const baseUrl = 'https://pb.venbait.in/api/getHomePageData'; + const baseUrl = 'https://pb.venbait.in/api/getUAENumbersData'; + try { + final response = await http.get(Uri.parse(baseUrl)); + if (response.statusCode == 200) { + setState(() { + homePageData = json.decode(response.body); + // print("HomeDAta $homePageData"); + isLoading = false; + }); + } else { + throw Exception('Failed to load data'); + } + } catch (e) { + setState(() { + isLoading = false; + }); + print('Error fetching data: $e'); + } + } + Widget build(BuildContext context) { double myheight = MediaQuery.of(context).size.height; double mywidth = MediaQuery.of(context).size.width; + return Padding( padding: const EdgeInsets.all(16.0), child: ListView( @@ -49,153 +88,112 @@ class uaenumberWidget extends StatelessWidget { SizedBox( height: myheight / 35, ), - CustomExpandableTile( - title: 'ECONOMY', - titleBackgroundColor: economyColor, - children: [ - buildCategoryTitle('National Accounts', economyColor), - buildCardRow([ - buildCard(context, 'GDP (Constant)', '1.62T', '2022 (AED)', - economyColor, economyColor, mywidth / 2.5), - buildCard(context, 'FDI', '1.45T', '2021 (AED)', economyColor, - economyColor, mywidth / 2.5), - ]), - buildCategoryTitle('International Trade', economyColor), - buildCardRow([ - buildCard( - context, - 'Total Trade', - '669.9B', - 'Jan - Mar 2024 (AED)', - economyColor, - economyColor, - mywidth / 2.5), - buildCard( - context, - 'Total Import', - '686B', - 'Jan - Mar 2024 (AED)', - economyColor, - economyColor, - mywidth / 2.5), - ]), - buildCardRow([ - buildCard( - context, - 'Total Export', - '669.9B', - 'Jan - Mar 2024 (AED)', - economyColor, - economyColor, - mywidth / 2.5), - buildCard( - context, - 'Total ReExport', - '686B', - 'Jan - Mar 2024 (AED)', - economyColor, - economyColor, - mywidth / 2.5), - ]), - buildCategoryTitle('Prices', economyColor), - buildCardRow([ - buildCard( - context, - 'Total Export', - '669.9B', - 'Jan - Mar 2024 (AED)', - economyColor, - economyColor, - mywidth / 1.2), - ]), - ], - ), - CustomExpandableTile( - title: 'SOCIAL', - titleBackgroundColor: socialColor, - children: [ - buildCategoryTitle('Population', socialColor), - buildCardRow([ - InkWell( - onTap: () {}, - child: buildCard(context, 'Population', '9.89M', '2024', - socialColor, socialColor, mywidth / 2.5)), - buildCard(context, 'Population Growth', '2.1%', '2023', - socialColor, socialColor, mywidth / 2.5), - ]), - buildCategoryTitle('Vital Statistics', socialColor), - buildCardRow([ - InkWell(onTap : (){ - context.go('/marriages'); - },child: buildCard(context,'Marriages', '96%', '2023',socialColor,socialColor,mywidth/2.5)), - InkWell(onTap : (){},child: buildCard(context,'Divorces', '1.2K', '2024',socialColor,socialColor,mywidth/2.5)), - ]), - buildCategoryTitle('Education', socialColor), - buildCardRow([ - buildCard(context, 'General Education', '96%', '2023', - socialColor, socialColor, mywidth / 2.5), - buildCard(context, 'Higher Education', '1.2K', '2024', - socialColor, socialColor, mywidth / 2.5), - ]), - buildCategoryTitle('Health', socialColor), - buildCardRow([ - buildCard(context, 'Hospital', '96%', '2023', socialColor, - socialColor, mywidth / 2.5), - buildCard(context, 'Clinic and Centres', '1.2K', '2024', - socialColor, socialColor, mywidth / 2.5), - ]), - ], - ), - CustomExpandableTile( - title: 'ENVIRONMENT', - titleBackgroundColor: environmentColor, - children: [ - buildCategoryTitle('Agriculture', environmentColor), - buildCardRow([ - buildCard(context, 'Crops - Total Area', '27°C', 'Average 2024', - environmentColor, environmentColor, mywidth / 2.5), - buildCard(context, 'Livestock', '120mm', '2024', - environmentColor, environmentColor, mywidth / 2.5), - ]), - buildCategoryTitle('Environment', environmentColor), - buildCardRow([ - buildCard(context, 'Climate - Max Temp', '15%', '2024', - environmentColor, environmentColor, mywidth / 2.5), - buildCard(context, 'Climate - Min Temp', '30%', '2023', - environmentColor, environmentColor, mywidth / 2.5), - ]), - buildCardRow([ - buildCard(context, 'Desalinated Produced Water', '15%', '2024', - environmentColor, environmentColor, mywidth / 2.5), - buildCard(context, 'Area of Natural Reserves', '30%', '2023', - environmentColor, environmentColor, mywidth / 2.5), - ]), - buildCategoryTitle('Energy', environmentColor), - buildCardRow([ - buildCard(context, 'Electricity Production', '15%', '2024', - environmentColor, environmentColor, mywidth / 2.5), - buildCard(context, 'Renewable Energy Production', '30%', '2023', - environmentColor, environmentColor, mywidth / 2.5), - ]), - ], - ), + ...homePageData.map((mainTopic) { + String colorPattern = mainTopic['color_pattern']; + print('colorPattern $colorPattern'); + Color backgroundColor = Color(int.parse(colorPattern)); + print('backgroundColor $backgroundColor'); + Color borderColor = backgroundColor; + int index = homePageData.indexOf(mainTopic); + bool isFirstTile = index == 0; + + return CustomExpandableTile( + index: index, + isExpanded: isFirstTile, + title: mainTopic['main_topic'], + titleBackgroundColor: backgroundColor, + children: _buildSubTopics( + mainTopic['sub_topics'] ?? [], + mywidth, + borderColor, + colorPattern, + ), + ); + }), ], ), ); } + List _buildSubTopics(List subTopics, double myWidth, + Color borderColor, String colorPattern) { + print('colorPattern123 $borderColor'); + // Sort sub-topics based on `sub_topic_list_order` + subTopics.sort((a, b) => (a['sub_topic_list_order'] ?? 0) + .compareTo(b['sub_topic_list_order'] ?? 0)); + + return subTopics + .map((subTopic) => Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + buildCategoryTitle(subTopic['sub_topic'], borderColor), + ..._buildDataSetCards(subTopic['tile_data'] ?? [], myWidth, + borderColor, colorPattern), + ], + )) + .toList(); + } + + List _buildDataSetCards( + List tileData, double myWidth, Color borderColor, colorPattern) { + // Sort datasets based on `data_set_list_order` + tileData.sort((a, b) => (a['data_set_list_order'] ?? 0) + .compareTo(b['data_set_list_order'] ?? 0)); + + List rows = []; + for (int i = 0; i < tileData.length; i += 2) { + // Take 1 or 2 items for the row + final rowItems = tileData.sublist( + i, + i + 2 > tileData.length ? tileData.length : i + 2, + ); + + rows.add( + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: rowItems.map((data) { + // Calculate width: full width for one item, half for two items + final cardWidth = rowItems.length == 1 + ? myWidth + : (myWidth - 16) / 2; // Subtract spacing for padding + + return Expanded( + child: Padding( + padding: + const EdgeInsets.symmetric(horizontal: 5.0), // Add spacing + child: buildCard( + context, + data['data_set_tile_heading'] ?? '', + data['value'] ?? '', + data['value_source'] ?? '', + data['data_set'] ?? '', + borderColor, + borderColor, + colorPattern, + cardWidth, // Pass the calculated width + ), + ), + ); + }).toList(), + ), + ); + } + return rows; + } + Widget buildCategoryTitle(String title, Color color) { return Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: Text( - title, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: color, - ), - ), - ); + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Center( + child: Text( + title, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: color, + ), + ), + )); } Widget buildCardRow(List cards) { @@ -212,43 +210,58 @@ class uaenumberWidget extends StatelessWidget { ); } - Widget buildCard(BuildContext context, String title, String value, - String subtitle, Color bordercolor, boldColor, double mywidth) { - // double myheight = MediaQuery.of(context).size.height; - // double mywidth = MediaQuery.of(context).size.width; - return Card( - elevation: 2, - child: Container( - width: mywidth, - decoration: BoxDecoration( - color: Colors.white, // Background color - border: Border.all( - color: bordercolor, // Border color - width: 2, // Border width + Widget buildCard( + BuildContext context, + String title, + String value, + String subtitle, + String data_set, + Color bordercolor, + Color boldColor, + colorPattern, + double mywidth, + ) { + return GestureDetector( + onTap: () { + print(colorPattern); + context.go('/chartScreen/$data_set?bgColor=$colorPattern'); + // context.go('/chartScreen/$data_set'); + }, + child: Card( + elevation: 1, + child: Container( + width: mywidth, + decoration: BoxDecoration( + color: Colors.white, // Background color + border: Border.all( + color: bordercolor, // Border color + width: 2, // Border width + ), + borderRadius: + BorderRadius.circular(12), // Optional: Rounded corners ), - borderRadius: BorderRadius.circular(12), // Optional: Rounded corners - ), - padding: const EdgeInsets.all(16.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - title, - textAlign: TextAlign.center, - style: robotoRegular11, - ), - SizedBox(height: 8), - Text(subtitle, textAlign: TextAlign.center, style: subtitleStyle), - SizedBox(height: 8), - Text( - value, - style: TextStyle( - fontSize: 26, - color: boldColor, - fontWeight: FontWeight.bold, + padding: const EdgeInsets.all(3.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + title, + textAlign: TextAlign.center, + style: robotoRegular11, ), - ), - ], + SizedBox(height: 0.2), + Text(subtitle, textAlign: TextAlign.center, style: subtitleStyle), + SizedBox(height: 0.7), + Text( + value, + style: TextStyle( + fontSize: 24, + color: boldColor, + fontWeight: FontWeight.bold, + ), + ), + ], + ), ), ), ); @@ -259,11 +272,15 @@ class CustomExpandableTile extends StatefulWidget { final String title; final Color titleBackgroundColor; final List children; + final int index; + final bool isExpanded; const CustomExpandableTile({ required this.title, required this.titleBackgroundColor, required this.children, + required this.index, + required this.isExpanded, }); @override @@ -271,13 +288,21 @@ class CustomExpandableTile extends StatefulWidget { } class _CustomExpandableTileState extends State { - bool isExpanded = false; + // bool isExpanded = false; + late bool isExpanded; + + @override + void initState() { + super.initState(); + isExpanded = + widget.isExpanded; // Initialize isExpanded based on widget's property + } @override Widget build(BuildContext context) { double myheight = MediaQuery.of(context).size.height; return Card( - elevation: 4, + elevation: 0, child: Column( children: [ GestureDetector( @@ -289,8 +314,9 @@ class _CustomExpandableTileState extends State { child: Container( decoration: BoxDecoration( color: widget.titleBackgroundColor, - borderRadius: BorderRadius.all(Radius.circular(12))), - padding: const EdgeInsets.all(12), + borderRadius: BorderRadius.all(Radius.circular(35))), + padding: const EdgeInsets.only( + left: 16, bottom: 10, top: 10, right: 10), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -307,6 +333,7 @@ class _CustomExpandableTileState extends State { ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down, color: Colors.white, + size: 28.0, ), ], ), @@ -317,14 +344,15 @@ class _CustomExpandableTileState extends State { duration: Duration(milliseconds: 300), curve: Curves.easeInOut, width: double.infinity, + height: isExpanded ? myheight * 0.52 : 0, child: isExpanded ? SingleChildScrollView( child: Container( decoration: BoxDecoration( - color: Colors.white, - borderRadius: - BorderRadius.all(Radius.circular(20))), - padding: const EdgeInsets.all(10), + // color: Colors.white, + // borderRadius: BorderRadius.all(Radius.circular(20)) + ), + padding: const EdgeInsets.all(1), child: Column( children: widget.children, ), diff --git a/lib/presentation/Screens/auth_verification/registration.dart b/lib/presentation/Screens/auth_verification/registration.dart index cd4fd874..2683cde7 100644 --- a/lib/presentation/Screens/auth_verification/registration.dart +++ b/lib/presentation/Screens/auth_verification/registration.dart @@ -193,11 +193,12 @@ class _RegisterScreenState extends State { print('adminToken- ${adminToken}'); // Create user in PocketBase final response = await pb.collection('users').create(body: { - 'username': _usernameController.text, + 'uname': _usernameController.text, 'email': _emailController.text, 'password': _passwordController.text, 'passwordConfirm': _passwordController.text, 'status': 'Pending', + 'role': 'user', }, headers: { 'Authorization': adminToken }); @@ -346,15 +347,7 @@ class _RegisterScreenState extends State { ), SizedBox(height: 10), ElevatedButton( - onPressed: () => { - Navigator.pushReplacement( - context, - MaterialPageRoute(builder: (context) => LoginRoute() - - //ProfileScreen(userId: userID) - ), - ), - }, + onPressed: () => {context.go('/')}, child: Text( 'Go to Login', ), diff --git a/lib/presentation/Screens/charts/chart.dart b/lib/presentation/Screens/charts/chart.dart index a34bf4a4..5c35d379 100644 --- a/lib/presentation/Screens/charts/chart.dart +++ b/lib/presentation/Screens/charts/chart.dart @@ -1,1038 +1,1038 @@ -import 'dart:collection'; -import 'dart:convert'; -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:intl/intl.dart'; -import 'package:syncfusion_flutter_charts/charts.dart'; // Import Syncfusion charts package -import 'package:http/http.dart' as http; - -void main() { - runApp(MyApp()); -} - -class MyApp extends StatelessWidget { - @override - Widget build(BuildContext context) { - return MaterialApp( - home: ChartScreen(dataSets: ''), - ); - } -} - -class ChartScreen extends StatefulWidget { - final String dataSets; - const ChartScreen({Key? key, required this.dataSets}); - @override - ChartScreenState createState() => ChartScreenState(); -} - -class ChartScreenState extends State { - List> selectedFiltersStorage = []; - List chartsData = []; - List cardData = []; - List filterData = []; - List> originalChartsData = []; - List> originalCardData = []; - bool isLoading = true; - List isChartData = []; - List nonChartData = []; - // dynamic firstYear; - // dynamic lastYearValue; - // dynamic secondLastYearValue; - // dynamic lastYear; - // dynamic secondLastYear; - // dynamic roundedAverage; - final GlobalKey _scaffoldKey = GlobalKey(); - - @override - void initState() { - super.initState(); - fetchChartData(widget.dataSets); - } - - Future fetchChartData(String dataSets) async { - const baseUrl = - 'https://pb.venbait.in/api/getDataSet'; // Replace with your server URL - final url = Uri.parse('$baseUrl?dataset=$dataSets'); - - try { - final response = await http.get(url); - if (response.statusCode == 200) { - final List data = jsonDecode(response.body); - - // Variables to store filtered data - for (var item in data) { - if (item['is_chart'] == 'true') { - isChartData.add(item); - } else if (item['is_chart'] == 'false') { - nonChartData.add(item); - } - } - - // Print or use the filtered data - print('Chart Data: $isChartData'); - print('Non-Chart Data: $nonChartData'); - - // Save original data for reset - originalChartsData = List.from(isChartData); // Store original data - originalCardData = List.from(nonChartData); // Store original data - setState(() { - chartsData = isChartData; - cardData = nonChartData; - print('chartsData $chartsData'); - print('cardData $cardData'); - isLoading = false; - }); - } else { - throw Exception('Failed to load data'); - } - } catch (error) { - setState(() { - isLoading = false; - }); - print('Error fetching data: $error'); - } - } - - // void extractLastTwoYearsData(Map nonChartData) { - // try { - // final responseData = nonChartData['response']; - // final response = responseData is String - // ? jsonDecode(responseData) as List - // : responseData as List; - // - // // Extracting the time periods and sorting them in descending order - // final sortedResponse = response - // .map((item) => item['ObsKey']['TIME_PERIOD'].toString()) - // .toList() - // ..sort((a, b) => b.compareTo(a)); - // - // // Get the last year and second-to-last year - // lastYear = sortedResponse.isNotEmpty ? sortedResponse.first : null; - // secondLastYear = sortedResponse.length > 1 ? sortedResponse[1] : null; - // firstYear = sortedResponse.isNotEmpty - // ? sortedResponse.last - // : null; // First year (oldest) - // - // // Extract the corresponding values - // lastYearValue = response.firstWhere( - // (item) => item['ObsKey']['TIME_PERIOD'].toString() == lastYear, - // orElse: () => null)?['ObsValue']['Value']; - // - // secondLastYearValue = response.firstWhere( - // (item) => item['ObsKey']['TIME_PERIOD'].toString() == secondLastYear, - // orElse: () => null)?['ObsValue']['Value']; - // - // // Print or use the extracted values - // print('Last Year: $lastYear, Value: $lastYearValue'); - // print( - // 'Second-to-Last Year: $secondLastYear, Value: $secondLastYearValue'); - // - // // Extract all values and calculate the sum and average - // List allValues = response - // .map((item) => - // double.tryParse(item['ObsValue']['Value'].toString()) ?? 0.0) - // .toList(); - // - // double sum = allValues.reduce((a, b) => a + b); - // double average = sum / allValues.length; - // // Round the average to the nearest whole number - // roundedAverage = average.round(); - // - // // Print sum and rounded average - // print('Sum of Values: $sum'); - // print('Rounded Average Value: $roundedAverage'); - // } catch (e) { - // print('Error processing data: $e'); - // } - // } - -// When decoding JSON, you can convert the LinkedMap to a Map - Map processNonChartData(item) { - print('processNonChartData check test case'); - try { - final response = item['response']; - - // If 'response' is a LinkedMap, convert it to Map - final List responseData = response is LinkedHashMap - ? Map.from( - response) // Convert to Map - : response; - - // Now you can process the Map as expected - final sortedResponse = List.from( - responseData.map((e) => e['ObsKey']['TIME_PERIOD'].toString())) - ..sort((a, b) => b.compareTo(a)); - - String? lastYear = - sortedResponse.isNotEmpty ? sortedResponse.first : null; - String? secondLastYear = - sortedResponse.length > 1 ? sortedResponse[1] : null; - String? firstYear = - sortedResponse.isNotEmpty ? sortedResponse.last : null; - - String? lastYearValue = response.firstWhere( - (item) => item['ObsKey']['TIME_PERIOD'].toString() == lastYear, - orElse: () => null, - )?['ObsValue']['Value']; - - String? secondLastYearValue = response.firstWhere( - (item) => item['ObsKey']['TIME_PERIOD'].toString() == secondLastYear, - orElse: () => null, - )?['ObsValue']['Value']; - - List allValues = responseData - .map((item) => - double.tryParse(item['ObsValue']['Value'].toString()) ?? 0.0) - .toList(); - - double sum = allValues.reduce((a, b) => a + b); - double average = sum / allValues.length; - double roundedAverage = - average.roundToDouble(); // Rounds to the nearest integer - - return { - 'lastYear': lastYear ?? 'NA', - 'secondLastYear': secondLastYear ?? 'NA', - 'firstYear': firstYear ?? 'NA', - 'lastYearValue': lastYearValue ?? 'NA', - 'secondLastYearValue': secondLastYearValue ?? 'NA', - 'roundedAverage': roundedAverage, - 'allValues': allValues.isEmpty ? [0.0] : allValues, - }; - } catch (e) { - print('Error processing data: $e'); - return {}; - } - } - - String capitalizeAndSplit(String text) { - if (text.isEmpty) return text; - return text - .split('_') // Split by underscores - .map((word) => word[0].toUpperCase() + word.substring(1).toLowerCase()) - .join(' '); // Join words with a space - } - - List parseLineChartData(List response) { - return response.map((entry) { - // Attempt to fetch the TIMEPERIOD - final rawTimePeriod = - entry['ObsKey']?['Year'] ?? entry['ObsKey']?['TIME_PERIOD']; - final formattedTimePeriod = rawTimePeriod != null - ? rawTimePeriod.toString() // Use as-is if valid - : 'Unknown'; // Fallback value if null - - // Parse the value or fallback to 0.0 - final value = - double.tryParse(entry['ObsValue']?['Value']?.toString() ?? '0.0') ?? - 0.0; - - return ChartData( - timePeriod: formattedTimePeriod, - value: value, - ); - }).toList(); - } - - List parseBarChartData(List response) { - return response - .asMap() - .entries - .map((entry) => ChartData( - timePeriod: entry.value['ObsKey']['TIME_PERIOD'] ?? - 'Unknown', // Fallback to 'Unknown' if null - value: double.tryParse( - entry.value['ObsValue']['Value'].toString()) ?? - 0.0, // Handle null/invalid value - )) - .toList(); - } - -// Update parseColumnChartData for column chart - List parseColumnChartData(List response) { - return response.map((entry) { - // Extract TIME_PERIOD as x - final x = - int.tryParse(entry['ObsKey']?['TIME_PERIOD']?.toString() ?? '0') ?? 0; - // Extract Value as y - final y = - double.tryParse(entry['ObsValue']?['Value']?.toString() ?? '0.0') ?? - 0.0; - return ChartData(xInt: x, y: y); - }).toList(); - } - -// Update parseScatterChartData for scatter chart - List parseScatterChartData(List response) { - return response.map((entry) { - // Parse TIME_PERIOD into DateTime - final timePeriod = entry['ObsKey']?['TIME_PERIOD']; - final x = timePeriod != null - ? DateTime.tryParse('$timePeriod-01-01') // Convert year to DateTime - : DateTime.now(); // Fallback to current date if null - - // Parse Value into double - final y = - double.tryParse(entry['ObsValue']?['Value']?.toString() ?? '0.0') ?? - 0.0; - - return ChartData(xDateTime: x, y: y); - }).toList(); - } - - List parseStackedBarChartData( - dynamic chartData, String groupByKey, String groupByValue) { - return chartData['response'] - .where((entry) => entry['ObsKey'][groupByKey] == groupByValue) - .map((entry) { - // Specify the type here - return ChartData( - x: entry['ObsKey']['TIME_PERIOD'], - y: double.tryParse(entry['ObsValue']['Value']) ?? 0.0, - ); - }).toList(); - } - - void applyFilters(BuildContext context, List filters, List data, - List dataCard, List selectedFilters) { - print("Selected Filters before applying: $selectedFilters"); - // Check if all filter_data is empty - if (selectedFilters.every((filter) => filter['filter_data'].isEmpty)) { - setState(() { - chartsData = List.from(originalChartsData); // Restore the original data - cardData = List.from(originalCardData); // Restore the original data - }); - print('Returning as no filters are selected'); - Navigator.pop(context); - return; // Exit early since all filter_data are empty - } - - // Loop through each chart data in the `data` list - List filteredData = []; - for (var chart in data) { - // Extract response data for filtering - List response = chart['response'] ?? []; - - // Filter the response based on selected filters - var chartFilteredData = 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']; - - // 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 (chartFilteredData.isNotEmpty) { - filteredData.add({ - ...chart, // Include all other properties of the chart object - 'response': chartFilteredData, // Only include filtered response data - }); - } - } - - List filteredCardData = []; - for (var chart in dataCard) { - Map chartData = Map.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']; - - // 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 - }); - } - } - - // Update the chartsData with the filtered data - setState(() { - chartsData = filteredData; - cardData = filteredCardData; - }); - - print("Filtered Data: $filteredData"); - print("Filtered Card: $filteredCardData"); - - // Go back after applying filters - Navigator.pop(context); - } - - Widget buildChart(dynamic chartData) { - // Extract group_by dynamically from the chartData - String groupByKey = chartData['group_by']; - - // Extract unique values for the group_by key dynamically - Set groupByValues = {}; - chartData['response'].forEach((entry) { - groupByValues.add(entry['ObsKey'][groupByKey]); - }); - switch (chartData['chart_type']) { - case 'scatter': - return SfCartesianChart( - primaryXAxis: DateTimeAxis(), // Ensure it's DateTimeAxis - tooltipBehavior: TooltipBehavior(enable: true), - title: ChartTitle(text: 'Divorces'), - series: [ - ScatterSeries( - dataSource: parseScatterChartData(chartData['response']), - xValueMapper: (ChartData data, _) => - data.xDateTime ?? DateTime.now(), - yValueMapper: (ChartData data, _) => data.y, - name: chartData['dataset'], - dataLabelSettings: DataLabelSettings(isVisible: true), - ), - ], - ); - case 'column': - return SfCartesianChart( - primaryXAxis: NumericAxis( - title: AxisTitle(text: 'Year'), - interval: 1, // Ensure no fractional intervals - ), - title: ChartTitle(text: 'Marriages'), - series: >[ - ColumnSeries( - dataSource: parseColumnChartData(chartData['response']), - xValueMapper: (ChartData data, _) => data.xInt ?? 0, - yValueMapper: (ChartData data, _) => data.y, - name: chartData['dataset'], - color: Color(0xFF7DAFBC), - width: 0.8, - spacing: 0.2, - dataLabelSettings: - DataLabelSettings(isVisible: true), // Show data labels - ), - ], - ); - case 'line': - return SfCartesianChart( - primaryXAxis: CategoryAxis(), - title: ChartTitle(text: 'Line Chart'), - legend: Legend(isVisible: true), - tooltipBehavior: TooltipBehavior(enable: true), - series: >[ - LineSeries( - dataSource: parseLineChartData(chartData['response']), - xValueMapper: (ChartData data, _) => data.timePeriod ?? '', - yValueMapper: (ChartData data, _) => data.value ?? 0.0, - name: 'Sales', - dataLabelSettings: DataLabelSettings(isVisible: true), - ), - ], - ); - case 'bar': - return SfCartesianChart( - primaryXAxis: CategoryAxis(), - title: ChartTitle(text: 'Bar Chart'), - tooltipBehavior: TooltipBehavior(enable: true), - series: >[ - BarSeries( - dataSource: parseBarChartData(chartData['response']), - xValueMapper: (ChartData data, _) => data.timePeriod ?? '', - yValueMapper: (ChartData data, _) => data.value ?? 0.0, - name: 'Gold', - color: Color.fromRGBO(8, 142, 255, 1), - ), - ], - ); - case 'stacked_bar': - String chartTitle = - capitalizeAndSplit(chartData['chart_heading'] ?? ''); - // Define a list of colors - final List uniqueColors = [ - Color(0xFF648CBA), - Color(0xFF90B0D5), - Color(0xFF98BCE5), - Color(0xFFA7B5C5), - Color(0xFFBED3EC), - Color(0xFFD4E3F4), - ]; - return SfCartesianChart( - primaryXAxis: CategoryAxis(), - title: ChartTitle(text: chartData['chart_heading']), - legend: Legend( - isVisible: true, - position: LegendPosition.bottom, - overflowMode: LegendItemOverflowMode.scroll, - ), - tooltipBehavior: TooltipBehavior( - enable: true, // Enable tooltips - format: 'point.x : point.y', // Custom tooltip format - ), - series: >[ - for (int i = 0; i < groupByValues.length; i++) - StackedBarSeries( - dataSource: parseStackedBarChartData( - chartData, groupByKey, groupByValues.elementAt(i)), - xValueMapper: (ChartData data, _) => data.x ?? '', - yValueMapper: (ChartData data, _) => data.y, - name: groupByValues.elementAt(i), - color: uniqueColors[i % uniqueColors.length], - enableTooltip: true, - ), - ], - ); - case 'stacked_column': - String chartTitle = - capitalizeAndSplit(chartData['chart_heading'] ?? ''); - // Define a list of colors - final List uniqueColors = [ - Color(0xFF648CBA), - Color(0xFF90B0D5), - Color(0xFF98BCE5), - Color(0xFFA7B5C5), - Color(0xFFBED3EC), - Color(0xFFD4E3F4), - ]; - return SfCartesianChart( - primaryXAxis: CategoryAxis(), - title: ChartTitle(text: chartData['chart_heading']), - legend: Legend( - isVisible: true, - position: LegendPosition.bottom, - overflowMode: LegendItemOverflowMode.scroll, - ), - tooltipBehavior: TooltipBehavior( - enable: true, // Enable tooltips - format: 'point.x : point.y', // Custom tooltip format - ), - series: >[ - for (int i = 0; i < groupByValues.length; i++) - StackedColumnSeries( - dataSource: parseStackedBarChartData( - chartData, groupByKey, groupByValues.elementAt(i)), - xValueMapper: (ChartData data, _) => data.x ?? '', - yValueMapper: (ChartData data, _) => data.y, - name: groupByValues.elementAt(i), - color: uniqueColors[i % uniqueColors.length], - enableTooltip: true, - ), - ], - ); - default: - return Center(child: Text('Unknown chart type')); - } - } - - @override - Widget build(BuildContext context) { - return Scaffold( - key: _scaffoldKey, - backgroundColor: Colors.brown[200]!, - appBar: AppBar( - backgroundColor: Colors.brown[200]!, - elevation: 0, - leading: IconButton( - icon: Icon(Icons.arrow_back_ios_new, color: Colors.white), - onPressed: () { - context.go('/myhomepage'); - }, - ), - title: Text( - 'UAE Numbers', - style: TextStyle(color: Colors.white), - ), - ), - body: isLoading - ? Center(child: CircularProgressIndicator()) - : Column( - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment - .end, // Aligns the row's content to the right - children: [ - Row( - children: [ - Text( - 'Bookmark', - style: const TextStyle( - fontSize: 16, - color: Colors.white, - ), - ), - Icon(Icons.bookmark_add_outlined, - color: Colors.white, size: 18), - ], - ), - SizedBox(width: 10), // Horizontal space between items - Row( - children: [ - Text( - 'Share', - style: const TextStyle( - fontSize: 16, - color: Colors.white, - ), - ), - Icon(Icons.share_sharp, - color: Colors.white, size: 18), - ], - ), - SizedBox(width: 10), // Horizontal space between items - IconButton( - icon: Icon(Icons.filter_alt_outlined, - color: Colors.white, size: 18), - onPressed: () { - showRightSideModal( - context, chartsData[0]["filters"], chartsData); - }, - ), - ], - ), - ], - ), - - // Padding( - // padding: const EdgeInsets.all(16.0), - // child: Align( - // alignment: Alignment.topRight, - // child: IconButton( - // icon: Icon(Icons.filter_list, color: Colors.white), - // onPressed: () { - // showRightSideModal( - // context, chartsData[0]["filters"], chartsData); - // }, - // ), - // ), - // ), - Expanded( - child: ListView( - children: [ - // nonChartData Cards - GridView.builder( - itemCount: cardData.length, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - gridDelegate: - const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, // 2 cards per row - crossAxisSpacing: 10, - mainAxisSpacing: 10, - childAspectRatio: 177.5 / - 180, // Adjusted to maintain width and fixed height - ), - itemBuilder: (context, index) { - final item = cardData[index]; - print('item item item $item'); - final chart_type = item['chart_type']; - final chart_heading = item['chart_heading']; - final data = processNonChartData(item); - print('processNonChartData'); - - if (chart_type == 'total') { - return Card( - margin: const EdgeInsets.all(10), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - elevation: 4, - child: Padding( - padding: const EdgeInsets.all(12.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Icon(Icons.public, - color: Color(0xFF90B0D5), size: 22), - const SizedBox(height: 5), - Text( - '${chart_heading ?? 'NA'}', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: Colors.black87, - ), - ), - Text( - '(${data['lastYear'] ?? 'NA'})', - style: const TextStyle( - fontSize: 10, color: Colors.grey), - ), - Text( - '${data['lastYearValue'] ?? 'NA'}', - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Color(0xFF90B0D5), - ), - ), - const Divider( - color: Colors.grey, thickness: 1), - Text( - '${data['secondLastYearValue'] ?? 'NA'}', - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: Color(0xFF90B0D5), - ), - ), - Text( - '(${data['secondLastYear'] ?? 'NA'})', - style: const TextStyle( - fontSize: 10, color: Colors.grey), - ), - ], - ), - ), - ); - } else if (chart_type == 'average') { - return Card( - margin: const EdgeInsets.all(10), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - elevation: 4, - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Icon(Icons.analytics, - color: Color(0xFF90B0D5), size: 22), - const SizedBox(height: 5), - Text( - '${chart_heading ?? 'NA'}', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: Colors.black87, - ), - ), - Text( - '(${data['firstYear'] ?? 'NA'} - ${data['lastYear'] ?? 'NA'})', - style: const TextStyle( - fontSize: 10, color: Colors.grey), - ), - Text( - '${data['roundedAverage'] ?? 'NA'}', - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Color(0xFF90B0D5), - ), - ), - ], - ), - ), - ); - } else { - return const SizedBox - .shrink(); // Ignore unknown KPIs - } - }, - ), - // chartsData Cards - ListView.builder( - itemCount: chartsData.length, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) { - return Card( - margin: const EdgeInsets.all(10), - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: 10), - Container( - height: 300, - child: buildChart(chartsData[index]), - ), - ], - ), - ), - ); - }, - ), - ], - ), - ), - ], - ), - ); - } - - void showRightSideModal(BuildContext context, List filters, List data) { - // Initialize selected filters structure from the stored value, if exists - List> selectedFilters = - selectedFiltersStorage.isNotEmpty - ? List.from(selectedFiltersStorage) // Use stored filters - : filters.map((filter) { - return {"filter_key": filter["filter_key"], "filter_data": []}; - }).toList(); // Or initialize empty filters - - showModalBottomSheet( - context: context, - isScrollControlled: true, - backgroundColor: Colors.transparent, - builder: (BuildContext context) { - return Align( - alignment: Alignment.centerRight, - child: Container( - width: MediaQuery.of(context).size.width * 0.7, - height: MediaQuery.of(context).size.height, - color: Colors.white, - child: Column( - children: [ - // Header Section - Padding( - padding: const EdgeInsets.all(16.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Filters', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - IconButton( - icon: Icon(Icons.close), - onPressed: () => Navigator.pop(context), - ), - ], - ), - ), - // Filters Section - Expanded( - child: ListView.builder( - itemCount: filters.length, - itemBuilder: (context, index) { - final filter = filters[index]; - final filterKey = filter["filter_key"]; - final filterData = filter["filter_data"]; - - return StatefulBuilder( - builder: (context, setState) { - // Get the corresponding selected filter object - var selectedFilter = selectedFilters - .firstWhere((f) => f["filter_key"] == filterKey); - - return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16.0, vertical: 8.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - filterKey, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - InkWell( - onTap: () { - showDialog( - context: context, - builder: (BuildContext context) { - return StatefulBuilder( - builder: (context, dialogSetState) { - return AlertDialog( - title: Text('Select $filterKey'), - content: SingleChildScrollView( - child: ListBody( - children: filterData - .map((value) { - return CheckboxListTile( - title: Text( - value.toString()), - value: selectedFilter[ - "filter_data"] - .contains(value), - onChanged: - (bool? isChecked) { - dialogSetState(() { - if (isChecked == - true) { - selectedFilter[ - "filter_data"] - .add(value); - } else { - selectedFilter[ - "filter_data"] - .remove(value); - } - }); - }, - ); - }).toList(), - ), - ), - actions: [ - TextButton( - onPressed: () { - // Store the updated selected filters after dialog closes - setState(() {}); - Navigator.pop(context); - }, - child: Text('OK'), - ), - ], - ); - }, - ); - }, - ); - }, - child: Container( - width: double.infinity, - padding: EdgeInsets.symmetric( - horizontal: 16.0, vertical: 12.0), - decoration: BoxDecoration( - border: Border.all(color: Colors.grey), - borderRadius: BorderRadius.circular(8.0), - ), - child: Wrap( - spacing: 8.0, - runSpacing: 4.0, - children: - selectedFilter["filter_data"].isEmpty - ? [ - Text('Select $filterKey', - style: TextStyle( - color: Colors.grey)) - ] - : selectedFilter["filter_data"] - .map((value) { - return Chip( - label: Text(value), - onDeleted: () { - setState(() { - selectedFilter[ - "filter_data"] - .remove(value); - }); - }, - ); - }).toList(), - ), - ), - ), - ], - ), - ); - }, - ); - }, - ), - ), - // Button Section - Padding( - padding: const EdgeInsets.all(16.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - ElevatedButton( - onPressed: () { - // Clear all selected filters - selectedFilters.forEach((filter) { - filter["filter_data"].clear(); - }); - setState(() { - chartsData = List.from(originalChartsData); - cardData = List.from(originalCardData); - }); - // Reset the selectedFiltersStorage to empty when clearing - selectedFiltersStorage.clear(); - Navigator.pop(context); - }, - child: Text('Clear'), - style: ElevatedButton.styleFrom( - backgroundColor: Colors.grey, - ), - ), - ElevatedButton( - onPressed: () { - print( - "Selected Filters before applying: $selectedFilters"); - setState(() { - chartsData = originalChartsData; - cardData = originalCardData; - }); - applyFilters(context, filters, chartsData, cardData, - selectedFilters); - // Save the selected filters to storage after applying - selectedFiltersStorage = List.from(selectedFilters); - }, - child: Text('Apply Filter'), - style: ElevatedButton.styleFrom( - backgroundColor: Colors.blue, - ), - ), - ], - ), - ), - ], - ), - ), - ); - }, - ); - } -} - -class ChartData { - final int? xInt; // For column and other charts, using int for x - final DateTime? xDateTime; // For scatter charts, using DateTime for x - final double? y; // For column and other charts - final String? timePeriod; // For line and bar charts - final double? value; // For line and bar charts - late final double? y2; // For secondary data (stacked column chart) - late final double? y3; // For tertiary data (stacked column chart) - final double? y4; // For quaternary data (stacked column chart) - final String? x; // For stacked bar charts, using String for x - - // Constructor that handles all chart cases - ChartData({ - this.xInt, - this.xDateTime, - this.y, - this.timePeriod, - this.value, - this.y2, - this.y3, - this.y4, - this.x, - }); -} - +// import 'dart:collection'; +// import 'dart:convert'; +// import 'package:flutter/material.dart'; +// import 'package:go_router/go_router.dart'; +// import 'package:intl/intl.dart'; +// import 'package:syncfusion_flutter_charts/charts.dart'; // Import Syncfusion charts package +// import 'package:http/http.dart' as http; +// +// void main() { +// runApp(MyApp()); +// } +// +// class MyApp extends StatelessWidget { +// @override +// Widget build(BuildContext context) { +// return MaterialApp( +// home: ChartScreen(dataSets: ''), +// ); +// } +// } +// +// class ChartScreen extends StatefulWidget { +// final String dataSets; +// const ChartScreen({Key? key, required this.dataSets}); +// @override +// ChartScreenState createState() => ChartScreenState(); +// } +// +// class ChartScreenState extends State { +// List> selectedFiltersStorage = []; +// List chartsData = []; +// List cardData = []; +// List filterData = []; +// List> originalChartsData = []; +// List> originalCardData = []; +// bool isLoading = true; +// List isChartData = []; +// List nonChartData = []; +// // dynamic firstYear; +// // dynamic lastYearValue; +// // dynamic secondLastYearValue; +// // dynamic lastYear; +// // dynamic secondLastYear; +// // dynamic roundedAverage; +// final GlobalKey _scaffoldKey = GlobalKey(); +// +// @override +// void initState() { +// super.initState(); +// fetchChartData(widget.dataSets); +// } +// +// Future fetchChartData(String dataSets) async { +// const baseUrl = +// 'https://pb.venbait.in/api/getDataSet'; // Replace with your server URL +// final url = Uri.parse('$baseUrl?dataset=$dataSets'); +// +// try { +// final response = await http.get(url); +// if (response.statusCode == 200) { +// final List data = jsonDecode(response.body); +// +// // Variables to store filtered data +// for (var item in data) { +// if (item['is_chart'] == 'true') { +// isChartData.add(item); +// } else if (item['is_chart'] == 'false') { +// nonChartData.add(item); +// } +// } +// +// // Print or use the filtered data +// print('Chart Data: $isChartData'); +// print('Non-Chart Data: $nonChartData'); +// +// // Save original data for reset +// originalChartsData = List.from(isChartData); // Store original data +// originalCardData = List.from(nonChartData); // Store original data +// setState(() { +// chartsData = isChartData; +// cardData = nonChartData; +// print('chartsData $chartsData'); +// print('cardData $cardData'); +// isLoading = false; +// }); +// } else { +// throw Exception('Failed to load data'); +// } +// } catch (error) { +// setState(() { +// isLoading = false; +// }); +// print('Error fetching data: $error'); +// } +// } +// +// // void extractLastTwoYearsData(Map nonChartData) { +// // try { +// // final responseData = nonChartData['response']; +// // final response = responseData is String +// // ? jsonDecode(responseData) as List +// // : responseData as List; +// // +// // // Extracting the time periods and sorting them in descending order +// // final sortedResponse = response +// // .map((item) => item['ObsKey']['TIME_PERIOD'].toString()) +// // .toList() +// // ..sort((a, b) => b.compareTo(a)); +// // +// // // Get the last year and second-to-last year +// // lastYear = sortedResponse.isNotEmpty ? sortedResponse.first : null; +// // secondLastYear = sortedResponse.length > 1 ? sortedResponse[1] : null; +// // firstYear = sortedResponse.isNotEmpty +// // ? sortedResponse.last +// // : null; // First year (oldest) +// // +// // // Extract the corresponding values +// // lastYearValue = response.firstWhere( +// // (item) => item['ObsKey']['TIME_PERIOD'].toString() == lastYear, +// // orElse: () => null)?['ObsValue']['Value']; +// // +// // secondLastYearValue = response.firstWhere( +// // (item) => item['ObsKey']['TIME_PERIOD'].toString() == secondLastYear, +// // orElse: () => null)?['ObsValue']['Value']; +// // +// // // Print or use the extracted values +// // print('Last Year: $lastYear, Value: $lastYearValue'); +// // print( +// // 'Second-to-Last Year: $secondLastYear, Value: $secondLastYearValue'); +// // +// // // Extract all values and calculate the sum and average +// // List allValues = response +// // .map((item) => +// // double.tryParse(item['ObsValue']['Value'].toString()) ?? 0.0) +// // .toList(); +// // +// // double sum = allValues.reduce((a, b) => a + b); +// // double average = sum / allValues.length; +// // // Round the average to the nearest whole number +// // roundedAverage = average.round(); +// // +// // // Print sum and rounded average +// // print('Sum of Values: $sum'); +// // print('Rounded Average Value: $roundedAverage'); +// // } catch (e) { +// // print('Error processing data: $e'); +// // } +// // } +// +// // When decoding JSON, you can convert the LinkedMap to a Map +// Map processNonChartData(item) { +// print('processNonChartData check test case'); +// try { +// final response = item['response']; +// +// // If 'response' is a LinkedMap, convert it to Map +// final List responseData = response is LinkedHashMap +// ? Map.from( +// response) // Convert to Map +// : response; +// +// // Now you can process the Map as expected +// final sortedResponse = List.from( +// responseData.map((e) => e['ObsKey']['TIME_PERIOD'].toString())) +// ..sort((a, b) => b.compareTo(a)); +// +// String? lastYear = +// sortedResponse.isNotEmpty ? sortedResponse.first : null; +// String? secondLastYear = +// sortedResponse.length > 1 ? sortedResponse[1] : null; +// String? firstYear = +// sortedResponse.isNotEmpty ? sortedResponse.last : null; +// +// String? lastYearValue = response.firstWhere( +// (item) => item['ObsKey']['TIME_PERIOD'].toString() == lastYear, +// orElse: () => null, +// )?['ObsValue']['Value']; +// +// String? secondLastYearValue = response.firstWhere( +// (item) => item['ObsKey']['TIME_PERIOD'].toString() == secondLastYear, +// orElse: () => null, +// )?['ObsValue']['Value']; +// +// List allValues = responseData +// .map((item) => +// double.tryParse(item['ObsValue']['Value'].toString()) ?? 0.0) +// .toList(); +// +// double sum = allValues.reduce((a, b) => a + b); +// double average = sum / allValues.length; +// double roundedAverage = +// average.roundToDouble(); // Rounds to the nearest integer +// +// return { +// 'lastYear': lastYear ?? 'NA', +// 'secondLastYear': secondLastYear ?? 'NA', +// 'firstYear': firstYear ?? 'NA', +// 'lastYearValue': lastYearValue ?? 'NA', +// 'secondLastYearValue': secondLastYearValue ?? 'NA', +// 'roundedAverage': roundedAverage, +// 'allValues': allValues.isEmpty ? [0.0] : allValues, +// }; +// } catch (e) { +// print('Error processing data: $e'); +// return {}; +// } +// } +// +// String capitalizeAndSplit(String text) { +// if (text.isEmpty) return text; +// return text +// .split('_') // Split by underscores +// .map((word) => word[0].toUpperCase() + word.substring(1).toLowerCase()) +// .join(' '); // Join words with a space +// } +// +// List parseLineChartData(List response) { +// return response.map((entry) { +// // Attempt to fetch the TIMEPERIOD +// final rawTimePeriod = +// entry['ObsKey']?['Year'] ?? entry['ObsKey']?['TIME_PERIOD']; +// final formattedTimePeriod = rawTimePeriod != null +// ? rawTimePeriod.toString() // Use as-is if valid +// : 'Unknown'; // Fallback value if null +// +// // Parse the value or fallback to 0.0 +// final value = +// double.tryParse(entry['ObsValue']?['Value']?.toString() ?? '0.0') ?? +// 0.0; +// +// return ChartData( +// timePeriod: formattedTimePeriod, +// value: value, +// ); +// }).toList(); +// } +// +// List parseBarChartData(List response) { +// return response +// .asMap() +// .entries +// .map((entry) => ChartData( +// timePeriod: entry.value['ObsKey']['TIME_PERIOD'] ?? +// 'Unknown', // Fallback to 'Unknown' if null +// value: double.tryParse( +// entry.value['ObsValue']['Value'].toString()) ?? +// 0.0, // Handle null/invalid value +// )) +// .toList(); +// } +// +// // Update parseColumnChartData for column chart +// List parseColumnChartData(List response) { +// return response.map((entry) { +// // Extract TIME_PERIOD as x +// final x = +// int.tryParse(entry['ObsKey']?['TIME_PERIOD']?.toString() ?? '0') ?? 0; +// // Extract Value as y +// final y = +// double.tryParse(entry['ObsValue']?['Value']?.toString() ?? '0.0') ?? +// 0.0; +// return ChartData(xInt: x, y: y); +// }).toList(); +// } +// +// // Update parseScatterChartData for scatter chart +// List parseScatterChartData(List response) { +// return response.map((entry) { +// // Parse TIME_PERIOD into DateTime +// final timePeriod = entry['ObsKey']?['TIME_PERIOD']; +// final x = timePeriod != null +// ? DateTime.tryParse('$timePeriod-01-01') // Convert year to DateTime +// : DateTime.now(); // Fallback to current date if null +// +// // Parse Value into double +// final y = +// double.tryParse(entry['ObsValue']?['Value']?.toString() ?? '0.0') ?? +// 0.0; +// +// return ChartData(xDateTime: x, y: y); +// }).toList(); +// } +// +// List parseStackedBarChartData( +// dynamic chartData, String groupByKey, String groupByValue) { +// return chartData['response'] +// .where((entry) => entry['ObsKey'][groupByKey] == groupByValue) +// .map((entry) { +// // Specify the type here +// return ChartData( +// x: entry['ObsKey']['TIME_PERIOD'], +// y: double.tryParse(entry['ObsValue']['Value']) ?? 0.0, +// ); +// }).toList(); +// } +// +// void applyFilters(BuildContext context, List filters, List data, +// List dataCard, List selectedFilters) { +// print("Selected Filters before applying: $selectedFilters"); +// // Check if all filter_data is empty +// if (selectedFilters.every((filter) => filter['filter_data'].isEmpty)) { +// setState(() { +// chartsData = List.from(originalChartsData); // Restore the original data +// cardData = List.from(originalCardData); // Restore the original data +// }); +// print('Returning as no filters are selected'); +// Navigator.pop(context); +// return; // Exit early since all filter_data are empty +// } +// +// // Loop through each chart data in the `data` list +// List filteredData = []; +// for (var chart in data) { +// // Extract response data for filtering +// List response = chart['response'] ?? []; +// +// // Filter the response based on selected filters +// var chartFilteredData = 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']; +// +// // 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 (chartFilteredData.isNotEmpty) { +// filteredData.add({ +// ...chart, // Include all other properties of the chart object +// 'response': chartFilteredData, // Only include filtered response data +// }); +// } +// } +// +// List filteredCardData = []; +// for (var chart in dataCard) { +// Map chartData = Map.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']; +// +// // 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 +// }); +// } +// } +// +// // Update the chartsData with the filtered data +// setState(() { +// chartsData = filteredData; +// cardData = filteredCardData; +// }); +// +// print("Filtered Data: $filteredData"); +// print("Filtered Card: $filteredCardData"); +// +// // Go back after applying filters +// Navigator.pop(context); +// } +// +// Widget buildChart(dynamic chartData) { +// // Extract group_by dynamically from the chartData +// String groupByKey = chartData['group_by']; +// +// // Extract unique values for the group_by key dynamically +// Set groupByValues = {}; +// chartData['response'].forEach((entry) { +// groupByValues.add(entry['ObsKey'][groupByKey]); +// }); +// switch (chartData['chart_type']) { +// case 'scatter': +// return SfCartesianChart( +// primaryXAxis: DateTimeAxis(), // Ensure it's DateTimeAxis +// tooltipBehavior: TooltipBehavior(enable: true), +// title: ChartTitle(text: 'Divorces'), +// series: [ +// ScatterSeries( +// dataSource: parseScatterChartData(chartData['response']), +// xValueMapper: (ChartData data, _) => +// data.xDateTime ?? DateTime.now(), +// yValueMapper: (ChartData data, _) => data.y, +// name: chartData['dataset'], +// dataLabelSettings: DataLabelSettings(isVisible: true), +// ), +// ], +// ); +// case 'column': +// return SfCartesianChart( +// primaryXAxis: NumericAxis( +// title: AxisTitle(text: 'Year'), +// interval: 1, // Ensure no fractional intervals +// ), +// title: ChartTitle(text: 'Marriages'), +// series: >[ +// ColumnSeries( +// dataSource: parseColumnChartData(chartData['response']), +// xValueMapper: (ChartData data, _) => data.xInt ?? 0, +// yValueMapper: (ChartData data, _) => data.y, +// name: chartData['dataset'], +// color: Color(0xFF7DAFBC), +// width: 0.8, +// spacing: 0.2, +// dataLabelSettings: +// DataLabelSettings(isVisible: true), // Show data labels +// ), +// ], +// ); +// case 'line': +// return SfCartesianChart( +// primaryXAxis: CategoryAxis(), +// title: ChartTitle(text: 'Line Chart'), +// legend: Legend(isVisible: true), +// tooltipBehavior: TooltipBehavior(enable: true), +// series: >[ +// LineSeries( +// dataSource: parseLineChartData(chartData['response']), +// xValueMapper: (ChartData data, _) => data.timePeriod ?? '', +// yValueMapper: (ChartData data, _) => data.value ?? 0.0, +// name: 'Sales', +// dataLabelSettings: DataLabelSettings(isVisible: true), +// ), +// ], +// ); +// case 'bar': +// return SfCartesianChart( +// primaryXAxis: CategoryAxis(), +// title: ChartTitle(text: 'Bar Chart'), +// tooltipBehavior: TooltipBehavior(enable: true), +// series: >[ +// BarSeries( +// dataSource: parseBarChartData(chartData['response']), +// xValueMapper: (ChartData data, _) => data.timePeriod ?? '', +// yValueMapper: (ChartData data, _) => data.value ?? 0.0, +// name: 'Gold', +// color: Color.fromRGBO(8, 142, 255, 1), +// ), +// ], +// ); +// case 'stacked_bar': +// String chartTitle = +// capitalizeAndSplit(chartData['chart_heading'] ?? ''); +// // Define a list of colors +// final List uniqueColors = [ +// Color(0xFF648CBA), +// Color(0xFF90B0D5), +// Color(0xFF98BCE5), +// Color(0xFFA7B5C5), +// Color(0xFFBED3EC), +// Color(0xFFD4E3F4), +// ]; +// return SfCartesianChart( +// primaryXAxis: CategoryAxis(), +// title: ChartTitle(text: chartData['chart_heading']), +// legend: Legend( +// isVisible: true, +// position: LegendPosition.bottom, +// overflowMode: LegendItemOverflowMode.scroll, +// ), +// tooltipBehavior: TooltipBehavior( +// enable: true, // Enable tooltips +// format: 'point.x : point.y', // Custom tooltip format +// ), +// series: >[ +// for (int i = 0; i < groupByValues.length; i++) +// StackedBarSeries( +// dataSource: parseStackedBarChartData( +// chartData, groupByKey, groupByValues.elementAt(i)), +// xValueMapper: (ChartData data, _) => data.x ?? '', +// yValueMapper: (ChartData data, _) => data.y, +// name: groupByValues.elementAt(i), +// color: uniqueColors[i % uniqueColors.length], +// enableTooltip: true, +// ), +// ], +// ); +// case 'stacked_column': +// String chartTitle = +// capitalizeAndSplit(chartData['chart_heading'] ?? ''); +// // Define a list of colors +// final List uniqueColors = [ +// Color(0xFF648CBA), +// Color(0xFF90B0D5), +// Color(0xFF98BCE5), +// Color(0xFFA7B5C5), +// Color(0xFFBED3EC), +// Color(0xFFD4E3F4), +// ]; +// return SfCartesianChart( +// primaryXAxis: CategoryAxis(), +// title: ChartTitle(text: chartData['chart_heading']), +// legend: Legend( +// isVisible: true, +// position: LegendPosition.bottom, +// overflowMode: LegendItemOverflowMode.scroll, +// ), +// tooltipBehavior: TooltipBehavior( +// enable: true, // Enable tooltips +// format: 'point.x : point.y', // Custom tooltip format +// ), +// series: >[ +// for (int i = 0; i < groupByValues.length; i++) +// StackedColumnSeries( +// dataSource: parseStackedBarChartData( +// chartData, groupByKey, groupByValues.elementAt(i)), +// xValueMapper: (ChartData data, _) => data.x ?? '', +// yValueMapper: (ChartData data, _) => data.y, +// name: groupByValues.elementAt(i), +// color: uniqueColors[i % uniqueColors.length], +// enableTooltip: true, +// ), +// ], +// ); +// default: +// return Center(child: Text('Unknown chart type')); +// } +// } +// +// @override +// Widget build(BuildContext context) { +// return Scaffold( +// key: _scaffoldKey, +// backgroundColor: Colors.brown[200]!, +// appBar: AppBar( +// backgroundColor: Colors.brown[200]!, +// elevation: 0, +// leading: IconButton( +// icon: Icon(Icons.arrow_back_ios_new, color: Colors.white), +// onPressed: () { +// context.go('/myhomepage'); +// }, +// ), +// title: Text( +// 'UAE Numbers', +// style: TextStyle(color: Colors.white), +// ), +// ), +// body: isLoading +// ? Center(child: CircularProgressIndicator()) +// : Column( +// children: [ +// Column( +// crossAxisAlignment: CrossAxisAlignment.end, +// children: [ +// Row( +// mainAxisAlignment: MainAxisAlignment +// .end, // Aligns the row's content to the right +// children: [ +// Row( +// children: [ +// Text( +// 'Bookmark', +// style: const TextStyle( +// fontSize: 16, +// color: Colors.white, +// ), +// ), +// Icon(Icons.bookmark_add_outlined, +// color: Colors.white, size: 18), +// ], +// ), +// SizedBox(width: 10), // Horizontal space between items +// Row( +// children: [ +// Text( +// 'Share', +// style: const TextStyle( +// fontSize: 16, +// color: Colors.white, +// ), +// ), +// Icon(Icons.share_sharp, +// color: Colors.white, size: 18), +// ], +// ), +// SizedBox(width: 10), // Horizontal space between items +// IconButton( +// icon: Icon(Icons.filter_alt_outlined, +// color: Colors.white, size: 18), +// onPressed: () { +// showRightSideModal( +// context, chartsData[0]["filters"], chartsData); +// }, +// ), +// ], +// ), +// ], +// ), +// +// // Padding( +// // padding: const EdgeInsets.all(16.0), +// // child: Align( +// // alignment: Alignment.topRight, +// // child: IconButton( +// // icon: Icon(Icons.filter_list, color: Colors.white), +// // onPressed: () { +// // showRightSideModal( +// // context, chartsData[0]["filters"], chartsData); +// // }, +// // ), +// // ), +// // ), +// Expanded( +// child: ListView( +// children: [ +// // nonChartData Cards +// GridView.builder( +// itemCount: cardData.length, +// shrinkWrap: true, +// physics: const NeverScrollableScrollPhysics(), +// gridDelegate: +// const SliverGridDelegateWithFixedCrossAxisCount( +// crossAxisCount: 2, // 2 cards per row +// crossAxisSpacing: 10, +// mainAxisSpacing: 10, +// childAspectRatio: 177.5 / +// 180, // Adjusted to maintain width and fixed height +// ), +// itemBuilder: (context, index) { +// final item = cardData[index]; +// print('item item item $item'); +// final chart_type = item['chart_type']; +// final chart_heading = item['chart_heading']; +// final data = processNonChartData(item); +// print('processNonChartData'); +// +// if (chart_type == 'total') { +// return Card( +// margin: const EdgeInsets.all(10), +// shape: RoundedRectangleBorder( +// borderRadius: BorderRadius.circular(12), +// ), +// elevation: 4, +// child: Padding( +// padding: const EdgeInsets.all(12.0), +// child: Column( +// mainAxisAlignment: MainAxisAlignment.center, +// children: [ +// const Icon(Icons.public, +// color: Color(0xFF90B0D5), size: 22), +// const SizedBox(height: 5), +// Text( +// '${chart_heading ?? 'NA'}', +// textAlign: TextAlign.center, +// style: TextStyle( +// fontSize: 14, +// fontWeight: FontWeight.bold, +// color: Colors.black87, +// ), +// ), +// Text( +// '(${data['lastYear'] ?? 'NA'})', +// style: const TextStyle( +// fontSize: 10, color: Colors.grey), +// ), +// Text( +// '${data['lastYearValue'] ?? 'NA'}', +// style: const TextStyle( +// fontSize: 16, +// fontWeight: FontWeight.bold, +// color: Color(0xFF90B0D5), +// ), +// ), +// const Divider( +// color: Colors.grey, thickness: 1), +// Text( +// '${data['secondLastYearValue'] ?? 'NA'}', +// style: const TextStyle( +// fontSize: 14, +// fontWeight: FontWeight.bold, +// color: Color(0xFF90B0D5), +// ), +// ), +// Text( +// '(${data['secondLastYear'] ?? 'NA'})', +// style: const TextStyle( +// fontSize: 10, color: Colors.grey), +// ), +// ], +// ), +// ), +// ); +// } else if (chart_type == 'average') { +// return Card( +// margin: const EdgeInsets.all(10), +// shape: RoundedRectangleBorder( +// borderRadius: BorderRadius.circular(12), +// ), +// elevation: 4, +// child: Padding( +// padding: const EdgeInsets.all(16.0), +// child: Column( +// mainAxisAlignment: MainAxisAlignment.center, +// children: [ +// const Icon(Icons.analytics, +// color: Color(0xFF90B0D5), size: 22), +// const SizedBox(height: 5), +// Text( +// '${chart_heading ?? 'NA'}', +// textAlign: TextAlign.center, +// style: TextStyle( +// fontSize: 14, +// fontWeight: FontWeight.bold, +// color: Colors.black87, +// ), +// ), +// Text( +// '(${data['firstYear'] ?? 'NA'} - ${data['lastYear'] ?? 'NA'})', +// style: const TextStyle( +// fontSize: 10, color: Colors.grey), +// ), +// Text( +// '${data['roundedAverage'] ?? 'NA'}', +// style: const TextStyle( +// fontSize: 16, +// fontWeight: FontWeight.bold, +// color: Color(0xFF90B0D5), +// ), +// ), +// ], +// ), +// ), +// ); +// } else { +// return const SizedBox +// .shrink(); // Ignore unknown KPIs +// } +// }, +// ), +// // chartsData Cards +// ListView.builder( +// itemCount: chartsData.length, +// shrinkWrap: true, +// physics: const NeverScrollableScrollPhysics(), +// itemBuilder: (context, index) { +// return Card( +// margin: const EdgeInsets.all(10), +// child: Padding( +// padding: const EdgeInsets.all(16.0), +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// const SizedBox(height: 10), +// Container( +// height: 300, +// child: buildChart(chartsData[index]), +// ), +// ], +// ), +// ), +// ); +// }, +// ), +// ], +// ), +// ), +// ], +// ), +// ); +// } +// +// void showRightSideModal(BuildContext context, List filters, List data) { +// // Initialize selected filters structure from the stored value, if exists +// List> selectedFilters = +// selectedFiltersStorage.isNotEmpty +// ? List.from(selectedFiltersStorage) // Use stored filters +// : filters.map((filter) { +// return {"filter_key": filter["filter_key"], "filter_data": []}; +// }).toList(); // Or initialize empty filters +// +// showModalBottomSheet( +// context: context, +// isScrollControlled: true, +// backgroundColor: Colors.transparent, +// builder: (BuildContext context) { +// return Align( +// alignment: Alignment.centerRight, +// child: Container( +// width: MediaQuery.of(context).size.width * 0.7, +// height: MediaQuery.of(context).size.height, +// color: Colors.white, +// child: Column( +// children: [ +// // Header Section +// Padding( +// padding: const EdgeInsets.all(16.0), +// child: Row( +// mainAxisAlignment: MainAxisAlignment.spaceBetween, +// children: [ +// Text( +// 'Filters', +// style: TextStyle( +// fontSize: 18, +// fontWeight: FontWeight.bold, +// ), +// ), +// IconButton( +// icon: Icon(Icons.close), +// onPressed: () => Navigator.pop(context), +// ), +// ], +// ), +// ), +// // Filters Section +// Expanded( +// child: ListView.builder( +// itemCount: filters.length, +// itemBuilder: (context, index) { +// final filter = filters[index]; +// final filterKey = filter["filter_key"]; +// final filterData = filter["filter_data"]; +// +// return StatefulBuilder( +// builder: (context, setState) { +// // Get the corresponding selected filter object +// var selectedFilter = selectedFilters +// .firstWhere((f) => f["filter_key"] == filterKey); +// +// return Padding( +// padding: const EdgeInsets.symmetric( +// horizontal: 16.0, vertical: 8.0), +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Text( +// filterKey, +// style: TextStyle( +// fontSize: 16, +// fontWeight: FontWeight.bold, +// ), +// ), +// InkWell( +// onTap: () { +// showDialog( +// context: context, +// builder: (BuildContext context) { +// return StatefulBuilder( +// builder: (context, dialogSetState) { +// return AlertDialog( +// title: Text('Select $filterKey'), +// content: SingleChildScrollView( +// child: ListBody( +// children: filterData +// .map((value) { +// return CheckboxListTile( +// title: Text( +// value.toString()), +// value: selectedFilter[ +// "filter_data"] +// .contains(value), +// onChanged: +// (bool? isChecked) { +// dialogSetState(() { +// if (isChecked == +// true) { +// selectedFilter[ +// "filter_data"] +// .add(value); +// } else { +// selectedFilter[ +// "filter_data"] +// .remove(value); +// } +// }); +// }, +// ); +// }).toList(), +// ), +// ), +// actions: [ +// TextButton( +// onPressed: () { +// // Store the updated selected filters after dialog closes +// setState(() {}); +// Navigator.pop(context); +// }, +// child: Text('OK'), +// ), +// ], +// ); +// }, +// ); +// }, +// ); +// }, +// child: Container( +// width: double.infinity, +// padding: EdgeInsets.symmetric( +// horizontal: 16.0, vertical: 12.0), +// decoration: BoxDecoration( +// border: Border.all(color: Colors.grey), +// borderRadius: BorderRadius.circular(8.0), +// ), +// child: Wrap( +// spacing: 8.0, +// runSpacing: 4.0, +// children: +// selectedFilter["filter_data"].isEmpty +// ? [ +// Text('Select $filterKey', +// style: TextStyle( +// color: Colors.grey)) +// ] +// : selectedFilter["filter_data"] +// .map((value) { +// return Chip( +// label: Text(value), +// onDeleted: () { +// setState(() { +// selectedFilter[ +// "filter_data"] +// .remove(value); +// }); +// }, +// ); +// }).toList(), +// ), +// ), +// ), +// ], +// ), +// ); +// }, +// ); +// }, +// ), +// ), +// // Button Section +// Padding( +// padding: const EdgeInsets.all(16.0), +// child: Row( +// mainAxisAlignment: MainAxisAlignment.spaceBetween, +// children: [ +// ElevatedButton( +// onPressed: () { +// // Clear all selected filters +// selectedFilters.forEach((filter) { +// filter["filter_data"].clear(); +// }); +// setState(() { +// chartsData = List.from(originalChartsData); +// cardData = List.from(originalCardData); +// }); +// // Reset the selectedFiltersStorage to empty when clearing +// selectedFiltersStorage.clear(); +// Navigator.pop(context); +// }, +// child: Text('Clear'), +// style: ElevatedButton.styleFrom( +// backgroundColor: Colors.grey, +// ), +// ), +// ElevatedButton( +// onPressed: () { +// print( +// "Selected Filters before applying: $selectedFilters"); +// setState(() { +// chartsData = originalChartsData; +// cardData = originalCardData; +// }); +// applyFilters(context, filters, chartsData, cardData, +// selectedFilters); +// // Save the selected filters to storage after applying +// selectedFiltersStorage = List.from(selectedFilters); +// }, +// child: Text('Apply Filter'), +// style: ElevatedButton.styleFrom( +// backgroundColor: Colors.blue, +// ), +// ), +// ], +// ), +// ), +// ], +// ), +// ), +// ); +// }, +// ); +// } +// } +// +// class ChartData { +// final int? xInt; // For column and other charts, using int for x +// final DateTime? xDateTime; // For scatter charts, using DateTime for x +// final double? y; // For column and other charts +// final String? timePeriod; // For line and bar charts +// final double? value; // For line and bar charts +// late final double? y2; // For secondary data (stacked column chart) +// late final double? y3; // For tertiary data (stacked column chart) +// final double? y4; // For quaternary data (stacked column chart) +// final String? x; // For stacked bar charts, using String for x +// +// // Constructor that handles all chart cases +// ChartData({ +// this.xInt, +// this.xDateTime, +// this.y, +// this.timePeriod, +// this.value, +// this.y2, +// this.y3, +// this.y4, +// this.x, +// }); +// } +// // [ // { // chart_heading :"Guest Nights by Region" @@ -1062,134 +1062,6 @@ class ChartData { // { // "ObsKey": { // "FREQ": "A", -// "GUEST_REGION": "AF", -// "H_INDICATOR": "GUN", -// "H_TYPE": "_Z", -// "MEASURE": "H", -// "REF_AREA": "AE", -// "SOURCE_DETAIL": "FCSC", -// "TIME_PERIOD": "2017", -// "UNIT_MEASURE": "NUMBER" -// }, -// "ObsValue": { -// "Value": "2721363" -// } -// }, -// { -// "ObsKey": { -// "FREQ": "A", -// "GUEST_REGION": "ASC", -// "H_INDICATOR": "GUN", -// "H_TYPE": "_Z", -// "MEASURE": "H", -// "REF_AREA": "AE", -// "SOURCE_DETAIL": "FCSC", -// "TIME_PERIOD": "2016", -// "UNIT_MEASURE": "NUMBER" -// }, -// "ObsValue": { -// "Value": "16454601" -// } -// }, -// { -// "ObsKey": { -// "FREQ": "A", -// "GUEST_REGION": "ASC", -// "H_INDICATOR": "GUN", -// "H_TYPE": "_Z", -// "MEASURE": "H", -// "REF_AREA": "AE", -// "SOURCE_DETAIL": "FCSC", -// "TIME_PERIOD": "2017", -// "UNIT_MEASURE": "NUMBER" -// }, -// "ObsValue": { -// "Value": "18960773" -// } -// }, -// { -// "ObsKey": { -// "FREQ": "A", -// "GUEST_REGION": "UAE", -// "H_INDICATOR": "GUN", -// "H_TYPE": "_Z", -// "MEASURE": "H", -// "REF_AREA": "AE", -// "SOURCE_DETAIL": "FCSC", -// "TIME_PERIOD": "2019", -// "UNIT_MEASURE": "NUMBER" -// }, -// "ObsValue": { -// "Value": "14286573" -// } -// }, -// { -// "ObsKey": { -// "FREQ": "A", -// "GUEST_REGION": "UAE", -// "H_INDICATOR": "GUN", -// "H_TYPE": "_Z", -// "MEASURE": "H", -// "REF_AREA": "AE", -// "SOURCE_DETAIL": "FCSC", -// "TIME_PERIOD": "2020", -// "UNIT_MEASURE": "NUMBER" -// }, -// "ObsValue": { -// "Value": "13982919" -// } -// }, -// { -// "ObsKey": { -// "FREQ": "A", -// "GUEST_REGION": "EC", -// "H_INDICATOR": "GUN", -// "H_TYPE": "_Z", -// "MEASURE": "H", -// "REF_AREA": "AE", -// "SOURCE_DETAIL": "FCSC", -// "TIME_PERIOD": "2019", -// "UNIT_MEASURE": "NUMBER" -// }, -// "ObsValue": { -// "Value": "19917654" -// } -// }, -// { -// "ObsKey": { -// "FREQ": "A", -// "GUEST_REGION": "EC", -// "H_INDICATOR": "GUN", -// "H_TYPE": "_Z", -// "MEASURE": "H", -// "REF_AREA": "AE", -// "SOURCE_DETAIL": "FCSC", -// "TIME_PERIOD": "2020", -// "UNIT_MEASURE": "NUMBER" -// }, -// "ObsValue": { -// "Value": "10041664" -// } -// }, -// { -// "ObsKey": { -// "FREQ": "A", -// "GUEST_REGION": "OC", -// "H_INDICATOR": "GUN", -// "H_TYPE": "_Z", -// "MEASURE": "H", -// "REF_AREA": "AE", -// "SOURCE_DETAIL": "FCSC", -// "TIME_PERIOD": "2017", -// "UNIT_MEASURE": "NUMBER" -// }, -// "ObsValue": { -// "Value": "1260359" -// } -// }, -// { -// "ObsKey": { -// "FREQ": "A", // "GUEST_REGION": "OC", // "H_INDICATOR": "GUN", // "H_TYPE": "_Z", diff --git a/lib/presentation/Screens/charts/screens/chart_screen.dart b/lib/presentation/Screens/charts/screens/chart_screen.dart index 0237b800..360e9d7a 100644 --- a/lib/presentation/Screens/charts/screens/chart_screen.dart +++ b/lib/presentation/Screens/charts/screens/chart_screen.dart @@ -7,7 +7,10 @@ import '../filters/search_filter_helper.dart'; class ChartScreen1 extends StatefulWidget { final String dataSets; - const ChartScreen1({Key? key, required this.dataSets}); + final String bgColor; + + const ChartScreen1( + {Key? key, required this.dataSets, required String this.bgColor}); @override _ChartScreen1State createState() => _ChartScreen1State(); } @@ -24,10 +27,13 @@ class _ChartScreen1State extends State { List cardData = []; List originalChartsData = []; List originalCardData = []; + late Color backgroundColor; @override void initState() { super.initState(); + final String bgColor = widget.bgColor; + print(' bgColor $bgColor'); fetchChartData(widget.dataSets); } @@ -368,11 +374,13 @@ class _ChartScreen1State extends State { @override Widget build(BuildContext context) { + final color = + Color(int.parse(widget.bgColor.replaceFirst('0x', ''), radix: 16)); return Scaffold( key: _scaffoldKey, - backgroundColor: Colors.brown[200]!, + backgroundColor: color, appBar: AppBar( - backgroundColor: Colors.brown[200]!, + backgroundColor: color, elevation: 0, leading: IconButton( icon: Icon(Icons.arrow_back_ios_new, color: Colors.white), @@ -451,8 +459,8 @@ class _ChartScreen1State extends State { crossAxisCount: 2, // 2 cards per row crossAxisSpacing: 10, mainAxisSpacing: 10, - childAspectRatio: 177.5 / - 180, // Adjusted to maintain width and fixed height + childAspectRatio: 190.5 / + 200, // Adjusted to maintain width and fixed height ), itemBuilder: (context, index) { final item = cardData[index]; @@ -470,49 +478,56 @@ class _ChartScreen1State extends State { ), elevation: 4, child: Padding( - padding: const EdgeInsets.all(12.0), + padding: const EdgeInsets.all(10.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.public, - color: Color(0xFF90B0D5), size: 22), - const SizedBox(height: 5), + color: Color(0xFF90B0D5), size: 30), + const SizedBox(height: 3), Text( '${chart_heading ?? 'NA'}', textAlign: TextAlign.center, style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, + fontSize: 11, + fontWeight: FontWeight.w400, color: Colors.black87, ), ), Text( '(${data['lastYear'] ?? 'NA'})', style: const TextStyle( - fontSize: 10, color: Colors.grey), + fontSize: 11, color: Colors.grey), ), Text( - '${data['lastYearValue'] ?? 'NA'}', + apiService + .formatAmount(data['lastYearValue']), style: const TextStyle( - fontSize: 16, + fontSize: 20, fontWeight: FontWeight.bold, color: Color(0xFF90B0D5), ), ), - const Divider( - color: Colors.grey, thickness: 1), + SizedBox( + height: 5, // Height of the divider + child: Divider( + color: Colors.grey, + thickness: 1, // Divider line thickness + ), + ), Text( - '${data['secondLastYearValue'] ?? 'NA'}', + apiService.formatAmount( + data['secondLastYearValue']), style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: Color(0xFF90B0D5), + fontSize: 16, + fontWeight: FontWeight.w600, + color: Color(0xFFD83731), ), ), Text( '(${data['secondLastYear'] ?? 'NA'})', style: const TextStyle( - fontSize: 10, color: Colors.grey), + fontSize: 11, color: Colors.grey), ), ], ), @@ -531,28 +546,28 @@ class _ChartScreen1State extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.analytics, - color: Color(0xFF90B0D5), size: 22), + color: Color(0xFF90B0D5), size: 30), const SizedBox(height: 5), Text( '${chart_heading ?? 'NA'}', textAlign: TextAlign.center, style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, + fontSize: 11, + fontWeight: FontWeight.w400, color: Colors.black87, ), ), Text( '(${data['firstYear'] ?? 'NA'} - ${data['lastYear'] ?? 'NA'})', style: const TextStyle( - fontSize: 10, color: Colors.grey), + fontSize: 11, color: Colors.grey), ), Text( '${data['roundedAverage'] ?? 'NA'}', style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Color(0xFF90B0D5), + fontSize: 26, + fontWeight: FontWeight.w900, + color: Color(0xFF11AF22), ), ), ], diff --git a/lib/presentation/Screens/charts/services/api_service.dart b/lib/presentation/Screens/charts/services/api_service.dart index 02952e20..31494a16 100644 --- a/lib/presentation/Screens/charts/services/api_service.dart +++ b/lib/presentation/Screens/charts/services/api_service.dart @@ -56,45 +56,6 @@ class ApiService { } } - /// Fetch chart data and categorize it into chart and non-chart data - // Future fetchChartData(String dataSets) async { - // final url = Uri.parse('$baseUrl?dataset=$dataSets'); - // - // List isChartData = []; - // List nonChartData = []; - // List originalChartsData = []; - // List originalCardData = []; - // - // try { - // final response = await http.get(url); - // - // if (response.statusCode == 200) { - // final List data = jsonDecode(response.body); - // - // for (var item in data) { - // if (item['is_chart'] == 'true') { - // isChartData.add(item); - // } else if (item['is_chart'] == 'false') { - // nonChartData.add(item); - // } - // } - // - // print('Chart Data: $isChartData'); - // print('Non-Chart Data: $nonChartData'); - // - // originalChartsData = List.from(isChartData); - // originalCardData = List.from(nonChartData); - // - // print('chartsData $isChartData'); - // print('cardData $nonChartData'); - // } else { - // throw Exception('Failed to load data'); - // } - // } catch (error) { - // print('Error fetching data: $error'); - // } - // } - /// Process non-chart data by extracting and calculating values Map processNonChartData(dynamic item) { print('Processing non-chart data...'); @@ -181,4 +142,22 @@ class ApiService { ); }).toList(); } + + String formatAmount(dynamic value) { + // Handle null or non-numeric values + if (value == null || num.tryParse(value.toString()) == null) { + return 'NA'; + } + + num amount = num.tryParse(value.toString())!; + + // Check if the amount is in millions or thousands + if (amount >= 1000000) { + return '${(amount / 1000000).toStringAsFixed(2)}M'; + } else if (amount >= 1000) { + return '${(amount / 1000).toStringAsFixed(2)}K'; + } else { + return '$amount'; + } + } } diff --git a/lib/presentation/Screens/charts/widgets/chart_widget.dart b/lib/presentation/Screens/charts/widgets/chart_widget.dart index 4e7c4836..ddff96f3 100644 --- a/lib/presentation/Screens/charts/widgets/chart_widget.dart +++ b/lib/presentation/Screens/charts/widgets/chart_widget.dart @@ -2,7 +2,7 @@ import 'dart:math'; import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/material.dart'; -import 'package:syncfusion_flutter_charts/charts.dart'; +// import 'package:syncfusion_flutter_charts/charts.dart'; class ChartWidget extends StatelessWidget { final dynamic chartData; @@ -121,80 +121,80 @@ class ChartWidget extends StatelessWidget { print('groupByValues $groupByValues'); switch (chartData['chart_type']) { - case 'stacked_bar': - String chartTitle = - capitalizeAndSplit(chartData['chart_heading'] ?? ''); - // Define a list of colors - final List uniqueColors = [ - Color(0xFF648CBA), - Color(0xFF90B0D5), - Color(0xFF98BCE5), - Color(0xFFA7B5C5), - Color(0xFFBED3EC), - Color(0xFFD4E3F4), - ]; - return SfCartesianChart( - primaryXAxis: CategoryAxis(), - title: ChartTitle(text: chartData['chart_heading']), - legend: Legend( - isVisible: true, - position: LegendPosition.bottom, - overflowMode: LegendItemOverflowMode.scroll, - ), - tooltipBehavior: TooltipBehavior( - enable: true, // Enable tooltips - format: 'point.x : point.y', // Custom tooltip format - ), - series: >[ - for (int i = 0; i < groupByValues.length; i++) - StackedBarSeries( - dataSource: parseStackedBarChartData( - chartData, groupByKey, groupByValues.elementAt(i)), - xValueMapper: (ChartData data, _) => data.x ?? '', - yValueMapper: (ChartData data, _) => data.y, - name: groupByValues.elementAt(i), - color: uniqueColors[i % uniqueColors.length], - enableTooltip: true, - ), - ], - ); - case 'stacked_column': - String chartTitle = - capitalizeAndSplit(chartData['chart_heading'] ?? ''); - // Define a list of colors - final List uniqueColors = [ - Color(0xFF648CBA), - Color(0xFF90B0D5), - Color(0xFF98BCE5), - Color(0xFFA7B5C5), - Color(0xFFBED3EC), - Color(0xFFD4E3F4), - ]; - return SfCartesianChart( - primaryXAxis: CategoryAxis(), - title: ChartTitle(text: chartData['chart_heading']), - legend: Legend( - isVisible: true, - position: LegendPosition.bottom, - overflowMode: LegendItemOverflowMode.scroll, - ), - tooltipBehavior: TooltipBehavior( - enable: true, // Enable tooltips - format: 'point.x : point.y', // Custom tooltip format - ), - series: >[ - for (int i = 0; i < groupByValues.length; i++) - StackedColumnSeries( - dataSource: parseStackedBarChartData( - chartData, groupByKey, groupByValues.elementAt(i)), - xValueMapper: (ChartData data, _) => data.x ?? '', - yValueMapper: (ChartData data, _) => data.y, - name: groupByValues.elementAt(i), - color: uniqueColors[i % uniqueColors.length], - enableTooltip: true, - ), - ], - ); + // case 'stacked_bar': + // String chartTitle = + // capitalizeAndSplit(chartData['chart_heading'] ?? ''); + // // Define a list of colors + // final List uniqueColors = [ + // Color(0xFF648CBA), + // Color(0xFF90B0D5), + // Color(0xFF98BCE5), + // Color(0xFFA7B5C5), + // Color(0xFFBED3EC), + // Color(0xFFD4E3F4), + // ]; + // return SfCartesianChart( + // primaryXAxis: CategoryAxis(), + // title: ChartTitle(text: chartData['chart_heading']), + // legend: Legend( + // isVisible: true, + // position: LegendPosition.bottom, + // overflowMode: LegendItemOverflowMode.scroll, + // ), + // tooltipBehavior: TooltipBehavior( + // enable: true, // Enable tooltips + // format: 'point.x : point.y', // Custom tooltip format + // ), + // series: >[ + // for (int i = 0; i < groupByValues.length; i++) + // StackedBarSeries( + // dataSource: parseStackedBarChartData( + // chartData, groupByKey, groupByValues.elementAt(i)), + // xValueMapper: (ChartData data, _) => data.x ?? '', + // yValueMapper: (ChartData data, _) => data.y, + // name: groupByValues.elementAt(i), + // color: uniqueColors[i % uniqueColors.length], + // enableTooltip: true, + // ), + // ], + // ); + // case 'stacked_column': + // String chartTitle = + // capitalizeAndSplit(chartData['chart_heading'] ?? ''); + // // Define a list of colors + // final List uniqueColors = [ + // Color(0xFF648CBA), + // Color(0xFF90B0D5), + // Color(0xFF98BCE5), + // Color(0xFFA7B5C5), + // Color(0xFFBED3EC), + // Color(0xFFD4E3F4), + // ]; + // return SfCartesianChart( + // primaryXAxis: CategoryAxis(), + // title: ChartTitle(text: chartData['chart_heading']), + // legend: Legend( + // isVisible: true, + // position: LegendPosition.bottom, + // overflowMode: LegendItemOverflowMode.scroll, + // ), + // tooltipBehavior: TooltipBehavior( + // enable: true, // Enable tooltips + // format: 'point.x : point.y', // Custom tooltip format + // ), + // series: >[ + // for (int i = 0; i < groupByValues.length; i++) + // StackedColumnSeries( + // dataSource: parseStackedBarChartData( + // chartData, groupByKey, groupByValues.elementAt(i)), + // xValueMapper: (ChartData data, _) => data.x ?? '', + // yValueMapper: (ChartData data, _) => data.y, + // name: groupByValues.elementAt(i), + // color: uniqueColors[i % uniqueColors.length], + // enableTooltip: true, + // ), + // ], + // ); case 'column_chart': // Case 3 for fl_chart column chart return BarChart( BarChartData( @@ -369,42 +369,37 @@ class ChartWidget extends StatelessWidget { Padding( padding: const EdgeInsets.all(5.0), child: Wrap( - spacing: 5, - runSpacing: 5, - children: chunkedGroupByValues.map((chunk) { - return Row( - mainAxisAlignment: MainAxisAlignment.center, - children: chunk.map((group) { - List groupByValuesList = groupByValues.toList(); - int index = groupByValuesList.indexOf(group); - Color groupColor = _getColorForGroup(index); - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 5.0), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - width: 10, - height: 10, - decoration: BoxDecoration( - color: groupColor, - shape: BoxShape.circle, - ), - ), - SizedBox(width: 3), - Text( - group, - overflow: TextOverflow.ellipsis, - style: TextStyle(fontSize: 11), - ), - ], + spacing: 10, // Horizontal spacing between items + runSpacing: 5, // Vertical spacing between rows + children: chunkedGroupByValues.expand((chunk) { + return chunk.map((group) { + List groupByValuesList = groupByValues.toList(); + int index = groupByValuesList.indexOf(group); + Color groupColor = _getColorForGroup(index); + + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: 10, + height: 10, + decoration: BoxDecoration( + color: groupColor, + shape: BoxShape.circle, + ), ), - ); - }).toList(), - ); + SizedBox(width: 5), + Text( + group, + overflow: TextOverflow.ellipsis, + style: TextStyle(fontSize: 11), + ), + ], + ); + }).toList(); }).toList(), ), - ), + ) ], ); case 'fl_multi_bar': diff --git a/lib/presentation/Screens/demo_home.dart b/lib/presentation/Screens/demo_home.dart index 895a5a29..bbfc6f7c 100644 --- a/lib/presentation/Screens/demo_home.dart +++ b/lib/presentation/Screens/demo_home.dart @@ -1,424 +1,424 @@ -import 'dart:convert'; -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:intl/intl.dart'; -import 'package:syncfusion_flutter_charts/charts.dart'; // Import Syncfusion charts package -import 'package:http/http.dart' as http; - -void main() { - runApp(MyApp()); -} - -class MyApp extends StatelessWidget { - @override - Widget build(BuildContext context) { - return MaterialApp( - home: ChartPage(dataSets: ''), - ); - } -} - -class ChartPage extends StatefulWidget { - final String dataSets; - const ChartPage({Key? key, required this.dataSets}); - - @override - ChartPageState createState() => ChartPageState(); -} - -class ChartPageState extends State { - List chartsData = []; - bool isLoading = true; - - @override - void initState() { - super.initState(); - fetchChartData(widget.dataSets); - } - - Future fetchChartData(datasets) async { - const baseUrl = - 'https://pb.venbait.in/api/custom/apicall'; // Replace with your server URL - final url = Uri.parse('$baseUrl?dataset=$datasets'); - - try { - final response = await http.get(url); - if (response.statusCode == 200) { - setState(() { - chartsData = jsonDecode(response.body); - isLoading = false; - }); - } else { - throw Exception('Failed to load data'); - } - } catch (error) { - setState(() { - isLoading = false; - }); - print('Error fetching data: $error'); - } - } - - List parseLineChartData(List response) { - // Group by timePeriod (year) and sum the values - Map groupedData = {}; - - response.forEach((entry) { - final year = entry['ObsKey']['TIME_PERIOD']?.toString() ?? 'Unknown'; - final value = - double.tryParse(entry['ObsValue']['Value']?.toString() ?? '0.0') ?? - 0.0; - - // Add the value to the existing year (if exists) or initialize it - if (groupedData.containsKey(year)) { - groupedData[year] = groupedData[year]! + value; - } else { - groupedData[year] = value; - } - }); - - // Sort the grouped data by year in ascending order - var sortedEntries = groupedData.entries.toList() - ..sort((a, b) => int.parse(a.key).compareTo(int.parse(b.key))); - - // Convert the sorted data to a list of ChartData - return sortedEntries - .map((entry) => ChartData( - timePeriod: entry.key, - value: entry.value, - value1: 0.0)) // Add value1 as 0.0 - .toList(); - } - - List parseBarChartData(List response) { - return response - .asMap() - .entries - .map((entry) => ChartData( - timePeriod: entry.value['ObsKey']['TIME_PERIOD'] ?? 'Unknown', - value: double.tryParse( - entry.value['ObsValue']['Value'].toString()) ?? - 0.0, - value1: 0.0, // Ensure value1 is passed as well - )) - .toList(); - } - - List parseColumnChartData(List response) { - List chartDataList = []; - - // Temporary map to store values by TIME_PERIOD - Map timePeriodMap = {}; - - for (var entry in response) { - String timePeriod = entry['ObsKey']['TIME_PERIOD'].toString(); - double value = - double.tryParse(entry['ObsValue']['Value']?.toString() ?? '0.0') ?? - 0.0; - String indicator = entry['ObsKey']['H_INDICATOR']; - - // If the entry is for TOR, map it to 'value' - if (indicator == 'TOR') { - if (timePeriodMap.containsKey(timePeriod)) { - // Update the value by creating a new ChartData object - timePeriodMap[timePeriod] = ChartData( - timePeriod: timePeriod, - value: value, // Set the new value - value1: timePeriodMap[timePeriod]?.value1 ?? 0.0, - ); - } else { - timePeriodMap[timePeriod] = ChartData( - timePeriod: timePeriod, - value: value, - value1: 0.0, - ); - } - } - - // If the entry is for TAR, map it to 'value1' - if (indicator == 'TAR') { - if (timePeriodMap.containsKey(timePeriod)) { - // Create a new ChartData object with the updated value1 - timePeriodMap[timePeriod] = ChartData( - timePeriod: timePeriod, - value: timePeriodMap[timePeriod]?.value ?? - 0.0, // Retain the current value - value1: value, // Update the value1 - ); - } else { - timePeriodMap[timePeriod] = ChartData( - timePeriod: timePeriod, - value: 0.0, - value1: value, - ); - } - } - } - - // Convert the map to a list - chartDataList = timePeriodMap.values.toList(); - - return chartDataList; - } - - Widget buildChart(dynamic chartData) { - print('chartData $chartData'); - switch (chartData['chart_type']) { - case 'area': - return SfCartesianChart( - primaryXAxis: CategoryAxis( - title: AxisTitle(text: 'Year'), - labelRotation: 45, // Rotate labels if they overlap - ), - title: ChartTitle(text: 'Hotel Estabhlishments'), - legend: Legend(isVisible: true), - tooltipBehavior: TooltipBehavior( - enable: true, - builder: (dynamic data, dynamic point, dynamic series, - int pointIndex, int seriesIndex) { - return Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(5), - ), - child: Text( - '${data.timePeriod}: ${formatNumber(data.value)}', - style: const TextStyle(color: Colors.black), - ), - ); - }, - ), - series: [ - // AreaSeries for the area chart - AreaSeries( - dataSource: parseLineChartData( - chartData['response']), // your chart data - color: Color(0xFF7DAFBC), // Area color - borderDrawMode: BorderDrawMode - .excludeBottom, // Optional, adjust border settings - borderColor: Colors.green, // Border color - borderWidth: 2, // Border width - xValueMapper: (ChartData data, _) => - data.timePeriod, // Map x to DateTime - yValueMapper: (ChartData data, _) => data.value, - // name: chartData['dataset'], - name: 'Hotels', - dataLabelSettings: DataLabelSettings( - isVisible: true, - builder: (dynamic data, dynamic point, dynamic series, - int pointIndex, int seriesIndex) { - return Text( - formatNumber(data.value), - style: const TextStyle(fontSize: 12, color: Colors.black), - ); - }, - ), // Map y to numerical value - ) - ]); - case 'bar': - return SfCartesianChart( - primaryXAxis: CategoryAxis(), - title: ChartTitle(text: 'Hotel Occupancy Rate'), - tooltipBehavior: TooltipBehavior( - enable: true, - builder: (dynamic data, dynamic point, dynamic series, - int pointIndex, int seriesIndex) { - return Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(5), - ), - child: Text( - '${data.timePeriod}: ${formatNumber(data.value)}', - style: const TextStyle(color: Colors.black), - ), - ); - }, - ), - series: >[ - BarSeries( - dataSource: parseBarChartData(chartData['response']), - xValueMapper: (ChartData data, _) => data.timePeriod, - yValueMapper: (ChartData data, _) => data.value, - name: chartData['dataset'], - color: Color(0xFF7DAFBC), - dataLabelSettings: DataLabelSettings( - isVisible: true, - builder: (dynamic data, dynamic point, dynamic series, - int pointIndex, int seriesIndex) { - return Text( - formatNumber(data.value), - style: const TextStyle(fontSize: 12, color: Colors.black), - ); - }, - ), - // isTrackVisible: true, - // trackColor: Colors.red - ), - ], - ); - case 'column': - return SfCartesianChart( - primaryXAxis: CategoryAxis( - title: AxisTitle(text: 'Year'), - labelRotation: 45, // Rotate labels if they overlap - ), - primaryYAxis: NumericAxis( - title: AxisTitle(text: 'No of rooms'), - ), - legend: Legend(isVisible: true), - title: ChartTitle(text: 'Hotel Occupancy Rate'), - enableSideBySideSeriesPlacement: true, - tooltipBehavior: TooltipBehavior(enable: true), - series: >[ - // First Series (value) - - ColumnSeries( - name: 'Available Rooms', - // opacity: 0.9, - // width: 0.4, - color: Color(0xFF587BA3), - dataSource: parseColumnChartData(chartData['response']), - xValueMapper: (ChartData data, _) => int.parse(data.timePeriod), - yValueMapper: (ChartData data, _) => data.value1, - ), - // Second Series (value1) - ColumnSeries( - color: Color(0xFF90B0D5), - name: 'Occupied Rooms', - dataSource: parseColumnChartData(chartData['response']), - xValueMapper: (ChartData data, _) => int.parse(data.timePeriod), - yValueMapper: (ChartData data, _) => data.value, - ), - ], // Numeric Y-axis to plot the values - ); - default: - return Center(child: Text('Unknown chart type')); - } - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: const Color(0xFF7DAFBC), - appBar: AppBar( - backgroundColor: const Color(0xFF7DAFBC), - elevation: 0, - leading: IconButton( - icon: const Icon(Icons.arrow_back_ios_new, color: Colors.white), - onPressed: () { - context.go('/myhomepage'); - }, - ), - title: const Text( - 'Charts', - style: TextStyle(color: Colors.white), - ), - ), - body: isLoading - ? const Center(child: CircularProgressIndicator()) - : Column( - children: [ - Card( - margin: const EdgeInsets.all(10), - color: Colors.white, - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: const [ - Text( - 'Card 1 Title', - style: TextStyle( - fontSize: 18, fontWeight: FontWeight.bold), - ), - SizedBox(height: 10), - Text('Content for the first card goes here.'), - ], - ), - ), - ), - Card( - margin: const EdgeInsets.all(10), - color: Colors.white, - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: const [ - Text( - 'Card 2 Title', - style: TextStyle( - fontSize: 18, fontWeight: FontWeight.bold), - ), - SizedBox(height: 10), - Text('Content for the second card goes here.'), - ], - ), - ), - ), - Expanded( - child: ListView.builder( - itemCount: chartsData.length, - itemBuilder: (context, index) { - return Card( - margin: const EdgeInsets.all(10), - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - height: 300, - child: buildChart(chartsData[index]), - ), - ], - ), - ), - ); - }, - ), - ), - ], - ), - ); - } -} - -class ChartData { - final String timePeriod; - final double value; - final double value1; - final String formattedValue; - - ChartData( - {required this.timePeriod, required this.value, required this.value1}) - : formattedValue = formatNumber(value); -} - +// import 'dart:convert'; +// import 'package:flutter/material.dart'; +// import 'package:go_router/go_router.dart'; +// import 'package:intl/intl.dart'; +// import 'package:syncfusion_flutter_charts/charts.dart'; // Import Syncfusion charts package +// import 'package:http/http.dart' as http; +// +// void main() { +// runApp(MyApp()); +// } +// +// class MyApp extends StatelessWidget { +// @override +// Widget build(BuildContext context) { +// return MaterialApp( +// home: ChartPage(dataSets: ''), +// ); +// } +// } +// +// class ChartPage extends StatefulWidget { +// final String dataSets; +// const ChartPage({Key? key, required this.dataSets}); +// +// @override +// ChartPageState createState() => ChartPageState(); +// } +// +// class ChartPageState extends State { +// List chartsData = []; +// bool isLoading = true; +// +// @override +// void initState() { +// super.initState(); +// fetchChartData(widget.dataSets); +// } +// +// Future fetchChartData(datasets) async { +// const baseUrl = +// 'https://pb.venbait.in/api/custom/apicall'; // Replace with your server URL +// final url = Uri.parse('$baseUrl?dataset=$datasets'); +// +// try { +// final response = await http.get(url); +// if (response.statusCode == 200) { +// setState(() { +// chartsData = jsonDecode(response.body); +// isLoading = false; +// }); +// } else { +// throw Exception('Failed to load data'); +// } +// } catch (error) { +// setState(() { +// isLoading = false; +// }); +// print('Error fetching data: $error'); +// } +// } +// +// List parseLineChartData(List response) { +// // Group by timePeriod (year) and sum the values +// Map groupedData = {}; +// +// response.forEach((entry) { +// final year = entry['ObsKey']['TIME_PERIOD']?.toString() ?? 'Unknown'; +// final value = +// double.tryParse(entry['ObsValue']['Value']?.toString() ?? '0.0') ?? +// 0.0; +// +// // Add the value to the existing year (if exists) or initialize it +// if (groupedData.containsKey(year)) { +// groupedData[year] = groupedData[year]! + value; +// } else { +// groupedData[year] = value; +// } +// }); +// +// // Sort the grouped data by year in ascending order +// var sortedEntries = groupedData.entries.toList() +// ..sort((a, b) => int.parse(a.key).compareTo(int.parse(b.key))); +// +// // Convert the sorted data to a list of ChartData +// return sortedEntries +// .map((entry) => ChartData( +// timePeriod: entry.key, +// value: entry.value, +// value1: 0.0)) // Add value1 as 0.0 +// .toList(); +// } +// +// List parseBarChartData(List response) { +// return response +// .asMap() +// .entries +// .map((entry) => ChartData( +// timePeriod: entry.value['ObsKey']['TIME_PERIOD'] ?? 'Unknown', +// value: double.tryParse( +// entry.value['ObsValue']['Value'].toString()) ?? +// 0.0, +// value1: 0.0, // Ensure value1 is passed as well +// )) +// .toList(); +// } +// +// List parseColumnChartData(List response) { +// List chartDataList = []; +// +// // Temporary map to store values by TIME_PERIOD +// Map timePeriodMap = {}; +// +// for (var entry in response) { +// String timePeriod = entry['ObsKey']['TIME_PERIOD'].toString(); +// double value = +// double.tryParse(entry['ObsValue']['Value']?.toString() ?? '0.0') ?? +// 0.0; +// String indicator = entry['ObsKey']['H_INDICATOR']; +// +// // If the entry is for TOR, map it to 'value' +// if (indicator == 'TOR') { +// if (timePeriodMap.containsKey(timePeriod)) { +// // Update the value by creating a new ChartData object +// timePeriodMap[timePeriod] = ChartData( +// timePeriod: timePeriod, +// value: value, // Set the new value +// value1: timePeriodMap[timePeriod]?.value1 ?? 0.0, +// ); +// } else { +// timePeriodMap[timePeriod] = ChartData( +// timePeriod: timePeriod, +// value: value, +// value1: 0.0, +// ); +// } +// } +// +// // If the entry is for TAR, map it to 'value1' +// if (indicator == 'TAR') { +// if (timePeriodMap.containsKey(timePeriod)) { +// // Create a new ChartData object with the updated value1 +// timePeriodMap[timePeriod] = ChartData( +// timePeriod: timePeriod, +// value: timePeriodMap[timePeriod]?.value ?? +// 0.0, // Retain the current value +// value1: value, // Update the value1 +// ); +// } else { +// timePeriodMap[timePeriod] = ChartData( +// timePeriod: timePeriod, +// value: 0.0, +// value1: value, +// ); +// } +// } +// } +// +// // Convert the map to a list +// chartDataList = timePeriodMap.values.toList(); +// +// return chartDataList; +// } +// +// Widget buildChart(dynamic chartData) { +// print('chartData $chartData'); +// switch (chartData['chart_type']) { +// case 'area': +// return SfCartesianChart( +// primaryXAxis: CategoryAxis( +// title: AxisTitle(text: 'Year'), +// labelRotation: 45, // Rotate labels if they overlap +// ), +// title: ChartTitle(text: 'Hotel Estabhlishments'), +// legend: Legend(isVisible: true), +// tooltipBehavior: TooltipBehavior( +// enable: true, +// builder: (dynamic data, dynamic point, dynamic series, +// int pointIndex, int seriesIndex) { +// return Container( +// padding: const EdgeInsets.all(8), +// decoration: BoxDecoration( +// color: Colors.white, +// borderRadius: BorderRadius.circular(5), +// ), +// child: Text( +// '${data.timePeriod}: ${formatNumber(data.value)}', +// style: const TextStyle(color: Colors.black), +// ), +// ); +// }, +// ), +// series: [ +// // AreaSeries for the area chart +// AreaSeries( +// dataSource: parseLineChartData( +// chartData['response']), // your chart data +// color: Color(0xFF7DAFBC), // Area color +// borderDrawMode: BorderDrawMode +// .excludeBottom, // Optional, adjust border settings +// borderColor: Colors.green, // Border color +// borderWidth: 2, // Border width +// xValueMapper: (ChartData data, _) => +// data.timePeriod, // Map x to DateTime +// yValueMapper: (ChartData data, _) => data.value, +// // name: chartData['dataset'], +// name: 'Hotels', +// dataLabelSettings: DataLabelSettings( +// isVisible: true, +// builder: (dynamic data, dynamic point, dynamic series, +// int pointIndex, int seriesIndex) { +// return Text( +// formatNumber(data.value), +// style: const TextStyle(fontSize: 12, color: Colors.black), +// ); +// }, +// ), // Map y to numerical value +// ) +// ]); +// case 'bar': +// return SfCartesianChart( +// primaryXAxis: CategoryAxis(), +// title: ChartTitle(text: 'Hotel Occupancy Rate'), +// tooltipBehavior: TooltipBehavior( +// enable: true, +// builder: (dynamic data, dynamic point, dynamic series, +// int pointIndex, int seriesIndex) { +// return Container( +// padding: const EdgeInsets.all(8), +// decoration: BoxDecoration( +// color: Colors.white, +// borderRadius: BorderRadius.circular(5), +// ), +// child: Text( +// '${data.timePeriod}: ${formatNumber(data.value)}', +// style: const TextStyle(color: Colors.black), +// ), +// ); +// }, +// ), +// series: >[ +// BarSeries( +// dataSource: parseBarChartData(chartData['response']), +// xValueMapper: (ChartData data, _) => data.timePeriod, +// yValueMapper: (ChartData data, _) => data.value, +// name: chartData['dataset'], +// color: Color(0xFF7DAFBC), +// dataLabelSettings: DataLabelSettings( +// isVisible: true, +// builder: (dynamic data, dynamic point, dynamic series, +// int pointIndex, int seriesIndex) { +// return Text( +// formatNumber(data.value), +// style: const TextStyle(fontSize: 12, color: Colors.black), +// ); +// }, +// ), +// // isTrackVisible: true, +// // trackColor: Colors.red +// ), +// ], +// ); +// case 'column': +// return SfCartesianChart( +// primaryXAxis: CategoryAxis( +// title: AxisTitle(text: 'Year'), +// labelRotation: 45, // Rotate labels if they overlap +// ), +// primaryYAxis: NumericAxis( +// title: AxisTitle(text: 'No of rooms'), +// ), +// legend: Legend(isVisible: true), +// title: ChartTitle(text: 'Hotel Occupancy Rate'), +// enableSideBySideSeriesPlacement: true, +// tooltipBehavior: TooltipBehavior(enable: true), +// series: >[ +// // First Series (value) +// +// ColumnSeries( +// name: 'Available Rooms', +// // opacity: 0.9, +// // width: 0.4, +// color: Color(0xFF587BA3), +// dataSource: parseColumnChartData(chartData['response']), +// xValueMapper: (ChartData data, _) => int.parse(data.timePeriod), +// yValueMapper: (ChartData data, _) => data.value1, +// ), +// // Second Series (value1) +// ColumnSeries( +// color: Color(0xFF90B0D5), +// name: 'Occupied Rooms', +// dataSource: parseColumnChartData(chartData['response']), +// xValueMapper: (ChartData data, _) => int.parse(data.timePeriod), +// yValueMapper: (ChartData data, _) => data.value, +// ), +// ], // Numeric Y-axis to plot the values +// ); +// default: +// return Center(child: Text('Unknown chart type')); +// } +// } +// +// @override +// Widget build(BuildContext context) { +// return Scaffold( +// backgroundColor: const Color(0xFF7DAFBC), +// appBar: AppBar( +// backgroundColor: const Color(0xFF7DAFBC), +// elevation: 0, +// leading: IconButton( +// icon: const Icon(Icons.arrow_back_ios_new, color: Colors.white), +// onPressed: () { +// context.go('/myhomepage'); +// }, +// ), +// title: const Text( +// 'Charts', +// style: TextStyle(color: Colors.white), +// ), +// ), +// body: isLoading +// ? const Center(child: CircularProgressIndicator()) +// : Column( +// children: [ +// Card( +// margin: const EdgeInsets.all(10), +// color: Colors.white, +// child: Padding( +// padding: const EdgeInsets.all(16.0), +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: const [ +// Text( +// 'Card 1 Title', +// style: TextStyle( +// fontSize: 18, fontWeight: FontWeight.bold), +// ), +// SizedBox(height: 10), +// Text('Content for the first card goes here.'), +// ], +// ), +// ), +// ), +// Card( +// margin: const EdgeInsets.all(10), +// color: Colors.white, +// child: Padding( +// padding: const EdgeInsets.all(16.0), +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: const [ +// Text( +// 'Card 2 Title', +// style: TextStyle( +// fontSize: 18, fontWeight: FontWeight.bold), +// ), +// SizedBox(height: 10), +// Text('Content for the second card goes here.'), +// ], +// ), +// ), +// ), +// Expanded( +// child: ListView.builder( +// itemCount: chartsData.length, +// itemBuilder: (context, index) { +// return Card( +// margin: const EdgeInsets.all(10), +// child: Padding( +// padding: const EdgeInsets.all(16.0), +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Container( +// height: 300, +// child: buildChart(chartsData[index]), +// ), +// ], +// ), +// ), +// ); +// }, +// ), +// ), +// ], +// ), +// ); +// } +// } +// +// class ChartData { +// final String timePeriod; +// final double value; +// final double value1; +// final String formattedValue; +// +// ChartData( +// {required this.timePeriod, required this.value, required this.value1}) +// : formattedValue = formatNumber(value); +// } +// +// // String formatNumber(double value) { +// // if (value >= 1e12) { +// // return '${(value / 1e12).toStringAsFixed(2)} T'; // Trillions +// // } else if (value >= 1e9) { +// // return '${(value / 1e9).toStringAsFixed(2)} B'; // Billions +// // } else if (value >= 1e6) { +// // return '${(value / 1e6).toStringAsFixed(2)} M'; // Millions +// // } else if (value >= 1e5) { +// // return '${(value / 1e5).toStringAsFixed(2)} L'; // Lakhs +// // } else if (value >= 1e3) { +// // return '${(value / 1e3).toStringAsFixed(2)} K'; // Thousands +// // } +// // return value.toStringAsFixed(2); // Default to two decimal places +// // } +// // String formatNumber(double value) { -// if (value >= 1e12) { -// return '${(value / 1e12).toStringAsFixed(2)} T'; // Trillions -// } else if (value >= 1e9) { +// if (value >= 1e9) { // return '${(value / 1e9).toStringAsFixed(2)} B'; // Billions // } else if (value >= 1e6) { // return '${(value / 1e6).toStringAsFixed(2)} M'; // Millions -// } else if (value >= 1e5) { -// return '${(value / 1e5).toStringAsFixed(2)} L'; // Lakhs -// } else if (value >= 1e3) { -// return '${(value / 1e3).toStringAsFixed(2)} K'; // Thousands // } -// return value.toStringAsFixed(2); // Default to two decimal places +// return value +// .toStringAsFixed(2); // Default to two decimal places for smaller numbers // } - -String formatNumber(double value) { - if (value >= 1e9) { - return '${(value / 1e9).toStringAsFixed(2)} B'; // Billions - } else if (value >= 1e6) { - return '${(value / 1e6).toStringAsFixed(2)} M'; // Millions - } - return value - .toStringAsFixed(2); // Default to two decimal places for smaller numbers -} diff --git a/lib/presentation/Screens/demo_home2.dart b/lib/presentation/Screens/demo_home2.dart index b1576aaa..2b994cdd 100644 --- a/lib/presentation/Screens/demo_home2.dart +++ b/lib/presentation/Screens/demo_home2.dart @@ -1,328 +1,328 @@ -import 'dart:convert'; -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:intl/intl.dart'; -import 'package:syncfusion_flutter_charts/charts.dart'; // Import Syncfusion charts package -import 'package:http/http.dart' as http; - -void main() { - runApp(MyApp()); -} - -class MyApp extends StatelessWidget { - @override - Widget build(BuildContext context) { - return MaterialApp( - home: ChartPage2(dataSets: ''), - ); - } -} - -class ChartPage2 extends StatefulWidget { - final String dataSets; - const ChartPage2({Key? key, required this.dataSets}); - @override - ChartPageState createState() => ChartPageState(); -} - -class ChartPageState extends State { - List chartsData = []; - bool isLoading = true; - - @override - void initState() { - super.initState(); - fetchChartData(widget.dataSets); - } - - Future fetchChartData(dataSets) async { - const baseUrl = - 'https://pb.venbait.in/api/custom/apicall'; // Replace with your server URL - final url = Uri.parse('$baseUrl?dataset=$dataSets'); - - try { - final response = await http.get(url); - if (response.statusCode == 200) { - setState(() { - chartsData = jsonDecode(response.body); - isLoading = false; - }); - } else { - throw Exception('Failed to load data'); - } - } catch (error) { - setState(() { - isLoading = false; - }); - print('Error fetching data: $error'); - } - } - - List parseLineChartData(List response) { - return response.map((entry) { - // Attempt to fetch the TIMEPERIOD - final rawTimePeriod = - entry['ObsKey']?['Year'] ?? entry['ObsKey']?['TIME_PERIOD']; - final formattedTimePeriod = rawTimePeriod != null - ? rawTimePeriod.toString() // Use as-is if valid - : 'Unknown'; // Fallback value if null - - // Parse the value or fallback to 0.0 - final value = - double.tryParse(entry['ObsValue']?['Value']?.toString() ?? '0.0') ?? - 0.0; - - return ChartData( - timePeriod: formattedTimePeriod, - value: value, - ); - }).toList(); - } - - List parseBarChartData(List response) { - return response - .asMap() - .entries - .map((entry) => ChartData( - timePeriod: entry.value['ObsKey']['TIME_PERIOD'] ?? - 'Unknown', // Fallback to 'Unknown' if null - value: double.tryParse( - entry.value['ObsValue']['Value'].toString()) ?? - 0.0, // Handle null/invalid value - )) - .toList(); - } - -// Update parseColumnChartData for column chart - List parseColumnChartData(List response) { - return response.map((entry) { - // Extract TIME_PERIOD as x - final x = - int.tryParse(entry['ObsKey']?['TIME_PERIOD']?.toString() ?? '0') ?? 0; - // Extract Value as y - final y = - double.tryParse(entry['ObsValue']?['Value']?.toString() ?? '0.0') ?? - 0.0; - return ChartData(xInt: x, y: y); - }).toList(); - } - -// Update parseScatterChartData for scatter chart - List parseScatterChartData(List response) { - return response.map((entry) { - // Parse TIME_PERIOD into DateTime - final timePeriod = entry['ObsKey']?['TIME_PERIOD']; - final x = timePeriod != null - ? DateTime.tryParse('$timePeriod-01-01') // Convert year to DateTime - : DateTime.now(); // Fallback to current date if null - - // Parse Value into double - final y = - double.tryParse(entry['ObsValue']?['Value']?.toString() ?? '0.0') ?? - 0.0; - - return ChartData(xDateTime: x, y: y); - }).toList(); - } - - Widget buildChart(dynamic chartData) { - switch (chartData['chart_type']) { - case 'scatter': - return SfCartesianChart( - primaryXAxis: DateTimeAxis(), // Ensure it's DateTimeAxis - tooltipBehavior: TooltipBehavior(enable: true), - title: ChartTitle(text: 'Divorces'), - series: [ - ScatterSeries( - dataSource: parseScatterChartData(chartData['response']), - xValueMapper: (ChartData data, _) => - data.xDateTime ?? DateTime.now(), - yValueMapper: (ChartData data, _) => data.y, - name: chartData['dataset'], - dataLabelSettings: DataLabelSettings(isVisible: true), - ), - ], - ); - case 'column': - return SfCartesianChart( - primaryXAxis: NumericAxis( - title: AxisTitle(text: 'Year'), - interval: 1, // Ensure no fractional intervals - ), - title: ChartTitle(text: 'Marriages'), - series: >[ - ColumnSeries( - dataSource: parseColumnChartData(chartData['response']), - xValueMapper: (ChartData data, _) => data.xInt ?? 0, - yValueMapper: (ChartData data, _) => data.y, - name: chartData['dataset'], - color: Color(0xFF7DAFBC), - width: 0.8, - spacing: 0.2, - dataLabelSettings: - DataLabelSettings(isVisible: true), // Show data labels - ), - ], - ); - - case 'line': - return SfCartesianChart( - primaryXAxis: CategoryAxis(), - title: ChartTitle(text: 'Line Chart'), - legend: Legend(isVisible: true), - tooltipBehavior: TooltipBehavior(enable: true), - series: >[ - LineSeries( - dataSource: parseLineChartData(chartData['response']), - xValueMapper: (ChartData data, _) => data.timePeriod ?? '', - yValueMapper: (ChartData data, _) => data.value ?? 0.0, - name: 'Sales', - dataLabelSettings: DataLabelSettings(isVisible: true), - ), - ], - ); - case 'bar': - return SfCartesianChart( - primaryXAxis: CategoryAxis(), - title: ChartTitle(text: 'Bar Chart'), - tooltipBehavior: TooltipBehavior(enable: true), - series: >[ - BarSeries( - dataSource: parseBarChartData(chartData['response']), - xValueMapper: (ChartData data, _) => data.timePeriod ?? '', - yValueMapper: (ChartData data, _) => data.value ?? 0.0, - name: 'Gold', - color: Color.fromRGBO(8, 142, 255, 1), - ), - ], - ); - - default: - return Center(child: Text('Unknown chart type')); - } - } - - @override - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: const Color(0xFF7DAFBC), - appBar: AppBar( - backgroundColor: Color(0xFF7DAFBC), - elevation: 0, - leading: IconButton( - icon: Icon(Icons.arrow_back_ios_new, color: Colors.white), - onPressed: () { - context.go('/myhomepage'); - }, - ), - title: Text( - 'Charts', - style: TextStyle(color: Colors.white), - ), - ), - body: isLoading - ? Center(child: CircularProgressIndicator()) - : Column( - children: [ - // Row for two cards - Row( - children: [ - // First Card - Expanded( - flex: 6, - child: Card( - margin: EdgeInsets.all(10), - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Card 1', - style: TextStyle( - fontSize: 18, fontWeight: FontWeight.bold), - ), - SizedBox(height: 10), - Text('Content for Card 1 goes here.'), - ], - ), - ), - ), - ), - // Second Card - Expanded( - flex: 6, - child: Card( - margin: EdgeInsets.all(10), - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Card 2', - style: TextStyle( - fontSize: 18, fontWeight: FontWeight.bold), - ), - SizedBox(height: 10), - Text('Content for Card 2 goes here.'), - ], - ), - ), - ), - ), - ], - ), - // List of charts - Expanded( - child: ListView.builder( - itemCount: chartsData.length, - itemBuilder: (context, index) { - return Card( - margin: EdgeInsets.all(10), - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox(height: 10), - Container( - height: 300, - child: buildChart(chartsData[index]), - ), - ], - ), - ), - ); - }, - ), - ), - ], - ), - ); - } -} - -class ChartData { - final int? xInt; // For column and other charts, using int for x - final DateTime? xDateTime; // For scatter charts, using DateTime for x - final double y; // For column and other charts - final String? timePeriod; // For line and bar charts - final double? value; // For line and bar charts - final double? y2; // For secondary data (stacked column chart) - final double? y3; // For tertiary data (stacked column chart) - final double? y4; // For quaternary data (stacked column chart) - - // Constructor that handles all chart cases - ChartData({ - this.xInt, - this.xDateTime, - this.y = 0.0, - this.timePeriod, - this.value, - this.y2, - this.y3, - this.y4, - }); -} +// import 'dart:convert'; +// import 'package:flutter/material.dart'; +// import 'package:go_router/go_router.dart'; +// import 'package:intl/intl.dart'; +// import 'package:syncfusion_flutter_charts/charts.dart'; // Import Syncfusion charts package +// import 'package:http/http.dart' as http; +// +// void main() { +// runApp(MyApp()); +// } +// +// class MyApp extends StatelessWidget { +// @override +// Widget build(BuildContext context) { +// return MaterialApp( +// home: ChartPage2(dataSets: ''), +// ); +// } +// } +// +// class ChartPage2 extends StatefulWidget { +// final String dataSets; +// const ChartPage2({Key? key, required this.dataSets}); +// @override +// ChartPageState createState() => ChartPageState(); +// } +// +// class ChartPageState extends State { +// List chartsData = []; +// bool isLoading = true; +// +// @override +// void initState() { +// super.initState(); +// fetchChartData(widget.dataSets); +// } +// +// Future fetchChartData(dataSets) async { +// const baseUrl = +// 'https://pb.venbait.in/api/custom/apicall'; // Replace with your server URL +// final url = Uri.parse('$baseUrl?dataset=$dataSets'); +// +// try { +// final response = await http.get(url); +// if (response.statusCode == 200) { +// setState(() { +// chartsData = jsonDecode(response.body); +// isLoading = false; +// }); +// } else { +// throw Exception('Failed to load data'); +// } +// } catch (error) { +// setState(() { +// isLoading = false; +// }); +// print('Error fetching data: $error'); +// } +// } +// +// List parseLineChartData(List response) { +// return response.map((entry) { +// // Attempt to fetch the TIMEPERIOD +// final rawTimePeriod = +// entry['ObsKey']?['Year'] ?? entry['ObsKey']?['TIME_PERIOD']; +// final formattedTimePeriod = rawTimePeriod != null +// ? rawTimePeriod.toString() // Use as-is if valid +// : 'Unknown'; // Fallback value if null +// +// // Parse the value or fallback to 0.0 +// final value = +// double.tryParse(entry['ObsValue']?['Value']?.toString() ?? '0.0') ?? +// 0.0; +// +// return ChartData( +// timePeriod: formattedTimePeriod, +// value: value, +// ); +// }).toList(); +// } +// +// List parseBarChartData(List response) { +// return response +// .asMap() +// .entries +// .map((entry) => ChartData( +// timePeriod: entry.value['ObsKey']['TIME_PERIOD'] ?? +// 'Unknown', // Fallback to 'Unknown' if null +// value: double.tryParse( +// entry.value['ObsValue']['Value'].toString()) ?? +// 0.0, // Handle null/invalid value +// )) +// .toList(); +// } +// +// // Update parseColumnChartData for column chart +// List parseColumnChartData(List response) { +// return response.map((entry) { +// // Extract TIME_PERIOD as x +// final x = +// int.tryParse(entry['ObsKey']?['TIME_PERIOD']?.toString() ?? '0') ?? 0; +// // Extract Value as y +// final y = +// double.tryParse(entry['ObsValue']?['Value']?.toString() ?? '0.0') ?? +// 0.0; +// return ChartData(xInt: x, y: y); +// }).toList(); +// } +// +// // Update parseScatterChartData for scatter chart +// List parseScatterChartData(List response) { +// return response.map((entry) { +// // Parse TIME_PERIOD into DateTime +// final timePeriod = entry['ObsKey']?['TIME_PERIOD']; +// final x = timePeriod != null +// ? DateTime.tryParse('$timePeriod-01-01') // Convert year to DateTime +// : DateTime.now(); // Fallback to current date if null +// +// // Parse Value into double +// final y = +// double.tryParse(entry['ObsValue']?['Value']?.toString() ?? '0.0') ?? +// 0.0; +// +// return ChartData(xDateTime: x, y: y); +// }).toList(); +// } +// +// Widget buildChart(dynamic chartData) { +// switch (chartData['chart_type']) { +// case 'scatter': +// return SfCartesianChart( +// primaryXAxis: DateTimeAxis(), // Ensure it's DateTimeAxis +// tooltipBehavior: TooltipBehavior(enable: true), +// title: ChartTitle(text: 'Divorces'), +// series: [ +// ScatterSeries( +// dataSource: parseScatterChartData(chartData['response']), +// xValueMapper: (ChartData data, _) => +// data.xDateTime ?? DateTime.now(), +// yValueMapper: (ChartData data, _) => data.y, +// name: chartData['dataset'], +// dataLabelSettings: DataLabelSettings(isVisible: true), +// ), +// ], +// ); +// case 'column': +// return SfCartesianChart( +// primaryXAxis: NumericAxis( +// title: AxisTitle(text: 'Year'), +// interval: 1, // Ensure no fractional intervals +// ), +// title: ChartTitle(text: 'Marriages'), +// series: >[ +// ColumnSeries( +// dataSource: parseColumnChartData(chartData['response']), +// xValueMapper: (ChartData data, _) => data.xInt ?? 0, +// yValueMapper: (ChartData data, _) => data.y, +// name: chartData['dataset'], +// color: Color(0xFF7DAFBC), +// width: 0.8, +// spacing: 0.2, +// dataLabelSettings: +// DataLabelSettings(isVisible: true), // Show data labels +// ), +// ], +// ); +// +// case 'line': +// return SfCartesianChart( +// primaryXAxis: CategoryAxis(), +// title: ChartTitle(text: 'Line Chart'), +// legend: Legend(isVisible: true), +// tooltipBehavior: TooltipBehavior(enable: true), +// series: >[ +// LineSeries( +// dataSource: parseLineChartData(chartData['response']), +// xValueMapper: (ChartData data, _) => data.timePeriod ?? '', +// yValueMapper: (ChartData data, _) => data.value ?? 0.0, +// name: 'Sales', +// dataLabelSettings: DataLabelSettings(isVisible: true), +// ), +// ], +// ); +// case 'bar': +// return SfCartesianChart( +// primaryXAxis: CategoryAxis(), +// title: ChartTitle(text: 'Bar Chart'), +// tooltipBehavior: TooltipBehavior(enable: true), +// series: >[ +// BarSeries( +// dataSource: parseBarChartData(chartData['response']), +// xValueMapper: (ChartData data, _) => data.timePeriod ?? '', +// yValueMapper: (ChartData data, _) => data.value ?? 0.0, +// name: 'Gold', +// color: Color.fromRGBO(8, 142, 255, 1), +// ), +// ], +// ); +// +// default: +// return Center(child: Text('Unknown chart type')); +// } +// } +// +// @override +// @override +// Widget build(BuildContext context) { +// return Scaffold( +// backgroundColor: const Color(0xFF7DAFBC), +// appBar: AppBar( +// backgroundColor: Color(0xFF7DAFBC), +// elevation: 0, +// leading: IconButton( +// icon: Icon(Icons.arrow_back_ios_new, color: Colors.white), +// onPressed: () { +// context.go('/myhomepage'); +// }, +// ), +// title: Text( +// 'Charts', +// style: TextStyle(color: Colors.white), +// ), +// ), +// body: isLoading +// ? Center(child: CircularProgressIndicator()) +// : Column( +// children: [ +// // Row for two cards +// Row( +// children: [ +// // First Card +// Expanded( +// flex: 6, +// child: Card( +// margin: EdgeInsets.all(10), +// child: Padding( +// padding: const EdgeInsets.all(16.0), +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Text( +// 'Card 1', +// style: TextStyle( +// fontSize: 18, fontWeight: FontWeight.bold), +// ), +// SizedBox(height: 10), +// Text('Content for Card 1 goes here.'), +// ], +// ), +// ), +// ), +// ), +// // Second Card +// Expanded( +// flex: 6, +// child: Card( +// margin: EdgeInsets.all(10), +// child: Padding( +// padding: const EdgeInsets.all(16.0), +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Text( +// 'Card 2', +// style: TextStyle( +// fontSize: 18, fontWeight: FontWeight.bold), +// ), +// SizedBox(height: 10), +// Text('Content for Card 2 goes here.'), +// ], +// ), +// ), +// ), +// ), +// ], +// ), +// // List of charts +// Expanded( +// child: ListView.builder( +// itemCount: chartsData.length, +// itemBuilder: (context, index) { +// return Card( +// margin: EdgeInsets.all(10), +// child: Padding( +// padding: const EdgeInsets.all(16.0), +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// SizedBox(height: 10), +// Container( +// height: 300, +// child: buildChart(chartsData[index]), +// ), +// ], +// ), +// ), +// ); +// }, +// ), +// ), +// ], +// ), +// ); +// } +// } +// +// class ChartData { +// final int? xInt; // For column and other charts, using int for x +// final DateTime? xDateTime; // For scatter charts, using DateTime for x +// final double y; // For column and other charts +// final String? timePeriod; // For line and bar charts +// final double? value; // For line and bar charts +// final double? y2; // For secondary data (stacked column chart) +// final double? y3; // For tertiary data (stacked column chart) +// final double? y4; // For quaternary data (stacked column chart) +// +// // Constructor that handles all chart cases +// ChartData({ +// this.xInt, +// this.xDateTime, +// this.y = 0.0, +// this.timePeriod, +// this.value, +// this.y2, +// this.y3, +// this.y4, +// }); +// } diff --git a/lib/presentation/Screens/profilepage.dart b/lib/presentation/Screens/profilepage.dart index e003a18f..d9c8ec7b 100644 --- a/lib/presentation/Screens/profilepage.dart +++ b/lib/presentation/Screens/profilepage.dart @@ -37,6 +37,8 @@ class _ProfileScreenState extends State { true ]; // One for each TextField + bool _isLoading = false; + String _getControllerText(int index) { if (index == 0) return _usernameController.text; if (index == 1) return _emailController.text; @@ -169,6 +171,9 @@ class _ProfileScreenState extends State { // Function to open the date picker void _pickImage() async { + setState(() { + _isLoading = true; // Start loading + }); final XFile? pickedFile = await _picker.pickImage(source: ImageSource.gallery); if (pickedFile != null) { @@ -179,6 +184,7 @@ class _ProfileScreenState extends State { fileExtension == 'png' || fileExtension == "heic") { setState(() { + _isLoading = false; _profileImage = File(pickedFile.path); }); } else { @@ -365,28 +371,68 @@ class _ProfileScreenState extends State { padding: const EdgeInsets.all(20.0), child: Column( children: [ - CircleAvatar( - radius: 50, - backgroundImage: _profileImage != null - ? FileImage(_profileImage!) - : AssetImage("assets/edit_profile/profile.png") - as ImageProvider, - child: Align( - alignment: Alignment.bottomRight, - child: GestureDetector( - onTap: _pickImage, // Call `_pickImage` on tap - child: CircleAvatar( - radius: 15, - backgroundColor: Colors.white, - child: Icon( - Icons.camera_alt, - size: 15, - color: Colors.grey, + // CircleAvatar( + // radius: 50, + // backgroundImage: _profileImage != null + // ? FileImage(_profileImage!) + // : AssetImage("assets/edit_profile/profile.png") + // as ImageProvider, + // child: Align( + // alignment: Alignment.bottomRight, + // child: GestureDetector( + // onTap: _pickImage, // Call `_pickImage` on tap + // child: CircleAvatar( + // radius: 15, + // backgroundColor: Colors.white, + // child: Icon( + // Icons.camera_alt, + // size: 15, + // color: Colors.grey, + // ), + // ), + // ), + // ), + // ), + + Stack( + alignment: Alignment.center, + children: [ + // CircleAvatar with the profile image + CircleAvatar( + radius: 50, + backgroundImage: _profileImage != null + ? FileImage(_profileImage!) + : AssetImage("assets/edit_profile/profile.png") + as ImageProvider, + child: Align( + alignment: Alignment.bottomRight, + child: GestureDetector( + onTap: _pickImage, // Call `_pickImage` on tap + child: CircleAvatar( + radius: 15, + backgroundColor: Colors.white, + child: Icon( + Icons.camera_alt, + size: 15, + color: Colors.grey, + ), + ), ), ), ), - ), + + // Conditional loader that shows when _isLoading is true + if (_isLoading) + Positioned( + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: + AlwaysStoppedAnimation(Colors.grey), + ), + ), + ], ), + SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.start, diff --git a/lib/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart b/lib/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart index 22e0dd14..82c4a1d4 100644 --- a/lib/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart +++ b/lib/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart @@ -160,42 +160,19 @@ // ); // } // } +import 'dart:convert'; + import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:uae_stat/infrastructure/services/InternetConnectivity_Service/InternetConnectivityService.dart'; -import 'package:uae_stat/presentation/Screens/online_offline_verification/internet_check.dart'; import '../../drawer_routes/custom_drawer_routes.dart'; +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; +import 'package:http/http.dart' as http; -class MyHomePage extends ConsumerWidget { +class MyHomePage extends StatefulWidget { const MyHomePage({super.key}); @override - Widget build(BuildContext context, WidgetRef ref) { - final isConnected = ref.watch(connectivityProvider); - //final isConnected = false; - double myheight = MediaQuery.of(context).size.height; - double mywidth = MediaQuery.of(context).size.width; - - print('Connectivity Status: $isConnected'); - - // Trigger navigation based on connectivity state - WidgetsBinding.instance.addPostFrameCallback((_) { - if (isConnected == false) { - context.go('/internetcheck'); - - } - }); - - return BaseScaffold( - mycenterTitle: true, - title: SizedBox( - height: myheight / 5, - width: mywidth / 3, - child: Image(image: AssetImage('assets/logos/uae_stat.png'))), - body: EconomyStats(), - ); - } + State createState() => _MyHomePageState(); } void handleInfoCardClick(BuildContext context, String data) { @@ -212,6 +189,22 @@ void handleInfoCardClick(BuildContext context, String data) { } } +class _MyHomePageState extends State { + @override + Widget build(BuildContext context) { + double myheight = MediaQuery.of(context).size.height; + double mywidth = MediaQuery.of(context).size.width; + return BaseScaffold( + mycenterTitle: true, + title: SizedBox( + height: myheight / 5, + width: mywidth / 3, + child: Image(image: AssetImage('assets/logos/uae_stat.png'))), + body: EconomyStats(), + ); + } +} + class EconomyStats extends StatelessWidget { const EconomyStats({Key? key}) : super(key: key); diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/edit_profile.dart b/lib/presentation/routes/drawer_routes/Drawer Items/edit_profile.dart index 74aa69b1..e21aca1b 100644 --- a/lib/presentation/routes/drawer_routes/Drawer Items/edit_profile.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/edit_profile.dart @@ -23,6 +23,7 @@ class _EditProfileState extends State { final _pb = PocketBase('https://pb.venbait.in'); // final _pb = PocketBase('http://127.0.0.1:8090'); bool _isProfileCompleted = false; + bool _isLoading = false; // Add focus nodes and hint states final List _focusNodes = List.generate(4, (_) => FocusNode()); @@ -207,16 +208,30 @@ class _EditProfileState extends State { // Function to open the date picker void _pickImage() async { + // setState(() { + // _isLoading = true; // Show loader + // print("Im Loading"); + // }); + // + // // Simulate an image loading process or network request + // await Future.delayed(Duration(seconds: 8)); // Example delay + final XFile? pickedFile = await _picker.pickImage(source: ImageSource.gallery); if (pickedFile != null) { + setState(() { + _isLoading = true; // Start loading + }); + print(pickedFile); final String fileExtension = pickedFile.path.split('.').last.toLowerCase(); + print('fileExtension $fileExtension'); if (fileExtension == 'jpg' || fileExtension == 'jpeg' || fileExtension == 'png' || fileExtension == "heic") { setState(() { + _isLoading = false; _profileImage = File(pickedFile.path); }); } else { @@ -225,6 +240,10 @@ class _EditProfileState extends State { ); } } + + setState(() { + _isLoading = false; // Hide loader + }); } Future _pickDate() async { @@ -369,6 +388,17 @@ class _EditProfileState extends State { }); } + Future _loadImage(String url) async { + try { + // Simulate a network delay of 2 seconds (this mimics loading an image from the internet) + // await Future.delayed(Duration(seconds: 3)); + print("Image loaded from URL: $url"); + } catch (e) { + print("Error loading image: $e"); + throw Exception('Failed to load image'); + } + } + @override Widget build(BuildContext context) { return BaseScaffold( @@ -385,34 +415,112 @@ class _EditProfileState extends State { padding: const EdgeInsets.all(20.0), child: Column( children: [ - CircleAvatar( - radius: 50, - backgroundImage: _profileImage != null - ? FileImage( - _profileImage!) // If a local file is selected - : _avatarUrl.isNotEmpty - ? NetworkImage(_avatarUrl) // Load from URL - : AssetImage( - "assets/edit_profile/profile.png") - as ImageProvider, + // CircleAvatar( + // radius: 50, + // backgroundImage: _profileImage != null + // ? FileImage( + // _profileImage!) // If a local file is selected + // : _avatarUrl.isNotEmpty + // ? NetworkImage(_avatarUrl) // Load from URL + // : AssetImage( + // "assets/edit_profile/profile.png") + // as ImageProvider, + // + // //backgroundImage: NetworkImage(_avatarUrl) as ImageProvider, + // + // child: + // Align( + // alignment: Alignment.bottomRight, + // child: GestureDetector( + // onTap: _pickImage, // Call `_pickImage` on tap + // child: CircleAvatar( + // radius: 15, + // backgroundColor: Colors.white, + // child: Icon( + // Icons.camera_alt, + // size: 15, + // color: Colors.grey, + // ), + // ), + // ), + // ), + // ), - //backgroundImage: NetworkImage(_avatarUrl) as ImageProvider, - child: Align( - alignment: Alignment.bottomRight, - child: GestureDetector( - onTap: _pickImage, // Call `_pickImage` on tap - child: CircleAvatar( - radius: 15, - backgroundColor: Colors.white, - child: Icon( - Icons.camera_alt, - size: 15, - color: Colors.grey, + Stack( + alignment: Alignment.center, + children: [ + CircleAvatar( + radius: 50, + backgroundImage: _profileImage != null + ? FileImage( + _profileImage!) // If a local file is selected + : _avatarUrl.isNotEmpty + ? NetworkImage( + _avatarUrl) // Load from URL + : AssetImage( + "assets/edit_profile/profile.png") + as ImageProvider, + child: _avatarUrl.isNotEmpty + ? FutureBuilder( + future: _loadImage(_avatarUrl), + builder: (context, snapshot) { + if (snapshot.connectionState == + ConnectionState.waiting) { + return Center( + child: CircularProgressIndicator(), + ); + } else if (snapshot.hasError) { + return Center( + child: Icon(Icons.error), + ); + } else { + return Align( + alignment: Alignment.bottomRight, + child: GestureDetector( + onTap: + _pickImage, // Call `_pickImage` on tap + child: CircleAvatar( + radius: 15, + backgroundColor: Colors.white, + child: Icon( + Icons.camera_alt, + size: 15, + color: Colors.grey, + ), + ), + ), + ); + } + }, + ) + : Align( + alignment: Alignment.bottomRight, + child: GestureDetector( + onTap: + _pickImage, // Call `_pickImage` on tap + child: CircleAvatar( + radius: 15, + backgroundColor: Colors.white, + child: Icon( + Icons.camera_alt, + size: 15, + color: Colors.grey, + ), + ), + ), + ), + ), + if (_isLoading) + Positioned( + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: AlwaysStoppedAnimation( + Colors.grey), ), ), - ), - ), + ], ), + SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.start, diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/feedback.dart b/lib/presentation/routes/drawer_routes/Drawer Items/feedback.dart index 9d519562..4d8a7f10 100644 --- a/lib/presentation/routes/drawer_routes/Drawer Items/feedback.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/feedback.dart @@ -529,7 +529,7 @@ class _FeedbackFormState extends State )), RatingBar.builder( initialRating: rating, - minRating: 1, + minRating: 0, direction: Axis.horizontal, allowHalfRating: true, itemCount: 5, diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/manage_users.dart b/lib/presentation/routes/drawer_routes/Drawer Items/manage_users.dart index 0d581a48..2406f9a8 100644 --- a/lib/presentation/routes/drawer_routes/Drawer Items/manage_users.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/manage_users.dart @@ -55,7 +55,7 @@ class _ManageUserRouterState extends State { final formattedDate = DateFormat('dd/MM/yyyy').format(createdDate); return User( id: record.id, // Correctly passing the ID - userName: record.getStringValue('username'), + userName: record.getStringValue('uname'), emailId: record.getStringValue('email'), registrationDate: formattedDate, status: record.getStringValue('status'), diff --git a/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart b/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart index 2f97d780..5bdb2c9f 100644 --- a/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart +++ b/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart @@ -1,15 +1,13 @@ import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; -import 'package:uae_stat/presentation/components/my_toggle.dart'; -import 'package:uae_stat/presentation/components/indicators/locale_provider.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:pocketbase/pocketbase.dart'; +import 'package:shared_preferences/shared_preferences.dart'; -class BaseScaffold extends ConsumerWidget { +class BaseScaffold extends StatefulWidget { final Widget body; final Widget title; - final bool ? showBackButton; - final bool ? mycenterTitle; + final bool? showBackButton; + final bool? mycenterTitle; final List? actions; final Color? appbarColor, mytitleColor; @@ -19,86 +17,126 @@ class BaseScaffold extends ConsumerWidget { required this.title, this.actions, this.showBackButton = false, - this.mycenterTitle = false, this.appbarColor, this.mytitleColor + this.mycenterTitle = false, + this.appbarColor, + this.mytitleColor, }) : super(key: key); - // final Widget body; - // - // const BaseScaffold({required this.body}); @override - Widget build(BuildContext context ,WidgetRef ref) { - final locale = ref.watch(localeProvider); - final localeNotifier = ref.read(localeProvider.notifier); - // Get the current route to highlight the active item + _BaseScaffoldState createState() => _BaseScaffoldState(); +} + +class _BaseScaffoldState extends State { + final _pb = PocketBase('https://pb.venbait.in'); + String _avatarUrl = ''; + dynamic userId; + String? userName; + String? userEmail; + String? userAvatar; + String? role; + + @override + void initState() { + super.initState(); + _checkUserId(); + } + + // Method to retrieve userId from SharedPreferences + Future getUserId() async { + final prefs = await SharedPreferences.getInstance(); + return prefs.getString('userId'); // Retrieve the userId + } + + // Method to check if userId exists and update state + Future _checkUserId() async { + String? fetchedUserId = await getUserId(); + if (fetchedUserId != null && fetchedUserId.isNotEmpty) { + setState(() { + userId = fetchedUserId; + }); + //print('NAVUser ID: $userId'); + _fetchUserData(); + } else { + print('No userId found'); + // Handle the case where userId is not available + } + } + + Future _fetchUserData() async { + try { + final adminAuth = await _pb.admins + .authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com'); + final adminToken = adminAuth.token; + //print('adminToken- ${adminToken}'); + final userDetailsResponse = await _pb.collection('users').getOne( + userId!, + headers: { + 'Authorization': 'Bearer $adminToken', + }, + ); + print('NAVuserDetails: $userDetailsResponse'); + + setState(() { + userName = userDetailsResponse.data['uname'] ?? ''; + userEmail = userDetailsResponse.data['email'] ?? ''; + userAvatar = userDetailsResponse.data['avatar'] ?? ''; + role = userDetailsResponse.data['role'] ?? ''; + String recordId = userId; + String collectionId = + userDetailsResponse.data['collectionId'] ?? '_pb_users_auth_'; + + if (userAvatar!.isNotEmpty && recordId.isNotEmpty) { + _avatarUrl = + 'https://pb.venbait.in/api/files/$collectionId/$recordId/$userAvatar'; + } else { + _avatarUrl = ''; // Reset to default or empty + } + }); + } catch (e) { + print('Error fetching user details: $e'); + } + } + + @override + Widget build(BuildContext context) { String currentRoute = GoRouterState.of(context).matchedLocation; double myheight = MediaQuery.of(context).size.height; double mywidth = MediaQuery.of(context).size.width; - return Scaffold( - appBar: AppBar(title: title, backgroundColor : appbarColor,actions: [ - // IconButton(onPressed: () {}, icon: Icon(Icons.toggle_off_outlined)), - MyToggle(isOn: locale?.languageCode == 'en', - knobTextWhenOn: 'ع', - knobTextWhenOff: 'EN', - pathColorWhenOn: Colors.grey.shade300, - pathColorWhenOff: Colors.grey.shade300, - onTap: (){ - ref.read(localeProvider.notifier).toggleLocale(); - },), - ], - leading: - // Stack( - // children: [ - // // Show the back button if showBackButton is true, otherwise show the drawer menu - // if (showBackButton == true) - // Positioned( - // left: 0, - // child: IconButton( - // color: Colors.white, - // icon: Icon(Icons.arrow_back_ios_new), - // onPressed: () { - // Navigator.of(context).pop(); - // }, - // ), - // ), - // // Show the drawer icon in all cases - // Positioned( - // right: 0, - // child: IconButton( - // color: (showBackButton == true)? Colors.white : Colors.black, - // icon: Icon(Icons.menu), - // onPressed: () { - // // Open the drawer using the Scaffold context - // Scaffold.of(context).openDrawer(); - // }, - // ), - // ), - // ], - // ), - Stack( + return Scaffold( + appBar: AppBar( + title: widget.title, + backgroundColor: widget.appbarColor, + actions: widget.actions ?? + [ + IconButton( + onPressed: () {}, + icon: const Icon(Icons.toggle_off_outlined), + ), + ], + leading: Stack( children: [ - // Show the back button if showBackButton is true - if (showBackButton == true) + if (widget.showBackButton == true) Positioned( left: 15, child: IconButton( color: Colors.white, - icon: Icon(Icons.arrow_back_ios_new), + icon: const Icon(Icons.arrow_back_ios_new), onPressed: () { Navigator.of(context).pop(); }, ), ), - // Show the drawer icon in all cases Positioned( right: 10, child: Builder( builder: (BuildContext context) { return IconButton( - color: (showBackButton == true) ? Colors.white : Colors.black, - icon: Icon(Icons.menu), + color: (widget.showBackButton == true) + ? Colors.white + : Colors.black, + icon: const Icon(Icons.menu), onPressed: () { - // Open the drawer using the Scaffold context Scaffold.of(context).openDrawer(); }, ); @@ -106,14 +144,12 @@ class BaseScaffold extends ConsumerWidget { ), ), ], - ) - + ), ), drawer: Drawer( child: ListView( children: [ DrawerHeader( - //decoration: BoxDecoration(color: Colors.blue), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ @@ -131,18 +167,39 @@ class BaseScaffold extends ConsumerWidget { child: Row( children: [ SizedBox( - width: mywidth / 8, - child: Image( - image: AssetImage( - 'assets/edit_profile/profile.png'))), + width: mywidth / 8, + height: mywidth / 8, + child: ClipOval( + child: _avatarUrl.isNotEmpty + ? Image( + image: NetworkImage(_avatarUrl), + fit: BoxFit.cover, + width: double.infinity, + height: double.infinity, + ) + : Image( + image: AssetImage( + 'assets/edit_profile/profile.png'), + fit: BoxFit.cover, + width: double.infinity, + height: double.infinity, + ), + ), + //child: Image(image: AssetImage('assets/edit_profile/profile.png')) + ), SizedBox( width: mywidth / 20, ), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('Mohammad'), - Text('Mohammad@fcsc.com') + // Text(userId ?? 'Loading user...'), // Display userId here + // Text('Mohammad@fcsc.com') + Text(userName ?? 'Loading...'), + Text( + userEmail ?? 'Loading...', + style: TextStyle(fontSize: 12), + ), ], ) ], @@ -152,33 +209,26 @@ class BaseScaffold extends ConsumerWidget { ), ), ListTile( - leading: SizedBox( - height: myheight / 15, - width: mywidth / 15, - child: Image( - image: AssetImage('assets/icons/drawer/message.png'))), - title: Text('Feedback'), + leading: Icon(Icons.feedback), + title: const Text('Feedback'), onTap: () => context.go('/feedback'), ), + if (role == 'admin') + ListTile( + leading: Icon(Icons.manage_accounts), + title: const Text('Manage User'), + onTap: () => context.go('/manageuser'), + ), ListTile( - leading: SizedBox( - height: myheight / 15, - width: mywidth / 15, - child: Image( - image: AssetImage('assets/icons/drawer/manageuser.png'))), - title: Text(AppLocalizations.of(context)!.manage_user), - onTap: () => context.go('/manageuser'), - ), - - ListTile( - leading: SizedBox( - height: myheight / 15, - width: mywidth / 15, - child: Image( - image: AssetImage('assets/icons/drawer/book.png'))), - title: Text('User Guide'), + leading: Icon(Icons.book), + title: const Text('User Guide'), onTap: () => context.go('/user-guide'), ), + ListTile( + leading: Icon(Icons.logout), + title: const Text('Logout'), + onTap: () => context.go('/'), + ), ], ), ), @@ -188,49 +238,33 @@ class BaseScaffold extends ConsumerWidget { type: BottomNavigationBarType.fixed, items: [ BottomNavigationBarItem( - icon: SizedBox( - height: myheight / 15, - width: mywidth / 15, - child: Image( - image: AssetImage('assets/icons/bottom_bar/home.png'))), + icon: Icon(Icons.home), label: 'Home', ), BottomNavigationBarItem( - icon: SizedBox( - height: myheight / 15, - width: mywidth / 15, - child: Image( - image: AssetImage('assets/icons/bottom_bar/uae_map.png'))), + icon: Icon(Icons.map), label: 'UAE Numbers', ), BottomNavigationBarItem( - icon: SizedBox( - height: myheight / 15, - width: mywidth / 15, - child: Image( - image: - AssetImage('assets/icons/bottom_bar/ranking.png'))), - label: 'Competitiveness'), + icon: Icon(Icons.bar_chart), + label: 'Competitiveness', + ), BottomNavigationBarItem( - icon: SizedBox( - height: myheight / 15, - width: mywidth / 15, - child: Image( - image: AssetImage('assets/icons/bottom_bar/globe.png'))), - label: 'Country Profile'), + icon: Icon(Icons.public), + label: 'Country Profile', + ), ], selectedItemColor: Colors.black, unselectedItemColor: Colors.grey, showUnselectedLabels: true, ), - body: body, + body: widget.body, ); } - //Map the current route to the selected index int _getSelectedIndex(String route) { switch (route) { - case '/': + case '/myhomepage': return 0; case '/uaenumbers': return 1; @@ -243,11 +277,10 @@ class BaseScaffold extends ConsumerWidget { } } - //Handle navigation when an item is tapped void _onItemTapped(BuildContext context, int index) { switch (index) { case 0: - context.go('/'); + context.go('/myhomepage'); break; case 1: context.go('/uaenumbers'); diff --git a/pubspec.lock b/pubspec.lock index a54ea449..f310f720 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab" + sha256: "88399e291da5f7e889359681a8f64b18c5123e03576b01f32a6a276611e511c3" url: "https://pub.dev" source: hosted - version: "76.0.0" + version: "78.0.0" _macros: dependency: transitive description: dart @@ -18,18 +18,18 @@ packages: dependency: transitive description: name: analyzer - sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e" + sha256: "62899ef43d0b962b056ed2ebac6b47ec76ffd003d5f7c4e4dc870afe63188e33" url: "https://pub.dev" source: hosted - version: "6.11.0" + version: "7.1.0" analyzer_plugin: dependency: transitive description: name: analyzer_plugin - sha256: "9661b30b13a685efaee9f02e5d01ed9f2b423bd889d28a304d02d704aee69161" + sha256: "1d460d14e3c2ae36dc2b32cef847c4479198cf87704f63c3c3c8150ee50c3916" url: "https://pub.dev" source: hosted - version: "0.11.3" + version: "0.12.0" ansicolor: dependency: transitive description: @@ -74,50 +74,50 @@ packages: dependency: transitive description: name: build - sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" + sha256: cef23f1eda9b57566c81e2133d196f8e3df48f244b317368d65c5943d91148f0 url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2" build_config: dependency: transitive description: name: build_config - sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" build_daemon: dependency: transitive description: name: build_daemon - sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9" + sha256: "294a2edaf4814a378725bfe6358210196f5ea37af89ecd81bfa32960113d4948" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.0.3" build_resolvers: dependency: transitive description: name: build_resolvers - sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" + sha256: "99d3980049739a985cf9b21f30881f46db3ebc62c5b8d5e60e27440876b1ba1e" url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.4.3" build_runner: dependency: "direct dev" description: name: build_runner - sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d" + sha256: "74691599a5bc750dc96a6b4bfd48f7d9d66453eab04c7f4063134800d6a5c573" url: "https://pub.dev" source: hosted - version: "2.4.13" + version: "2.4.14" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0 + sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021" url: "https://pub.dev" source: hosted - version: "7.3.2" + version: "8.0.0" built_collection: dependency: transitive description: @@ -258,42 +258,42 @@ packages: dependency: "direct dev" description: name: custom_lint - sha256: "3486c470bb93313a9417f926c7dd694a2e349220992d7b9d14534dc49c15bba9" + sha256: "6d509673c4dd0baa90e60dc8366bc2acc6690f16a7d44bfae31294d82c5d2a62" url: "https://pub.dev" source: hosted - version: "0.7.0" + version: "0.7.1" custom_lint_builder: dependency: transitive description: name: custom_lint_builder - sha256: "42cdc41994eeeddab0d7a722c7093ec52bd0761921eeb2cbdbf33d192a234759" + sha256: "8cc525c7b160eb47bb1ded8b2633c0f8b907930eb986ac577aded87cdd2835fe" url: "https://pub.dev" source: hosted - version: "0.7.0" + version: "0.7.1" custom_lint_core: dependency: transitive description: name: custom_lint_core - sha256: "02450c3e45e2a6e8b26c4d16687596ab3c4644dd5792e3313aa9ceba5a49b7f5" + sha256: "6dcee8a017181941c51a110da7e267c1d104dc74bec8862eeb8c85b5c8759a9e" url: "https://pub.dev" source: hosted - version: "0.7.0" + version: "0.7.1" custom_lint_visitor: dependency: transitive description: name: custom_lint_visitor - sha256: bfe9b7a09c4775a587b58d10ebb871d4fe618237639b1e84d5ec62d7dfef25f9 + sha256: "14df0760dfa81b7b0c398c876045f4e4a343eb2c9d200c66163671dd3e337c1b" url: "https://pub.dev" source: hosted - version: "1.0.0+6.11.0" + version: "1.0.0+7.1.0" dart_style: dependency: transitive description: name: dart_style - sha256: "7856d364b589d1f08986e140938578ed36ed948581fbc3bc9aef1805039ac5ab" + sha256: "27eb0ae77836989a3bc541ce55595e8ceee0992807f14511552a898ddd0d88ac" url: "https://pub.dev" source: hosted - version: "2.3.7" + version: "3.0.1" dbus: dependency: transitive description: @@ -491,10 +491,10 @@ packages: dependency: "direct main" description: name: flutter_secure_storage - sha256: "1913841ac4c7bf57cd2e05b717e1fbff7841b542962feff827b16525a781b3e4" + sha256: "9cad52d75ebc511adfae3d447d5d13da15a55a92c9410e50f67335b6d21d16ea" url: "https://pub.dev" source: hosted - version: "9.2.3" + version: "9.2.4" flutter_secure_storage_linux: dependency: transitive description: @@ -565,10 +565,10 @@ packages: dependency: "direct dev" description: name: freezed - sha256: "44c19278dd9d89292cf46e97dc0c1e52ce03275f40a97c5a348e802a924bf40e" + sha256: "59a584c24b3acdc5250bb856d0d3e9c0b798ed14a4af1ddb7dc1c7b41df91c9c" url: "https://pub.dev" source: hosted - version: "2.5.7" + version: "2.5.8" freezed_annotation: dependency: "direct main" description: @@ -661,10 +661,10 @@ packages: dependency: transitive description: name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.1.2" image: dependency: transitive description: @@ -685,10 +685,10 @@ packages: dependency: transitive description: name: image_picker_android - sha256: aa6f1280b670861ac45220cc95adc59bb6ae130259d36f980ccb62220dc5e59f + sha256: b62d34a506e12bb965e824b6db4fbf709ee4589cf5d3e99b45ab2287b008ee0c url: "https://pub.dev" source: hosted - version: "0.8.12+19" + version: "0.8.12+20" image_picker_for_web: dependency: transitive description: @@ -749,10 +749,10 @@ packages: dependency: "direct dev" description: name: injectable_generator - sha256: af403d76c7b18b4217335e0075e950cd0579fd7f8d7bd47ee7c85ada31680ba1 + sha256: b04673a4c88b3a848c0c77bf58b8309f9b9e064d9fe1df5450c8ee1675eaea1a url: "https://pub.dev" source: hosted - version: "2.6.2" + version: "2.7.0" intl: dependency: "direct main" description: @@ -789,10 +789,10 @@ packages: dependency: "direct dev" description: name: json_serializable - sha256: c2fcb3920cf2b6ae6845954186420fca40bc0a8abcc84903b7801f17d7050d7c + sha256: b0a98230538fe5d0b60a22fb6bf1b6cb03471b53e3324ff6069c591679dd59c9 url: "https://pub.dev" source: hosted - version: "6.9.0" + version: "6.9.3" jwt_decoder: dependency: "direct main" description: @@ -829,10 +829,10 @@ packages: dependency: transitive description: name: lints - sha256: "3315600f3fb3b135be672bf4a178c55f274bebe368325ae18462c89ac1e3b413" + sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7 url: "https://pub.dev" source: hosted - version: "5.0.0" + version: "5.1.1" logging: dependency: transitive description: @@ -853,10 +853,10 @@ packages: dependency: "direct main" description: name: mailer - sha256: e907087cd00719898c493f720dd326af73b00b406ab4af8e79f15d7c5fc24035 + sha256: c6ae65c1d40cfe9c06fa50ff9be6c1cfb18cca60a7bb935e318163bd7f1f0d17 url: "https://pub.dev" source: hosted - version: "6.3.0" + version: "6.4.1" marquee: dependency: "direct main" description: @@ -1045,10 +1045,10 @@ packages: dependency: transitive description: name: pubspec_parse - sha256: "81876843eb50dc2e1e5b151792c9a985c5ed2536914115ed04e9c8528f6647b0" + sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.5.0" recase: dependency: transitive description: @@ -1077,10 +1077,10 @@ packages: dependency: transitive description: name: riverpod_analyzer_utils - sha256: c6b8222b2b483cb87ae77ad147d6408f400c64f060df7a225b127f4afef4f8c8 + sha256: "837a6dc33f490706c7f4632c516bcd10804ee4d9ccc8046124ca56388715fdf3" url: "https://pub.dev" source: hosted - version: "0.5.8" + version: "0.5.9" riverpod_annotation: dependency: "direct main" description: @@ -1093,18 +1093,18 @@ packages: dependency: "direct dev" description: name: riverpod_generator - sha256: "63546d70952015f0981361636bf8f356d9cfd9d7f6f0815e3c07789a41233188" + sha256: "120d3310f687f43e7011bb213b90a436f1bbc300f0e4b251a72c39bccb017a4f" url: "https://pub.dev" source: hosted - version: "2.6.3" + version: "2.6.4" riverpod_lint: dependency: "direct dev" description: name: riverpod_lint - sha256: "83e4caa337a9840469b7b9bd8c2351ce85abad80f570d84146911b32086fbd99" + sha256: b05408412b0f75dec954e032c855bc28349eeed2d2187f94519e1ddfdf8b3693 url: "https://pub.dev" source: hosted - version: "2.6.3" + version: "2.6.4" rxdart: dependency: transitive description: @@ -1124,10 +1124,10 @@ packages: dependency: "direct main" description: name: share_plus - sha256: "6327c3f233729374d0abaafd61f6846115b2a481b4feddd8534211dc10659400" + sha256: fce43200aa03ea87b91ce4c3ac79f0cecd52e2a7a56c7a4185023c271fbfa6da url: "https://pub.dev" source: hosted - version: "10.1.3" + version: "10.1.4" share_plus_platform_interface: dependency: transitive description: @@ -1148,10 +1148,10 @@ packages: dependency: transitive description: name: shared_preferences_android - sha256: "02a7d8a9ef346c9af715811b01fbd8e27845ad2c41148eefd31321471b41863d" + sha256: bf808be89fe9dc467475e982c1db6c2faf3d2acf54d526cd5ec37d86c99dbd84 url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" shared_preferences_foundation: dependency: transitive description: @@ -1196,10 +1196,10 @@ packages: dependency: transitive description: name: shelf - sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 url: "https://pub.dev" source: hosted - version: "1.4.1" + version: "1.4.2" shelf_web_socket: dependency: transitive description: @@ -1224,10 +1224,10 @@ packages: dependency: transitive description: name: source_gen - sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" + sha256: "35c8150ece9e8c8d263337a265153c3329667640850b9304861faea59fc98f6b" url: "https://pub.dev" source: hosted - version: "1.5.0" + version: "2.0.0" source_helper: dependency: transitive description: @@ -1296,18 +1296,18 @@ packages: dependency: "direct main" description: name: syncfusion_flutter_charts - sha256: b2a9f0fd585ef96c081c37697b46d48d3b0f3fe6bddc5011a3542962814fafa8 + sha256: "117823c9e2ffcb7fb9868c73263df88751e3bb1f3d81f617cbaf63112f530e9c" url: "https://pub.dev" source: hosted - version: "28.1.33" + version: "28.1.39" syncfusion_flutter_core: dependency: transitive description: name: syncfusion_flutter_core - sha256: b1071c698b502e7d55f91352a8b82d42f49f4c96e523d43b6fade5d5af710048 + sha256: "794870919ca73e29c6cb25392a097cdfe58da4d6f3f3d3eccc529ecf52f78752" url: "https://pub.dev" source: hosted - version: "28.1.33" + version: "28.1.39" term_glyph: dependency: transitive description: @@ -1408,18 +1408,18 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e" + sha256: "3ba963161bd0fe395917ba881d320b9c4f6dd3c4a233da62ab18a5025c85f1e9" url: "https://pub.dev" source: hosted - version: "2.3.3" + version: "2.4.0" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: "44cf3aabcedde30f2dba119a9dea3b0f2672fbe6fa96e85536251d678216b3c4" + sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "3.1.4" uuid: dependency: transitive description: @@ -1448,18 +1448,18 @@ packages: dependency: transitive description: name: video_player_android - sha256: "391e092ba4abe2f93b3e625bd6b6a6ec7d7414279462c1c0ee42b5ab8d0a0898" + sha256: "7018dbcb395e2bca0b9a898e73989e67c0c4a5db269528e1b036ca38bcca0d0b" url: "https://pub.dev" source: hosted - version: "2.7.16" + version: "2.7.17" video_player_avfoundation: dependency: transitive description: name: video_player_avfoundation - sha256: "33224c19775fd244be2d6e3dbd8e1826ab162877bd61123bf71890772119a2b7" + sha256: "8a4e73a3faf2b13512978a43cf1cdda66feeeb900a0527f1fbfd7b19cf3458d3" url: "https://pub.dev" source: hosted - version: "2.6.5" + version: "2.6.7" video_player_platform_interface: dependency: transitive description: @@ -1528,10 +1528,10 @@ packages: dependency: transitive description: name: webview_flutter_android - sha256: "3d535126f7244871542b2f0b0fcf94629c9a14883250461f9abe1a6644c1c379" + sha256: d1ee28f44894cbabb1d94cc42f9980297f689ff844d067ec50ff88d86e27d63f url: "https://pub.dev" source: hosted - version: "4.2.0" + version: "4.3.0" webview_flutter_platform_interface: dependency: transitive description: @@ -1581,5 +1581,5 @@ packages: source: hosted version: "3.1.3" sdks: - dart: ">=3.5.2 <4.0.0" - flutter: ">=3.24.0" + dart: ">=3.6.0 <4.0.0" + flutter: ">=3.27.0" diff --git a/pubspec.yaml b/pubspec.yaml index cf520c0b..0145a0ed 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -57,9 +57,9 @@ dependencies: provider: ^6.1.2 mailer: ^6.2.0 image_picker: ^1.1.2 - syncfusion_flutter_charts: 28.1.33 material_charts: ^0.0.23 flutter_staggered_grid_view: ^0.7.0 + syncfusion_flutter_charts: ^28.1.39 connectivity_plus: ^6.1.2 dependency_overrides: