Language Translation
This commit is contained in:
commit
069db374fa
3
l10n.yaml
Normal file
3
l10n.yaml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
arb-dir: lib/l10n
|
||||||
|
template-arb-file: intl_en.arb
|
||||||
|
output-localization-file: app_localizations.dart
|
||||||
@ -294,20 +294,23 @@
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.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/UAE_Numbers/Social/marriages.dart';
|
||||||
import 'package:uae_stat/presentation/Screens/Bottom%20Navigation%20Pages/country_profile.dart';
|
|
||||||
import 'package:uae_stat/presentation/Screens/Bottom%20Navigation%20Pages/uae_numbers.dart';
|
|
||||||
import 'package:uae_stat/presentation/Screens/auth_verification/registration.dart';
|
import 'package:uae_stat/presentation/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/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/Drawer%20Items/user_guide/getting_started.dart';
|
||||||
import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.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 '../domain/use_cases/preferences_use_case.dart';
|
||||||
import '../presentation/Screens/auth_verification/changepassword.dart';
|
import '../presentation/Screens/auth_verification/changepassword.dart';
|
||||||
import '../presentation/Screens/auth_verification/confirm_password.dart';
|
import '../presentation/Screens/auth_verification/confirm_password.dart';
|
||||||
import '../presentation/Screens/auth_verification/create_new_pw.dart';
|
import '../presentation/Screens/auth_verification/create_new_pw.dart';
|
||||||
import '../presentation/Screens/auth_verification/otp_verification.dart';
|
import '../presentation/Screens/auth_verification/otp_verification.dart';
|
||||||
import '../presentation/Screens/charts/chart.dart';
|
|
||||||
import '../presentation/Screens/demo_home.dart';
|
import '../presentation/Screens/demo_home.dart';
|
||||||
import '../presentation/Screens/profilepage.dart';
|
import '../presentation/Screens/profilepage.dart';
|
||||||
import '../presentation/routes/auth_routes/login_route.dart';
|
import '../presentation/routes/auth_routes/login_route.dart';
|
||||||
@ -323,8 +326,8 @@ final GoRouter router = GoRouter(
|
|||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/',
|
path: '/',
|
||||||
builder: (context, state) => LoginRoute(),
|
//builder: (context, state) => LoginRoute(),
|
||||||
// builder: (context, state) => MyHomePage(),
|
builder: (context, state) => MyHomePage(),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/login',
|
path: '/login',
|
||||||
@ -355,6 +358,15 @@ final GoRouter router = GoRouter(
|
|||||||
return ChartScreen(dataSets: dataSets);
|
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(
|
GoRoute(
|
||||||
path: '/mailverification',
|
path: '/mailverification',
|
||||||
builder: (context, state) => EmailVerificationScreen(
|
builder: (context, state) => EmailVerificationScreen(
|
||||||
@ -439,9 +451,13 @@ final GoRouter router = GoRouter(
|
|||||||
),
|
),
|
||||||
|
|
||||||
// Bottom Navigation Routes
|
// Bottom Navigation Routes
|
||||||
|
// GoRoute(
|
||||||
|
// path: '/uaenumbers',
|
||||||
|
// builder: (context, state) => UaeNumbers(),
|
||||||
|
// ),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/uaenumbers',
|
path: '/uaenumbers',
|
||||||
builder: (context, state) => UaeNumbers(),
|
builder: (context,state) => UaeNumbers()
|
||||||
),
|
),
|
||||||
|
|
||||||
GoRoute(
|
GoRoute(
|
||||||
@ -453,5 +469,10 @@ final GoRouter router = GoRouter(
|
|||||||
path: '/countryprofile',
|
path: '/countryprofile',
|
||||||
builder: (context, state) => CountryProfile(),
|
builder: (context, state) => CountryProfile(),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
GoRoute(
|
||||||
|
path: '/marriages',
|
||||||
|
builder: (context, state) => Marriages(),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|||||||
86
lib/l10n/intl_ar.arb
Normal file
86
lib/l10n/intl_ar.arb
Normal file
@ -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": "تأكيد كلمة المرور مطلوب"
|
||||||
|
}
|
||||||
87
lib/l10n/intl_en.arb
Normal file
87
lib/l10n/intl_en.arb
Normal file
@ -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"
|
||||||
|
}
|
||||||
@ -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/domain/use_cases/auth_use_case.dart';
|
||||||
import 'package:uae_stat/presentation/Screens/profilepage.dart';
|
import 'package:uae_stat/presentation/Screens/profilepage.dart';
|
||||||
import 'package:uae_stat/presentation/Screens/auth_verification/registration.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 {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
@ -22,14 +24,19 @@ void main() async {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class MainApp extends StatelessWidget {
|
class MainApp extends ConsumerWidget {
|
||||||
const MainApp({super.key});
|
const MainApp({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final locale = ref.watch(localeProvider);
|
||||||
|
|
||||||
return MaterialApp.router(
|
return MaterialApp.router(
|
||||||
debugShowCheckedModeBanner: false,
|
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
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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<String> xAxisData = ['2019', '2020', '2021', '2022', '2023'];
|
||||||
|
final List<double> 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()));
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -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<String> xAxisData = ['2019', '2020', '2021', '2022', '2023'];
|
||||||
|
final List<double> 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,
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -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<Widget> 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<Widget> children;
|
||||||
|
|
||||||
|
const CustomExpandableTile({
|
||||||
|
required this.title,
|
||||||
|
required this.titleBackgroundColor,
|
||||||
|
required this.children,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
_CustomExpandableTileState createState() => _CustomExpandableTileState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CustomExpandableTileState extends State<CustomExpandableTile> {
|
||||||
|
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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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"),);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -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<Widget> 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<Widget> children;
|
|
||||||
|
|
||||||
const CustomExpandableTile({
|
|
||||||
required this.title,
|
|
||||||
required this.titleBackgroundColor,
|
|
||||||
required this.children,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
_CustomExpandableTileState createState() => _CustomExpandableTileState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _CustomExpandableTileState extends State<CustomExpandableTile> {
|
|
||||||
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,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@ -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/domain/use_cases/language.dart';
|
||||||
import 'package:uae_stat/presentation/Screens/profilepage.dart';
|
import 'package:uae_stat/presentation/Screens/profilepage.dart';
|
||||||
import 'package:uae_stat/presentation/components/space.dart';
|
import 'package:uae_stat/presentation/components/space.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
import '../../../config/my_theme.dart';
|
import '../../../config/my_theme.dart';
|
||||||
|
|
||||||
@ -206,7 +207,8 @@ class _CreateNewPwState extends State<CreateNewPw> {
|
|||||||
children: [
|
children: [
|
||||||
SizedBox(height: screenHeight / 6),
|
SizedBox(height: screenHeight / 6),
|
||||||
Text(
|
Text(
|
||||||
"Create New Password",
|
// "Create New Password",
|
||||||
|
AppLocalizations.of(context)!.create_new_password,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
@ -216,7 +218,8 @@ class _CreateNewPwState extends State<CreateNewPw> {
|
|||||||
TextFormField(
|
TextFormField(
|
||||||
obscureText: _obscureOldPassword,
|
obscureText: _obscureOldPassword,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: 'Enter old password',
|
// hintText: 'Enter old password',
|
||||||
|
hintText: AppLocalizations.of(context)!.old_password,
|
||||||
prefixIcon: Icon(Icons.lock, color: Colors.blue),
|
prefixIcon: Icon(Icons.lock, color: Colors.blue),
|
||||||
suffixIcon: IconButton(
|
suffixIcon: IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
@ -240,7 +243,8 @@ class _CreateNewPwState extends State<CreateNewPw> {
|
|||||||
TextFormField(
|
TextFormField(
|
||||||
obscureText: _obscureNewPassword,
|
obscureText: _obscureNewPassword,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: 'Enter new password',
|
// hintText: 'Enter new password',
|
||||||
|
hintText: AppLocalizations.of(context)!.enter_new_password,
|
||||||
prefixIcon: Icon(Icons.lock, color: Colors.blue),
|
prefixIcon: Icon(Icons.lock, color: Colors.blue),
|
||||||
suffixIcon: IconButton(
|
suffixIcon: IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
@ -263,7 +267,8 @@ class _CreateNewPwState extends State<CreateNewPw> {
|
|||||||
TextFormField(
|
TextFormField(
|
||||||
obscureText: _obscureConfirmPassword,
|
obscureText: _obscureConfirmPassword,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: 'Confirm new password',
|
// hintText: 'Confirm new password',
|
||||||
|
hintText: AppLocalizations.of(context)!.confirm_new_password,
|
||||||
prefixIcon: Icon(Icons.lock, color: Colors.blue),
|
prefixIcon: Icon(Icons.lock, color: Colors.blue),
|
||||||
suffixIcon: IconButton(
|
suffixIcon: IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
@ -306,7 +311,7 @@ class _CreateNewPwState extends State<CreateNewPw> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Save",
|
AppLocalizations.of(context)!.save,
|
||||||
style: TextStyle(fontSize: 18, color: Colors.white),
|
style: TextStyle(fontSize: 18, color: Colors.white),
|
||||||
),
|
),
|
||||||
SizedBox(width: 2),
|
SizedBox(width: 2),
|
||||||
@ -348,7 +353,8 @@ class _CreateNewPwState extends State<CreateNewPw> {
|
|||||||
Icon(Icons.check_circle_outlined, color: Color(0xFF8AC681), size: 80),
|
Icon(Icons.check_circle_outlined, color: Color(0xFF8AC681), size: 80),
|
||||||
SizedBox(height: 20),
|
SizedBox(height: 20),
|
||||||
Text(
|
Text(
|
||||||
"Password Changed Successfully",
|
// "Password Changed Successfully",
|
||||||
|
AppLocalizations.of(context)!.password_changed_successfully,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
|
|||||||
@ -1,11 +1,15 @@
|
|||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:pocketbase/pocketbase.dart';
|
import 'package:pocketbase/pocketbase.dart';
|
||||||
import 'package:uae_stat/domain/use_cases/language.dart';
|
import 'package:uae_stat/domain/use_cases/language.dart';
|
||||||
import 'package:uae_stat/presentation/Screens/profilepage.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';
|
import '../../routes/auth_routes/login_route.dart';
|
||||||
|
|
||||||
class RegisterScreen extends StatefulWidget {
|
class RegisterScreen extends StatefulWidget {
|
||||||
@ -287,6 +291,32 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Scaffold(
|
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,
|
backgroundColor: Colors.white,
|
||||||
body: registrationSuccess
|
body: registrationSuccess
|
||||||
? Padding(
|
? Padding(
|
||||||
@ -414,12 +444,13 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
children: [
|
children: [
|
||||||
SizedBox(height: screenheight / 15),
|
SizedBox(height: screenheight / 15),
|
||||||
Text(
|
Text(
|
||||||
'Register',
|
// 'Register',
|
||||||
|
AppLocalizations.of(context)!.register_title,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 32, fontWeight: FontWeight.w400),
|
fontSize: 32, fontWeight: FontWeight.w400),
|
||||||
),
|
),
|
||||||
SizedBox(height: 10),
|
SizedBox(height: 10),
|
||||||
Text('Please enter your details'),
|
Text(AppLocalizations.of(context)!.register_details),
|
||||||
|
|
||||||
SizedBox(height: 20),
|
SizedBox(height: 20),
|
||||||
// Display this if registration is pending approval
|
// Display this if registration is pending approval
|
||||||
@ -427,7 +458,8 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
controller: _usernameController,
|
controller: _usernameController,
|
||||||
focusNode: _focusNodes[0],
|
focusNode: _focusNodes[0],
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: _showHints[0] ? 'Username' : null,
|
// hintText: _showHints[0] ? 'Username' : null,
|
||||||
|
hintText: _showHints[0] ? AppLocalizations.of(context)!.register_name : null,
|
||||||
prefixIcon: Icon(
|
prefixIcon: Icon(
|
||||||
Icons.person,
|
Icons.person,
|
||||||
color: Colors.blue,
|
color: Colors.blue,
|
||||||
@ -447,7 +479,8 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
// hintText: 'Enter your email',
|
// hintText: 'Enter your email',
|
||||||
hintText:
|
hintText:
|
||||||
_showHints[1] ? 'Enter your email' : null,
|
_showHints[1] ? AppLocalizations.of(context)!.register_email : null,
|
||||||
|
// _showHints[1] ? 'Enter your email' : null,
|
||||||
prefixIcon: Icon(
|
prefixIcon: Icon(
|
||||||
Icons.email,
|
Icons.email,
|
||||||
color: Colors.blue,
|
color: Colors.blue,
|
||||||
@ -470,7 +503,8 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
obscureText: _obscurePassword,
|
obscureText: _obscurePassword,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText:
|
hintText:
|
||||||
_showHints[2] ? 'Enter your password' : null,
|
_showHints[2] ? AppLocalizations.of(context)!.register_password : null,
|
||||||
|
// _showHints[2] ? 'Enter your password' : null,
|
||||||
prefixIcon: Icon(
|
prefixIcon: Icon(
|
||||||
Icons.lock,
|
Icons.lock,
|
||||||
color: Colors.blue,
|
color: Colors.blue,
|
||||||
@ -502,7 +536,8 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
obscureText: _obscureConfirmPassword,
|
obscureText: _obscureConfirmPassword,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText:
|
hintText:
|
||||||
_showHints[3] ? 'Confirm password' : null,
|
_showHints[3] ? AppLocalizations.of(context)!.register_Confirm_password : null,
|
||||||
|
// _showHints[3] ? 'Confirm password' : null,
|
||||||
prefixIcon: Icon(
|
prefixIcon: Icon(
|
||||||
Icons.lock,
|
Icons.lock,
|
||||||
color: Colors.blue,
|
color: Colors.blue,
|
||||||
@ -551,17 +586,20 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: Text.rich(
|
child: Text.rich(
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: 'I agree to ',
|
text: AppLocalizations.of(context)!.agree,
|
||||||
|
// text: 'I agree to ',
|
||||||
children: [
|
children: [
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: 'Terms & Conditions',
|
text: AppLocalizations.of(context)!.terms_conditions,
|
||||||
|
// text: 'Terms & Conditions',
|
||||||
style: TextStyle(color: Colors.blue),
|
style: TextStyle(color: Colors.blue),
|
||||||
),
|
),
|
||||||
TextSpan(text: ' and '),
|
TextSpan(text: AppLocalizations.of(context)!.t_and),
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: 'Privacy Policy',
|
text: AppLocalizations.of(context)!.privacy_policy,
|
||||||
style: TextStyle(color: Colors.blue),
|
style: TextStyle(color: Colors.blue),
|
||||||
),
|
),
|
||||||
|
TextSpan(text: AppLocalizations.of(context)!.conditions),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -600,7 +638,8 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Register",
|
// "Register",
|
||||||
|
AppLocalizations.of(context)!.register_title,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16, color: Colors.white),
|
fontSize: 16, color: Colors.white),
|
||||||
),
|
),
|
||||||
@ -613,7 +652,7 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
),
|
),
|
||||||
SizedBox(height: 10),
|
SizedBox(height: 10),
|
||||||
Text(
|
Text(
|
||||||
"Already have an account?",
|
AppLocalizations.of(context)!.account_confirmation,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16, color: Colors.grey[600]),
|
fontSize: 16, color: Colors.grey[600]),
|
||||||
),
|
),
|
||||||
@ -635,7 +674,7 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Login",
|
AppLocalizations.of(context)!.login_title,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16, color: Colors.white),
|
fontSize: 16, color: Colors.white),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -1035,191 +1035,177 @@ class ChartData {
|
|||||||
|
|
||||||
// [
|
// [
|
||||||
// {
|
// {
|
||||||
// chart_type :"scatter"
|
// chart_heading :"Guest Nights by Region"
|
||||||
// dataset :"divorces"
|
// chart_type :"fl_stacked_bar"
|
||||||
// is_chart :"true"
|
// dataset :"hotels"
|
||||||
// kpi:"divorces"
|
// group_by :"GUEST_REGION"
|
||||||
// filters:[
|
// is_chart :"true"
|
||||||
// {
|
// kpi :"hotel_occupancy_rate_chart_1"
|
||||||
// "filter_key": "REF_AREA",
|
// main_id :"economy"
|
||||||
// "filter_data": [
|
|
||||||
// "AE",
|
|
||||||
// "AE-AJ",
|
|
||||||
// "AE-RK",
|
|
||||||
// "AE-FJ",
|
|
||||||
// "AE-AZ",
|
|
||||||
// "AE-DU",
|
|
||||||
// "AE-SH",
|
|
||||||
// "AE-UQ"
|
|
||||||
// ]
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "filter_key": "TIME_PERIOD",
|
|
||||||
// "filter_data": [
|
|
||||||
// "2021",
|
|
||||||
// "2017",
|
|
||||||
// "2018",
|
|
||||||
// "2019",
|
|
||||||
// "2020"
|
|
||||||
// ]
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "filter_key": "DV_TYPE",
|
|
||||||
// "filter_data": [
|
|
||||||
// "D_EM_NEF",
|
|
||||||
// "D_EM_EF",
|
|
||||||
// "D_NEW_NEF",
|
|
||||||
// "D_TOT",
|
|
||||||
// "D_NEM_EF"
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// group_by:"DV_TYPE"
|
|
||||||
// main_id :"social"
|
|
||||||
// response:[
|
// response:[
|
||||||
// {
|
// {
|
||||||
// "ObsKey": {
|
// "ObsKey": {
|
||||||
// "DV_TYPE": "D_TOT",
|
|
||||||
// "FREQ": "A",
|
// "FREQ": "A",
|
||||||
// "MEASURE": "D",
|
// "GUEST_REGION": "AF",
|
||||||
// "REF_AREA": "AE-DU",
|
// "H_INDICATOR": "GUN",
|
||||||
// "SOURCE_DETAIL": "FCSAMD",
|
// "H_TYPE": "_Z",
|
||||||
// "TIME_PERIOD": "2017",
|
// "MEASURE": "H",
|
||||||
|
// "REF_AREA": "AE",
|
||||||
|
// "SOURCE_DETAIL": "FCSC",
|
||||||
|
// "TIME_PERIOD": "2016",
|
||||||
// "UNIT_MEASURE": "NUMBER"
|
// "UNIT_MEASURE": "NUMBER"
|
||||||
// },
|
// },
|
||||||
// "ObsValue": {
|
// "ObsValue": {
|
||||||
// "Value": "1484"
|
// "Value": "2659446"
|
||||||
// }
|
// }
|
||||||
// },
|
// },
|
||||||
// {
|
// {
|
||||||
// "ObsKey": {
|
// "ObsKey": {
|
||||||
// "DV_TYPE": "D_TOT",
|
|
||||||
// "FREQ": "A",
|
// "FREQ": "A",
|
||||||
// "MEASURE": "D",
|
// "GUEST_REGION": "AF",
|
||||||
// "REF_AREA": "AE-DU",
|
// "H_INDICATOR": "GUN",
|
||||||
// "SOURCE_DETAIL": "FCSAMD",
|
// "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",
|
// "TIME_PERIOD": "2019",
|
||||||
// "UNIT_MEASURE": "NUMBER"
|
// "UNIT_MEASURE": "NUMBER"
|
||||||
// },
|
// },
|
||||||
// "ObsValue": {
|
// "ObsValue": {
|
||||||
// "Value": "1308"
|
// "Value": "14286573"
|
||||||
// }
|
// }
|
||||||
// },
|
// },
|
||||||
// {
|
// {
|
||||||
// "ObsKey": {
|
// "ObsKey": {
|
||||||
// "DV_TYPE": "D_TOT",
|
|
||||||
// "FREQ": "A",
|
// "FREQ": "A",
|
||||||
// "MEASURE": "D",
|
// "GUEST_REGION": "UAE",
|
||||||
// "REF_AREA": "AE-DU",
|
// "H_INDICATOR": "GUN",
|
||||||
// "SOURCE_DETAIL": "FCSAMD",
|
// "H_TYPE": "_Z",
|
||||||
// "TIME_PERIOD": "2017",
|
// "MEASURE": "H",
|
||||||
// "UNIT_MEASURE": "NUMBER"
|
|
||||||
// },
|
|
||||||
// "ObsValue": {
|
|
||||||
// "Value": "1484"
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "ObsKey": {
|
|
||||||
// "DV_TYPE": "D_TOT",
|
|
||||||
// "FREQ": "A",
|
|
||||||
// "MEASURE": "D",
|
|
||||||
// "REF_AREA": "AE-DU",
|
|
||||||
// "SOURCE_DETAIL": "FCSAMD",
|
|
||||||
// "TIME_PERIOD": "2018",
|
|
||||||
// "UNIT_MEASURE": "NUMBER"
|
|
||||||
// },
|
|
||||||
// "ObsValue": {
|
|
||||||
// "Value": "1321"
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "ObsKey": {
|
|
||||||
// "DV_TYPE": "D_NEM_EF",
|
|
||||||
// "FREQ": "A",
|
|
||||||
// "MEASURE": "D",
|
|
||||||
// "REF_AREA": "AE",
|
// "REF_AREA": "AE",
|
||||||
// "SOURCE_DETAIL": "FCSAMD",
|
// "SOURCE_DETAIL": "FCSC",
|
||||||
// "TIME_PERIOD": "2017",
|
|
||||||
// "UNIT_MEASURE": "NUMBER"
|
|
||||||
// },
|
|
||||||
// "ObsValue": {
|
|
||||||
// "Value": "181"
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "ObsKey": {
|
|
||||||
// "DV_TYPE": "D_NEM_EF",
|
|
||||||
// "FREQ": "A",
|
|
||||||
// "MEASURE": "D",
|
|
||||||
// "REF_AREA": "AE",
|
|
||||||
// "SOURCE_DETAIL": "FCSAMD",
|
|
||||||
// "TIME_PERIOD": "2019",
|
|
||||||
// "UNIT_MEASURE": "NUMBER"
|
|
||||||
// },
|
|
||||||
// "ObsValue": {
|
|
||||||
// "Value": "182"
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "ObsKey": {
|
|
||||||
// "DV_TYPE": "D_EM_NEF",
|
|
||||||
// "FREQ": "A",
|
|
||||||
// "MEASURE": "D",
|
|
||||||
// "REF_AREA": "AE",
|
|
||||||
// "SOURCE_DETAIL": "FCSAMD",
|
|
||||||
// "TIME_PERIOD": "2017",
|
|
||||||
// "UNIT_MEASURE": "NUMBER"
|
|
||||||
// },
|
|
||||||
// "ObsValue": {
|
|
||||||
// "Value": "766"
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "ObsKey": {
|
|
||||||
// "DV_TYPE": "D_EM_NEF",
|
|
||||||
// "FREQ": "A",
|
|
||||||
// "MEASURE": "D",
|
|
||||||
// "REF_AREA": "AE",
|
|
||||||
// "SOURCE_DETAIL": "FCSAMD",
|
|
||||||
// "TIME_PERIOD": "2020",
|
// "TIME_PERIOD": "2020",
|
||||||
// "UNIT_MEASURE": "NUMBER"
|
// "UNIT_MEASURE": "NUMBER"
|
||||||
// },
|
// },
|
||||||
// "ObsValue": {
|
// "ObsValue": {
|
||||||
// "Value": "618"
|
// "Value": "13982919"
|
||||||
// }
|
// }
|
||||||
// },
|
// },
|
||||||
// {
|
// {
|
||||||
// "ObsKey": {
|
// "ObsKey": {
|
||||||
// "DV_TYPE": "D_EM_EF",
|
|
||||||
// "FREQ": "A",
|
// "FREQ": "A",
|
||||||
// "MEASURE": "D",
|
// "GUEST_REGION": "EC",
|
||||||
|
// "H_INDICATOR": "GUN",
|
||||||
|
// "H_TYPE": "_Z",
|
||||||
|
// "MEASURE": "H",
|
||||||
// "REF_AREA": "AE",
|
// "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",
|
// "TIME_PERIOD": "2017",
|
||||||
// "UNIT_MEASURE": "NUMBER"
|
// "UNIT_MEASURE": "NUMBER"
|
||||||
// },
|
// },
|
||||||
// "ObsValue": {
|
// "ObsValue": {
|
||||||
// "Value": "1717"
|
// "Value": "1260359"
|
||||||
// }
|
// }
|
||||||
// },
|
// },
|
||||||
// {
|
// {
|
||||||
// "ObsKey": {
|
// "ObsKey": {
|
||||||
// "DV_TYPE": "D_EM_EF",
|
|
||||||
// "FREQ": "A",
|
// "FREQ": "A",
|
||||||
// "MEASURE": "D",
|
// "GUEST_REGION": "OC",
|
||||||
|
// "H_INDICATOR": "GUN",
|
||||||
|
// "H_TYPE": "_Z",
|
||||||
|
// "MEASURE": "H",
|
||||||
// "REF_AREA": "AE",
|
// "REF_AREA": "AE",
|
||||||
// "SOURCE_DETAIL": "FCSAMD",
|
// "SOURCE_DETAIL": "FCSC",
|
||||||
// "TIME_PERIOD": "2018",
|
// "TIME_PERIOD": "2018",
|
||||||
// "UNIT_MEASURE": "NUMBER"
|
// "UNIT_MEASURE": "NUMBER"
|
||||||
// },
|
// },
|
||||||
// "ObsValue": {
|
// "ObsValue": {
|
||||||
// "Value": "1720"
|
// "Value": "1127282"
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// ]
|
// ]
|
||||||
// sub_id :"vital_statistics"
|
// sub_id :"tourism"
|
||||||
// url :"https://releaseeuaestat.fcsc.gov.ae/rest/data/FCSA,DF_DV_NA,1.5.0/.A....?startPeriod=2017&endPeriod=2024&dimensionAtObservation=AllDimensions"
|
// 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"
|
||||||
// }
|
// }
|
||||||
// ]
|
// ]
|
||||||
|
|||||||
@ -0,0 +1,33 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
|
List<dynamic> filterCharts({
|
||||||
|
required List<dynamic> apiData,
|
||||||
|
required Map<String, List<String>> filters,
|
||||||
|
}) {
|
||||||
|
// Initialize the filtered data as the original dataset
|
||||||
|
List<dynamic> filteredData = apiData;
|
||||||
|
|
||||||
|
// Apply filtering for each filter key dynamically
|
||||||
|
for (var filterKey in filters.keys) {
|
||||||
|
List<String>? filterValues = filters[filterKey];
|
||||||
|
if (filterValues != null && filterValues.isNotEmpty) {
|
||||||
|
// Filter data based on the current filter key
|
||||||
|
List<dynamic> 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
|
||||||
|
}
|
||||||
13
lib/presentation/Screens/charts/models/chart_data.dart
Normal file
13
lib/presentation/Screens/charts/models/chart_data.dart
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
class ChartData {
|
||||||
|
final String xLabel;
|
||||||
|
final double yValue;
|
||||||
|
|
||||||
|
ChartData({required this.xLabel, required this.yValue});
|
||||||
|
|
||||||
|
factory ChartData.fromJson(Map<String, dynamic> json) {
|
||||||
|
return ChartData(
|
||||||
|
xLabel: json['x_label'] as String,
|
||||||
|
yValue: (json['y_value'] as num).toDouble(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
600
lib/presentation/Screens/charts/screens/chart_screen.dart
Normal file
600
lib/presentation/Screens/charts/screens/chart_screen.dart
Normal file
@ -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<ChartScreen1> {
|
||||||
|
List<Map<String, dynamic>> selectedFiltersStorage = [];
|
||||||
|
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||||
|
final ApiService apiService = ApiService();
|
||||||
|
bool isLoading = true;
|
||||||
|
List<dynamic> isChartData = [];
|
||||||
|
List<dynamic> nonChartData = [];
|
||||||
|
List<dynamic> filterData = [];
|
||||||
|
List<dynamic> chartsData = [];
|
||||||
|
List<dynamic> cardData = [];
|
||||||
|
List<dynamic> originalChartsData = [];
|
||||||
|
List<dynamic> originalCardData = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
fetchChartData(widget.dataSets);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> 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<String, dynamic> chartData = Map<String, dynamic>.from(chart);
|
||||||
|
// Extract response data for filtering
|
||||||
|
List response = chartData['response'] ?? [];
|
||||||
|
|
||||||
|
// Filter the response based on selected filters
|
||||||
|
var cardFilteredData = response.where((responseItem) {
|
||||||
|
final obsKey = responseItem['ObsKey'];
|
||||||
|
|
||||||
|
// 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<Map<String, dynamic>> 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<Widget>((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<Widget>((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])),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
184
lib/presentation/Screens/charts/services/api_service.dart
Normal file
184
lib/presentation/Screens/charts/services/api_service.dart
Normal file
@ -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<Map<String, dynamic>> fetchChartData(String dataSets) async {
|
||||||
|
List<dynamic> isChartData = [];
|
||||||
|
List<dynamic> nonChartData = [];
|
||||||
|
List<dynamic> originalChartsData = [];
|
||||||
|
List<dynamic> originalCardData = [];
|
||||||
|
|
||||||
|
final url = Uri.parse('$baseUrl?dataset=$dataSets');
|
||||||
|
|
||||||
|
try {
|
||||||
|
final response = await http.get(url);
|
||||||
|
print('data');
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
final Map<String, dynamic> 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<void> fetchChartData(String dataSets) async {
|
||||||
|
// final url = Uri.parse('$baseUrl?dataset=$dataSets');
|
||||||
|
//
|
||||||
|
// List<dynamic> isChartData = [];
|
||||||
|
// List<dynamic> nonChartData = [];
|
||||||
|
// List<dynamic> originalChartsData = [];
|
||||||
|
// List<dynamic> originalCardData = [];
|
||||||
|
//
|
||||||
|
// try {
|
||||||
|
// final response = await http.get(url);
|
||||||
|
//
|
||||||
|
// if (response.statusCode == 200) {
|
||||||
|
// final List<dynamic> 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<String, dynamic> processNonChartData(dynamic item) {
|
||||||
|
print('Processing non-chart data...');
|
||||||
|
|
||||||
|
try {
|
||||||
|
final response = item['response'];
|
||||||
|
|
||||||
|
final List<dynamic> responseData = response is LinkedHashMap
|
||||||
|
? Map<String, dynamic>.from(response)
|
||||||
|
: response;
|
||||||
|
|
||||||
|
final sortedResponse = List<String>.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<double> 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<ChartData> parseScatterChartData(List<dynamic> 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<ChartData> parseStackedBarChartData(
|
||||||
|
dynamic chartData, String groupByKey, String groupByValue) {
|
||||||
|
return chartData['response']
|
||||||
|
.where((entry) => entry['ObsKey'][groupByKey] == groupByValue)
|
||||||
|
.map<ChartData>((entry) {
|
||||||
|
return ChartData(
|
||||||
|
x: entry['ObsKey']['TIME_PERIOD'],
|
||||||
|
y: double.tryParse(entry['ObsValue']['Value']) ?? 0.0,
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
632
lib/presentation/Screens/charts/widgets/chart_widget.dart
Normal file
632
lib/presentation/Screens/charts/widgets/chart_widget.dart
Normal file
@ -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<ChartData> parseStackedBarChartData(
|
||||||
|
dynamic chartData, String groupByKey, String groupByValue) {
|
||||||
|
return chartData['response']
|
||||||
|
.where((entry) => entry['ObsKey'][groupByKey] == groupByValue)
|
||||||
|
.map<ChartData>((entry) {
|
||||||
|
return ChartData(
|
||||||
|
x: entry['ObsKey']['TIME_PERIOD'],
|
||||||
|
y: double.tryParse(entry['ObsValue']['Value']) ?? 0.0,
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<BarChartGroupData> parseColumnChartData(dynamic chartData) {
|
||||||
|
return chartData['response'].map<BarChartGroupData>((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<PieChartSectionData> parsePieChartData(
|
||||||
|
dynamic chartData,
|
||||||
|
double totalValue,
|
||||||
|
int? touchedIndex,
|
||||||
|
) {
|
||||||
|
return chartData['response']
|
||||||
|
.asMap()
|
||||||
|
.entries
|
||||||
|
.map<PieChartSectionData>((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<Widget> generateIndicators(dynamic chartData, groupByValue) {
|
||||||
|
return chartData['response'].asMap().entries.map<Widget>((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<String> extractGroupByValues(dynamic chartData, String groupByKey) {
|
||||||
|
return (chartData['response'] as List<dynamic>).map<String>((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<String> 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<Color> 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: <StackedBarSeries<ChartData, String>>[
|
||||||
|
for (int i = 0; i < groupByValues.length; i++)
|
||||||
|
StackedBarSeries<ChartData, String>(
|
||||||
|
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<Color> 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: <CartesianSeries<ChartData, String>>[
|
||||||
|
for (int i = 0; i < groupByValues.length; i++)
|
||||||
|
StackedColumnSeries<ChartData, String>(
|
||||||
|
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<double>(
|
||||||
|
(entry) => double.tryParse(entry['ObsValue']['Value']) ?? 0.0)
|
||||||
|
.fold(0.0, (prev, element) => prev + element);
|
||||||
|
|
||||||
|
ValueNotifier<int?> 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<int?>(
|
||||||
|
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<String> groupByValuesList = groupByValues.toList();
|
||||||
|
int chunkSize = 5;
|
||||||
|
List<List<String>> 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<String> timePeriods =
|
||||||
|
// groupedData.values.first.keys.toList();
|
||||||
|
// String timePeriod = timePeriods[groupIndex];
|
||||||
|
// List<BarChartRodStackItem> 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<String> 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<Color> 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<BarChartGroupData> _generateBarGroups(
|
||||||
|
dynamic chartData, String groupByKey) {
|
||||||
|
Map<String, Map<String, double>> 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<BarChartGroupData> barGroups = [];
|
||||||
|
List<String> 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<BarChartRodStackItem> 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<Widget> _generateXTitles(dynamic chartData) {
|
||||||
|
Set<String> 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<BarChartGroupData> _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});
|
||||||
|
}
|
||||||
21
lib/presentation/components/indicators/locale_provider.dart
Normal file
21
lib/presentation/components/indicators/locale_provider.dart
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class LocaleNotifier extends StateNotifier<Locale?> {
|
||||||
|
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<LocaleNotifier, Locale?>(
|
||||||
|
(ref) => LocaleNotifier(),
|
||||||
|
);
|
||||||
@ -177,11 +177,11 @@ void handleInfoCardClick(BuildContext context, String data) {
|
|||||||
final dataSets = data;
|
final dataSets = data;
|
||||||
print(dataSets);
|
print(dataSets);
|
||||||
if (dataSets == 'hotels') {
|
if (dataSets == 'hotels') {
|
||||||
context.go('/Chart/$dataSets');
|
context.go('/chartScreen/$dataSets');
|
||||||
} else if (dataSets == 'divorces') {
|
} else if (dataSets == 'divorces') {
|
||||||
context.go('/Chart/$dataSets');
|
context.go('/chartScreen/$dataSets');
|
||||||
} else if (dataSets == 'marriages') {
|
} else if (dataSets == 'marriages') {
|
||||||
context.go('/Chart/$dataSets');
|
context.go('/chartScreen/$dataSets');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,11 +191,11 @@ class _MyHomePageState extends State<MyHomePage> {
|
|||||||
double myheight = MediaQuery.of(context).size.height;
|
double myheight = MediaQuery.of(context).size.height;
|
||||||
double mywidth = MediaQuery.of(context).size.width;
|
double mywidth = MediaQuery.of(context).size.width;
|
||||||
return BaseScaffold(
|
return BaseScaffold(
|
||||||
title: Center(
|
mycenterTitle: true,
|
||||||
child: SizedBox(
|
title: SizedBox(
|
||||||
height: myheight / 5,
|
height: myheight / 5,
|
||||||
width: mywidth / 3,
|
width: mywidth / 3,
|
||||||
child: Image(image: AssetImage('assets/logos/uae_stat.png')))),
|
child: Image(image: AssetImage('assets/logos/uae_stat.png'))),
|
||||||
body: EconomyStats(),
|
body: EconomyStats(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import 'package:image_picker/image_picker.dart';
|
|||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:pocketbase/pocketbase.dart';
|
import 'package:pocketbase/pocketbase.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
import '../../../Screens/auth_verification/changepassword.dart';
|
import '../../../Screens/auth_verification/changepassword.dart';
|
||||||
import '../custom_drawer_routes.dart';
|
import '../custom_drawer_routes.dart';
|
||||||
|
|
||||||
@ -372,7 +372,7 @@ class _EditProfileState extends State<EditProfile> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BaseScaffold(
|
return BaseScaffold(
|
||||||
title: Text("Profile"),
|
title: Text(AppLocalizations.of(context)!.my_profile),
|
||||||
body: SingleChildScrollView(
|
body: SingleChildScrollView(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(left: 10.0, right: 10.0, top: 3.0),
|
padding: const EdgeInsets.only(left: 10.0, right: 10.0, top: 3.0),
|
||||||
@ -418,7 +418,7 @@ class _EditProfileState extends State<EditProfile> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"User Name",
|
AppLocalizations.of(context)!.register_name,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
@ -444,7 +444,7 @@ class _EditProfileState extends State<EditProfile> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Email ID",
|
AppLocalizations.of(context)!.email_id,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
@ -469,7 +469,7 @@ class _EditProfileState extends State<EditProfile> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Full Name*",
|
AppLocalizations.of(context)!.full_name,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
@ -543,7 +543,7 @@ class _EditProfileState extends State<EditProfile> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Country/Region*",
|
AppLocalizations.of(context)!.region,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16, fontWeight: FontWeight.w500),
|
fontSize: 16, fontWeight: FontWeight.w500),
|
||||||
),
|
),
|
||||||
@ -602,12 +602,12 @@ class _EditProfileState extends State<EditProfile> {
|
|||||||
SizedBox(height: 10),
|
SizedBox(height: 10),
|
||||||
Text.rich(
|
Text.rich(
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: 'I agree to the ',
|
text: AppLocalizations.of(context)!.agree,
|
||||||
style:
|
style:
|
||||||
TextStyle(color: Colors.black),
|
TextStyle(color: Colors.black),
|
||||||
children: [
|
children: [
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: 'Terms & Conditions',
|
text: AppLocalizations.of(context)!.terms_conditions,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.blue,
|
color: Colors.blue,
|
||||||
decoration:
|
decoration:
|
||||||
@ -620,12 +620,12 @@ class _EditProfileState extends State<EditProfile> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: ' and ',
|
text: AppLocalizations.of(context)!.t_and,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.black),
|
color: Colors.black),
|
||||||
),
|
),
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: 'Privacy Policy',
|
text: AppLocalizations.of(context)!.privacy_policy,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.blue,
|
color: Colors.blue,
|
||||||
decoration:
|
decoration:
|
||||||
@ -638,7 +638,7 @@ class _EditProfileState extends State<EditProfile> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: ' of FCSC.',
|
text: AppLocalizations.of(context)!.conditions,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.black),
|
color: Colors.black),
|
||||||
),
|
),
|
||||||
@ -681,7 +681,7 @@ class _EditProfileState extends State<EditProfile> {
|
|||||||
context.go('/createNewPw/$userId/$email');
|
context.go('/createNewPw/$userId/$email');
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
"Change Password",
|
AppLocalizations.of(context)!.change_password,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.blue,
|
color: Colors.blue,
|
||||||
decoration: TextDecoration.underline),
|
decoration: TextDecoration.underline),
|
||||||
@ -698,7 +698,7 @@ class _EditProfileState extends State<EditProfile> {
|
|||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
),
|
),
|
||||||
label: Text(
|
label: Text(
|
||||||
'Save',
|
AppLocalizations.of(context)!.save,
|
||||||
style: TextStyle(color: Colors.white),
|
style: TextStyle(color: Colors.white),
|
||||||
),
|
),
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import 'package:flutter_rating_bar/flutter_rating_bar.dart';
|
|||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
import 'package:pocketbase/pocketbase.dart';
|
import 'package:pocketbase/pocketbase.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:uae_stat/domain/use_cases/language.dart';
|
import 'package:uae_stat/domain/use_cases/language.dart';
|
||||||
@ -208,7 +209,8 @@ class _FeedbackFormState extends State<FeedbackForm>
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BaseScaffold(
|
return BaseScaffold(
|
||||||
title: Text("Feedback"),
|
// title: Text("Feedback"),
|
||||||
|
title: Text(AppLocalizations.of(context)!.feedback_title),
|
||||||
// appBar: AppBar(
|
// appBar: AppBar(
|
||||||
// backgroundColor: const Color(0xFFf8f9ff),
|
// backgroundColor: const Color(0xFFf8f9ff),
|
||||||
// title: Text(context.translate('Feedback Form', 'نموذج الملاحظات')),
|
// title: Text(context.translate('Feedback Form', 'نموذج الملاحظات')),
|
||||||
@ -464,8 +466,8 @@ class _FeedbackFormState extends State<FeedbackForm>
|
|||||||
const Text("Failed to Share Feedback",
|
const Text("Failed to Share Feedback",
|
||||||
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
|
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
const Text("Your feedback could not be submitted. Please try again.",
|
Text(AppLocalizations.of(context)!.feedback_failed_msg,
|
||||||
style: TextStyle(fontSize: 16), textAlign: TextAlign.center),
|
style: const TextStyle(fontSize: 16), textAlign: TextAlign.center),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
|||||||
@ -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_bottom_nav_bar.dart';
|
||||||
import 'package:uae_stat/presentation/components/my_drawer.dart';
|
import 'package:uae_stat/presentation/components/my_drawer.dart';
|
||||||
import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.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 {
|
class ManageUserRouter extends StatefulWidget {
|
||||||
late final Widget title;
|
late final Widget title;
|
||||||
@ -18,7 +19,7 @@ class _ManageUserRouterState extends State<ManageUserRouter> {
|
|||||||
bool _isAscending = true;
|
bool _isAscending = true;
|
||||||
List<User> filteredUserData = [];
|
List<User> filteredUserData = [];
|
||||||
|
|
||||||
final List<String> statusOptions = ['Approved', 'Denied', 'Pending'];
|
// final List<String> statusOptions = ['Approved', 'Denied', 'Pending'];
|
||||||
|
|
||||||
Color getStatusColor(String status) {
|
Color getStatusColor(String status) {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
@ -130,7 +131,8 @@ class _ManageUserRouterState extends State<ManageUserRouter> {
|
|||||||
height: myheight / 30,
|
height: myheight / 30,
|
||||||
),
|
),
|
||||||
Text(
|
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),
|
style: TextStyle(fontSize: 15),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
@ -168,7 +170,7 @@ class _ManageUserRouterState extends State<ManageUserRouter> {
|
|||||||
width: 2.0, // Set the border width
|
width: 2.0, // Set the border width
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Text('No'),
|
child: Text(AppLocalizations.of(context)!.no),
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
@ -207,7 +209,8 @@ class _ManageUserRouterState extends State<ManageUserRouter> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Yes',
|
// 'Yes',
|
||||||
|
AppLocalizations.of(context)!.yes,
|
||||||
style: TextStyle(color: Colors.white),
|
style: TextStyle(color: Colors.white),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -221,9 +224,20 @@ class _ManageUserRouterState extends State<ManageUserRouter> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
||||||
|
final Map<String, String> statusOptions = {
|
||||||
|
'Approved': AppLocalizations.of(context)!.approved,
|
||||||
|
'Denied': AppLocalizations.of(context)!.denied,
|
||||||
|
'Pending': AppLocalizations.of(context)!.pending,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
double myheight = MediaQuery.of(context).size.height;
|
double myheight = MediaQuery.of(context).size.height;
|
||||||
return BaseScaffold(
|
return BaseScaffold(
|
||||||
title: Text("Manage User"),
|
// title: Text("Manage User"),
|
||||||
|
title: Text(
|
||||||
|
AppLocalizations.of(context)!.manage_user,
|
||||||
|
),
|
||||||
body: SingleChildScrollView(
|
body: SingleChildScrollView(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(left: 10.0, right: 10.0, top: 3.0),
|
padding: const EdgeInsets.only(left: 10.0, right: 10.0, top: 3.0),
|
||||||
@ -251,21 +265,23 @@ class _ManageUserRouterState extends State<ManageUserRouter> {
|
|||||||
sortAscending: _isAscending,
|
sortAscending: _isAscending,
|
||||||
columns: [
|
columns: [
|
||||||
DataColumn(
|
DataColumn(
|
||||||
label: const Text('User Name'),
|
label: Text(
|
||||||
|
AppLocalizations.of(context)!.user_name,
|
||||||
|
),
|
||||||
onSort: (columnIndex, ascending) {
|
onSort: (columnIndex, ascending) {
|
||||||
_sort((user) => user.userName.toLowerCase(),
|
_sort((user) => user.userName.toLowerCase(),
|
||||||
columnIndex, ascending);
|
columnIndex, ascending);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
DataColumn(
|
DataColumn(
|
||||||
label: const Text('Email ID'),
|
label: Text( AppLocalizations.of(context)!.email_id,),
|
||||||
onSort: (columnIndex, ascending) {
|
onSort: (columnIndex, ascending) {
|
||||||
_sort((user) => user.emailId.toLowerCase(),
|
_sort((user) => user.emailId.toLowerCase(),
|
||||||
columnIndex, ascending);
|
columnIndex, ascending);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
DataColumn(
|
DataColumn(
|
||||||
label: const Text('Registration Date'),
|
label: Text(AppLocalizations.of(context)!.reg_date,),
|
||||||
onSort: (columnIndex, ascending) {
|
onSort: (columnIndex, ascending) {
|
||||||
_sort(
|
_sort(
|
||||||
(user) => DateFormat('dd/MM/yyyy')
|
(user) => DateFormat('dd/MM/yyyy')
|
||||||
@ -276,7 +292,7 @@ class _ManageUserRouterState extends State<ManageUserRouter> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
DataColumn(
|
DataColumn(
|
||||||
label: const Text('Status'),
|
label: Text(AppLocalizations.of(context)!.status,),
|
||||||
onSort: (columnIndex, ascending) {
|
onSort: (columnIndex, ascending) {
|
||||||
_sort((user) => user.status.toLowerCase(),
|
_sort((user) => user.status.toLowerCase(),
|
||||||
columnIndex, ascending);
|
columnIndex, ascending);
|
||||||
@ -311,13 +327,13 @@ class _ManageUserRouterState extends State<ManageUserRouter> {
|
|||||||
DataCell(
|
DataCell(
|
||||||
DropdownButton<String>(
|
DropdownButton<String>(
|
||||||
value: user.status,
|
value: user.status,
|
||||||
items: statusOptions.map((status) {
|
items: statusOptions.entries.map((status) {
|
||||||
return DropdownMenuItem<String>(
|
return DropdownMenuItem<String>(
|
||||||
value: status,
|
value: status.key,
|
||||||
child: Text(
|
child: Text(
|
||||||
status,
|
status.value,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: getStatusColor(status)),
|
color: getStatusColor(status.key),),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
|
|||||||
@ -18,7 +18,7 @@ class _FAQPageState extends State<FAQPage> {
|
|||||||
color:Color(0xFF7296BE),
|
color:Color(0xFF7296BE),
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
),),
|
),),
|
||||||
showBackIcon: true,
|
showBackButton: true,
|
||||||
body: SafeArea(child:Column(
|
body: SafeArea(child:Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@ -521,7 +521,7 @@ class UsingFeatures extends StatelessWidget {
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Color(0xFFAA8E83),
|
color: Color(0xFFAA8E83),
|
||||||
),),
|
),),
|
||||||
showBackIcon: true,
|
showBackButton: true,
|
||||||
body:SafeArea(child: Column(
|
body:SafeArea(child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@ -72,7 +72,7 @@ class GettingStarted extends StatelessWidget {
|
|||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
showBackIcon: true,
|
showBackButton: true,
|
||||||
body:SafeArea(child: Column(
|
body:SafeArea(child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@ -1,144 +1,113 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:pocketbase/pocketbase.dart';
|
import 'package:uae_stat/presentation/components/my_toggle.dart';
|
||||||
import 'package:share_plus/share_plus.dart';
|
import 'package:uae_stat/presentation/components/indicators/locale_provider.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
class BaseScaffold extends StatefulWidget {
|
class BaseScaffold extends ConsumerWidget {
|
||||||
final Widget body;
|
final Widget body;
|
||||||
final Widget title;
|
final Widget title;
|
||||||
|
final bool ? showBackButton;
|
||||||
|
final bool ? mycenterTitle;
|
||||||
final List<Widget>? actions;
|
final List<Widget>? actions;
|
||||||
final bool showBackIcon;
|
final Color? appbarColor, mytitleColor;
|
||||||
final VoidCallback? onBackIconPressed;
|
|
||||||
|
|
||||||
const BaseScaffold({
|
const BaseScaffold({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.body,
|
required this.body,
|
||||||
required this.title,
|
required this.title,
|
||||||
this.actions,
|
this.actions,
|
||||||
this.showBackIcon=false,
|
this.showBackButton = false,
|
||||||
this.onBackIconPressed,
|
this.mycenterTitle = false, this.appbarColor, this.mytitleColor
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
// final Widget body;
|
||||||
|
//
|
||||||
|
// const BaseScaffold({required this.body});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_BaseScaffoldState createState() => _BaseScaffoldState();
|
Widget build(BuildContext context ,WidgetRef ref) {
|
||||||
}
|
final locale = ref.watch(localeProvider);
|
||||||
|
final localeNotifier = ref.read(localeProvider.notifier);
|
||||||
class _BaseScaffoldState extends State<BaseScaffold> {
|
|
||||||
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<String?> getUserId() async {
|
|
||||||
final prefs = await SharedPreferences.getInstance();
|
|
||||||
return prefs.getString('userId'); // Retrieve the userId
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method to check if userId exists and update state
|
|
||||||
Future<void> _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<void> _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) {
|
|
||||||
// Get the current route to highlight the active item
|
// Get the current route to highlight the active item
|
||||||
String currentRoute = GoRouterState.of(context).matchedLocation;
|
String currentRoute = GoRouterState.of(context).matchedLocation;
|
||||||
double myheight = MediaQuery.of(context).size.height;
|
double myheight = MediaQuery.of(context).size.height;
|
||||||
double mywidth = MediaQuery.of(context).size.width;
|
double mywidth = MediaQuery.of(context).size.width;
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(title: title, backgroundColor : appbarColor,actions: [
|
||||||
title: widget.title,
|
// IconButton(onPressed: () {}, icon: Icon(Icons.toggle_off_outlined)),
|
||||||
leading:widget.showBackIcon
|
MyToggle(isOn: locale?.languageCode == 'en',
|
||||||
? IconButton(
|
knobTextWhenOn: 'ع',
|
||||||
padding: EdgeInsets.zero,
|
knobTextWhenOff: 'EN',
|
||||||
icon: const Icon(Icons.arrow_back_ios_new_sharp),
|
pathColorWhenOn: Colors.grey.shade300,
|
||||||
onPressed: widget.onBackIconPressed ??
|
pathColorWhenOff: Colors.grey.shade300,
|
||||||
() {
|
onTap: (){
|
||||||
Navigator.of(context).pop(); // Default back button behavior
|
ref.read(localeProvider.notifier).toggleLocale();
|
||||||
},
|
},),
|
||||||
) : null,
|
],
|
||||||
actions: [
|
leading:
|
||||||
// IconButton(
|
// Stack(
|
||||||
// onPressed: () {
|
// children: [
|
||||||
// // Share logic here
|
// // Show the back button if showBackButton is true, otherwise show the drawer menu
|
||||||
// print("Share icon pressed");
|
// if (showBackButton == true)
|
||||||
// Share.share(
|
// Positioned(
|
||||||
// 'Open the app: fcscapp://home\n\n'
|
// left: 0,
|
||||||
// 'If you don’t have the app installed, '
|
// child: IconButton(
|
||||||
// 'visit: http://localhost:65493');
|
// color: Colors.white,
|
||||||
// },
|
// icon: Icon(Icons.arrow_back_ios_new),
|
||||||
// icon: Icon(Icons.share),
|
// onPressed: () {
|
||||||
// ),
|
// Navigator.of(context).pop();
|
||||||
IconButton(onPressed: () {}, icon: Icon(Icons.toggle_off_outlined)),
|
// },
|
||||||
if (widget.showBackIcon)
|
// ),
|
||||||
Builder(
|
// ),
|
||||||
builder: (context) => IconButton(
|
// // Show the drawer icon in all cases
|
||||||
padding: EdgeInsets.zero,
|
// Positioned(
|
||||||
icon: const Icon(Icons.menu),
|
// right: 0,
|
||||||
onPressed: () {
|
// child: IconButton(
|
||||||
Scaffold.of(context).openDrawer(); // Opens the drawer
|
// 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(
|
drawer: Drawer(
|
||||||
child: ListView(
|
child: ListView(
|
||||||
@ -162,39 +131,18 @@ class _BaseScaffoldState extends State<BaseScaffold> {
|
|||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: mywidth / 8,
|
width: mywidth / 8,
|
||||||
height: mywidth / 8,
|
child: Image(
|
||||||
child: ClipOval(
|
image: AssetImage(
|
||||||
child: _avatarUrl.isNotEmpty
|
'assets/edit_profile/profile.png'))),
|
||||||
? Image(
|
|
||||||
image: NetworkImage(_avatarUrl),
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
width: double.infinity,
|
|
||||||
height: double.infinity,
|
|
||||||
)
|
|
||||||
: Image(
|
|
||||||
image: AssetImage(
|
|
||||||
'assets/edit_profile/profile.png'),
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
width: double.infinity,
|
|
||||||
height: double.infinity,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
//child: Image(image: AssetImage('assets/edit_profile/profile.png'))
|
|
||||||
),
|
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: mywidth / 20,
|
width: mywidth / 20,
|
||||||
),
|
),
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
// Text(userId ?? 'Loading user...'), // Display userId here
|
Text('Mohammad'),
|
||||||
// Text('Mohammad@fcsc.com')
|
Text('Mohammad@fcsc.com')
|
||||||
Text(userName ?? 'Loading...'),
|
|
||||||
Text(
|
|
||||||
userEmail ?? 'Loading...',
|
|
||||||
style: TextStyle(fontSize: 12),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
@ -203,44 +151,33 @@ class _BaseScaffoldState extends State<BaseScaffold> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
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(
|
ListTile(
|
||||||
leading: SizedBox(
|
leading: SizedBox(
|
||||||
height: myheight / 15,
|
height: myheight / 15,
|
||||||
width: mywidth / 15,
|
width: mywidth / 15,
|
||||||
child:
|
child: Image(
|
||||||
Image(image: AssetImage('assets/icons/drawer/book.png'))),
|
image: AssetImage('assets/icons/drawer/message.png'))),
|
||||||
title: Text('User Guide'),
|
title: Text('Feedback'),
|
||||||
onTap: () => context.go('/user-guide'),
|
onTap: () => context.go('/feedback'),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: SizedBox(
|
leading: SizedBox(
|
||||||
height: myheight / 15,
|
height: myheight / 15,
|
||||||
width: mywidth / 15,
|
width: mywidth / 15,
|
||||||
child: Image(
|
child: Image(
|
||||||
image: AssetImage('assets/icons/drawer/logout.png'))),
|
image: AssetImage('assets/icons/drawer/manageuser.png'))),
|
||||||
title: Text('Logout'),
|
title: Text(AppLocalizations.of(context)!.manage_user),
|
||||||
onTap: () => context.go('/'),
|
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<BaseScaffold> {
|
|||||||
unselectedItemColor: Colors.grey,
|
unselectedItemColor: Colors.grey,
|
||||||
showUnselectedLabels: true,
|
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) {
|
int _getSelectedIndex(String route) {
|
||||||
switch (route) {
|
switch (route) {
|
||||||
case '/myhomepage':
|
case '/':
|
||||||
return 0;
|
return 0;
|
||||||
case '/about':
|
case '/uaenumbers':
|
||||||
return 1;
|
return 1;
|
||||||
case '/settings':
|
case '/competitiveness':
|
||||||
return 2;
|
return 2;
|
||||||
case '/profile':
|
case '/countryprofile':
|
||||||
return 3;
|
return 3;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
@ -310,16 +247,16 @@ class _BaseScaffoldState extends State<BaseScaffold> {
|
|||||||
void _onItemTapped(BuildContext context, int index) {
|
void _onItemTapped(BuildContext context, int index) {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0:
|
case 0:
|
||||||
context.go('/myhomepage');
|
context.go('/');
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
context.go('/about');
|
context.go('/uaenumbers');
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
context.go('/settings');
|
context.go('/competitiveness');
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
context.go('/profile');
|
context.go('/countryprofile');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
48
pubspec.lock
48
pubspec.lock
@ -435,10 +435,10 @@ packages:
|
|||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: flutter_native_splash
|
name: flutter_native_splash
|
||||||
sha256: "1152ab0067ca5a2ebeb862fe0a762057202cceb22b7e62692dcbabf6483891bb"
|
sha256: "7062602e0dbd29141fb8eb19220b5871ca650be5197ab9c1f193a28b17537bc7"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.3"
|
version: "2.4.4"
|
||||||
flutter_plugin_android_lifecycle:
|
flutter_plugin_android_lifecycle:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -467,26 +467,26 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_secure_storage
|
name: flutter_secure_storage
|
||||||
sha256: "165164745e6afb5c0e3e3fcc72a012fb9e58496fb26ffb92cf22e16a821e85d0"
|
sha256: "1913841ac4c7bf57cd2e05b717e1fbff7841b542962feff827b16525a781b3e4"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "9.2.2"
|
version: "9.2.3"
|
||||||
flutter_secure_storage_linux:
|
flutter_secure_storage_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_secure_storage_linux
|
name: flutter_secure_storage_linux
|
||||||
sha256: "4d91bfc23047422cbcd73ac684bc169859ee766482517c22172c86596bf1464b"
|
sha256: bf7404619d7ab5c0a1151d7c4e802edad8f33535abfbeff2f9e1fe1274e2d705
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.1"
|
version: "1.2.2"
|
||||||
flutter_secure_storage_macos:
|
flutter_secure_storage_macos:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_secure_storage_macos
|
name: flutter_secure_storage_macos
|
||||||
sha256: "1693ab11121a5f925bbea0be725abfcfbbcf36c1e29e571f84a0c0f436147a81"
|
sha256: "6c0a2795a2d1de26ae202a0d78527d163f4acbb11cde4c75c670f3a0fc064247"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.3"
|
||||||
flutter_secure_storage_platform_interface:
|
flutter_secure_storage_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -511,6 +511,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
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:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -573,10 +581,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: go_router
|
name: go_router
|
||||||
sha256: "2fd11229f59e23e967b0775df8d5948a519cd7e1e8b6e849729e010587b46539"
|
sha256: "7c2d40b59890a929824f30d442e810116caf5088482629c894b9e4478c67472d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "14.6.2"
|
version: "14.6.3"
|
||||||
graphs:
|
graphs:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -669,10 +677,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: image_picker_ios
|
name: image_picker_ios
|
||||||
sha256: "4f0568120c6fcc0aaa04511cb9f9f4d29fc3d0139884b1d06be88dcec7641d6b"
|
sha256: "05da758e67bc7839e886b3959848aa6b44ff123ab4b28f67891008afe8ef9100"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.8.12+1"
|
version: "0.8.12+2"
|
||||||
image_picker_linux:
|
image_picker_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -693,10 +701,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: image_picker_platform_interface
|
name: image_picker_platform_interface
|
||||||
sha256: "9ec26d410ff46f483c5519c29c02ef0e02e13a543f882b152d4bfd2f06802f80"
|
sha256: "886d57f0be73c4b140004e78b9f28a8914a09e50c2d816bdd0520051a71236a0"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.10.0"
|
version: "2.10.1"
|
||||||
image_picker_windows:
|
image_picker_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1100,10 +1108,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: shared_preferences
|
name: shared_preferences
|
||||||
sha256: "3c7e73920c694a436afaf65ab60ce3453d91f84208d761fbd83fc21182134d93"
|
sha256: a752ce92ea7540fc35a0d19722816e04d0e72828a4200e83a98cf1a1eb524c9a
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.4"
|
version: "2.3.5"
|
||||||
shared_preferences_android:
|
shared_preferences_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1504,18 +1512,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: webview_flutter_wkwebview
|
name: webview_flutter_wkwebview
|
||||||
sha256: b7e92f129482460951d96ef9a46b49db34bd2e1621685de26e9eaafd9674e7eb
|
sha256: "4adc14ea9a770cc9e2c8f1ac734536bd40e82615bd0fa6b94be10982de656cc7"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.16.3"
|
version: "3.17.0"
|
||||||
win32:
|
win32:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32
|
name: win32
|
||||||
sha256: "8b338d4486ab3fbc0ba0db9f9b4f5239b6697fcee427939a40e720cbb9ee0a69"
|
sha256: "154360849a56b7b67331c21f09a386562d88903f90a1099c5987afc1912e1f29"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.9.0"
|
version: "5.10.0"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@ -20,7 +20,9 @@ dependencies:
|
|||||||
injectable: ^2.3.2
|
injectable: ^2.3.2
|
||||||
riverpod_annotation: ^2.3.3
|
riverpod_annotation: ^2.3.3
|
||||||
cupertino_icons: ^1.0.6
|
cupertino_icons: ^1.0.6
|
||||||
|
|
||||||
fl_chart: ^0.69.2
|
fl_chart: ^0.69.2
|
||||||
|
|
||||||
marquee: ^2.2.3
|
marquee: ^2.2.3
|
||||||
url_launcher: ^6.3.1
|
url_launcher: ^6.3.1
|
||||||
# dynamic_layouts:
|
# dynamic_layouts:
|
||||||
@ -57,6 +59,7 @@ dependencies:
|
|||||||
image_picker: ^1.1.2
|
image_picker: ^1.1.2
|
||||||
syncfusion_flutter_charts: 28.1.33
|
syncfusion_flutter_charts: 28.1.33
|
||||||
material_charts: ^0.0.23
|
material_charts: ^0.0.23
|
||||||
|
flutter_staggered_grid_view: ^0.7.0
|
||||||
|
|
||||||
dependency_overrides:
|
dependency_overrides:
|
||||||
fading_edge_scrollview: ^4.1.1
|
fading_edge_scrollview: ^4.1.1
|
||||||
@ -77,6 +80,7 @@ dev_dependencies:
|
|||||||
# flutter_splash_screen: ^3.0.0
|
# flutter_splash_screen: ^3.0.0
|
||||||
|
|
||||||
flutter:
|
flutter:
|
||||||
|
generate: true
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
assets:
|
assets:
|
||||||
- assets/user_guide_videos/
|
- assets/user_guide_videos/
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user