From 630b004ed01161545dca59de2e5cee425af1bf11 Mon Sep 17 00:00:00 2001 From: VINISTAN Date: Thu, 2 Jan 2025 19:00:26 +0530 Subject: [PATCH 1/4] UAE Number tab added --- android/gradle.properties | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- lib/config/my_router.dart | 63 ++- .../competitiveness.dart | 21 + .../country_profile.dart | 272 +++++++++++ .../Bottom Navigation Pages/uae_numbers.dart | 455 ++++++++++++++++++ .../components/constant/constant.dart | 18 + .../drawer_routes/custom_drawer_routes.dart | 12 +- 8 files changed, 813 insertions(+), 32 deletions(-) create mode 100644 lib/presentation/Screens/Bottom Navigation Pages/competitiveness.dart create mode 100644 lib/presentation/Screens/Bottom Navigation Pages/country_profile.dart create mode 100644 lib/presentation/Screens/Bottom Navigation Pages/uae_numbers.dart create mode 100644 lib/presentation/components/constant/constant.dart diff --git a/android/gradle.properties b/android/gradle.properties index 7f5b17ec..303728bd 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,4 +1,4 @@ org.gradle.jvmargs=-Xmx4G -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true -org.gradle.java.home=C:\\Program Files\\Eclipse Adoptium\\jdk-17.0.13.11-hotspot +org.gradle.java.home=C:/Program Files/Eclipse Adoptium/jdk-21.0.5.11-hotspot diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index e1ca574e..5e6b5427 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip diff --git a/lib/config/my_router.dart b/lib/config/my_router.dart index 062e04af..1e6d9a68 100644 --- a/lib/config/my_router.dart +++ b/lib/config/my_router.dart @@ -294,6 +294,9 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:uae_stat/presentation/Screens/Bottom%20Navigation%20Pages/competitiveness.dart'; +import 'package:uae_stat/presentation/Screens/Bottom%20Navigation%20Pages/country_profile.dart'; +import 'package:uae_stat/presentation/Screens/Bottom%20Navigation%20Pages/uae_numbers.dart'; import 'package:uae_stat/presentation/Screens/auth_verification/registration.dart'; import 'package:uae_stat/presentation/routes/drawer_routes/Drawer%20Items/user_guide/getting_started.dart'; import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart'; @@ -317,8 +320,8 @@ final GoRouter router = GoRouter( routes: [ GoRoute( path: '/', -//builder: (context, state) => LoginRoute(), - builder: (context, state) => LoginRoute(), + //builder: (context, state) => LoginRoute(), + builder: (context, state) => MyHomePage(), ), GoRoute( path: '/myhomepage', @@ -378,31 +381,24 @@ 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: '/gettingStarted', + name: 'gettingStarted', + builder: (context, state) => GettingStarted(), ), - -GoRoute(path: '/faq', -name: 'faq', -builder: (context, state) => FAQPage(), -), - - -GoRoute(path: '/gettingStarted', -name: 'gettingStarted', -builder: (context, state) => GettingStarted(), -), ], ), - // GoRoute( - // path: '/manageuser', - // builder: (context, state) { - // // Retrieve the title from extra or query params - // final title = state.extra as String? ?? 'Manage users'; - // return ManageUserRouter(title: title); - // }, - // ), + GoRoute( path: '/editProfile', builder: (context, state) => EditProfile(), @@ -411,5 +407,24 @@ builder: (context, state) => GettingStarted(), path: '/manageuser', builder: (context, state) => ManageUserRouter(), ), + + + + // Bottom Navigation Routes + GoRoute( + path: '/uaenumbers', + builder: (context, state) => UaeNumbers(), + ), + + GoRoute( + path: '/competitiveness', + builder: (context, state) => Competitiveness(), + ), + + GoRoute( + path: '/countryprofile', + builder: (context, state) => CountryProfile(), + ), + ], ); diff --git a/lib/presentation/Screens/Bottom Navigation Pages/competitiveness.dart b/lib/presentation/Screens/Bottom Navigation Pages/competitiveness.dart new file mode 100644 index 00000000..aca6ea73 --- /dev/null +++ b/lib/presentation/Screens/Bottom Navigation Pages/competitiveness.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; +import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart'; + +class Competitiveness extends StatelessWidget { + const Competitiveness({super.key}); + + @override + Widget build(BuildContext context) { + double myheight = MediaQuery.of(context).size.height; + double mywidth = MediaQuery.of(context).size.width; + return BaseScaffold( + title: Center( + child: SizedBox( + height: myheight / 5, + width: mywidth / 3, + child: Image(image: AssetImage('assets/logos/uae_stat.png')))), + body: CompetitivenessState(context), + ); + } + Widget CompetitivenessState(BuildContext context) {return Center(child: Text("Competitiveness"));} +} diff --git a/lib/presentation/Screens/Bottom Navigation Pages/country_profile.dart b/lib/presentation/Screens/Bottom Navigation Pages/country_profile.dart new file mode 100644 index 00000000..7967d316 --- /dev/null +++ b/lib/presentation/Screens/Bottom Navigation Pages/country_profile.dart @@ -0,0 +1,272 @@ +import 'package:flutter/material.dart'; +import 'package:uae_stat/presentation/components/constant/constant.dart'; +import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart'; + +class CountryProfile extends StatelessWidget { + const CountryProfile({super.key}); + + @override + Widget build(BuildContext context) { + double myheight = MediaQuery.of(context).size.height; + double mywidth = MediaQuery.of(context).size.width; + return BaseScaffold( + title: Center( + child: SizedBox( + height: myheight / 5, + width: mywidth / 3, + child: Image(image: AssetImage('assets/logos/uae_stat.png')))), + body: CountryProfileWidget(), + ); + } +} + +class CountryProfileWidget extends StatelessWidget { + const CountryProfileWidget({super.key}); + + @override + Widget build(BuildContext context) { + double mywidth = MediaQuery.of(context).size.width; + return Padding( + padding: const EdgeInsets.all(16.0), + child: ListView( + children: [ + 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([ + buildCard(context,'Marriages', '96%', '2023',socialColor,socialColor,mywidth/2.5), + 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), + ]), + ], + ), + ], + ), + ); + } + + 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, + ), + ), + ); + } + + Widget buildCardRow(List cards) { + return SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: cards.map((card) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: card, + ); + }).toList(), + ), + ); + } + + 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 + ), + 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, + ), + ), + ], + ), + ), + ); + } +} + +class CustomExpandableTile extends StatefulWidget { + final String title; + final Color titleBackgroundColor; + final List children; + + const CustomExpandableTile({ + required this.title, + required this.titleBackgroundColor, + required this.children, + }); + + @override + _CustomExpandableTileState createState() => _CustomExpandableTileState(); +} + +class _CustomExpandableTileState extends State { + bool isExpanded = false; + + @override + Widget build(BuildContext context) { + double myheight = MediaQuery.of(context).size.height; + return Card( + elevation: 4, + child: Column( + children: [ + GestureDetector( + onTap: () { + setState(() { + isExpanded = !isExpanded; + }); + }, + child: Container( + decoration: BoxDecoration( + color: widget.titleBackgroundColor, + borderRadius: BorderRadius.all(Radius.circular(12)) + ), + padding: const EdgeInsets.all(12), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + widget.title, + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + Icon( + isExpanded + ? Icons.keyboard_arrow_up + : Icons.keyboard_arrow_down, + color: Colors.white, + ), + ], + ), + ), + ), + ClipRRect( + child: AnimatedContainer( + duration: Duration(milliseconds: 300), + curve: Curves.easeInOut, + width: double.infinity, + height: isExpanded ? myheight : 0, + child: isExpanded + ? SingleChildScrollView( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(20)) + ), + + padding: const EdgeInsets.all(10), + child: Column( + children: widget.children, + ), + ), + ) + : null, + ), + ), + ], + ), + ); + } +} diff --git a/lib/presentation/Screens/Bottom Navigation Pages/uae_numbers.dart b/lib/presentation/Screens/Bottom Navigation Pages/uae_numbers.dart new file mode 100644 index 00000000..d7b77af8 --- /dev/null +++ b/lib/presentation/Screens/Bottom Navigation Pages/uae_numbers.dart @@ -0,0 +1,455 @@ +import 'package:flutter/material.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'; + +class UaeNumbers extends StatelessWidget { + const UaeNumbers({super.key}); + + @override + Widget build(BuildContext context) { + double myheight = MediaQuery.of(context).size.height; + double mywidth = MediaQuery.of(context).size.width; + return BaseScaffold( + title: Text("UAE Numbers"), + body: + //EconomicDashboard(), + //EconomyExpandTile() + CustomExpandableTile() + ); + } +} + +// class EconomicDashboard extends StatelessWidget { +// const EconomicDashboard({Key? key}) : super(key: key); +// +// @override +// Widget build(BuildContext context) { +// +// return SingleChildScrollView( +// child: Padding( +// padding: const EdgeInsets.all(16.0), +// child: Column( +// children: [ +// // Search Bar +// Container( +// padding: const EdgeInsets.symmetric(horizontal: 16), +// decoration: BoxDecoration( +// color: Colors.white, +// borderRadius: BorderRadius.circular(20), +// border: Border.all( +// color: Color(0xFFAA8E83), // Border color +// width: 3, // Border width +// ), +// +// ), +// child: const Row( +// children: [ +// Icon(Icons.search, color: Colors.grey), +// SizedBox(width: 8), +// Expanded( +// child: TextField( +// decoration: InputDecoration( +// hintText: 'Search', +// border: InputBorder.none, +// hintStyle: TextStyle(color: Colors.grey), +// ), +// ), +// ), +// ], +// ), +// ), +// +// const SizedBox(height: 16), +// +// // Economy Section +// _buildSection( +// 'ECONOMY', +// [ +// _buildRow( +// [ +// _buildCard('GDP (Growth)', '1.62T', Colors.blue[100]!), +// _buildCard('CPI', '1.45T', Colors.blue[100]!), +// ], +// ), +// const SizedBox(height: 8), +// const Text( +// 'International Trade', +// style: TextStyle(fontWeight: FontWeight.bold), +// ), +// _buildRow( +// [ +// _buildCard('Total Trade\nLast Year (2023) YOY', '669.9B', Colors.white), +// _buildCard('Total Import\nLast Year (2023) YOY', '686B', Colors.white), +// ], +// ), +// _buildRow( +// [ +// _buildCard('Total Export', '122.9B', Colors.white), +// _buildCard('Total Import', '161B', Colors.white), +// ], +// ), +// const SizedBox(height: 8), +// const Text( +// 'Prices', +// style: TextStyle(fontWeight: FontWeight.bold), +// ), +// _buildCard('Inflation Rate', '215.4B', Colors.white, fullWidth: true,), +// ],context +// ), +// +// const SizedBox(height: 16), +// +// // Social Section +// _buildSection('SOCIAL', [ +// _buildCard('Total Export', '122.9B', Colors.white), +// _buildCard('Total Import', '161B', Colors.white), +// ],context), +// +// const SizedBox(height: 16), +// +// // Environment Section +// _buildSection('ENVIRONMENT', [ +// _buildCard('Total Export', '122.9B', Colors.white), +// _buildCard('Total Import', '161B', Colors.white), +// ],context) +// ], +// ), +// ), +// ); +// } +// +// Widget _buildSection(String title, List children,BuildContext context) { +// double myheight = MediaQuery.of(context).size.height; +// double mywidth = MediaQuery.of(context).size.width; +// return Container( +// decoration: BoxDecoration( +// color: title == 'ECONOMY' ? Color(0xFF7DAFBC) : Color(0xFFAA8E83), +// borderRadius: BorderRadius.circular(16), +// ), +// child: +// ExpansionTile( +// iconColor: Colors.white, +// collapsedIconColor: Colors.white, +// title: Text( +// title, +// style: const TextStyle(fontWeight: FontWeight.bold,color: Colors.white), +// ), +// children: children, +// ), +// ); +// } +// +// Widget _buildRow(List children) { +// return Padding( +// padding: const EdgeInsets.symmetric(vertical: 4), +// child: Row( +// children: children.map((child) => Expanded(child: child)).toList(), +// ), +// ); +// } +// +// Widget _buildCard(String title, String value, Color color, {bool fullWidth = false}) { +// return Container( +// margin: EdgeInsets.symmetric(horizontal: fullWidth ? 0 : 4), +// padding: const EdgeInsets.all(12), +// decoration: BoxDecoration( +// color: color, +// borderRadius: BorderRadius.circular(8), +// border: Border.all(color: Colors.grey[300]!), +// ), +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Text( +// title, +// style: TextStyle( +// fontSize: 12, +// color: Colors.grey[600], +// ), +// ), +// const SizedBox(height: 4), +// Text( +// value, +// style: const TextStyle( +// fontSize: 16, +// fontWeight: FontWeight.bold, +// ), +// ), +// ], +// ), +// ); +// } +// } + + + +// class EconomyExpandTile extends StatefulWidget { +// @override +// _EconomyExpandTileState createState() => _EconomyExpandTileState(); +// } +// +// class _EconomyExpandTileState extends State { +// bool isExpanded = false; +// +// @override +// Widget build(BuildContext context) { +// return Card( +// elevation: 4, +// child: ExpansionTile( +// onExpansionChanged: (value) { +// setState(() { +// isExpanded = value; +// }); +// }, +// title: Container( +// color: Colors.blue, +// padding: const EdgeInsets.all(16), +// child: Text( +// 'ECONOMY', +// style: TextStyle( +// color: Colors.white, +// fontWeight: FontWeight.bold, +// fontSize: 18, +// ), +// ), +// ), +// backgroundColor: Colors.white, +// collapsedBackgroundColor: Colors.blue, +// children: [ +// Padding( +// padding: const EdgeInsets.all(16.0), +// child: Column( +// children: [ +// buildCategoryTitle('National Accounts'), +// buildCardRow([ +// buildCard('GDP (Constant)', '1.62T', '2022 (AED)'), +// buildCard('FDI', '1.45T', '2021 (AED)'), +// ]), +// buildCategoryTitle('International Trade'), +// buildCardRow([ +// buildCard('Total Trade', '669.9B', 'Jan - Mar 2024 (AED)'), +// buildCard('Total Import', '686B', 'Jan - Mar 2024 (AED)'), +// ]), +// buildCardRow([ +// buildCard('Total Export', '122.9B', 'Jan - Mar 2024 (AED)'), +// buildCard('Total ReExport', '161B', 'Jan - Mar 2024 (AED)'), +// ]), +// buildCategoryTitle('Prices'), +// buildCardRow([ +// buildCard('Inflation Rate', '215.4B', '2023'), +// ]), +// ], +// ), +// ), +// ], +// ), +// ); +// } +// +// Widget buildCategoryTitle(String title) { +// return Padding( +// padding: const EdgeInsets.symmetric(vertical: 8.0), +// child: Text( +// title, +// style: TextStyle( +// fontSize: 16, +// fontWeight: FontWeight.bold, +// color: Colors.black54, +// ), +// ), +// ); +// } +// +// Widget buildCardRow(List cards) { +// return SingleChildScrollView( +// scrollDirection: Axis.horizontal, +// child: Row( +// children: cards.map((card) { +// return Padding( +// padding: const EdgeInsets.symmetric(horizontal: 8.0), +// child: card, +// ); +// }).toList(), +// ), +// ); +// } +// +// Widget buildCard(String title, String value, String subtitle) { +// return Card( +// elevation: 2, +// child: Container( +// width: 150, // Fixed width for cards to make scrolling smoother +// padding: const EdgeInsets.all(16.0), +// child: Column( +// mainAxisAlignment: MainAxisAlignment.center, +// children: [ +// Text( +// title, +// textAlign: TextAlign.center, +// style: TextStyle(fontWeight: FontWeight.bold), +// ), +// SizedBox(height: 8), +// Text( +// value, +// style: TextStyle( +// fontSize: 18, +// color: Colors.blue, +// fontWeight: FontWeight.bold, +// ), +// ), +// SizedBox(height: 8), +// Text( +// subtitle, +// textAlign: TextAlign.center, +// style: TextStyle(color: Colors.black54, fontSize: 12), +// ), +// ], +// ), +// ), +// ); +// } +// } + +class CustomExpandableTile extends StatefulWidget { + @override + _CustomExpandableTileState createState() => _CustomExpandableTileState(); +} + +class _CustomExpandableTileState extends State { + bool isExpanded = false; + + @override + Widget build(BuildContext context) { + return Card( + elevation: 4, + child: SingleChildScrollView( + child: Column( + children: [ + // The tile header + GestureDetector( + onTap: () { + setState(() { + isExpanded = !isExpanded; + }); + }, + child: Container( + color: Colors.blue, + padding: const EdgeInsets.all(16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'ECONOMY', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + Icon( + isExpanded ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down, + color: Colors.white, + ), + ], + ), + ), + ), + // Animated container for expansion + AnimatedContainer( + duration: Duration(milliseconds: 300), + curve: Curves.easeInOut, + height: isExpanded ? null : 0, + child: isExpanded + ? Container( + color: Colors.white, + padding: const EdgeInsets.all(16), + child: Column( + children: [ + buildCategoryTitle('National Accounts'), + buildCardRow([ + buildCard('GDP (Constant)', '1.62T', '2022 (AED)'), + buildCard('FDI', '1.45T', '2021 (AED)'), + ]), + buildCategoryTitle('International Trade'), + buildCardRow([ + buildCard('Total Trade', '669.9B', 'Jan - Mar 2024 (AED)'), + buildCard('Total Import', '686B', 'Jan - Mar 2024 (AED)'), + ]), + buildCategoryTitle('Prices'), + buildCardRow([ + buildCard('Inflation Rate', '215.4B', '2023'), + ]), + ], + ), + ) + : Container(), + ), + ], + ), + ), + ); + } + + Widget buildCategoryTitle(String title) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Text( + title, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Colors.black54, + ), + ), + ); + } + + Widget buildCardRow(List cards) { + return SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: cards.map((card) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: card, + ); + }).toList(), + ), + ); + } + + Widget buildCard(String title, String value, String subtitle) { + return Card( + elevation: 2, + child: Container( + width: 150, + padding: const EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + title, + textAlign: TextAlign.center, + style: TextStyle(fontWeight: FontWeight.bold), + ), + SizedBox(height: 8), + Text( + value, + style: TextStyle( + fontSize: 18, + color: Colors.blue, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: 8), + Text( + subtitle, + textAlign: TextAlign.center, + style: TextStyle(color: Colors.black54, fontSize: 12), + ), + ], + ), + ), + ); + } +} diff --git a/lib/presentation/components/constant/constant.dart b/lib/presentation/components/constant/constant.dart new file mode 100644 index 00000000..4b65a141 --- /dev/null +++ b/lib/presentation/components/constant/constant.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; + +const Color economyColor = Color(0xFF90B0D5); +const Color socialColor = Color(0xFFAA8E83); +const Color environmentColor = Color(0xFF7DAFBC); +const Color environmentboldColor = Color(0xFF90B0D5); +const TextStyle subtitleStyle = TextStyle( + fontFamily: 'Roboto', // Font family set to Roboto + fontWeight: FontWeight.w400, // Regular weight (w400) + fontSize: 11, + color: Color(0xFF8E8E8E) // Font size 11 + ); +const TextStyle robotoRegular11 = TextStyle( + fontFamily: 'Roboto', // Font family set to Roboto + fontWeight: FontWeight.w400, // Regular weight (w400) + fontSize: 11, + color: Color(0xFF000000) // Font size 11 + ); diff --git a/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart b/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart index 52fc756b..de8715ed 100644 --- a/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart +++ b/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart @@ -149,11 +149,11 @@ class BaseScaffold extends StatelessWidget { switch (route) { case '/': return 0; - case '/about': + case '/uaenumbers': return 1; - case '/settings': + case '/competitiveness': return 2; - case '/profile': + case '/countryprofile': return 3; default: return 0; @@ -167,13 +167,13 @@ class BaseScaffold extends StatelessWidget { context.go('/'); break; case 1: - context.go('/about'); + context.go('/uaenumbers'); break; case 2: - context.go('/settings'); + context.go('/competitiveness'); break; case 3: - context.go('/profile'); + context.go('/countryprofile'); break; } } From d84a438c0f0b240355e8d0e0183e116cd6171a5a Mon Sep 17 00:00:00 2001 From: VINISTAN Date: Mon, 6 Jan 2025 07:47:59 +0530 Subject: [PATCH 2/4] Alignment Issue UAE numbers - Fixed --- android/app/build.gradle | 4 +- android/settings.gradle | 5 +- .../competitiveness.dart | 2 + .../country_profile.dart | 245 +------ .../Bottom Navigation Pages/uae_numbers.dart | 603 +++++++----------- 5 files changed, 229 insertions(+), 630 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index a5fbd77b..490ff3ac 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -29,8 +29,8 @@ android { ndkVersion = flutter.ndkVersion compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 } defaultConfig { diff --git a/android/settings.gradle b/android/settings.gradle index 8a53adcd..2db302b0 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -18,8 +18,9 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "7.3.0" apply false - id "org.jetbrains.kotlin.android" version "1.8.22" apply false + id "com.android.application" version "8.2.1" apply false + id "org.jetbrains.kotlin.android" version "2.1.0" apply false + } include ":app" diff --git a/lib/presentation/Screens/Bottom Navigation Pages/competitiveness.dart b/lib/presentation/Screens/Bottom Navigation Pages/competitiveness.dart index aca6ea73..1ba3fb58 100644 --- a/lib/presentation/Screens/Bottom Navigation Pages/competitiveness.dart +++ b/lib/presentation/Screens/Bottom Navigation Pages/competitiveness.dart @@ -19,3 +19,5 @@ class Competitiveness extends StatelessWidget { } Widget CompetitivenessState(BuildContext context) {return Center(child: Text("Competitiveness"));} } + + diff --git a/lib/presentation/Screens/Bottom Navigation Pages/country_profile.dart b/lib/presentation/Screens/Bottom Navigation Pages/country_profile.dart index 7967d316..8d3f1081 100644 --- a/lib/presentation/Screens/Bottom Navigation Pages/country_profile.dart +++ b/lib/presentation/Screens/Bottom Navigation Pages/country_profile.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:uae_stat/presentation/components/constant/constant.dart'; import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart'; class CountryProfile extends StatelessWidget { @@ -15,258 +14,18 @@ class CountryProfile extends StatelessWidget { height: myheight / 5, width: mywidth / 3, child: Image(image: AssetImage('assets/logos/uae_stat.png')))), - body: CountryProfileWidget(), + body: CountryProfileWidget() ); } } - class CountryProfileWidget extends StatelessWidget { const CountryProfileWidget({super.key}); @override Widget build(BuildContext context) { - double mywidth = MediaQuery.of(context).size.width; - return Padding( - padding: const EdgeInsets.all(16.0), - child: ListView( - children: [ - 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([ - buildCard(context,'Marriages', '96%', '2023',socialColor,socialColor,mywidth/2.5), - 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), - ]), - ], - ), - ], - ), - ); - } - - 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, - ), - ), - ); - } - - Widget buildCardRow(List cards) { - return SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Row( - children: cards.map((card) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: card, - ); - }).toList(), - ), - ); - } - - 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 - ), - 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, - ), - ), - ], - ), - ), - ); + return Center(child: Text("COuntry Profile"),); } } -class CustomExpandableTile extends StatefulWidget { - final String title; - final Color titleBackgroundColor; - final List children; - const CustomExpandableTile({ - required this.title, - required this.titleBackgroundColor, - required this.children, - }); - @override - _CustomExpandableTileState createState() => _CustomExpandableTileState(); -} - -class _CustomExpandableTileState extends State { - bool isExpanded = false; - - @override - Widget build(BuildContext context) { - double myheight = MediaQuery.of(context).size.height; - return Card( - elevation: 4, - child: Column( - children: [ - GestureDetector( - onTap: () { - setState(() { - isExpanded = !isExpanded; - }); - }, - child: Container( - decoration: BoxDecoration( - color: widget.titleBackgroundColor, - borderRadius: BorderRadius.all(Radius.circular(12)) - ), - padding: const EdgeInsets.all(12), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - widget.title, - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - fontSize: 18, - ), - ), - Icon( - isExpanded - ? Icons.keyboard_arrow_up - : Icons.keyboard_arrow_down, - color: Colors.white, - ), - ], - ), - ), - ), - ClipRRect( - child: AnimatedContainer( - duration: Duration(milliseconds: 300), - curve: Curves.easeInOut, - width: double.infinity, - height: isExpanded ? myheight : 0, - child: isExpanded - ? SingleChildScrollView( - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.all(Radius.circular(20)) - ), - - padding: const EdgeInsets.all(10), - child: Column( - children: widget.children, - ), - ), - ) - : null, - ), - ), - ], - ), - ); - } -} diff --git a/lib/presentation/Screens/Bottom Navigation Pages/uae_numbers.dart b/lib/presentation/Screens/Bottom Navigation Pages/uae_numbers.dart index d7b77af8..b1899ffa 100644 --- a/lib/presentation/Screens/Bottom Navigation Pages/uae_numbers.dart +++ b/lib/presentation/Screens/Bottom Navigation Pages/uae_numbers.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.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'; + class UaeNumbers extends StatelessWidget { const UaeNumbers({super.key}); @@ -10,387 +12,123 @@ class UaeNumbers extends StatelessWidget { double myheight = MediaQuery.of(context).size.height; double mywidth = MediaQuery.of(context).size.width; return BaseScaffold( - title: Text("UAE Numbers"), - body: - //EconomicDashboard(), - //EconomyExpandTile() - CustomExpandableTile() - ); + title: Text("UAE Numbers"), + body: + //EconomicDashboard(), + //EconomyExpandTile() + uaenumberWidget()); } } -// class EconomicDashboard extends StatelessWidget { -// const EconomicDashboard({Key? key}) : super(key: key); -// -// @override -// Widget build(BuildContext context) { -// -// return SingleChildScrollView( -// child: Padding( -// padding: const EdgeInsets.all(16.0), -// child: Column( -// children: [ -// // Search Bar -// Container( -// padding: const EdgeInsets.symmetric(horizontal: 16), -// decoration: BoxDecoration( -// color: Colors.white, -// borderRadius: BorderRadius.circular(20), -// border: Border.all( -// color: Color(0xFFAA8E83), // Border color -// width: 3, // Border width -// ), -// -// ), -// child: const Row( -// children: [ -// Icon(Icons.search, color: Colors.grey), -// SizedBox(width: 8), -// Expanded( -// child: TextField( -// decoration: InputDecoration( -// hintText: 'Search', -// border: InputBorder.none, -// hintStyle: TextStyle(color: Colors.grey), -// ), -// ), -// ), -// ], -// ), -// ), -// -// const SizedBox(height: 16), -// -// // Economy Section -// _buildSection( -// 'ECONOMY', -// [ -// _buildRow( -// [ -// _buildCard('GDP (Growth)', '1.62T', Colors.blue[100]!), -// _buildCard('CPI', '1.45T', Colors.blue[100]!), -// ], -// ), -// const SizedBox(height: 8), -// const Text( -// 'International Trade', -// style: TextStyle(fontWeight: FontWeight.bold), -// ), -// _buildRow( -// [ -// _buildCard('Total Trade\nLast Year (2023) YOY', '669.9B', Colors.white), -// _buildCard('Total Import\nLast Year (2023) YOY', '686B', Colors.white), -// ], -// ), -// _buildRow( -// [ -// _buildCard('Total Export', '122.9B', Colors.white), -// _buildCard('Total Import', '161B', Colors.white), -// ], -// ), -// const SizedBox(height: 8), -// const Text( -// 'Prices', -// style: TextStyle(fontWeight: FontWeight.bold), -// ), -// _buildCard('Inflation Rate', '215.4B', Colors.white, fullWidth: true,), -// ],context -// ), -// -// const SizedBox(height: 16), -// -// // Social Section -// _buildSection('SOCIAL', [ -// _buildCard('Total Export', '122.9B', Colors.white), -// _buildCard('Total Import', '161B', Colors.white), -// ],context), -// -// const SizedBox(height: 16), -// -// // Environment Section -// _buildSection('ENVIRONMENT', [ -// _buildCard('Total Export', '122.9B', Colors.white), -// _buildCard('Total Import', '161B', Colors.white), -// ],context) -// ], -// ), -// ), -// ); -// } -// -// Widget _buildSection(String title, List children,BuildContext context) { -// double myheight = MediaQuery.of(context).size.height; -// double mywidth = MediaQuery.of(context).size.width; -// return Container( -// decoration: BoxDecoration( -// color: title == 'ECONOMY' ? Color(0xFF7DAFBC) : Color(0xFFAA8E83), -// borderRadius: BorderRadius.circular(16), -// ), -// child: -// ExpansionTile( -// iconColor: Colors.white, -// collapsedIconColor: Colors.white, -// title: Text( -// title, -// style: const TextStyle(fontWeight: FontWeight.bold,color: Colors.white), -// ), -// children: children, -// ), -// ); -// } -// -// Widget _buildRow(List children) { -// return Padding( -// padding: const EdgeInsets.symmetric(vertical: 4), -// child: Row( -// children: children.map((child) => Expanded(child: child)).toList(), -// ), -// ); -// } -// -// Widget _buildCard(String title, String value, Color color, {bool fullWidth = false}) { -// return Container( -// margin: EdgeInsets.symmetric(horizontal: fullWidth ? 0 : 4), -// padding: const EdgeInsets.all(12), -// decoration: BoxDecoration( -// color: color, -// borderRadius: BorderRadius.circular(8), -// border: Border.all(color: Colors.grey[300]!), -// ), -// child: Column( -// crossAxisAlignment: CrossAxisAlignment.start, -// children: [ -// Text( -// title, -// style: TextStyle( -// fontSize: 12, -// color: Colors.grey[600], -// ), -// ), -// const SizedBox(height: 4), -// Text( -// value, -// style: const TextStyle( -// fontSize: 16, -// fontWeight: FontWeight.bold, -// ), -// ), -// ], -// ), -// ); -// } -// } - - - -// class EconomyExpandTile extends StatefulWidget { -// @override -// _EconomyExpandTileState createState() => _EconomyExpandTileState(); -// } -// -// class _EconomyExpandTileState extends State { -// bool isExpanded = false; -// -// @override -// Widget build(BuildContext context) { -// return Card( -// elevation: 4, -// child: ExpansionTile( -// onExpansionChanged: (value) { -// setState(() { -// isExpanded = value; -// }); -// }, -// title: Container( -// color: Colors.blue, -// padding: const EdgeInsets.all(16), -// child: Text( -// 'ECONOMY', -// style: TextStyle( -// color: Colors.white, -// fontWeight: FontWeight.bold, -// fontSize: 18, -// ), -// ), -// ), -// backgroundColor: Colors.white, -// collapsedBackgroundColor: Colors.blue, -// children: [ -// Padding( -// padding: const EdgeInsets.all(16.0), -// child: Column( -// children: [ -// buildCategoryTitle('National Accounts'), -// buildCardRow([ -// buildCard('GDP (Constant)', '1.62T', '2022 (AED)'), -// buildCard('FDI', '1.45T', '2021 (AED)'), -// ]), -// buildCategoryTitle('International Trade'), -// buildCardRow([ -// buildCard('Total Trade', '669.9B', 'Jan - Mar 2024 (AED)'), -// buildCard('Total Import', '686B', 'Jan - Mar 2024 (AED)'), -// ]), -// buildCardRow([ -// buildCard('Total Export', '122.9B', 'Jan - Mar 2024 (AED)'), -// buildCard('Total ReExport', '161B', 'Jan - Mar 2024 (AED)'), -// ]), -// buildCategoryTitle('Prices'), -// buildCardRow([ -// buildCard('Inflation Rate', '215.4B', '2023'), -// ]), -// ], -// ), -// ), -// ], -// ), -// ); -// } -// -// Widget buildCategoryTitle(String title) { -// return Padding( -// padding: const EdgeInsets.symmetric(vertical: 8.0), -// child: Text( -// title, -// style: TextStyle( -// fontSize: 16, -// fontWeight: FontWeight.bold, -// color: Colors.black54, -// ), -// ), -// ); -// } -// -// Widget buildCardRow(List cards) { -// return SingleChildScrollView( -// scrollDirection: Axis.horizontal, -// child: Row( -// children: cards.map((card) { -// return Padding( -// padding: const EdgeInsets.symmetric(horizontal: 8.0), -// child: card, -// ); -// }).toList(), -// ), -// ); -// } -// -// Widget buildCard(String title, String value, String subtitle) { -// return Card( -// elevation: 2, -// child: Container( -// width: 150, // Fixed width for cards to make scrolling smoother -// padding: const EdgeInsets.all(16.0), -// child: Column( -// mainAxisAlignment: MainAxisAlignment.center, -// children: [ -// Text( -// title, -// textAlign: TextAlign.center, -// style: TextStyle(fontWeight: FontWeight.bold), -// ), -// SizedBox(height: 8), -// Text( -// value, -// style: TextStyle( -// fontSize: 18, -// color: Colors.blue, -// fontWeight: FontWeight.bold, -// ), -// ), -// SizedBox(height: 8), -// Text( -// subtitle, -// textAlign: TextAlign.center, -// style: TextStyle(color: Colors.black54, fontSize: 12), -// ), -// ], -// ), -// ), -// ); -// } -// } - -class CustomExpandableTile extends StatefulWidget { - @override - _CustomExpandableTileState createState() => _CustomExpandableTileState(); -} - -class _CustomExpandableTileState extends State { - bool isExpanded = false; +class uaenumberWidget extends StatelessWidget { + const uaenumberWidget({super.key}); @override Widget build(BuildContext context) { - return Card( - elevation: 4, - child: SingleChildScrollView( - child: Column( - children: [ - // The tile header - GestureDetector( - onTap: () { - setState(() { - isExpanded = !isExpanded; - }); - }, - child: Container( - color: Colors.blue, - padding: const EdgeInsets.all(16), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'ECONOMY', - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - fontSize: 18, - ), - ), - Icon( - isExpanded ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down, - color: Colors.white, - ), - ], - ), - ), - ), - // Animated container for expansion - AnimatedContainer( - duration: Duration(milliseconds: 300), - curve: Curves.easeInOut, - height: isExpanded ? null : 0, - child: isExpanded - ? Container( - color: Colors.white, - padding: const EdgeInsets.all(16), - child: Column( - children: [ - buildCategoryTitle('National Accounts'), - buildCardRow([ - buildCard('GDP (Constant)', '1.62T', '2022 (AED)'), - buildCard('FDI', '1.45T', '2021 (AED)'), - ]), - buildCategoryTitle('International Trade'), - buildCardRow([ - buildCard('Total Trade', '669.9B', 'Jan - Mar 2024 (AED)'), - buildCard('Total Import', '686B', 'Jan - Mar 2024 (AED)'), - ]), - buildCategoryTitle('Prices'), - buildCardRow([ - buildCard('Inflation Rate', '215.4B', '2023'), - ]), - ], - ), - ) - : Container(), - ), - ], + double myheight = MediaQuery.of(context).size.height; + double mywidth = MediaQuery.of(context).size.width; + return Padding( + padding: const EdgeInsets.all(16.0), + child: ListView( + children: [ + Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(30.0), + border: Border.all(width: 1) + + ), + child: TextField( + decoration: InputDecoration( + hintText: "Search", + prefixIcon: Icon(Icons.search), + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric(vertical: 15.0, horizontal: 20.0), ), ), + ), + 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([ + buildCard(context,'Marriages', '96%', '2023',socialColor,socialColor,mywidth/2.5), + 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), + ]), + ], + ), + ], + ), ); } - Widget buildCategoryTitle(String title) { + Widget buildCategoryTitle(String title,Color color) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), child: Text( @@ -398,7 +136,7 @@ class _CustomExpandableTileState extends State { style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, - color: Colors.black54, + color: color, ), ), ); @@ -410,7 +148,7 @@ class _CustomExpandableTileState extends State { child: Row( children: cards.map((card) { return Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), + padding: const EdgeInsets.symmetric(horizontal: 2.0), child: card, ); }).toList(), @@ -418,11 +156,21 @@ class _CustomExpandableTileState extends State { ); } - Widget buildCard(String title, String value, String subtitle) { + 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: 150, + 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 + ), padding: const EdgeInsets.all(16.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, @@ -430,26 +178,115 @@ class _CustomExpandableTileState extends State { Text( title, textAlign: TextAlign.center, - style: TextStyle(fontWeight: FontWeight.bold), + style: robotoRegular11, + ), + SizedBox(height: 8), + Text( + subtitle, + textAlign: TextAlign.center, + style: subtitleStyle ), SizedBox(height: 8), Text( value, style: TextStyle( - fontSize: 18, - color: Colors.blue, + fontSize: 26, + color: boldColor, fontWeight: FontWeight.bold, ), ), - SizedBox(height: 8), - Text( - subtitle, - textAlign: TextAlign.center, - style: TextStyle(color: Colors.black54, fontSize: 12), - ), ], ), ), ); } } + +class CustomExpandableTile extends StatefulWidget { + final String title; + final Color titleBackgroundColor; + final List children; + + const CustomExpandableTile({ + required this.title, + required this.titleBackgroundColor, + required this.children, + }); + + @override + _CustomExpandableTileState createState() => _CustomExpandableTileState(); +} + +class _CustomExpandableTileState extends State { + bool isExpanded = false; + + @override + Widget build(BuildContext context) { + double myheight = MediaQuery.of(context).size.height; + return Card( + elevation: 4, + child: Column( + children: [ + GestureDetector( + onTap: () { + setState(() { + isExpanded = !isExpanded; + }); + }, + child: Container( + decoration: BoxDecoration( + color: widget.titleBackgroundColor, + borderRadius: BorderRadius.all(Radius.circular(12)) + ), + padding: const EdgeInsets.all(12), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + widget.title, + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + Icon( + isExpanded + ? Icons.keyboard_arrow_up + : Icons.keyboard_arrow_down, + color: Colors.white, + ), + ], + ), + ), + ), + ClipRRect( + child: AnimatedContainer( + duration: Duration(milliseconds: 300), + curve: Curves.easeInOut, + width: double.infinity, + height: isExpanded ? myheight : 0, + child: isExpanded + ? SingleChildScrollView( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(20)) + ), + + padding: const EdgeInsets.all(10), + child: Column( + children: widget.children, + ), + ), + ) + : null, + ), + ), + ], + ), + ); + } +} + + From 066235889bc1c641fc60f143ce89e07e27cc7158 Mon Sep 17 00:00:00 2001 From: venbaittech Date: Tue, 7 Jan 2025 09:35:28 +0530 Subject: [PATCH 3/4] charts added --- .run/main.dart.run.xml | 2 +- lib/config/my_router.dart | 22 +- lib/presentation/Screens/charts/chart.dart | 1225 +++++++++++++++++ lib/presentation/Screens/demo_home.dart | 352 +++-- lib/presentation/Screens/demo_home2.dart | 328 +++++ .../tab_routes/home_route.dart | 53 +- pubspec.yaml | 2 +- 7 files changed, 1873 insertions(+), 111 deletions(-) create mode 100644 lib/presentation/Screens/charts/chart.dart create mode 100644 lib/presentation/Screens/demo_home2.dart diff --git a/.run/main.dart.run.xml b/.run/main.dart.run.xml index 4767aff8..4a58a7c9 100644 --- a/.run/main.dart.run.xml +++ b/.run/main.dart.run.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/lib/config/my_router.dart b/lib/config/my_router.dart index a4e4693f..da605ad4 100644 --- a/lib/config/my_router.dart +++ b/lib/config/my_router.dart @@ -295,6 +295,7 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:uae_stat/presentation/Screens/auth_verification/registration.dart'; +import 'package:uae_stat/presentation/Screens/demo_home2.dart'; import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart'; import '../domain/use_cases/preferences_use_case.dart'; @@ -302,6 +303,7 @@ import '../presentation/Screens/auth_verification/changepassword.dart'; import '../presentation/Screens/auth_verification/confirm_password.dart'; import '../presentation/Screens/auth_verification/create_new_pw.dart'; import '../presentation/Screens/auth_verification/otp_verification.dart'; +import '../presentation/Screens/charts/chart.dart'; import '../presentation/Screens/demo_home.dart'; import '../presentation/Screens/profilepage.dart'; import '../presentation/routes/auth_routes/login_route.dart'; @@ -313,13 +315,12 @@ final GoRouter router = GoRouter( routes: [ GoRoute( path: '/', -builder: (context, state) => LoginRoute(), + builder: (context, state) => LoginRoute(), //builder: (context, state) => MyHomePage(), ), GoRoute( path: '/login', builder: (context, state) => LoginRoute(), - ), GoRoute( path: '/myhomepage', @@ -330,8 +331,20 @@ builder: (context, state) => LoginRoute(), builder: (context, state) => RegisterScreen(), ), GoRoute( - path: '/DemoHome', - builder: (context, state) => ChartPage(), + 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: '/mailverification', @@ -390,4 +403,3 @@ builder: (context, state) => LoginRoute(), ), ], ); - diff --git a/lib/presentation/Screens/charts/chart.dart b/lib/presentation/Screens/charts/chart.dart new file mode 100644 index 00000000..1911ddee --- /dev/null +++ b/lib/presentation/Screens/charts/chart.dart @@ -0,0 +1,1225 @@ +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_type :"scatter" +// dataset :"divorces" +// is_chart :"true" +// kpi:"divorces" +// filters:[ +// { +// "filter_key": "REF_AREA", +// "filter_data": [ +// "AE", +// "AE-AJ", +// "AE-RK", +// "AE-FJ", +// "AE-AZ", +// "AE-DU", +// "AE-SH", +// "AE-UQ" +// ] +// }, +// { +// "filter_key": "TIME_PERIOD", +// "filter_data": [ +// "2021", +// "2017", +// "2018", +// "2019", +// "2020" +// ] +// }, +// { +// "filter_key": "DV_TYPE", +// "filter_data": [ +// "D_EM_NEF", +// "D_EM_EF", +// "D_NEW_NEF", +// "D_TOT", +// "D_NEM_EF" +// ] +// } +// ] +// group_by:"DV_TYPE" +// main_id :"social" +// response:[ +// { +// "ObsKey": { +// "DV_TYPE": "D_TOT", +// "FREQ": "A", +// "MEASURE": "D", +// "REF_AREA": "AE-DU", +// "SOURCE_DETAIL": "FCSAMD", +// "TIME_PERIOD": "2017", +// "UNIT_MEASURE": "NUMBER" +// }, +// "ObsValue": { +// "Value": "1484" +// } +// }, +// { +// "ObsKey": { +// "DV_TYPE": "D_TOT", +// "FREQ": "A", +// "MEASURE": "D", +// "REF_AREA": "AE-DU", +// "SOURCE_DETAIL": "FCSAMD", +// "TIME_PERIOD": "2019", +// "UNIT_MEASURE": "NUMBER" +// }, +// "ObsValue": { +// "Value": "1308" +// } +// }, +// { +// "ObsKey": { +// "DV_TYPE": "D_TOT", +// "FREQ": "A", +// "MEASURE": "D", +// "REF_AREA": "AE-DU", +// "SOURCE_DETAIL": "FCSAMD", +// "TIME_PERIOD": "2017", +// "UNIT_MEASURE": "NUMBER" +// }, +// "ObsValue": { +// "Value": "1484" +// } +// }, +// { +// "ObsKey": { +// "DV_TYPE": "D_TOT", +// "FREQ": "A", +// "MEASURE": "D", +// "REF_AREA": "AE-DU", +// "SOURCE_DETAIL": "FCSAMD", +// "TIME_PERIOD": "2018", +// "UNIT_MEASURE": "NUMBER" +// }, +// "ObsValue": { +// "Value": "1321" +// } +// }, +// { +// "ObsKey": { +// "DV_TYPE": "D_NEM_EF", +// "FREQ": "A", +// "MEASURE": "D", +// "REF_AREA": "AE", +// "SOURCE_DETAIL": "FCSAMD", +// "TIME_PERIOD": "2017", +// "UNIT_MEASURE": "NUMBER" +// }, +// "ObsValue": { +// "Value": "181" +// } +// }, +// { +// "ObsKey": { +// "DV_TYPE": "D_NEM_EF", +// "FREQ": "A", +// "MEASURE": "D", +// "REF_AREA": "AE", +// "SOURCE_DETAIL": "FCSAMD", +// "TIME_PERIOD": "2019", +// "UNIT_MEASURE": "NUMBER" +// }, +// "ObsValue": { +// "Value": "182" +// } +// }, +// { +// "ObsKey": { +// "DV_TYPE": "D_EM_NEF", +// "FREQ": "A", +// "MEASURE": "D", +// "REF_AREA": "AE", +// "SOURCE_DETAIL": "FCSAMD", +// "TIME_PERIOD": "2017", +// "UNIT_MEASURE": "NUMBER" +// }, +// "ObsValue": { +// "Value": "766" +// } +// }, +// { +// "ObsKey": { +// "DV_TYPE": "D_EM_NEF", +// "FREQ": "A", +// "MEASURE": "D", +// "REF_AREA": "AE", +// "SOURCE_DETAIL": "FCSAMD", +// "TIME_PERIOD": "2020", +// "UNIT_MEASURE": "NUMBER" +// }, +// "ObsValue": { +// "Value": "618" +// } +// }, +// { +// "ObsKey": { +// "DV_TYPE": "D_EM_EF", +// "FREQ": "A", +// "MEASURE": "D", +// "REF_AREA": "AE", +// "SOURCE_DETAIL": "FCSAMD", +// "TIME_PERIOD": "2017", +// "UNIT_MEASURE": "NUMBER" +// }, +// "ObsValue": { +// "Value": "1717" +// } +// }, +// { +// "ObsKey": { +// "DV_TYPE": "D_EM_EF", +// "FREQ": "A", +// "MEASURE": "D", +// "REF_AREA": "AE", +// "SOURCE_DETAIL": "FCSAMD", +// "TIME_PERIOD": "2018", +// "UNIT_MEASURE": "NUMBER" +// }, +// "ObsValue": { +// "Value": "1720" +// } +// } +// +// ] +// sub_id :"vital_statistics" +// url :"https://releaseeuaestat.fcsc.gov.ae/rest/data/FCSA,DF_DV_NA,1.5.0/.A....?startPeriod=2017&endPeriod=2024&dimensionAtObservation=AllDimensions" +// } +// ] diff --git a/lib/presentation/Screens/demo_home.dart b/lib/presentation/Screens/demo_home.dart index 225f1b1b..895a5a29 100644 --- a/lib/presentation/Screens/demo_home.dart +++ b/lib/presentation/Screens/demo_home.dart @@ -13,12 +13,15 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( - home: ChartPage(), + home: ChartPage(dataSets: ''), ); } } class ChartPage extends StatefulWidget { + final String dataSets; + const ChartPage({Key? key, required this.dataSets}); + @override ChartPageState createState() => ChartPageState(); } @@ -30,13 +33,13 @@ class ChartPageState extends State { @override void initState() { super.initState(); - fetchChartData(); + fetchChartData(widget.dataSets); } - Future fetchChartData() async { + Future fetchChartData(datasets) async { const baseUrl = 'https://pb.venbait.in/api/custom/apicall'; // Replace with your server URL - final url = Uri.parse('$baseUrl?dataset=hotels'); + final url = Uri.parse('$baseUrl?dataset=$datasets'); try { final response = await http.get(url); @@ -57,24 +60,34 @@ class ChartPageState extends State { } 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 + // Group by timePeriod (year) and sum the values + Map groupedData = {}; - // Parse the value or fallback to 0.0 + response.forEach((entry) { + final year = entry['ObsKey']['TIME_PERIOD']?.toString() ?? 'Unknown'; final value = - double.tryParse(entry['ObsValue']?['Value']?.toString() ?? '0.0') ?? + double.tryParse(entry['ObsValue']['Value']?.toString() ?? '0.0') ?? 0.0; - return ChartData( - timePeriod: formattedTimePeriod, - value: value, - ); - }).toList(); + // 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) { @@ -82,63 +95,127 @@ class ChartPageState extends State { .asMap() .entries .map((entry) => ChartData( - timePeriod: entry.value['ObsKey']['TIME_PERIOD'] ?? - 'Unknown', // Fallback to 'Unknown' if null + timePeriod: entry.value['ObsKey']['TIME_PERIOD'] ?? 'Unknown', value: double.tryParse( entry.value['ObsValue']['Value'].toString()) ?? - 0.0, // Handle null/invalid value + 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 'line': + 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: >[ - LineSeries( - dataSource: parseLineChartData(chartData['response']), - xValueMapper: (ChartData data, _) => data.timePeriod, - yValueMapper: (ChartData data, _) => data.value, - name: chartData['dataset'], - color: Colors.red, - 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), - ); - }, - ), + 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(), @@ -166,7 +243,7 @@ class ChartPageState extends State { xValueMapper: (ChartData data, _) => data.timePeriod, yValueMapper: (ChartData data, _) => data.value, name: chartData['dataset'], - color: Colors.red, + color: Color(0xFF7DAFBC), dataLabelSettings: DataLabelSettings( isVisible: true, builder: (dynamic data, dynamic point, dynamic series, @@ -182,6 +259,41 @@ class ChartPageState extends State { ), ], ); + 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')); } @@ -192,46 +304,84 @@ class ChartPageState extends State { return Scaffold( backgroundColor: const Color(0xFF7DAFBC), appBar: AppBar( - backgroundColor: Color(0xFF7DAFBC), + backgroundColor: const Color(0xFF7DAFBC), elevation: 0, leading: IconButton( - icon: Icon(Icons.arrow_back_ios_new, color: Colors.white), + icon: const Icon(Icons.arrow_back_ios_new, color: Colors.white), onPressed: () { context.go('/myhomepage'); }, ), - title: Text( + title: const Text( 'Charts', style: TextStyle(color: Colors.white), ), ), body: isLoading - ? Center(child: CircularProgressIndicator()) - : ListView.builder( - itemCount: chartsData.length, - itemBuilder: (context, index) { - return Card( - margin: EdgeInsets.all(10), + ? 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: [ - // Text( - // 'Chart: ${chartsData[index]['chart_type']}', - // style: TextStyle( - // fontSize: 18, fontWeight: FontWeight.bold), - // ), - // SizedBox(height: 10), - Container( - height: 300, - child: buildChart(chartsData[index]), + 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]), + ), + ], + ), + ), + ); + }, + ), + ), + ], ), ); } @@ -240,23 +390,35 @@ class ChartPageState extends State { class ChartData { final String timePeriod; final double value; + final double value1; final String formattedValue; - ChartData({required this.timePeriod, required this.value}) + 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 } diff --git a/lib/presentation/Screens/demo_home2.dart b/lib/presentation/Screens/demo_home2.dart new file mode 100644 index 00000000..b1576aaa --- /dev/null +++ b/lib/presentation/Screens/demo_home2.dart @@ -0,0 +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, + }); +} 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 cc4702c4..70ed8841 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 @@ -171,6 +171,20 @@ class MyHomePage extends StatefulWidget { State createState() => _MyHomePageState(); } +void handleInfoCardClick(BuildContext context, String data) { + // Handle navigation and pass dynamic data + print(data); + final dataSets = data; + print(dataSets); + if (dataSets == 'hotels') { + context.go('/Chart/$dataSets'); + } else if (dataSets == 'divorces') { + context.go('/Chart/$dataSets'); + } else if (dataSets == 'marriages') { + context.go('/Chart/$dataSets'); + } +} + class _MyHomePageState extends State { @override Widget build(BuildContext context) { @@ -226,6 +240,7 @@ class EconomyStats extends StatelessWidget { value: '1.62T', bordercolor: Color(0xFF7DAFBC), textcolor: Color(0xFF7DAFBC), + onTap: () => handleInfoCardClick(context, 'Inflation'), ), InfoCard( title: 'Inflation Rate', @@ -233,6 +248,7 @@ class EconomyStats extends StatelessWidget { value: '4.82%', bordercolor: Color(0xFF7DAFBC), textcolor: Color(0xFF7DAFBC), + onTap: () => handleInfoCardClick(context, 'Inflation'), ), ], ), @@ -247,6 +263,8 @@ class EconomyStats extends StatelessWidget { value: '215.4B', bordercolor: Color(0xFF7DAFBC), textcolor: Color(0xFF7DAFBC), + onTap: () => + handleInfoCardClick(context, 'commodities'), ), InfoCard( title: 'Hotel Guests', @@ -254,6 +272,7 @@ class EconomyStats extends StatelessWidget { value: '25.21M', bordercolor: Color(0xFF7DAFBC), textcolor: Color(0xFF7DAFBC), + onTap: () => handleInfoCardClick(context, 'hotels'), ), ], ), @@ -280,18 +299,22 @@ class EconomyStats extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ InfoCard( - title: 'Population', - subtitle: '(2022) (AED)', - value: '1.62T', + title: 'Divorces', + subtitle: '(2022)', + value: '0', bordercolor: Colors.brown[200]!, textcolor: Colors.brown[200]!, + onTap: () => + handleInfoCardClick(context, 'divorces'), ), InfoCard( - title: 'Labor Force', + title: 'Marriages', subtitle: '(2022)', - value: '4.82%', + value: '0', bordercolor: Colors.brown[200]!, textcolor: Colors.brown[200]!, + onTap: () => + handleInfoCardClick(context, 'marriages'), ), ], ), @@ -301,11 +324,13 @@ class EconomyStats extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ InfoCard( - title: 'Hospitals (Gov )', + title: 'Hospitals (Gov)', subtitle: '(Jan - Jan 2024) - AED', value: '215.4B', bordercolor: Colors.brown[200]!, textcolor: Colors.brown[200]!, + onTap: () => + handleInfoCardClick(context, 'Hospitals'), ), InfoCard( title: 'Schools', @@ -313,6 +338,8 @@ class EconomyStats extends StatelessWidget { value: '25.21M', bordercolor: Colors.brown[200]!, textcolor: Colors.brown[200]!, + onTap: () => + handleInfoCardClick(context, 'Schools'), ), ], ), @@ -345,6 +372,8 @@ class EconomyStats extends StatelessWidget { value: '1.62T', bordercolor: Color(0xFF7DAFBC), textcolor: Color(0xFF7DAFBC), + onTap: () => handleInfoCardClick( + context, 'Electricity'), ), InfoCard( title: 'Cruid oil', @@ -352,6 +381,8 @@ class EconomyStats extends StatelessWidget { value: '4.82%', bordercolor: Color(0xFF7DAFBC), textcolor: Color(0xFF7DAFBC), + onTap: () => + handleInfoCardClick(context, 'Cruid'), ), ], ), @@ -367,6 +398,8 @@ class EconomyStats extends StatelessWidget { value: '215.4B', bordercolor: Color(0xFF7DAFBC), textcolor: Color(0xFF7DAFBC), + onTap: () => + handleInfoCardClick(context, 'Export'), ), InfoCard( title: 'Desalinated water', @@ -374,6 +407,8 @@ class EconomyStats extends StatelessWidget { value: '25.21M', bordercolor: Color(0xFF7DAFBC), textcolor: Color(0xFF7DAFBC), + onTap: () => handleInfoCardClick( + context, 'Desalinated'), ), ], ), @@ -433,6 +468,7 @@ class InfoCard extends StatelessWidget { final String value; final Color bordercolor; final Color? textcolor; + final VoidCallback onTap; // New callback parameter const InfoCard({ Key? key, @@ -441,6 +477,7 @@ class InfoCard extends StatelessWidget { required this.value, required this.bordercolor, this.textcolor, + required this.onTap, // Initialize in constructor }) : super(key: key); @override @@ -450,9 +487,7 @@ class InfoCard extends StatelessWidget { return Expanded( child: GestureDetector( - onTap: () { - context.go('/DemoHome'); - }, + onTap: onTap, // Use callback for handling clicks child: Container( height: myheight / 9, width: mywidth / 4, diff --git a/pubspec.yaml b/pubspec.yaml index ebd8679b..315a6f95 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -20,7 +20,7 @@ dependencies: injectable: ^2.3.2 riverpod_annotation: ^2.3.3 cupertino_icons: ^1.0.6 - fl_chart: ^0.69.0 + fl_chart: ^0.69.2 marquee: ^2.2.3 # dynamic_layouts: # git: From fb68b1aa7969729ecfdb43358adcf15baf8ffce0 Mon Sep 17 00:00:00 2001 From: venbaittech Date: Tue, 7 Jan 2025 10:56:50 +0530 Subject: [PATCH 4/4] drawer profile functionality added --- lib/config/my_router.dart | 2 +- .../drawer_routes/custom_drawer_routes.dart | 213 ++++++++++++++---- pubspec.lock | 48 ++-- 3 files changed, 192 insertions(+), 71 deletions(-) diff --git a/lib/config/my_router.dart b/lib/config/my_router.dart index e45df2d3..c200ac19 100644 --- a/lib/config/my_router.dart +++ b/lib/config/my_router.dart @@ -324,7 +324,7 @@ final GoRouter router = GoRouter( GoRoute( path: '/', builder: (context, state) => LoginRoute(), - //builder: (context, state) => MyHomePage(), + // builder: (context, state) => MyHomePage(), ), GoRoute( path: '/login', diff --git a/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart b/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart index de8715ed..cad24495 100644 --- a/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart +++ b/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart @@ -1,7 +1,10 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:pocketbase/pocketbase.dart'; +import 'package:share_plus/share_plus.dart'; +import 'package:shared_preferences/shared_preferences.dart'; -class BaseScaffold extends StatelessWidget { +class BaseScaffold extends StatefulWidget { final Widget body; final Widget title; final List? actions; @@ -12,9 +15,81 @@ class BaseScaffold extends StatelessWidget { required this.title, this.actions, }) : super(key: key); - // final Widget body; - // - // const BaseScaffold({required this.body}); + + @override + _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['username'] ?? ''; + 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) { @@ -22,15 +97,29 @@ class BaseScaffold extends StatelessWidget { 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, actions: [ - IconButton(onPressed: () {}, icon: Icon(Icons.toggle_off_outlined)), - ]), + appBar: AppBar( + title: widget.title, + actions: [ + // IconButton( + // onPressed: () { + // // Share logic here + // print("Share icon pressed"); + // Share.share( + // 'Open the app: fcscapp://home\n\n' + // 'If you don’t have the app installed, ' + // 'visit: http://localhost:65493'); + // }, + // icon: Icon(Icons.share), + // ), + IconButton(onPressed: () {}, icon: Icon(Icons.toggle_off_outlined)), + ], + ), drawer: Drawer( child: ListView( children: [ DrawerHeader( - //decoration: BoxDecoration(color: Colors.blue), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ @@ -48,18 +137,39 @@ class BaseScaffold extends StatelessWidget { 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), + ), ], ) ], @@ -68,34 +178,45 @@ class BaseScaffold extends StatelessWidget { ], ), ), + if (role != 'admin') + ListTile( + leading: SizedBox( + height: myheight / 15, + width: mywidth / 15, + child: Image( + image: AssetImage('assets/icons/drawer/message.png'))), + title: Text('Feedback'), + onTap: () => context.go('/feedback'), + ), + if (role == 'admin') + ListTile( + leading: SizedBox( + height: myheight / 15, + width: mywidth / 15, + child: Image( + image: + AssetImage('assets/icons/drawer/manageuser.png'))), + title: Text('Manage User'), + onTap: () => context.go('/manageuser'), + ), ListTile( leading: SizedBox( height: myheight / 15, width: mywidth / 15, - child: Image( - image: AssetImage('assets/icons/drawer/message.png'))), - title: Text('Feedback'), - onTap: () => context.go('/feedback'), - ), - ListTile( - leading: SizedBox( - height: myheight / 15, - width: mywidth / 15, - child: Image( - image: AssetImage('assets/icons/drawer/manageuser.png'))), - title: Text('Manage User'), - onTap: () => context.go('/manageuser'), - ), - - ListTile( - leading: SizedBox( - height: myheight / 15, - width: mywidth / 15, - child: Image( - image: AssetImage('assets/icons/drawer/book.png'))), + child: + Image(image: AssetImage('assets/icons/drawer/book.png'))), title: Text('User Guide'), onTap: () => context.go('/user-guide'), ), + ListTile( + leading: SizedBox( + height: myheight / 15, + width: mywidth / 15, + child: Image( + image: AssetImage('assets/icons/drawer/logout.png'))), + title: Text('Logout'), + onTap: () => context.go('/'), + ), ], ), ), @@ -140,40 +261,40 @@ class BaseScaffold extends StatelessWidget { unselectedItemColor: Colors.grey, showUnselectedLabels: true, ), - body: body, + body: widget.body, ); } - //Map the current route to the selected index + // Map the current route to the selected index int _getSelectedIndex(String route) { switch (route) { - case '/': + case '/myhomepage': return 0; - case '/uaenumbers': + case '/about': return 1; - case '/competitiveness': + case '/settings': return 2; - case '/countryprofile': + case '/profile': return 3; default: return 0; } } - //Handle navigation when an item is tapped + // 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'); + context.go('/about'); break; case 2: - context.go('/competitiveness'); + context.go('/settings'); break; case 3: - context.go('/countryprofile'); + context.go('/profile'); break; } } diff --git a/pubspec.lock b/pubspec.lock index cc69ece0..3996cee4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,23 +5,23 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab" + sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834 url: "https://pub.dev" source: hosted - version: "76.0.0" + version: "72.0.0" _macros: dependency: transitive description: dart source: sdk - version: "0.3.3" + version: "0.3.2" analyzer: dependency: transitive description: name: analyzer - sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e" + sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139 url: "https://pub.dev" source: hosted - version: "6.11.0" + version: "6.7.0" analyzer_plugin: dependency: transitive description: @@ -186,10 +186,10 @@ packages: dependency: transitive description: name: collection - sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.19.0" + version: "1.18.0" convert: dependency: transitive description: @@ -266,10 +266,10 @@ packages: dependency: transitive description: name: custom_lint_visitor - sha256: bfe9b7a09c4775a587b58d10ebb871d4fe618237639b1e84d5ec62d7dfef25f9 + sha256: "8aeb3b6ae2bb765e7716b93d1d10e8356d04e0ff6d7592de6ee04e0dd7d6587d" url: "https://pub.dev" source: hosted - version: "1.0.0+6.11.0" + version: "1.0.0+6.7.0" dart_style: dependency: transitive description: @@ -773,18 +773,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "10.0.7" + version: "10.0.5" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "3.0.8" + version: "3.0.5" leak_tracker_testing: dependency: transitive description: @@ -813,10 +813,10 @@ packages: dependency: transitive description: name: macros - sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656" + sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" url: "https://pub.dev" source: hosted - version: "0.1.3-main.0" + version: "0.1.2-main.4" mailer: dependency: "direct main" description: @@ -1172,7 +1172,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.0" + version: "0.0.99" smart_api_client: dependency: "direct main" description: @@ -1216,10 +1216,10 @@ packages: dependency: transitive description: name: stack_trace - sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.11.1" state_notifier: dependency: transitive description: @@ -1248,10 +1248,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.2.0" syncfusion_flutter_charts: dependency: "direct main" description: @@ -1280,10 +1280,10 @@ packages: dependency: transitive description: name: test_api - sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.7.3" + version: "0.7.2" the_validator: dependency: "direct main" description: @@ -1408,10 +1408,10 @@ packages: dependency: transitive description: name: vm_service - sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" url: "https://pub.dev" source: hosted - version: "14.3.0" + version: "14.2.5" watcher: dependency: transitive description: