diff --git a/l10n.yaml b/l10n.yaml new file mode 100644 index 00000000..42544565 --- /dev/null +++ b/l10n.yaml @@ -0,0 +1,3 @@ +arb-dir: lib/l10n +template-arb-file: intl_en.arb +output-localization-file: app_localizations.dart diff --git a/lib/config/my_router.dart b/lib/config/my_router.dart index 0eeecdff..8a8a1fc8 100644 --- a/lib/config/my_router.dart +++ b/lib/config/my_router.dart @@ -294,20 +294,23 @@ 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/Bottom%20Navigation%20Pages/UAE_Numbers/Social/marriages.dart'; import 'package:uae_stat/presentation/Screens/auth_verification/registration.dart'; +import 'package:uae_stat/presentation/Screens/charts/chart.dart'; +import 'package:uae_stat/presentation/Screens/charts/screens/chart_screen.dart'; import 'package:uae_stat/presentation/Screens/demo_home2.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'; +import 'package:uae_stat/presentation/Screens/Bottom Navigation Pages/UAE_Numbers/uae_numbers.dart'; +import 'package:uae_stat/presentation/Screens/Bottom Navigation Pages/Competitiveness/competitiveness.dart'; +import 'package:uae_stat/presentation/Screens/Bottom Navigation Pages/Country_Profile/country_profile.dart'; + import '../domain/use_cases/preferences_use_case.dart'; 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'; @@ -323,8 +326,8 @@ final GoRouter router = GoRouter( routes: [ GoRoute( path: '/', - builder: (context, state) => LoginRoute(), - // builder: (context, state) => MyHomePage(), + //builder: (context, state) => LoginRoute(), + builder: (context, state) => MyHomePage(), ), GoRoute( path: '/login', @@ -355,6 +358,15 @@ final GoRouter router = GoRouter( return ChartScreen(dataSets: dataSets); }, ), + GoRoute( + path: '/chartScreen/:dataSets', + builder: (context, state) { + final dataSets = state.pathParameters['dataSets']!; + print('Router $dataSets'); + // return ChartScreen(dataSets: dataSets); + return ChartScreen1(dataSets: dataSets); + }, + ), GoRoute( path: '/mailverification', builder: (context, state) => EmailVerificationScreen( @@ -439,9 +451,13 @@ final GoRouter router = GoRouter( ), // Bottom Navigation Routes + // GoRoute( + // path: '/uaenumbers', + // builder: (context, state) => UaeNumbers(), + // ), GoRoute( - path: '/uaenumbers', - builder: (context, state) => UaeNumbers(), + path: '/uaenumbers', + builder: (context,state) => UaeNumbers() ), GoRoute( @@ -453,5 +469,10 @@ final GoRouter router = GoRouter( path: '/countryprofile', builder: (context, state) => CountryProfile(), ), + + GoRoute( + path: '/marriages', + builder: (context, state) => Marriages(), + ), ], ); diff --git a/lib/l10n/intl_ar.arb b/lib/l10n/intl_ar.arb new file mode 100644 index 00000000..e01858b5 --- /dev/null +++ b/lib/l10n/intl_ar.arb @@ -0,0 +1,86 @@ +{ + "feedback_title": "نموذج الملاحظات", + "feedback_failed_msg": "لم يتم إرسال تعليقاتك. يرجى المحاولة مرة أخرى", + + "guide_title": "نموذج الملاحظات", + + "register_title": "التسجيل", + "register_details": "من فضلك ادخل بياناتك", + "register_name": "اسم المستخدم", + "email_id": "الاسم الكامل", + "enter_name": "أدخل الاسم", + "register_email": "أدخل بريدك الإلكتروني", + "register_password": "دخل كلمة المرور", + "register_Confirm_password": "أكيد كلمة المرو", + "agree": " وافق على", + "t_and": "و ", + "conditions": " الخاصة بالمركز الاتحادي للتنافسية والإحصاء", + "terms_conditions": "الشروط والأحكام ", + "privacy_policy":" وسياسة الخصوصية", + "account_confirmation": "ل لديك حساب؟ سجل الدخول ", + "login_title": "سجيل الدخول", + + "profile_title": "نموذج الملاحظات", + "my_profile": "ملفي الشخصي", + "logout": "تسجيل الخروج", + "full_name": "الاسم الكامل", + "dob": "تاريخ الميلاد", + "region": "الدولة/المنطقة", + "cancel": "إلغاء", + "confirm": "تأكيد", + "change_password": "تغيير كلمة المرور", + "sure_save_page": " هل أنت متأكد أنك ترغب في حفظ هذه الصفحة؟", + "not_able_to_change": " بمجرد الحفظ، لن تتمكن من تعديل اسمك أو تاريخ ", + "save": "يحفظ", + "name": "اسم", + + + "nav_home": "الصفحة الرئيسية", + "nav_uae": "أرقام الإمارات", + "nav_competitiveness": "القدرة التنافسية", + "country_profile": "ملف تعريف الدولة", + + + "agree_terms_conditions": "يرجى الموافقة على الشروط والأحكام.", + "retry":"Retry", + "select": "يختار", + "email_exists": "البريد الإلكتروني موجود", + "email_exists_msg": "معرف البريد الإلكتروني موجود بالفعل. الرجاء استخدام بريد إلكتروني مختلف.", + "email_invalid": "البريد الإلكتروني غير صالح أو قيد الاستخدام بالفعل.", + "required": "مطلوب", + "only40charac": "يجب ألا يتجاوز 40 حرفًا", + "invalid_characters": "أحرف غير صالحة", + "invalid_email": "البريد الإلكتروني غير صالح", + "password_invalid": "تحتوي كلمة المرور على أحرف غير صالحة", + "password_match": "كلمات المرور غير متطابقة", + "only8charac": "يجب أن تتكون كلمة المرور من 8 أحرف على الأقل", + + "manage_user": "دارة المستخدمين", + "user_name": "اسم المستخدم", + "reg_date": "تاريخ التسجيل", + "status": "تمت الموافقة", + "denied": "مرفوض", + "pending": "يد الانتظار", + "approve_msg": "هل أنت متأكد أنك ترغب في تغيير الحالة إلى \"{newStatus}\"؟", + "yes": "نعم", + "no": "لا", + "no_result_found": "لم يتم العثور على نتائج", + "search": "يبحث", + "approved": "موافقة", + + "create_new_password": "إنشاء كلمة مرور جديدة", + "different_password": "يجب أن تكون كلمة المرور الجديدة مختلفة عن كلمة المرور المستخدمة سابقًا.", + "old_password": "كلمة المرور القديمة", + "enter_new_password": "أدخل كلمة المرور الجديدة", + "confirm_new_password": "تأكيد كلمة المرور الجديدة", + "password_changed_successfully": "م تغيير كلمة المرور بنجاح", + "enter_old_password": "أدخل كلمة المرور القديمة", + "your_old_password_incorrect": "كلمة المرور القديمة الخاصة بك غير صحيحة.", + "failed_to_update_password": "", + "password_update_successfully": "تم تحديث كلمة المرور بنجاح.", + "new_password_not_same_as_old": "كلمة المرور الجديدة يجب ألا تكون نفس كلمة المرور القديمة", + "password_between_8_to_40": "يجب أن تتراوح كلمة المرور بين 8 و64 حرفًا", + "new_password_required": "كلمة المرور الجديدة مطلوبة", + "old_password_is_required": "كلمة المرور القديمة مطلوبة", + "confirm_password_is_required": "تأكيد كلمة المرور مطلوب" + } \ No newline at end of file diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb new file mode 100644 index 00000000..5b58e7ce --- /dev/null +++ b/lib/l10n/intl_en.arb @@ -0,0 +1,87 @@ +{ + + + "feedback_title": "FeedBack", + "feedback_failed_msg": "Your feedback could not be submitted. Please try again", + + "register_title": "Register", + "register_details": "Please enter your details", + "register_name": "Username", + "email_id": "Email ID", + "enter_name": "Enter your User Name", + "register_email": "Enter your email", + "register_password": "Enter your password", + "register_Confirm_password": "Confirm password", + "agree": "I agree to ", + "t_and": "and", + "conditions": " of Fcsc", + "terms_conditions": "terms & conditions", + "privacy_policy":"privacy policy", + "account_confirmation": "Already have an account? Login", + "login_title": "Login", + + "profile_title": "Edit Profile", + "my_profile": "My Profile", + "logout": "Logout", + "full_name": "Full Name*", + "dob": "Date of Birth*", + "region": "Country/Region", + "cancel": "Cancel", + "confirm": "Confirm", + "change_password": "Change Password", + "sure_save_page": "Are you sure you want to save this page? ", + "not_able_to_change": "Once saved, you will not be able to change your ", + "save": "Save", + "name": "Name", + + + "guide_title": "User Guide", + + "nav_home": "HOME", + "nav_uae": "UAE Numbers", + "nav_competitiveness": "Competitiveness", + "country_profile": "Country Profile", + + "agree_terms_conditions": "Please agree to terms and conditions.", + "retry": "Retry", + "select": "Select", + "email_exists": "Email exists", + "email_exists_msg": "Email ID already exists. Please use a different email.", + "email_invalid": "The email is invalid or already in use.", + "required": "Required", + "only40charac": "Must not exceed 40 characters", + "invalid_characters": "Invalid Characters", + "invalid_email": "Invalid Email", + "password_invalid": "Password contains invalid characters", + "password_match": "Passwords do not match", + "only8charac": "Password must be at least 8characters", + + "manage_user": "Manage user", + "user_name": "User Name", + "reg_date": "Registration Date", + "status": "Status", + "denied": "Denied", + "pending": "Pending", + "approved": "Approved", + "approve_msg": "Are you sure you want to change the status to {newStatus}?", + "yes": "Yes", + "no": "No", + "no_result_found": "No results found", + "search": "Search", + + "create_new_password": "Create New Password", + "different_password": "Your New Password Must Be Different form Previously Used Password", + "old_password": "Old Password", + "enter_new_password": "Enter new password", + "confirm_new_password": "Confirm new password", + "password_changed_successfully": "Password Changed Successfully", + "enter_old_password": "Enter old Password", + "your_old_password_incorrect": "Your old password is incorrect.", + "failed_to_update_password": "", + "password_update_successfully": "Password updated successfully.", + "new_password_not_same_as_old": "New password must not be the same as the old password", + "password_between_8_to_40": "Password must be between 8 and 64 characters", + "new_password_required": "New password is required", + "old_password_is_required": "Old password is required", + "confirm_password_is_required": "Confirm password is required" +} diff --git a/lib/main.dart b/lib/main.dart index a388e49b..4500ffd5 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -10,6 +10,8 @@ import 'package:uae_stat/domain/entities/language_locale.dart'; import 'package:uae_stat/domain/use_cases/auth_use_case.dart'; import 'package:uae_stat/presentation/Screens/profilepage.dart'; import 'package:uae_stat/presentation/Screens/auth_verification/registration.dart'; +import 'package:uae_stat/presentation/components/indicators/locale_provider.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -22,14 +24,19 @@ void main() async { ); } -class MainApp extends StatelessWidget { +class MainApp extends ConsumerWidget { const MainApp({super.key}); @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { + final locale = ref.watch(localeProvider); + return MaterialApp.router( debugShowCheckedModeBanner: false, - routerConfig: router, // Use the GoRouter instance from app_router.dart + routerConfig: router, + locale: locale, + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales,// Use the GoRouter instance from app_router.dart ); } } diff --git a/lib/presentation/Screens/Bottom Navigation Pages/competitiveness.dart b/lib/presentation/Screens/Bottom Navigation Pages/Competitiveness/competitiveness.dart similarity index 100% rename from lib/presentation/Screens/Bottom Navigation Pages/competitiveness.dart rename to lib/presentation/Screens/Bottom Navigation Pages/Competitiveness/competitiveness.dart diff --git a/lib/presentation/Screens/Bottom Navigation Pages/Country_Profile/country_profile.dart b/lib/presentation/Screens/Bottom Navigation Pages/Country_Profile/country_profile.dart new file mode 100644 index 00000000..58a1c5ae --- /dev/null +++ b/lib/presentation/Screens/Bottom Navigation Pages/Country_Profile/country_profile.dart @@ -0,0 +1,142 @@ +import 'package:flutter/material.dart'; +import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart'; +import 'package:fl_chart/fl_chart.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) { + return HorizontalBarChart(); + } +} + + + + + +class HorizontalBarChart extends StatelessWidget { + final List xAxisData = ['2019', '2020', '2021', '2022', '2023']; + final List yAxisData = [2, 4, 1, 5, 3]; + + + @override + Widget build(BuildContext context) { + double myheight = MediaQuery.of(context).size.height; + return Scaffold( + appBar: AppBar(title: Text('Horizontal Bar Chart')), + body: Padding( + padding: const EdgeInsets.all(16.0), + child: + Container( + height: myheight/4, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.black12, + blurRadius: 8, + offset: Offset(0, 4), + ), + ], + ), + child: + Padding( + padding: const EdgeInsets.only(top: 16,left: 8.0,right: 8.0,bottom: 8.0), + child: BarChart( + BarChartData( + alignment: BarChartAlignment.spaceAround, + maxY: 8, + barTouchData: BarTouchData(enabled: false), + titlesData: FlTitlesData( + leftTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + interval: 2, + getTitlesWidget: (value, meta) { + return Padding( + padding: const EdgeInsets.only(right: 8.0), + child: Text('${value.toInt()}K'), + ); + }, + reservedSize: 60, + ), + ), + bottomTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + getTitlesWidget: (value, meta) { + return Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Text(xAxisData[value.toInt()]), + ); + }, + reservedSize: 40, + ), + ), + topTitles: AxisTitles( + sideTitles: SideTitles(showTitles: false), // Hides top titles + ), + rightTitles: AxisTitles( + sideTitles: SideTitles(showTitles: false), // Hides right titles + ), + ), + gridData: FlGridData(show: false), + borderData: FlBorderData(show: false), + barGroups: List.generate( + xAxisData.length, + (index) => BarChartGroupData( + x: index, + barRods: [ + BarChartRodData( + toY: yAxisData[index], + color: Colors.blueAccent, + //colors: [Colors.blueAccent], + borderRadius: BorderRadius.circular(4), + width: 20, + ), + ], + ), + ), + ), + ), + ), + ), + ), + ); + } +} + +void main() { + runApp(MaterialApp(home: HorizontalBarChart())); +} + + +// void main() { +// runApp(MaterialApp(home: HorizontalBarChart())); +// } + + + + + + + diff --git a/lib/presentation/Screens/Bottom Navigation Pages/UAE_Numbers/Social/marriages.dart b/lib/presentation/Screens/Bottom Navigation Pages/UAE_Numbers/Social/marriages.dart new file mode 100644 index 00000000..0a9a7e50 --- /dev/null +++ b/lib/presentation/Screens/Bottom Navigation Pages/UAE_Numbers/Social/marriages.dart @@ -0,0 +1,265 @@ +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'; +import 'package:fl_chart/fl_chart.dart'; + + +class Marriages extends StatelessWidget { + const Marriages({super.key}); + + @override + Widget build(BuildContext context) { + double myheight = MediaQuery.of(context).size.height; + double mywidth = MediaQuery.of(context).size.width; + final List xAxisData = ['2019', '2020', '2021', '2022', '2023']; + final List yAxisData = [2, 4, 1, 5, 3]; + return BaseScaffold( + appbarColor: Color(0xFFC6BEB2), + title: Text("UAE Numbers",style: TextStyle(color: Colors.white,fontWeight: FontWeight.bold),), + showBackButton: true, + body: SingleChildScrollView( + child: Column( + children : [ + Container( + height: myheight/4.5, + width: double.infinity, + color: Color(0xFFC6BEB2), + child: Padding(padding: EdgeInsets.only(left: 30,right: 30,top: 20,bottom: 10),child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("SOCIAL",style: TextStyle(color: Colors.white,fontSize: 30),), + Container(width: mywidth/5,child: Divider(thickness: 10,color: Colors.white,)), + Text("Marriages",style: TextStyle(color: Colors.white,fontSize: 20),), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + IconButton(onPressed: (){}, icon: Icon(Icons.bookmark_add_outlined,color: Colors.white,size: 40,)), + IconButton(onPressed: (){}, icon: Icon(Icons.share,color: Colors.white,size: 30,)), + ],), + ], + ),) + ), + SingleChildScrollView(child: Container( + height: myheight, + color: Color(0xFFC6BEB2), + child: Padding( + padding: const EdgeInsets.only(top: 0.0,left: 10,right: 10,bottom: 20), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Container(height: myheight/3.5,width: mywidth/2.5, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(10)) + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + 'assets/icons/indicator/social/marriage.png', + height: myheight / 10, // This ensures the image fits within the container's height + width: myheight / 10, // You can adjust the size as needed + ), + Text("Total",style: TextStyle(fontWeight: FontWeight.bold,fontSize: 26),), + Text("2022",style: TextStyle(fontSize: 15,color: Colors.grey),), + Text("16759",style: TextStyle(fontSize: 26,fontWeight: FontWeight.bold,color: socialColor),), + ], + ), + ), + Container(height: myheight/3.5,width: mywidth/2.5, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(10)) + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + 'assets/icons/indicator/social/marriage.png', + height: myheight / 10, // This ensures the image fits within the container's height + width: myheight / 10, // You can adjust the size as needed + ), + Text("Average",style: TextStyle(fontWeight: FontWeight.bold,fontSize: 26),), + Text("(2021 - 2022)",style: TextStyle(fontSize: 15,color: Colors.grey),), + Text("15987",style: TextStyle(fontSize: 26,fontWeight: FontWeight.bold,color: socialColor),), + ], + ), + ), + ], + ), + SizedBox(height: myheight/20,), + Container( + height: myheight/2.5, + width: mywidth/1.2, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(10)) + ), + child: Padding( + padding: const EdgeInsets.all(10.0), + child: Column( + children: [ + SizedBox(height: myheight/30,), + Center(child: Text("Total Marriages by Marriage Type",style: TextStyle(fontSize: 16,fontWeight: FontWeight.bold),), + ), + SizedBox(height: myheight/30,), + Container( + height: myheight/4, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.black12, + blurRadius: 8, + offset: Offset(0, 4), + ), + ], + ), + child: + Padding( + padding: const EdgeInsets.only(top: 16,left: 8.0,right: 8.0,bottom: 8.0), + child: BarChart( + BarChartData( + alignment: BarChartAlignment.spaceAround, + maxY: 8, + barTouchData: BarTouchData(enabled: false), + titlesData: FlTitlesData( + leftTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + interval: 2, + getTitlesWidget: (value, meta) { + return Padding( + padding: const EdgeInsets.only(right: 8.0), + child: Text('${value.toInt()}K'), + ); + }, + reservedSize: 60, + ), + ), + bottomTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + getTitlesWidget: (value, meta) { + return Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Text(xAxisData[value.toInt()]), + ); + }, + reservedSize: 40, + ), + ), + topTitles: AxisTitles( + sideTitles: SideTitles(showTitles: false), // Hides top titles + ), + rightTitles: AxisTitles( + sideTitles: SideTitles(showTitles: false), // Hides right titles + ), + ), + gridData: FlGridData(show: false), + borderData: FlBorderData(show: false), + barGroups: List.generate( + xAxisData.length, + (index) => BarChartGroupData( + x: index, + barRods: [ + BarChartRodData( + toY: yAxisData[index], + color: Colors.blueAccent, + //colors: [Colors.blueAccent], + borderRadius: BorderRadius.circular(4), + width: 20, + ), + ], + ), + ), + ), + ), + ), + ), + // Container( + // decoration: BoxDecoration( + // color: Colors.white, + // borderRadius: BorderRadius.circular(12), + // boxShadow: [ + // BoxShadow( + // color: Colors.black12, + // blurRadius: 8, + // offset: Offset(0, 4), + // ), + // ], + // ), + // child: + // BarChart( + // BarChartData( + // alignment: BarChartAlignment.spaceAround, + // maxY: 20, + // barTouchData: BarTouchData(enabled: false), + // titlesData: FlTitlesData( + // leftTitles: AxisTitles( + // sideTitles: SideTitles( + // showTitles: true, + // getTitlesWidget: (value, meta) { + // return Padding( + // padding: const EdgeInsets.only(right: 8.0), + // child: Text('${value.toInt()}K'), + // ); + // }, + // reservedSize: 40, + // ), + // ), + // bottomTitles: AxisTitles( + // sideTitles: SideTitles( + // showTitles: true, + // getTitlesWidget: (value, meta) { + // return Padding( + // padding: const EdgeInsets.only(top: 8.0), + // child: Text(xAxisData[value.toInt()]), + // ); + // }, + // reservedSize: 40, + // ), + // ), + // ), + // gridData: FlGridData(show: false), + // borderData: FlBorderData(show: false), + // barGroups: List.generate( + // xAxisData.length, + // (index) => BarChartGroupData( + // x: index, + // barRods: [ + // BarChartRodData( + // toY: yAxisData[index], + // color: Colors.blueAccent, + // //colors: [Colors.blueAccent], + // borderRadius: BorderRadius.circular(4), + // width: 20, + // ), + // ], + // ), + // ), + // ), + // ), + // ), + + ], + ), + ), + ) + ], + ), + ), + + + ),) + ] + ), + ), mycenterTitle: false, + + ); + } +} + diff --git a/lib/presentation/Screens/Bottom Navigation Pages/UAE_Numbers/uae_numbers.dart b/lib/presentation/Screens/Bottom Navigation Pages/UAE_Numbers/uae_numbers.dart new file mode 100644 index 00000000..51c0e2aa --- /dev/null +++ b/lib/presentation/Screens/Bottom Navigation Pages/UAE_Numbers/uae_numbers.dart @@ -0,0 +1,340 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:uae_stat/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart'; +import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart'; +import 'package:uae_stat/presentation/components/constant/constant.dart'; + +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() + uaenumberWidget()); + } +} + +class uaenumberWidget extends StatelessWidget { + const uaenumberWidget({super.key}); + + @override + Widget build(BuildContext context) { + double myheight = MediaQuery.of(context).size.height; + double mywidth = MediaQuery.of(context).size.width; + return Padding( + padding: const EdgeInsets.all(16.0), + child: ListView( + 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([ + InkWell(onTap : (){ + context.go('/marriages'); + },child: buildCard(context,'Marriages', '96%', '2023',socialColor,socialColor,mywidth/2.5)), + InkWell(onTap : (){},child: buildCard(context,'Divorces', '1.2K', '2024',socialColor,socialColor,mywidth/2.5)), + ]), + buildCategoryTitle('Education', socialColor), + buildCardRow([ + buildCard(context, 'General Education', '96%', '2023', + socialColor, socialColor, mywidth / 2.5), + buildCard(context, 'Higher Education', '1.2K', '2024', + socialColor, socialColor, mywidth / 2.5), + ]), + buildCategoryTitle('Health', socialColor), + buildCardRow([ + buildCard(context, 'Hospital', '96%', '2023', socialColor, + socialColor, mywidth / 2.5), + buildCard(context, 'Clinic and Centres', '1.2K', '2024', + socialColor, socialColor, mywidth / 2.5), + ]), + ], + ), + CustomExpandableTile( + title: 'ENVIRONMENT', + titleBackgroundColor: environmentColor, + children: [ + buildCategoryTitle('Agriculture', environmentColor), + buildCardRow([ + buildCard(context, 'Crops - Total Area', '27°C', 'Average 2024', + environmentColor, environmentColor, mywidth / 2.5), + buildCard(context, 'Livestock', '120mm', '2024', + environmentColor, environmentColor, mywidth / 2.5), + ]), + buildCategoryTitle('Environment', environmentColor), + buildCardRow([ + buildCard(context, 'Climate - Max Temp', '15%', '2024', + environmentColor, environmentColor, mywidth / 2.5), + buildCard(context, 'Climate - Min Temp', '30%', '2023', + environmentColor, environmentColor, mywidth / 2.5), + ]), + buildCardRow([ + buildCard(context, 'Desalinated Produced Water', '15%', '2024', + environmentColor, environmentColor, mywidth / 2.5), + buildCard(context, 'Area of Natural Reserves', '30%', '2023', + environmentColor, environmentColor, mywidth / 2.5), + ]), + buildCategoryTitle('Energy', environmentColor), + buildCardRow([ + buildCard(context, 'Electricity Production', '15%', '2024', + environmentColor, environmentColor, mywidth / 2.5), + buildCard(context, 'Renewable Energy Production', '30%', '2023', + environmentColor, environmentColor, mywidth / 2.5), + ]), + ], + ), + ], + ), + ); + } + + 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: 2.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, + 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/country_profile.dart b/lib/presentation/Screens/Bottom Navigation Pages/country_profile.dart deleted file mode 100644 index 8d3f1081..00000000 --- a/lib/presentation/Screens/Bottom Navigation Pages/country_profile.dart +++ /dev/null @@ -1,31 +0,0 @@ -import 'package:flutter/material.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) { - return Center(child: Text("COuntry Profile"),); - } -} - - - diff --git a/lib/presentation/Screens/Bottom Navigation Pages/uae_numbers.dart b/lib/presentation/Screens/Bottom Navigation Pages/uae_numbers.dart deleted file mode 100644 index b1899ffa..00000000 --- a/lib/presentation/Screens/Bottom Navigation Pages/uae_numbers.dart +++ /dev/null @@ -1,292 +0,0 @@ -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}); - - @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() - uaenumberWidget()); - } -} - -class uaenumberWidget extends StatelessWidget { - const uaenumberWidget({super.key}); - - @override - Widget build(BuildContext context) { - double myheight = MediaQuery.of(context).size.height; - double mywidth = MediaQuery.of(context).size.width; - return Padding( - padding: const EdgeInsets.all(16.0), - child: ListView( - 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,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: 2.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/auth_verification/create_new_pw.dart b/lib/presentation/Screens/auth_verification/create_new_pw.dart index 1d0ddbda..1fa3a802 100644 --- a/lib/presentation/Screens/auth_verification/create_new_pw.dart +++ b/lib/presentation/Screens/auth_verification/create_new_pw.dart @@ -6,6 +6,7 @@ import 'package:uae_stat/config/my_router.dart'; import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/presentation/Screens/profilepage.dart'; import 'package:uae_stat/presentation/components/space.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import '../../../config/my_theme.dart'; @@ -206,7 +207,8 @@ class _CreateNewPwState extends State { children: [ SizedBox(height: screenHeight / 6), Text( - "Create New Password", + // "Create New Password", + AppLocalizations.of(context)!.create_new_password, style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, @@ -216,7 +218,8 @@ class _CreateNewPwState extends State { TextFormField( obscureText: _obscureOldPassword, decoration: InputDecoration( - hintText: 'Enter old password', + // hintText: 'Enter old password', + hintText: AppLocalizations.of(context)!.old_password, prefixIcon: Icon(Icons.lock, color: Colors.blue), suffixIcon: IconButton( icon: Icon( @@ -240,7 +243,8 @@ class _CreateNewPwState extends State { TextFormField( obscureText: _obscureNewPassword, decoration: InputDecoration( - hintText: 'Enter new password', + // hintText: 'Enter new password', + hintText: AppLocalizations.of(context)!.enter_new_password, prefixIcon: Icon(Icons.lock, color: Colors.blue), suffixIcon: IconButton( icon: Icon( @@ -263,7 +267,8 @@ class _CreateNewPwState extends State { TextFormField( obscureText: _obscureConfirmPassword, decoration: InputDecoration( - hintText: 'Confirm new password', + // hintText: 'Confirm new password', + hintText: AppLocalizations.of(context)!.confirm_new_password, prefixIcon: Icon(Icons.lock, color: Colors.blue), suffixIcon: IconButton( icon: Icon( @@ -306,7 +311,7 @@ class _CreateNewPwState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ Text( - "Save", + AppLocalizations.of(context)!.save, style: TextStyle(fontSize: 18, color: Colors.white), ), SizedBox(width: 2), @@ -348,7 +353,8 @@ class _CreateNewPwState extends State { Icon(Icons.check_circle_outlined, color: Color(0xFF8AC681), size: 80), SizedBox(height: 20), Text( - "Password Changed Successfully", + // "Password Changed Successfully", + AppLocalizations.of(context)!.password_changed_successfully, textAlign: TextAlign.center, style: TextStyle( fontSize: 16, diff --git a/lib/presentation/Screens/auth_verification/registration.dart b/lib/presentation/Screens/auth_verification/registration.dart index 8b69722d..cd4fd874 100644 --- a/lib/presentation/Screens/auth_verification/registration.dart +++ b/lib/presentation/Screens/auth_verification/registration.dart @@ -1,11 +1,15 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:pocketbase/pocketbase.dart'; import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/presentation/Screens/profilepage.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:uae_stat/presentation/components/indicators/locale_provider.dart'; +import '../../components/my_toggle.dart'; import '../../routes/auth_routes/login_route.dart'; class RegisterScreen extends StatefulWidget { @@ -287,6 +291,32 @@ class _RegisterScreenState extends State { } return Scaffold( + appBar: AppBar( + actions: [ + Consumer( + builder: (context, ref, _) { + final locale = ref.watch(localeProvider); // Current locale + return + MyToggle(isOn: locale?.languageCode == 'en', + knobTextWhenOn: 'ع', + knobTextWhenOff: 'EN', + pathColorWhenOn: Colors.grey.shade300, + pathColorWhenOff: Colors.grey.shade300, + onTap: (){ + ref.read(localeProvider.notifier).toggleLocale(); + },); + // IconButton( + // icon: Icon(locale?.languageCode == 'en' + // ? Icons.toggle_off_outlined + // : Icons.toggle_on_outlined,), + // onPressed: () { + // ref.read(localeProvider.notifier).toggleLocale(); + // }, + // ); + }, + ), + ], + ), backgroundColor: Colors.white, body: registrationSuccess ? Padding( @@ -414,12 +444,13 @@ class _RegisterScreenState extends State { children: [ SizedBox(height: screenheight / 15), Text( - 'Register', + // 'Register', + AppLocalizations.of(context)!.register_title, style: TextStyle( fontSize: 32, fontWeight: FontWeight.w400), ), SizedBox(height: 10), - Text('Please enter your details'), + Text(AppLocalizations.of(context)!.register_details), SizedBox(height: 20), // Display this if registration is pending approval @@ -427,7 +458,8 @@ class _RegisterScreenState extends State { controller: _usernameController, focusNode: _focusNodes[0], decoration: InputDecoration( - hintText: _showHints[0] ? 'Username' : null, + // hintText: _showHints[0] ? 'Username' : null, + hintText: _showHints[0] ? AppLocalizations.of(context)!.register_name : null, prefixIcon: Icon( Icons.person, color: Colors.blue, @@ -447,7 +479,8 @@ class _RegisterScreenState extends State { decoration: InputDecoration( // hintText: 'Enter your email', hintText: - _showHints[1] ? 'Enter your email' : null, + _showHints[1] ? AppLocalizations.of(context)!.register_email : null, + // _showHints[1] ? 'Enter your email' : null, prefixIcon: Icon( Icons.email, color: Colors.blue, @@ -470,7 +503,8 @@ class _RegisterScreenState extends State { obscureText: _obscurePassword, decoration: InputDecoration( hintText: - _showHints[2] ? 'Enter your password' : null, + _showHints[2] ? AppLocalizations.of(context)!.register_password : null, + // _showHints[2] ? 'Enter your password' : null, prefixIcon: Icon( Icons.lock, color: Colors.blue, @@ -502,7 +536,8 @@ class _RegisterScreenState extends State { obscureText: _obscureConfirmPassword, decoration: InputDecoration( hintText: - _showHints[3] ? 'Confirm password' : null, + _showHints[3] ? AppLocalizations.of(context)!.register_Confirm_password : null, + // _showHints[3] ? 'Confirm password' : null, prefixIcon: Icon( Icons.lock, color: Colors.blue, @@ -551,17 +586,20 @@ class _RegisterScreenState extends State { Expanded( child: Text.rich( TextSpan( - text: 'I agree to ', + text: AppLocalizations.of(context)!.agree, + // text: 'I agree to ', children: [ TextSpan( - text: 'Terms & Conditions', + text: AppLocalizations.of(context)!.terms_conditions, + // text: 'Terms & Conditions', style: TextStyle(color: Colors.blue), ), - TextSpan(text: ' and '), + TextSpan(text: AppLocalizations.of(context)!.t_and), TextSpan( - text: 'Privacy Policy', + text: AppLocalizations.of(context)!.privacy_policy, style: TextStyle(color: Colors.blue), ), + TextSpan(text: AppLocalizations.of(context)!.conditions), ], ), ), @@ -600,7 +638,8 @@ class _RegisterScreenState extends State { mainAxisSize: MainAxisSize.min, children: [ Text( - "Register", + // "Register", + AppLocalizations.of(context)!.register_title, style: TextStyle( fontSize: 16, color: Colors.white), ), @@ -613,7 +652,7 @@ class _RegisterScreenState extends State { ), SizedBox(height: 10), Text( - "Already have an account?", + AppLocalizations.of(context)!.account_confirmation, style: TextStyle( fontSize: 16, color: Colors.grey[600]), ), @@ -635,7 +674,7 @@ class _RegisterScreenState extends State { mainAxisSize: MainAxisSize.min, children: [ Text( - "Login", + AppLocalizations.of(context)!.login_title, style: TextStyle( fontSize: 16, color: Colors.white), ), diff --git a/lib/presentation/Screens/charts/chart.dart b/lib/presentation/Screens/charts/chart.dart index 1911ddee..a34bf4a4 100644 --- a/lib/presentation/Screens/charts/chart.dart +++ b/lib/presentation/Screens/charts/chart.dart @@ -1035,191 +1035,177 @@ class ChartData { // [ // { -// 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" +// chart_heading :"Guest Nights by Region" +// chart_type :"fl_stacked_bar" +// dataset :"hotels" +// group_by :"GUEST_REGION" +// is_chart :"true" +// kpi :"hotel_occupancy_rate_chart_1" +// main_id :"economy" // response:[ // { // "ObsKey": { -// "DV_TYPE": "D_TOT", // "FREQ": "A", -// "MEASURE": "D", -// "REF_AREA": "AE-DU", -// "SOURCE_DETAIL": "FCSAMD", -// "TIME_PERIOD": "2017", +// "GUEST_REGION": "AF", +// "H_INDICATOR": "GUN", +// "H_TYPE": "_Z", +// "MEASURE": "H", +// "REF_AREA": "AE", +// "SOURCE_DETAIL": "FCSC", +// "TIME_PERIOD": "2016", // "UNIT_MEASURE": "NUMBER" // }, // "ObsValue": { -// "Value": "1484" +// "Value": "2659446" // } // }, // { // "ObsKey": { -// "DV_TYPE": "D_TOT", // "FREQ": "A", -// "MEASURE": "D", -// "REF_AREA": "AE-DU", -// "SOURCE_DETAIL": "FCSAMD", +// "GUEST_REGION": "AF", +// "H_INDICATOR": "GUN", +// "H_TYPE": "_Z", +// "MEASURE": "H", +// "REF_AREA": "AE", +// "SOURCE_DETAIL": "FCSC", +// "TIME_PERIOD": "2017", +// "UNIT_MEASURE": "NUMBER" +// }, +// "ObsValue": { +// "Value": "2721363" +// } +// }, +// { +// "ObsKey": { +// "FREQ": "A", +// "GUEST_REGION": "ASC", +// "H_INDICATOR": "GUN", +// "H_TYPE": "_Z", +// "MEASURE": "H", +// "REF_AREA": "AE", +// "SOURCE_DETAIL": "FCSC", +// "TIME_PERIOD": "2016", +// "UNIT_MEASURE": "NUMBER" +// }, +// "ObsValue": { +// "Value": "16454601" +// } +// }, +// { +// "ObsKey": { +// "FREQ": "A", +// "GUEST_REGION": "ASC", +// "H_INDICATOR": "GUN", +// "H_TYPE": "_Z", +// "MEASURE": "H", +// "REF_AREA": "AE", +// "SOURCE_DETAIL": "FCSC", +// "TIME_PERIOD": "2017", +// "UNIT_MEASURE": "NUMBER" +// }, +// "ObsValue": { +// "Value": "18960773" +// } +// }, +// { +// "ObsKey": { +// "FREQ": "A", +// "GUEST_REGION": "UAE", +// "H_INDICATOR": "GUN", +// "H_TYPE": "_Z", +// "MEASURE": "H", +// "REF_AREA": "AE", +// "SOURCE_DETAIL": "FCSC", // "TIME_PERIOD": "2019", // "UNIT_MEASURE": "NUMBER" // }, // "ObsValue": { -// "Value": "1308" +// "Value": "14286573" // } // }, // { // "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", +// "GUEST_REGION": "UAE", +// "H_INDICATOR": "GUN", +// "H_TYPE": "_Z", +// "MEASURE": "H", // "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", +// "SOURCE_DETAIL": "FCSC", // "TIME_PERIOD": "2020", // "UNIT_MEASURE": "NUMBER" // }, // "ObsValue": { -// "Value": "618" +// "Value": "13982919" // } // }, // { // "ObsKey": { -// "DV_TYPE": "D_EM_EF", // "FREQ": "A", -// "MEASURE": "D", +// "GUEST_REGION": "EC", +// "H_INDICATOR": "GUN", +// "H_TYPE": "_Z", +// "MEASURE": "H", // "REF_AREA": "AE", -// "SOURCE_DETAIL": "FCSAMD", +// "SOURCE_DETAIL": "FCSC", +// "TIME_PERIOD": "2019", +// "UNIT_MEASURE": "NUMBER" +// }, +// "ObsValue": { +// "Value": "19917654" +// } +// }, +// { +// "ObsKey": { +// "FREQ": "A", +// "GUEST_REGION": "EC", +// "H_INDICATOR": "GUN", +// "H_TYPE": "_Z", +// "MEASURE": "H", +// "REF_AREA": "AE", +// "SOURCE_DETAIL": "FCSC", +// "TIME_PERIOD": "2020", +// "UNIT_MEASURE": "NUMBER" +// }, +// "ObsValue": { +// "Value": "10041664" +// } +// }, +// { +// "ObsKey": { +// "FREQ": "A", +// "GUEST_REGION": "OC", +// "H_INDICATOR": "GUN", +// "H_TYPE": "_Z", +// "MEASURE": "H", +// "REF_AREA": "AE", +// "SOURCE_DETAIL": "FCSC", // "TIME_PERIOD": "2017", // "UNIT_MEASURE": "NUMBER" // }, // "ObsValue": { -// "Value": "1717" +// "Value": "1260359" // } // }, // { // "ObsKey": { -// "DV_TYPE": "D_EM_EF", // "FREQ": "A", -// "MEASURE": "D", +// "GUEST_REGION": "OC", +// "H_INDICATOR": "GUN", +// "H_TYPE": "_Z", +// "MEASURE": "H", // "REF_AREA": "AE", -// "SOURCE_DETAIL": "FCSAMD", +// "SOURCE_DETAIL": "FCSC", // "TIME_PERIOD": "2018", // "UNIT_MEASURE": "NUMBER" // }, // "ObsValue": { -// "Value": "1720" +// "Value": "1127282" // } // } // // ] -// 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" +// sub_id :"tourism" +// url :"https://releaseeuaestat.fcsc.gov.ae/rest/data/FCSA,DF_GUEST_REGION,4.3.0/...A..GUN.OTH+OC+AF+EC+AM+AC+ASC+GCC+UAE.?startPeriod=2016&dimensionAtObservation=AllDimensions" // } // ] diff --git a/lib/presentation/Screens/charts/filters/search_filter_helper.dart b/lib/presentation/Screens/charts/filters/search_filter_helper.dart new file mode 100644 index 00000000..afaa9f75 --- /dev/null +++ b/lib/presentation/Screens/charts/filters/search_filter_helper.dart @@ -0,0 +1,33 @@ +import 'dart:convert'; + +import 'package:flutter/cupertino.dart'; + +List filterCharts({ + required List apiData, + required Map> filters, +}) { +// Initialize the filtered data as the original dataset + List filteredData = apiData; + +// Apply filtering for each filter key dynamically + for (var filterKey in filters.keys) { + List? filterValues = filters[filterKey]; + if (filterValues != null && filterValues.isNotEmpty) { + // Filter data based on the current filter key + List currentFilteredData = filteredData.where((item) { + var obsKey = item["ObsKey"]; + return filterValues.contains(obsKey[filterKey]); + }).toList(); + + // If current filter excludes all items, return previous filtered data + if (currentFilteredData.isEmpty) { + return filteredData; + } + + // Update filtered data for the next iteration + filteredData = currentFilteredData; + } + } + print('filteredData $filteredData'); + return filteredData; // Return the final filtered data +} diff --git a/lib/presentation/Screens/charts/models/chart_data.dart b/lib/presentation/Screens/charts/models/chart_data.dart new file mode 100644 index 00000000..227d11fc --- /dev/null +++ b/lib/presentation/Screens/charts/models/chart_data.dart @@ -0,0 +1,13 @@ +class ChartData { + final String xLabel; + final double yValue; + + ChartData({required this.xLabel, required this.yValue}); + + factory ChartData.fromJson(Map json) { + return ChartData( + xLabel: json['x_label'] as String, + yValue: (json['y_value'] as num).toDouble(), + ); + } +} diff --git a/lib/presentation/Screens/charts/screens/chart_screen.dart b/lib/presentation/Screens/charts/screens/chart_screen.dart new file mode 100644 index 00000000..0237b800 --- /dev/null +++ b/lib/presentation/Screens/charts/screens/chart_screen.dart @@ -0,0 +1,600 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:uae_stat/presentation/Screens/charts/services/api_service.dart'; +import 'package:uae_stat/presentation/Screens/charts/widgets/chart_widget.dart'; + +import '../filters/search_filter_helper.dart'; + +class ChartScreen1 extends StatefulWidget { + final String dataSets; + const ChartScreen1({Key? key, required this.dataSets}); + @override + _ChartScreen1State createState() => _ChartScreen1State(); +} + +class _ChartScreen1State extends State { + List> selectedFiltersStorage = []; + final GlobalKey _scaffoldKey = GlobalKey(); + final ApiService apiService = ApiService(); + bool isLoading = true; + List isChartData = []; + List nonChartData = []; + List filterData = []; + List chartsData = []; + List cardData = []; + List originalChartsData = []; + List originalCardData = []; + + @override + void initState() { + super.initState(); + fetchChartData(widget.dataSets); + } + + Future fetchChartData(String dataSets) async { + var data = await apiService.fetchChartData(dataSets); + setState(() { + isChartData = data['isChartData'] ?? []; + nonChartData = data['nonChartData'] ?? []; + filterData = data['filterData'] ?? []; + + originalChartsData = List.from(isChartData); // Store original data + originalCardData = List.from(nonChartData); + + chartsData = isChartData; + cardData = nonChartData; + print('chartsData :- $chartsData'); + print('cardData :- $cardData'); + print('filterData :- $filterData'); + isLoading = false; + }); + print(chartsData); + print(cardData); + } + + 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); + } + + 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, + ), + ), + ], + ), + ), + ], + ), + ), + ); + }, + ); + } + + @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: [ + Expanded( + child: ListView( + 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, filterData, chartsData); + }, + ), + ], + ), + ], + ), + // 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 = apiService.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]), + child: ChartWidget( + chartData: chartsData[index])), + ], + ), + ), + ); + }, + ), + ], + ), + ), + ], + ), + ); + } +} diff --git a/lib/presentation/Screens/charts/services/api_service.dart b/lib/presentation/Screens/charts/services/api_service.dart new file mode 100644 index 00000000..02952e20 --- /dev/null +++ b/lib/presentation/Screens/charts/services/api_service.dart @@ -0,0 +1,184 @@ +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'dart:collection'; + +class ChartData { + final DateTime? xDateTime; + final String? x; // Optional for non-DateTime-based charts + final double y; + + ChartData({this.xDateTime, this.x, required this.y}); +} + +class ApiService { + static const String baseUrl = 'https://pb.venbait.in/api/getDataSet'; + + Future> fetchChartData(String dataSets) async { + List isChartData = []; + List nonChartData = []; + List originalChartsData = []; + List originalCardData = []; + + final url = Uri.parse('$baseUrl?dataset=$dataSets'); + + try { + final response = await http.get(url); + print('data'); + if (response.statusCode == 200) { + final Map jsonData = jsonDecode(response.body); + // Variables to store filtered data + for (var item in jsonData['data']) { + if (item['is_chart'] == 'true') { + isChartData.add(item); + } else if (item['is_chart'] == 'false') { + nonChartData.add(item); + } + } + + // Save original data for reset + // originalChartsData = List.from(isChartData); // Store original data + // originalCardData = List.from(nonChartData); // Store original data + + // Return the data as a Map + return { + 'isChartData': isChartData, + 'nonChartData': nonChartData, + 'filterData': jsonData['filter_data'] + // 'originalChartsData': originalChartsData, + // 'originalCardData': originalCardData, + }; + } else { + throw Exception('Failed to load data'); + } + } catch (error) { + print('Error fetching data: $error'); + return {}; + } + } + + /// Fetch chart data and categorize it into chart and non-chart data + // Future fetchChartData(String dataSets) async { + // final url = Uri.parse('$baseUrl?dataset=$dataSets'); + // + // List isChartData = []; + // List nonChartData = []; + // List originalChartsData = []; + // List originalCardData = []; + // + // try { + // final response = await http.get(url); + // + // if (response.statusCode == 200) { + // final List data = jsonDecode(response.body); + // + // for (var item in data) { + // if (item['is_chart'] == 'true') { + // isChartData.add(item); + // } else if (item['is_chart'] == 'false') { + // nonChartData.add(item); + // } + // } + // + // print('Chart Data: $isChartData'); + // print('Non-Chart Data: $nonChartData'); + // + // originalChartsData = List.from(isChartData); + // originalCardData = List.from(nonChartData); + // + // print('chartsData $isChartData'); + // print('cardData $nonChartData'); + // } else { + // throw Exception('Failed to load data'); + // } + // } catch (error) { + // print('Error fetching data: $error'); + // } + // } + + /// Process non-chart data by extracting and calculating values + Map processNonChartData(dynamic item) { + print('Processing non-chart data...'); + + try { + final response = item['response']; + + final List responseData = response is LinkedHashMap + ? Map.from(response) + : response; + + 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(); + + 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 {}; + } + } + + /// Parse scatter chart data + 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(); + } + + /// Parse stacked bar chart data + List parseStackedBarChartData( + dynamic chartData, String groupByKey, String groupByValue) { + return chartData['response'] + .where((entry) => entry['ObsKey'][groupByKey] == groupByValue) + .map((entry) { + return ChartData( + x: entry['ObsKey']['TIME_PERIOD'], + y: double.tryParse(entry['ObsValue']['Value']) ?? 0.0, + ); + }).toList(); + } +} diff --git a/lib/presentation/Screens/charts/widgets/chart_widget.dart b/lib/presentation/Screens/charts/widgets/chart_widget.dart new file mode 100644 index 00000000..4e7c4836 --- /dev/null +++ b/lib/presentation/Screens/charts/widgets/chart_widget.dart @@ -0,0 +1,632 @@ +import 'dart:math'; + +import 'package:fl_chart/fl_chart.dart'; +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_charts/charts.dart'; + +class ChartWidget extends StatelessWidget { + final dynamic chartData; + + ChartWidget({Key? key, required this.chartData}) : super(key: key); + + String capitalizeAndSplit(String input) { + return input + .split('_') + .map((word) => word[0].toUpperCase() + word.substring(1)) + .join(' '); + } + + List parseStackedBarChartData( + dynamic chartData, String groupByKey, String groupByValue) { + return chartData['response'] + .where((entry) => entry['ObsKey'][groupByKey] == groupByValue) + .map((entry) { + return ChartData( + x: entry['ObsKey']['TIME_PERIOD'], + y: double.tryParse(entry['ObsValue']['Value']) ?? 0.0, + ); + }).toList(); + } + + List parseColumnChartData(dynamic chartData) { + return chartData['response'].map((entry) { + return BarChartGroupData( + x: int.tryParse(entry['ObsKey']['TIME_PERIOD']) ?? 0, + barRods: [ + BarChartRodData( + toY: double.tryParse(entry['ObsValue']['Value']) ?? 0.0, + color: Colors.blue, + width: 16, + borderRadius: BorderRadius.zero, + ), + ], + ); + }).toList(); + } + + List parsePieChartData( + dynamic chartData, + double totalValue, + int? touchedIndex, + ) { + return chartData['response'] + .asMap() + .entries + .map((entry) { + int index = entry.key; + var data = entry.value; + double value = double.tryParse(data['ObsValue']['Value']) ?? 0.0; + double percentage = (value / totalValue) * 100; + bool isTouched = index == touchedIndex; + return PieChartSectionData( + value: value, + color: Colors.primaries[index % Colors.primaries.length], + title: '${percentage.toStringAsFixed(1)}%', + radius: isTouched ? 60 : 50, // Increase size when touched + titleStyle: TextStyle( + fontSize: isTouched ? 12 : 10, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ); + }).toList(); + } + + List generateIndicators(dynamic chartData, groupByValue) { + return chartData['response'].asMap().entries.map((entry) { + int index = entry.key; + var data = entry.value; + Color color = Colors.primaries[index % Colors.primaries.length]; + String title = data['ObsKey'][groupByValue] ?? ''; + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: 16, + height: 16, + decoration: BoxDecoration( + color: color, + shape: BoxShape.circle, + ), + ), + SizedBox(width: 8), + Text( + title, + style: TextStyle(fontSize: 14), + ), + ], + ); + }).toList(); + } + + Set extractGroupByValues(dynamic chartData, String groupByKey) { + return (chartData['response'] as List).map((entry) { + var value = entry['ObsKey'][groupByKey]; + return value != null + ? value.toString() + : ''; // Handle null and ensure conversion to String + }).toSet(); + } + + Widget buildChart(dynamic chartData) { + print('chartDataccccccc $chartData'); + // Extract group_by dynamically from the chartData + if (chartData == null || chartData['response'] == null) { + return Center(child: Text('No chart data available')); + } + + String groupByKey = chartData['group_by'] ?? ''; + print('groupByKey $groupByKey'); + Set groupByValues = extractGroupByValues(chartData, groupByKey); + print('groupByValues $groupByValues'); + + switch (chartData['chart_type']) { + case 'stacked_bar': + String chartTitle = + capitalizeAndSplit(chartData['chart_heading'] ?? ''); + // Define a list of colors + final List uniqueColors = [ + Color(0xFF648CBA), + Color(0xFF90B0D5), + Color(0xFF98BCE5), + Color(0xFFA7B5C5), + Color(0xFFBED3EC), + Color(0xFFD4E3F4), + ]; + return SfCartesianChart( + primaryXAxis: CategoryAxis(), + title: ChartTitle(text: chartData['chart_heading']), + legend: Legend( + isVisible: true, + position: LegendPosition.bottom, + overflowMode: LegendItemOverflowMode.scroll, + ), + tooltipBehavior: TooltipBehavior( + enable: true, // Enable tooltips + format: 'point.x : point.y', // Custom tooltip format + ), + series: >[ + for (int i = 0; i < groupByValues.length; i++) + StackedBarSeries( + dataSource: parseStackedBarChartData( + chartData, groupByKey, groupByValues.elementAt(i)), + xValueMapper: (ChartData data, _) => data.x ?? '', + yValueMapper: (ChartData data, _) => data.y, + name: groupByValues.elementAt(i), + color: uniqueColors[i % uniqueColors.length], + enableTooltip: true, + ), + ], + ); + case 'stacked_column': + String chartTitle = + capitalizeAndSplit(chartData['chart_heading'] ?? ''); + // Define a list of colors + final List uniqueColors = [ + Color(0xFF648CBA), + Color(0xFF90B0D5), + Color(0xFF98BCE5), + Color(0xFFA7B5C5), + Color(0xFFBED3EC), + Color(0xFFD4E3F4), + ]; + return SfCartesianChart( + primaryXAxis: CategoryAxis(), + title: ChartTitle(text: chartData['chart_heading']), + legend: Legend( + isVisible: true, + position: LegendPosition.bottom, + overflowMode: LegendItemOverflowMode.scroll, + ), + tooltipBehavior: TooltipBehavior( + enable: true, // Enable tooltips + format: 'point.x : point.y', // Custom tooltip format + ), + series: >[ + for (int i = 0; i < groupByValues.length; i++) + StackedColumnSeries( + dataSource: parseStackedBarChartData( + chartData, groupByKey, groupByValues.elementAt(i)), + xValueMapper: (ChartData data, _) => data.x ?? '', + yValueMapper: (ChartData data, _) => data.y, + name: groupByValues.elementAt(i), + color: uniqueColors[i % uniqueColors.length], + enableTooltip: true, + ), + ], + ); + case 'column_chart': // Case 3 for fl_chart column chart + return BarChart( + BarChartData( + gridData: FlGridData(show: false), + titlesData: FlTitlesData(show: true), + borderData: FlBorderData(show: false), + barGroups: parseColumnChartData(chartData), + ), + ); + case 'pie_chart': + double totalValue = chartData['response'] + .map( + (entry) => double.tryParse(entry['ObsValue']['Value']) ?? 0.0) + .fold(0.0, (prev, element) => prev + element); + + ValueNotifier touchedIndex = ValueNotifier(null); + + return Column( + children: [ + Text( + chartData['chart_heading'] ?? + 'Pie Chart', // Chart title from data + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w400, + ), + textAlign: TextAlign.center, + ), + SizedBox(height: 20), + Expanded( + child: ValueListenableBuilder( + valueListenable: touchedIndex, + builder: (context, value, child) { + return PieChart( + PieChartData( + sections: parsePieChartData( + chartData, totalValue, touchedIndex.value), + borderData: FlBorderData(show: false), + sectionsSpace: 2, + centerSpaceRadius: 50, + pieTouchData: PieTouchData( + touchCallback: (FlTouchEvent event, pieTouchResponse) { + if (pieTouchResponse?.touchedSection != null && + event is! FlTapUpEvent) { + touchedIndex.value = pieTouchResponse! + .touchedSection!.touchedSectionIndex; + } else { + touchedIndex.value = + null; // Reset when not touching + } + }, + ), + ), + ); + }, + ), + ), + SizedBox(height: 20), + Padding( + padding: + const EdgeInsets.all(8.0), // Add spacing around indicators + child: Wrap( + spacing: 12, + runSpacing: 8, + children: generateIndicators(chartData, chartData['group_by']), + ), + ), + ], + ); + case 'fl_stacked_bar': + // Divide groupByValuesList into chunks of 5 items per row + List groupByValuesList = groupByValues.toList(); + int chunkSize = 5; + List> chunkedGroupByValues = []; + for (int i = 0; i < groupByValuesList.length; i += chunkSize) { + chunkedGroupByValues.add( + groupByValuesList.sublist( + i, + i + chunkSize > groupByValuesList.length + ? groupByValuesList.length + : i + chunkSize), + ); + } + return Column( + children: [ + Text( + chartData['chart_heading'] ?? + 'Pie Chart', // Chart title from data + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w400, + ), + textAlign: TextAlign.center, + ), + SizedBox(height: 10), + AspectRatio( + aspectRatio: 1.5, + child: BarChart( + BarChartData( + alignment: BarChartAlignment.spaceBetween, + barTouchData: BarTouchData( + touchTooltipData: BarTouchTooltipData( + getTooltipItem: + (groupData, groupIndex, rodData, rodIndex) { + // print('groupData $groupData'); + // print('groupIndex $groupIndex'); + // print('rodData $rodData'); + // print('rodIndex $rodIndex'); + // Assume groupedData is passed as a parameter + // List timePeriods = + // groupedData.values.first.keys.toList(); + // String timePeriod = timePeriods[groupIndex]; + // List rodStackItems = + // rodData.rodStackItems; + // + // String tooltipText = ''; + // for (int i = 0; i < rodStackItems.length; i++) { + // double fromY = rodStackItems[i].fromY; + // double toY = rodStackItems[i].toY; + // double value = toY - fromY; + // String groupName = groupedData.keys.elementAt(i); + // + // tooltipText += + // '$timePeriod - ${value.toStringAsFixed(0)} - $groupName\n'; + // } + // + // return BarTooltipItem( + // tooltipText, + // TextStyle(color: Colors.white, fontSize: 12), + // ); + }, + ), + // touchCallback: (BarTouchResponse touchResponse) { + // // Handle touch events, such as hover + // if (touchResponse.touchInput is PointerDownEvent) { + // // If you want to handle touch down events, you can add your logic here. + // print('Bar touched: ${touchResponse.touchInput}'); + // } + // }, + handleBuiltInTouches: true, // Enable built-in touch events + ), + titlesData: FlTitlesData( + show: true, + bottomTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + reservedSize: 28, + getTitlesWidget: (double value, TitleMeta meta) { + return _generateXTitles(chartData)[value.toInt()]; + }, + ), + ), + leftTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + reservedSize: 40, + getTitlesWidget: _generateLeftTitles, + ), + ), + topTitles: + AxisTitles(sideTitles: SideTitles(showTitles: false)), + rightTitles: + AxisTitles(sideTitles: SideTitles(showTitles: false)), + ), + gridData: FlGridData(show: true), + borderData: FlBorderData(show: false), + barGroups: _generateBarGroups(chartData, groupByKey), + ), + ), + ), + // Legend + Padding( + padding: const EdgeInsets.all(5.0), + child: Wrap( + spacing: 5, + runSpacing: 5, + children: chunkedGroupByValues.map((chunk) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: chunk.map((group) { + List groupByValuesList = groupByValues.toList(); + int index = groupByValuesList.indexOf(group); + Color groupColor = _getColorForGroup(index); + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 5.0), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: 10, + height: 10, + decoration: BoxDecoration( + color: groupColor, + shape: BoxShape.circle, + ), + ), + SizedBox(width: 3), + Text( + group, + overflow: TextOverflow.ellipsis, + style: TextStyle(fontSize: 11), + ), + ], + ), + ); + }).toList(), + ); + }).toList(), + ), + ), + ], + ); + case 'fl_multi_bar': + return BarChart( + BarChartData( + alignment: BarChartAlignment.spaceAround, + maxY: 100, // Maximum value for the bar + barGroups: _buildBarGroups(), + titlesData: FlTitlesData( + leftTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + getTitlesWidget: (value, meta) { + return Text( + '${value.toInt()}%', + style: TextStyle(fontSize: 12), + ); + }, + ), + ), + bottomTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + getTitlesWidget: (value, meta) { + return Text( + "Bar ${value.toInt()}", + style: TextStyle(fontSize: 12), + ); + }, + ), + ), + topTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)), + rightTitles: + AxisTitles(sideTitles: SideTitles(showTitles: false)), + ), + borderData: FlBorderData( + show: false, + ), + barTouchData: BarTouchData(enabled: true), + gridData: FlGridData(show: false), + ), + ); + default: + return Center(child: Text('Unknown chart type')); + } + } + + // Define the list of unique colors + final List uniqueColors = [ + Color(0xFF648CBA), + Color(0xFF90B0D5), + Color(0xFF98BCE5), + Color(0xFFA7B5C5), + Color(0xFFBED3EC), + Color(0xFFD4E3F4), + ]; + + Color _getColorForGroup(int index) { + // Use the index to get a color from the uniqueColors list + return uniqueColors[index % uniqueColors.length]; + } + + List _generateBarGroups( + dynamic chartData, String groupByKey) { + Map> groupedData = {}; + + // Group data by `group_by` and `TIME_PERIOD`, accumulating the values for each group and year + for (var entry in chartData['response']) { + String groupValue = entry['ObsKey'][groupByKey]; + String timePeriod = entry['ObsKey']['TIME_PERIOD']; + double value = double.tryParse(entry['ObsValue']['Value']) ?? 0.0; + + // print('fl_groupValue $groupValue'); + // print('fl_timePeriod $timePeriod'); + // print('fl_value $value'); + + if (!groupedData.containsKey(groupValue)) { + groupedData[groupValue] = {}; + } + if (!groupedData[groupValue]!.containsKey(timePeriod)) { + groupedData[groupValue]![timePeriod] = 0.0; + } + groupedData[groupValue]![timePeriod] = + groupedData[groupValue]![timePeriod]! + value; + } + + // Create BarChartGroupData for each group + List barGroups = []; + List timePeriods = groupedData.values.first.keys.toList(); + print('timePeriods $timePeriods'); + + // For each time period, generate a BarChartGroupData + for (int i = 0; i < timePeriods.length; i++) { + // Intermediate variable to track the current toY value as we stack bars + double currentToY = 0; + + List rodStackItems = []; + + // For each group (e.g., region), create stacked bars + int groupIndex = 0; // Track group index for color assignment + for (var group in groupedData.keys) { + double value = groupedData[group]![timePeriods[i]] ?? 0.0; + + // Add stacked item with current `toY` value and the incremented one + rodStackItems.add( + BarChartRodStackItem( + currentToY, // The current bottom of the stack + currentToY + value, // The new top of the stack + _getColorForGroup(groupIndex), // Color based on the index + ), + ); + + // Update currentToY after adding the value for this stack + currentToY += value; + + groupIndex++; // Increment group index for the next group + } + + // Create BarChartGroupData with the final stacked value + BarChartGroupData barGroup = BarChartGroupData( + x: i, // Index for the x-axis based on the time period + barRods: [ + BarChartRodData( + toY: currentToY, // Use the accumulated `currentToY` value + rodStackItems: rodStackItems, // Add the stacked items + width: 20, + borderRadius: BorderRadius.zero, + color: Colors + .transparent, // This will act as a container for stacked items + ), + ], + ); + + barGroups.add(barGroup); + } + + return barGroups; + } + + // Function to dynamically generate titles for the x-axis (time periods) + List _generateXTitles(dynamic chartData) { + Set timePeriods = {}; + for (var entry in chartData['response']) { + timePeriods.add(entry['ObsKey']['TIME_PERIOD']); + } + return timePeriods.map((period) { + return Text( + period, + style: TextStyle(fontSize: 12), + ); + }).toList(); + } + +// Function to dynamically set left axis titles (values) + Widget _generateLeftTitles(double value, TitleMeta meta) { + if (value % 1000 == 0) { + return Text(value.toStringAsFixed(0), style: TextStyle(fontSize: 10)); + } + return Container(); + } + + /// Build the data for the bar groups + List _buildBarGroups() { + return [ + BarChartGroupData( + x: 1, // Identifier for the group + barRods: [ + BarChartRodData( + toY: 40, // Value for the first part of the stack + color: Colors.blue, + width: 10, + ), + BarChartRodData( + toY: 60, // Value for the second part of the stack + color: Colors.green, + width: 10, + ), + ], + ), + BarChartGroupData( + x: 2, + barRods: [ + BarChartRodData( + toY: 30, + color: Colors.orange, + width: 10, + ), + BarChartRodData( + toY: 70, + color: Colors.red, + width: 10, + ), + ], + ), + BarChartGroupData( + x: 3, + barRods: [ + BarChartRodData( + toY: 50, + color: Colors.purple, + width: 10, + ), + BarChartRodData( + toY: 50, + color: Colors.cyan, + width: 10, + ), + ], + ), + ]; + } + + @override + Widget build(BuildContext context) { + return buildChart(chartData); + } +} + +class ChartData { + final String? x; + final double y; + final DateTime? xDateTime; + + ChartData({this.x, required this.y, this.xDateTime}); +} diff --git a/lib/presentation/components/indicators/locale_provider.dart b/lib/presentation/components/indicators/locale_provider.dart new file mode 100644 index 00000000..45ef764b --- /dev/null +++ b/lib/presentation/components/indicators/locale_provider.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + + +class LocaleNotifier extends StateNotifier { + LocaleNotifier() : super(const Locale('en')); // Default locale is English + + /// Toggles between English and Arabic + void toggleLocale() { + state = (state == const Locale('en')) ? const Locale('ar') : const Locale('en'); + } + + + void setLocale(Locale locale) { + state = locale; + } +} + +final localeProvider = StateNotifierProvider( + (ref) => LocaleNotifier(), +); 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 70ed8841..9779c61f 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 @@ -177,11 +177,11 @@ void handleInfoCardClick(BuildContext context, String data) { final dataSets = data; print(dataSets); if (dataSets == 'hotels') { - context.go('/Chart/$dataSets'); + context.go('/chartScreen/$dataSets'); } else if (dataSets == 'divorces') { - context.go('/Chart/$dataSets'); + context.go('/chartScreen/$dataSets'); } else if (dataSets == 'marriages') { - context.go('/Chart/$dataSets'); + context.go('/chartScreen/$dataSets'); } } @@ -191,11 +191,11 @@ class _MyHomePageState extends State { 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')))), + mycenterTitle: true, + title: SizedBox( + height: myheight / 5, + width: mywidth / 3, + child: Image(image: AssetImage('assets/logos/uae_stat.png'))), body: EconomyStats(), ); } diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/edit_profile.dart b/lib/presentation/routes/drawer_routes/Drawer Items/edit_profile.dart index 8c513234..74aa69b1 100644 --- a/lib/presentation/routes/drawer_routes/Drawer Items/edit_profile.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/edit_profile.dart @@ -10,7 +10,7 @@ import 'package:image_picker/image_picker.dart'; import 'package:intl/intl.dart'; import 'package:pocketbase/pocketbase.dart'; import 'package:shared_preferences/shared_preferences.dart'; - +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import '../../../Screens/auth_verification/changepassword.dart'; import '../custom_drawer_routes.dart'; @@ -372,7 +372,7 @@ class _EditProfileState extends State { @override Widget build(BuildContext context) { return BaseScaffold( - title: Text("Profile"), + title: Text(AppLocalizations.of(context)!.my_profile), body: SingleChildScrollView( child: Padding( padding: const EdgeInsets.only(left: 10.0, right: 10.0, top: 3.0), @@ -418,7 +418,7 @@ class _EditProfileState extends State { mainAxisAlignment: MainAxisAlignment.start, children: [ Text( - "User Name", + AppLocalizations.of(context)!.register_name, style: TextStyle( fontSize: 16, fontWeight: FontWeight.w500, @@ -444,7 +444,7 @@ class _EditProfileState extends State { mainAxisAlignment: MainAxisAlignment.start, children: [ Text( - "Email ID", + AppLocalizations.of(context)!.email_id, style: TextStyle( fontSize: 16, fontWeight: FontWeight.w500, @@ -469,7 +469,7 @@ class _EditProfileState extends State { mainAxisAlignment: MainAxisAlignment.start, children: [ Text( - "Full Name*", + AppLocalizations.of(context)!.full_name, style: TextStyle( fontSize: 16, fontWeight: FontWeight.w500, @@ -543,7 +543,7 @@ class _EditProfileState extends State { mainAxisAlignment: MainAxisAlignment.start, children: [ Text( - "Country/Region*", + AppLocalizations.of(context)!.region, style: TextStyle( fontSize: 16, fontWeight: FontWeight.w500), ), @@ -602,12 +602,12 @@ class _EditProfileState extends State { SizedBox(height: 10), Text.rich( TextSpan( - text: 'I agree to the ', + text: AppLocalizations.of(context)!.agree, style: TextStyle(color: Colors.black), children: [ TextSpan( - text: 'Terms & Conditions', + text: AppLocalizations.of(context)!.terms_conditions, style: TextStyle( color: Colors.blue, decoration: @@ -620,12 +620,12 @@ class _EditProfileState extends State { }, ), TextSpan( - text: ' and ', + text: AppLocalizations.of(context)!.t_and, style: TextStyle( color: Colors.black), ), TextSpan( - text: 'Privacy Policy', + text: AppLocalizations.of(context)!.privacy_policy, style: TextStyle( color: Colors.blue, decoration: @@ -638,7 +638,7 @@ class _EditProfileState extends State { }, ), TextSpan( - text: ' of FCSC.', + text: AppLocalizations.of(context)!.conditions, style: TextStyle( color: Colors.black), ), @@ -681,7 +681,7 @@ class _EditProfileState extends State { context.go('/createNewPw/$userId/$email'); }, child: Text( - "Change Password", + AppLocalizations.of(context)!.change_password, style: TextStyle( color: Colors.blue, decoration: TextDecoration.underline), @@ -698,7 +698,7 @@ class _EditProfileState extends State { color: Colors.white, ), label: Text( - 'Save', + AppLocalizations.of(context)!.save, style: TextStyle(color: Colors.white), ), style: ElevatedButton.styleFrom( diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/feedback.dart b/lib/presentation/routes/drawer_routes/Drawer Items/feedback.dart index 7934ed17..9d519562 100644 --- a/lib/presentation/routes/drawer_routes/Drawer Items/feedback.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/feedback.dart @@ -4,6 +4,7 @@ import 'package:flutter_rating_bar/flutter_rating_bar.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:intl/intl.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:pocketbase/pocketbase.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:uae_stat/domain/use_cases/language.dart'; @@ -208,7 +209,8 @@ class _FeedbackFormState extends State @override Widget build(BuildContext context) { return BaseScaffold( - title: Text("Feedback"), + // title: Text("Feedback"), + title: Text(AppLocalizations.of(context)!.feedback_title), // appBar: AppBar( // backgroundColor: const Color(0xFFf8f9ff), // title: Text(context.translate('Feedback Form', 'نموذج الملاحظات')), @@ -464,8 +466,8 @@ class _FeedbackFormState extends State const Text("Failed to Share Feedback", style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)), const SizedBox(height: 10), - const Text("Your feedback could not be submitted. Please try again.", - style: TextStyle(fontSize: 16), textAlign: TextAlign.center), + Text(AppLocalizations.of(context)!.feedback_failed_msg, + style: const TextStyle(fontSize: 16), textAlign: TextAlign.center), const SizedBox(height: 30), ElevatedButton( onPressed: () { diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/manage_users.dart b/lib/presentation/routes/drawer_routes/Drawer Items/manage_users.dart index 8652db61..0d581a48 100644 --- a/lib/presentation/routes/drawer_routes/Drawer Items/manage_users.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/manage_users.dart @@ -4,6 +4,7 @@ import 'package:pocketbase/pocketbase.dart'; import 'package:uae_stat/presentation/components/my_bottom_nav_bar.dart'; import 'package:uae_stat/presentation/components/my_drawer.dart'; import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class ManageUserRouter extends StatefulWidget { late final Widget title; @@ -18,7 +19,7 @@ class _ManageUserRouterState extends State { bool _isAscending = true; List filteredUserData = []; - final List statusOptions = ['Approved', 'Denied', 'Pending']; + // final List statusOptions = ['Approved', 'Denied', 'Pending']; Color getStatusColor(String status) { switch (status) { @@ -130,7 +131,8 @@ class _ManageUserRouterState extends State { height: myheight / 30, ), Text( - 'Are you sure you want to change \n the status to $newStatus?', + // 'Are you sure you want to change \n the status to $newStatus?', + AppLocalizations.of(context)!.approve_msg(newStatus), style: TextStyle(fontSize: 15), textAlign: TextAlign.center, ), @@ -168,7 +170,7 @@ class _ManageUserRouterState extends State { width: 2.0, // Set the border width ), ), - child: Text('No'), + child: Text(AppLocalizations.of(context)!.no), ), TextButton( onPressed: () async { @@ -207,7 +209,8 @@ class _ManageUserRouterState extends State { ), ), child: Text( - 'Yes', + // 'Yes', + AppLocalizations.of(context)!.yes, style: TextStyle(color: Colors.white), ), ), @@ -221,9 +224,20 @@ class _ManageUserRouterState extends State { @override Widget build(BuildContext context) { + + final Map statusOptions = { + 'Approved': AppLocalizations.of(context)!.approved, + 'Denied': AppLocalizations.of(context)!.denied, + 'Pending': AppLocalizations.of(context)!.pending, + }; + + double myheight = MediaQuery.of(context).size.height; return BaseScaffold( - title: Text("Manage User"), + // title: Text("Manage User"), + title: Text( + AppLocalizations.of(context)!.manage_user, + ), body: SingleChildScrollView( child: Padding( padding: const EdgeInsets.only(left: 10.0, right: 10.0, top: 3.0), @@ -251,21 +265,23 @@ class _ManageUserRouterState extends State { sortAscending: _isAscending, columns: [ DataColumn( - label: const Text('User Name'), + label: Text( + AppLocalizations.of(context)!.user_name, + ), onSort: (columnIndex, ascending) { _sort((user) => user.userName.toLowerCase(), columnIndex, ascending); }, ), DataColumn( - label: const Text('Email ID'), + label: Text( AppLocalizations.of(context)!.email_id,), onSort: (columnIndex, ascending) { _sort((user) => user.emailId.toLowerCase(), columnIndex, ascending); }, ), DataColumn( - label: const Text('Registration Date'), + label: Text(AppLocalizations.of(context)!.reg_date,), onSort: (columnIndex, ascending) { _sort( (user) => DateFormat('dd/MM/yyyy') @@ -276,7 +292,7 @@ class _ManageUserRouterState extends State { }, ), DataColumn( - label: const Text('Status'), + label: Text(AppLocalizations.of(context)!.status,), onSort: (columnIndex, ascending) { _sort((user) => user.status.toLowerCase(), columnIndex, ascending); @@ -311,13 +327,13 @@ class _ManageUserRouterState extends State { DataCell( DropdownButton( value: user.status, - items: statusOptions.map((status) { + items: statusOptions.entries.map((status) { return DropdownMenuItem( - value: status, + value: status.key, child: Text( - status, + status.value, style: TextStyle( - color: getStatusColor(status)), + color: getStatusColor(status.key),), ), ); }).toList(), diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/faq_page.dart b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/faq_page.dart index bf2b4771..880584e7 100644 --- a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/faq_page.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/faq_page.dart @@ -18,7 +18,7 @@ class _FAQPageState extends State { color:Color(0xFF7296BE), fontWeight: FontWeight.w500, ),), - showBackIcon: true, + showBackButton: true, body: SafeArea(child:Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/features.dart b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/features.dart index 9ad1c659..fa8bb66a 100644 --- a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/features.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/features.dart @@ -521,7 +521,7 @@ class UsingFeatures extends StatelessWidget { style: TextStyle( color: Color(0xFFAA8E83), ),), - showBackIcon: true, + showBackButton: true, body:SafeArea(child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/getting_started.dart b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/getting_started.dart index ad4510b6..c4dafe91 100644 --- a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/getting_started.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/getting_started.dart @@ -72,7 +72,7 @@ class GettingStarted extends StatelessWidget { fontWeight: FontWeight.w500, ), ), - showBackIcon: true, + showBackButton: true, body:SafeArea(child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart b/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart index 5d1ef116..2f97d780 100644 --- a/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart +++ b/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart @@ -1,144 +1,113 @@ import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.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'; +import 'package:uae_stat/presentation/components/my_toggle.dart'; +import 'package:uae_stat/presentation/components/indicators/locale_provider.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -class BaseScaffold extends StatefulWidget { +class BaseScaffold extends ConsumerWidget { final Widget body; final Widget title; + final bool ? showBackButton; + final bool ? mycenterTitle; final List? actions; - final bool showBackIcon; - final VoidCallback? onBackIconPressed; + final Color? appbarColor, mytitleColor; const BaseScaffold({ Key? key, required this.body, required this.title, this.actions, - this.showBackIcon=false, - this.onBackIconPressed, + this.showBackButton = false, + this.mycenterTitle = false, this.appbarColor, this.mytitleColor }) : 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) { + Widget build(BuildContext context ,WidgetRef ref) { + final locale = ref.watch(localeProvider); + final localeNotifier = ref.read(localeProvider.notifier); // Get the current route to highlight the active item 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: widget.title, - leading:widget.showBackIcon - ? IconButton( - padding: EdgeInsets.zero, - icon: const Icon(Icons.arrow_back_ios_new_sharp), - onPressed: widget.onBackIconPressed ?? - () { - Navigator.of(context).pop(); // Default back button behavior - }, - ) : null, - 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)), - if (widget.showBackIcon) - Builder( - builder: (context) => IconButton( - padding: EdgeInsets.zero, - icon: const Icon(Icons.menu), - onPressed: () { - Scaffold.of(context).openDrawer(); // Opens the drawer + appBar: AppBar(title: title, backgroundColor : appbarColor,actions: [ + // IconButton(onPressed: () {}, icon: Icon(Icons.toggle_off_outlined)), + MyToggle(isOn: locale?.languageCode == 'en', + knobTextWhenOn: 'ع', + knobTextWhenOff: 'EN', + pathColorWhenOn: Colors.grey.shade300, + pathColorWhenOff: Colors.grey.shade300, + onTap: (){ + ref.read(localeProvider.notifier).toggleLocale(); + },), + ], + leading: + // Stack( + // children: [ + // // Show the back button if showBackButton is true, otherwise show the drawer menu + // if (showBackButton == true) + // Positioned( + // left: 0, + // child: IconButton( + // color: Colors.white, + // icon: Icon(Icons.arrow_back_ios_new), + // onPressed: () { + // Navigator.of(context).pop(); + // }, + // ), + // ), + // // Show the drawer icon in all cases + // Positioned( + // right: 0, + // child: IconButton( + // color: (showBackButton == true)? Colors.white : Colors.black, + // icon: Icon(Icons.menu), + // onPressed: () { + // // Open the drawer using the Scaffold context + // Scaffold.of(context).openDrawer(); + // }, + // ), + // ), + // ], + // ), + + Stack( + children: [ + // Show the back button if showBackButton is true + if (showBackButton == true) + Positioned( + left: 15, + child: IconButton( + color: Colors.white, + icon: Icon(Icons.arrow_back_ios_new), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ), + // Show the drawer icon in all cases + Positioned( + right: 10, + child: Builder( + builder: (BuildContext context) { + return IconButton( + color: (showBackButton == true) ? Colors.white : Colors.black, + icon: Icon(Icons.menu), + onPressed: () { + // Open the drawer using the Scaffold context + Scaffold.of(context).openDrawer(); + }, + ); }, ), ), - ], + ], + ) + ), drawer: Drawer( child: ListView( @@ -162,39 +131,18 @@ class _BaseScaffoldState extends State { child: Row( children: [ SizedBox( - 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')) - ), + width: mywidth / 8, + child: Image( + image: AssetImage( + 'assets/edit_profile/profile.png'))), SizedBox( width: mywidth / 20, ), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - // Text(userId ?? 'Loading user...'), // Display userId here - // Text('Mohammad@fcsc.com') - Text(userName ?? 'Loading...'), - Text( - userEmail ?? 'Loading...', - style: TextStyle(fontSize: 12), - ), + Text('Mohammad'), + Text('Mohammad@fcsc.com') ], ) ], @@ -203,44 +151,33 @@ class _BaseScaffoldState extends State { ], ), ), - 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/book.png'))), - title: Text('User Guide'), - onTap: () => context.go('/user-guide'), + 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/logout.png'))), - title: Text('Logout'), - onTap: () => context.go('/'), + image: AssetImage('assets/icons/drawer/manageuser.png'))), + title: Text(AppLocalizations.of(context)!.manage_user), + onTap: () => context.go('/manageuser'), + ), + + ListTile( + leading: SizedBox( + height: myheight / 15, + width: mywidth / 15, + child: Image( + image: AssetImage('assets/icons/drawer/book.png'))), + title: Text('User Guide'), + onTap: () => context.go('/user-guide'), ), ], ), @@ -286,20 +223,20 @@ class _BaseScaffoldState extends State { unselectedItemColor: Colors.grey, showUnselectedLabels: true, ), - body: widget.body, + body: body, ); } - // Map the current route to the selected index + //Map the current route to the selected index int _getSelectedIndex(String route) { switch (route) { - case '/myhomepage': + case '/': return 0; - case '/about': + case '/uaenumbers': return 1; - case '/settings': + case '/competitiveness': return 2; - case '/profile': + case '/countryprofile': return 3; default: return 0; @@ -310,16 +247,16 @@ class _BaseScaffoldState extends State { void _onItemTapped(BuildContext context, int index) { switch (index) { case 0: - context.go('/myhomepage'); + 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; } } diff --git a/pubspec.lock b/pubspec.lock index 7f0df837..827e44dc 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -435,10 +435,10 @@ packages: dependency: "direct dev" description: name: flutter_native_splash - sha256: "1152ab0067ca5a2ebeb862fe0a762057202cceb22b7e62692dcbabf6483891bb" + sha256: "7062602e0dbd29141fb8eb19220b5871ca650be5197ab9c1f193a28b17537bc7" url: "https://pub.dev" source: hosted - version: "2.4.3" + version: "2.4.4" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -467,26 +467,26 @@ packages: dependency: "direct main" description: name: flutter_secure_storage - sha256: "165164745e6afb5c0e3e3fcc72a012fb9e58496fb26ffb92cf22e16a821e85d0" + sha256: "1913841ac4c7bf57cd2e05b717e1fbff7841b542962feff827b16525a781b3e4" url: "https://pub.dev" source: hosted - version: "9.2.2" + version: "9.2.3" flutter_secure_storage_linux: dependency: transitive description: name: flutter_secure_storage_linux - sha256: "4d91bfc23047422cbcd73ac684bc169859ee766482517c22172c86596bf1464b" + sha256: bf7404619d7ab5c0a1151d7c4e802edad8f33535abfbeff2f9e1fe1274e2d705 url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" flutter_secure_storage_macos: dependency: transitive description: name: flutter_secure_storage_macos - sha256: "1693ab11121a5f925bbea0be725abfcfbbcf36c1e29e571f84a0c0f436147a81" + sha256: "6c0a2795a2d1de26ae202a0d78527d163f4acbb11cde4c75c670f3a0fc064247" url: "https://pub.dev" source: hosted - version: "3.1.2" + version: "3.1.3" flutter_secure_storage_platform_interface: dependency: transitive description: @@ -511,6 +511,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.2" + flutter_staggered_grid_view: + dependency: "direct main" + description: + name: flutter_staggered_grid_view + sha256: "19e7abb550c96fbfeb546b23f3ff356ee7c59a019a651f8f102a4ba9b7349395" + url: "https://pub.dev" + source: hosted + version: "0.7.0" flutter_test: dependency: "direct dev" description: flutter @@ -573,10 +581,10 @@ packages: dependency: "direct main" description: name: go_router - sha256: "2fd11229f59e23e967b0775df8d5948a519cd7e1e8b6e849729e010587b46539" + sha256: "7c2d40b59890a929824f30d442e810116caf5088482629c894b9e4478c67472d" url: "https://pub.dev" source: hosted - version: "14.6.2" + version: "14.6.3" graphs: dependency: transitive description: @@ -669,10 +677,10 @@ packages: dependency: transitive description: name: image_picker_ios - sha256: "4f0568120c6fcc0aaa04511cb9f9f4d29fc3d0139884b1d06be88dcec7641d6b" + sha256: "05da758e67bc7839e886b3959848aa6b44ff123ab4b28f67891008afe8ef9100" url: "https://pub.dev" source: hosted - version: "0.8.12+1" + version: "0.8.12+2" image_picker_linux: dependency: transitive description: @@ -693,10 +701,10 @@ packages: dependency: transitive description: name: image_picker_platform_interface - sha256: "9ec26d410ff46f483c5519c29c02ef0e02e13a543f882b152d4bfd2f06802f80" + sha256: "886d57f0be73c4b140004e78b9f28a8914a09e50c2d816bdd0520051a71236a0" url: "https://pub.dev" source: hosted - version: "2.10.0" + version: "2.10.1" image_picker_windows: dependency: transitive description: @@ -1100,10 +1108,10 @@ packages: dependency: "direct main" description: name: shared_preferences - sha256: "3c7e73920c694a436afaf65ab60ce3453d91f84208d761fbd83fc21182134d93" + sha256: a752ce92ea7540fc35a0d19722816e04d0e72828a4200e83a98cf1a1eb524c9a url: "https://pub.dev" source: hosted - version: "2.3.4" + version: "2.3.5" shared_preferences_android: dependency: transitive description: @@ -1504,18 +1512,18 @@ packages: dependency: transitive description: name: webview_flutter_wkwebview - sha256: b7e92f129482460951d96ef9a46b49db34bd2e1621685de26e9eaafd9674e7eb + sha256: "4adc14ea9a770cc9e2c8f1ac734536bd40e82615bd0fa6b94be10982de656cc7" url: "https://pub.dev" source: hosted - version: "3.16.3" + version: "3.17.0" win32: dependency: transitive description: name: win32 - sha256: "8b338d4486ab3fbc0ba0db9f9b4f5239b6697fcee427939a40e720cbb9ee0a69" + sha256: "154360849a56b7b67331c21f09a386562d88903f90a1099c5987afc1912e1f29" url: "https://pub.dev" source: hosted - version: "5.9.0" + version: "5.10.0" xdg_directories: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 96c06d7a..68b54414 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -20,7 +20,9 @@ dependencies: injectable: ^2.3.2 riverpod_annotation: ^2.3.3 cupertino_icons: ^1.0.6 + fl_chart: ^0.69.2 + marquee: ^2.2.3 url_launcher: ^6.3.1 # dynamic_layouts: @@ -57,6 +59,7 @@ dependencies: image_picker: ^1.1.2 syncfusion_flutter_charts: 28.1.33 material_charts: ^0.0.23 + flutter_staggered_grid_view: ^0.7.0 dependency_overrides: fading_edge_scrollview: ^4.1.1 @@ -77,6 +80,7 @@ dev_dependencies: # flutter_splash_screen: ^3.0.0 flutter: + generate: true uses-material-design: true assets: - assets/user_guide_videos/