diff --git a/android/app/build.gradle b/android/app/build.gradle index c1188579..21ef3342 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -15,12 +15,12 @@ if (localPropertiesFile.exists()) { def flutterVersionCode = localProperties.getProperty("flutter.versionCode") if (flutterVersionCode == null) { - flutterVersionCode = "20" + flutterVersionCode = "24" } def flutterVersionName = localProperties.getProperty("flutter.versionName") if (flutterVersionName == null) { - flutterVersionName = "1.0.19" + flutterVersionName = "1.0.23" } def keystorePropertiesFile = rootProject.file("key.properties") diff --git a/lib/presentation/Screens/auth_verification/create_new_pw.dart b/lib/presentation/Screens/auth_verification/create_new_pw.dart index 47b1c34e..be8a8564 100644 --- a/lib/presentation/Screens/auth_verification/create_new_pw.dart +++ b/lib/presentation/Screens/auth_verification/create_new_pw.dart @@ -39,7 +39,7 @@ class _CreateNewPwState extends ConsumerState { String? _validateOldPassword(String? value) { if (value == null || value.isEmpty) { - return 'Old password is required'; + return AppLocalizations.of(context)!.old_password_is_required; } return null; } @@ -56,37 +56,38 @@ class _CreateNewPwState extends ConsumerState { final hasSpecialCharacter = RegExp(r'[~!@#$%^&*()_+=[\]{}|;:,.<>?/-]'); if (value == null || value.isEmpty) { - return 'New password is required'; + return AppLocalizations.of(context)!.new_password_required; } else if (value.length < 8 || value.length > 64) { - return 'Password must be between 8 and 64 characters'; + return AppLocalizations.of(context)!.password_between_8_to_40; } else if (value == _oldPassword) { - return 'New password must not be the same as the old password'; + // return 'New password must not be the same as the old password'; + return AppLocalizations.of(context)!.new_password_not_same_as_old; } // Check the regular expression for allowed characters if (!regex.hasMatch(value)) { - return 'Password contains invalid characters'; + return AppLocalizations.of(context)!.password_invalid; } // Track missing constraints List missingConstraints = []; if (!hasUppercase.hasMatch(value)) { - missingConstraints.add('uppercase letter'); + missingConstraints.add(context.translate('uppercase letter','حرف كبير')); } if (!hasLowercase.hasMatch(value)) { - missingConstraints.add('lowercase letter'); + missingConstraints.add(context.translate('lowercase letter','حرف صغير')); } if (!hasDigit.hasMatch(value)) { - missingConstraints.add('numeric digit'); + missingConstraints.add(context.translate('numeric digit','رقم')); } if (!hasSpecialCharacter.hasMatch(value)) { - missingConstraints.add('special character'); + missingConstraints.add(context.translate('special character','رمز خاص')); } // If there are missing constraints, return a consolidated message if (missingConstraints.isNotEmpty) { - return 'At least one ${missingConstraints.join(', ')}'; + return context.translate('At least one ${missingConstraints.join(', ')}','${missingConstraints.join(', ')}على الأقل واحد '); } _newPassword = value; // Store for validation @@ -95,9 +96,10 @@ class _CreateNewPwState extends ConsumerState { String? _validateConfirmPassword(String? value) { if (value == null || value.isEmpty) { - return 'Confirm password is required'; + return AppLocalizations.of(context)!.confirm_new_password; } else if (value != _newPassword) { - return 'Passwords do not match'; + // return 'Passwords do not match'; + return AppLocalizations.of(context)!.password_match; } _confirmPassword = value; return null; @@ -151,7 +153,7 @@ class _CreateNewPwState extends ConsumerState { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text('Password updated successfully.'), + content: Text(AppLocalizations.of(context)!.password_update_successfully), backgroundColor: Colors.green, ), ); @@ -171,7 +173,7 @@ class _CreateNewPwState extends ConsumerState { }); ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text('Your old password is incorrect.'), + content: Text(AppLocalizations.of(context)!.your_old_password_incorrect), backgroundColor: Colors.red, ), ); @@ -191,7 +193,6 @@ class _CreateNewPwState extends ConsumerState { Widget build(BuildContext context) { double screenHeight = MediaQuery.of(context).size.height; double screenWidth = MediaQuery.of(context).size.width; - final passwordLocale = ref.watch(localeProvider); return Scaffold( backgroundColor: Colors.white, diff --git a/lib/presentation/Screens/auth_verification/privacy_policy.dart b/lib/presentation/Screens/auth_verification/privacy_policy.dart index cb4cdc60..80dc22a7 100644 --- a/lib/presentation/Screens/auth_verification/privacy_policy.dart +++ b/lib/presentation/Screens/auth_verification/privacy_policy.dart @@ -1,10 +1,16 @@ import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; import 'package:uae_stat/domain/use_cases/language.dart'; +import 'package:uae_stat/infrastructure/services/img_asset_paths/banner_asset_path.dart'; import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart'; class PrivacyPolicy extends StatelessWidget { - const PrivacyPolicy({super.key}); - + PrivacyPolicy({super.key}); + final fcscBanner = Image.asset( + BannerAssetPath.fcsc, + height: 40, + alignment: Alignment.center, + ); @override Widget build(BuildContext context) { return Theme( @@ -17,6 +23,12 @@ class PrivacyPolicy extends StatelessWidget { ), child: Scaffold( appBar: AppBar( + leading: IconButton( + icon: Icon(Icons.arrow_back_ios_new,size: 24,), + onPressed: (){ + context.pop(); + }, + ), scrolledUnderElevation: 0, title:Text(context.translate( 'Privacy Policy', @@ -872,7 +884,8 @@ class PrivacyPolicy extends StatelessWidget { style: TextStyle(fontSize: 16, color: Color(0xFF898C81), fontFamily: 'Roboto'), ), SizedBox(height: 20), - + Center(child: fcscBanner), + SizedBox(height: 20), ], ) ), diff --git a/lib/presentation/Screens/auth_verification/terms&conditions.dart b/lib/presentation/Screens/auth_verification/terms&conditions.dart index 5ea68038..150c2b2f 100644 --- a/lib/presentation/Screens/auth_verification/terms&conditions.dart +++ b/lib/presentation/Screens/auth_verification/terms&conditions.dart @@ -1,9 +1,16 @@ import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; import 'package:uae_stat/domain/use_cases/language.dart'; +import 'package:uae_stat/infrastructure/services/img_asset_paths/banner_asset_path.dart'; import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart'; class TermsOfUse extends StatelessWidget { - const TermsOfUse({super.key}); + TermsOfUse({super.key}); + final fcscBanner = Image.asset( + BannerAssetPath.fcsc, + height: 40, + alignment: Alignment.center, + ); @override Widget build(BuildContext context) { @@ -17,6 +24,12 @@ class TermsOfUse extends StatelessWidget { ), child: Scaffold( appBar: AppBar( + leading: IconButton( + icon: Icon(Icons.arrow_back_ios_new,size: 24,), + onPressed: (){ + context.pop(); + }, + ), scrolledUnderElevation: 0, title:Text(context.translate( 'Terms & Conditions', @@ -699,6 +712,8 @@ class TermsOfUse extends StatelessWidget { ), ), SizedBox(height: 10), + Center(child: fcscBanner), + SizedBox(height: 20), ], ), ), diff --git a/lib/presentation/Screens/charts/screens/chart_screen.dart b/lib/presentation/Screens/charts/screens/chart_screen.dart index 675a39b8..2111236f 100644 --- a/lib/presentation/Screens/charts/screens/chart_screen.dart +++ b/lib/presentation/Screens/charts/screens/chart_screen.dart @@ -78,6 +78,7 @@ class _ChartScreen1State extends ConsumerState { final GlobalKey cardKey = GlobalKey(); bool isBookmarked = false; // Track bookmark state String? bookmarkId; // Stores the ID of the bookmark record in PocketBase + late final Locale locale; @override void initState() { @@ -86,7 +87,7 @@ class _ChartScreen1State extends ConsumerState { print(' bgColor $bgColor'); // fetchChartData(widget.dataSets); checkIfBookmarked(); - final locale = ref.read(localeProvider); + locale = ref.read(localeProvider) ?? const Locale('en'); fetchChartData(widget.dataSets, locale?.languageCode ?? 'en').then((_) { if (_tabsData.isNotEmpty) { // Call onTabSelected for the first tab @@ -232,90 +233,91 @@ class _ChartScreen1State extends ConsumerState { } /// Show confirmation dialog before removing bookmark - // void showRemoveBookmarkDialog() { - // double myheight = MediaQuery.of(context).size.height; - // showDialog( - // context: context, - // barrierDismissible: false, // User must tap button to dismiss dialog - // builder: (context) => AlertDialog( - // shape: RoundedRectangleBorder( - // borderRadius: BorderRadius.circular(5.0), // Rounded corners - // ), - // contentPadding: EdgeInsets.zero, - // content: Stack( - // children: [ - // Padding( - // padding: const EdgeInsets.all(10.0), - // child: Column( - // mainAxisSize: MainAxisSize.min, - // children: [ - // SizedBox( - // height: myheight / 30, - // ), - // Text( - // context.translate( - // 'Are you sure you want to remove this bookmark?', - // 'هل أنت متأكد أنك تريد إزالة هذه الإشارة المرجعية؟'), - // textAlign: TextAlign.center, - // style: TextStyle( - // fontSize: 18, - // color: Color(0xFF898C81), - // ), - // ) - // ], - // ), - // ), - // ], - // ), - // actions: [ - // SizedBox(height: 20), - // SizedBox( - // width: 100, // Set the desired width - // child: TextButton( - // onPressed: () => Navigator.pop(context), - // style: TextButton.styleFrom( - // shape: RoundedRectangleBorder( - // borderRadius: BorderRadius.circular( - // 10.0), // Adjust the radius as needed - // ), - // side: BorderSide( - // color: Color(0xFFAA8E83), // Set the outline color - // width: 1, // Set the border width - // ), - // ), - // child: Text( - // context.translate('No', 'لا'), - // style: TextStyle( - // color: Color(0xFFAA8E83), - // fontSize: 16, - // ), - // ), - // ), - // ), - // SizedBox( - // width: 100, // Set the desired width - // child: TextButton( - // onPressed: () { - // Navigator.pop(context); - // removeBookmark(); // Close dialog - // }, - // style: TextButton.styleFrom( - // backgroundColor: Color(0xFFAA8E83), // Set background color - // foregroundColor: Colors.white, - // shape: RoundedRectangleBorder( - // borderRadius: BorderRadius.circular(10.0), // Set text color - // ), - // ), - // child: Text( - // context.translate('Yes', 'نعم'), - // style: TextStyle(color: Colors.white, fontSize: 16), - // ), - // ), - // ), - // ], - // ), - // ); - // } + void showRemoveBookmarkDialog() { + double myheight = MediaQuery.of(context).size.height; + showDialog( + context: context, + barrierDismissible: false, // User must tap button to dismiss dialog + builder: (context) => AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(5.0), // Rounded corners + ), + contentPadding: EdgeInsets.zero, + content: Stack( + children: [ + Padding( + padding: const EdgeInsets.all(10.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: myheight / 30, + ), + Text( + context.translate( + 'Are you sure you want to remove this bookmark?', + 'هل أنت متأكد أنك تريد إزالة هذه الإشارة المرجعية؟'), + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 18, + color: Color(0xFF898C81), + ), + ) + ], + ), + ), + ], + ), + actions: [ + SizedBox(height: 20), + SizedBox( + width: 100, // Set the desired width + child: TextButton( + onPressed: () => Navigator.pop(context), + style: TextButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular( + 10.0), // Adjust the radius as needed + ), + side: BorderSide( + color: Color(0xFFAA8E83), // Set the outline color + width: 1, // Set the border width + ), + ), + child: Text( + context.translate('No', 'لا'), + style: TextStyle( + color: Color(0xFFAA8E83), + fontSize: 16, + ), + ), + ), + ), + SizedBox( + width: 100, // Set the desired width + child: TextButton( + onPressed: () { + Navigator.pop(context); + removeBookmark(); // Close dialog + }, + style: TextButton.styleFrom( + backgroundColor: Color(0xFFAA8E83), // Set background color + foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10.0), // Set text color + ), + ), + child: Text( + context.translate('Yes', 'نعم'), + style: TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ], + ), + ); + } + //when the popup need for bookmark // void showAddBookmarkDialog() { // double myheight = MediaQuery.of(context).size.height; @@ -404,30 +406,15 @@ class _ChartScreen1State extends ConsumerState { // } void showAddBookmarkDialog() { addBookmark(); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - 'Added to Bookmark', - style: TextStyle(color: Colors.white, fontSize: 14), - ), - backgroundColor: Colors.black, // Match the dark background - duration: Duration(seconds: 2), - ), - ); - } - - void showRemoveBookmarkDialog() { - removeBookmark(); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - 'Removed from BookMark', - style: TextStyle(color: Colors.white, fontSize: 14), - ), - backgroundColor: Colors.black, // Match the dark background - duration: Duration(seconds: 2), - ), - ); + // ScaffoldMessenger.of(context).showSnackBar( + // SnackBar( + // content: Text( + // 'The bookmark is added successfully', + // ), + // backgroundColor: Colors.green, + // duration: Duration(seconds: 2), + // ), + // ); } void handleSkip() { @@ -547,9 +534,9 @@ class _ChartScreen1State extends ConsumerState { backgroundColor: Colors.transparent, elevation: 0, ), - child: const Text( - 'Skip', - style: TextStyle( + child: Text( + AppLocalizations.of(context)!.skip, + style: const TextStyle( color: Colors.white, fontSize: 14, ), @@ -560,22 +547,32 @@ class _ChartScreen1State extends ConsumerState { Container( decoration: BoxDecoration( shape: BoxShape.circle, + color: locale.languageCode == 'ar' + ? Color(0xFF7DAFBC) + : null, border: Border.all( - color: Colors.white, width: 2.0), + color: locale.languageCode == 'ar' + ? Color(0xFF7DAFBC) + : Colors.white, + width: 2.0), ), child: IconButton( iconSize: 20, icon: const Icon(Icons.arrow_back, color: Colors.white), onPressed: () { - ref - .read(chartsTourProvider.notifier) - .state = true; - ref - .read( - previousHomeTourProvider.notifier) - .state = false; - tutorialCoachMark.finish(); + if (locale.languageCode == 'ar') { + tutorialCoachMark.next(); + } else { + ref + .read(chartsTourProvider.notifier) + .state = true; + ref + .read(previousHomeTourProvider + .notifier) + .state = false; + tutorialCoachMark.finish(); + } }, ), ), @@ -583,16 +580,32 @@ class _ChartScreen1State extends ConsumerState { Container( decoration: BoxDecoration( shape: BoxShape.circle, - color: Color(0xFF7DAFBC), + color: locale.languageCode == 'ar' + ? null + : Color(0xFF7DAFBC), border: Border.all( - color: Color(0xFF7DAFBC), width: 1.5), + color: locale.languageCode == 'ar' + ? Colors.white + : Color(0xFF7DAFBC), + width: 1), ), child: IconButton( iconSize: 20, icon: const Icon(Icons.arrow_forward, color: Colors.white), onPressed: () { - tutorialCoachMark.next(); + if (locale.languageCode == 'ar') { + ref + .read(chartsTourProvider.notifier) + .state = true; + ref + .read(previousHomeTourProvider + .notifier) + .state = false; + tutorialCoachMark.finish(); + } else { + tutorialCoachMark.next(); + } }, ), ), @@ -631,107 +644,6 @@ class _ChartScreen1State extends ConsumerState { ), ], ), - // TargetFocus( - // identify: 'chartKey', - // keyTarget: chartKey, - // shape: ShapeLightFocus.RRect, - // paddingFocus: 0, - // contents: [ - // createTargetContent( - // text: AppLocalizations.of(context)!.kpiCards, - // alignment: ContentAlign.top, - // gap:0, - // space: 0, - // ), - // TargetContent( - // align: ContentAlign.bottom, - // child: SizedBox( - // width: double.infinity, - // height: MediaQuery.of(context).size.height * - // 0.30, // Set an appropriate height for the Stack - // child: Stack( - // children: [ - // Positioned( - // bottom: 25, - // left: 16, - // right: 16, - // child: Row( - // mainAxisAlignment: MainAxisAlignment.spaceBetween, - // children: [ - // ElevatedButton( - // onPressed: () => handleSkip(), - // style: ElevatedButton.styleFrom( - // shape: RoundedRectangleBorder( - // borderRadius: BorderRadius.circular(12), - // ), - // side: const BorderSide(color: Colors.white), - // backgroundColor: Colors.transparent, - // elevation: 0, - // ), - // child: const Text( - // 'Skip', - // style: TextStyle( - // color: Colors.white, - // fontSize: 14, - // ), - // ), - // ), - // Column( - // children: [ - // Text( - // '5/7', - // style: const TextStyle( - // color: Colors.white, - // fontSize: 14, - // ), - // ), - // const SizedBox(height: 3), - // Row( - // children: [ - // Container( - // decoration: BoxDecoration( - // shape: BoxShape.circle, - // border: Border.all( - // color: Colors.white, width: 2.0), - // ), - // child: IconButton( - // icon: const Icon(Icons.arrow_back, - // color: Colors.white), - // onPressed: () { - // scrollToTargetThenShowTutorial(bookMarkKey); - // tutorialCoachMark.next(); - // }, - // ), - // ), - // const SizedBox(width: 10), - // Container( - // decoration: BoxDecoration( - // shape: BoxShape.circle, - // color: Color(0xFF7DAFBC), - // border: Border.all( - // color: Color(0xFF7DAFBC), width: 1.5), - // ), - // child: IconButton( - // icon: const Icon(Icons.arrow_forward, - // color: Colors.white), - // onPressed: () { - // tutorialCoachMark.next(); - // }, - // ), - // ), - // ], - // ), - // ], - // ), - // ], - // ), - // ), - // ], - // ), - // ), - // ), - // ], - // ), TargetFocus( identify: 'BookMarkKey', keyTarget: bookMarkKey, @@ -743,7 +655,7 @@ class _ChartScreen1State extends ConsumerState { text: AppLocalizations.of(context)!.bookMark, alignment: ContentAlign.bottom, gap: 53, - space: 50, + space: screenWidth * 0.22, ), TargetContent( align: ContentAlign.bottom, @@ -785,9 +697,9 @@ class _ChartScreen1State extends ConsumerState { backgroundColor: Colors.transparent, elevation: 0, ), - child: const Text( - 'Skip', - style: TextStyle( + child: Text( + AppLocalizations.of(context)!.skip, + style: const TextStyle( color: Colors.white, fontSize: 14, ), @@ -798,15 +710,33 @@ class _ChartScreen1State extends ConsumerState { Container( decoration: BoxDecoration( shape: BoxShape.circle, + color: locale.languageCode == 'ar' + ? Color(0xFF7DAFBC) + : null, border: Border.all( - color: Colors.white, width: 2.0), + color: locale.languageCode == 'ar' + ? Color(0xFF7DAFBC) + : Colors.white, + width: 2.0), ), child: IconButton( iconSize: 20, - icon: const Icon(Icons.arrow_back, - color: Colors.white), + icon: const Icon( + Icons.arrow_back, + color: Colors.white, + ), onPressed: () { - tutorialCoachMark.previous(); + if (locale.languageCode == 'ar') { + ref + .read(chartsTourProvider.notifier) + .state = true; + ref + .read(scaffoldTourProvider.notifier) + .state = false; + tutorialCoachMark.finish(); + } else { + tutorialCoachMark.previous(); + } }, ), ), @@ -814,22 +744,33 @@ class _ChartScreen1State extends ConsumerState { Container( decoration: BoxDecoration( shape: BoxShape.circle, - color: Color(0xFF7DAFBC), + color: locale.languageCode == 'ar' + ? null + : Color(0xFF7DAFBC), border: Border.all( - color: Color(0xFF7DAFBC), width: 1), + color: locale.languageCode == 'ar' + ? Colors.white + : Color(0xFF7DAFBC), + width: 1), ), child: IconButton( iconSize: 20, - icon: const Icon(Icons.arrow_forward, - color: Colors.white), + icon: const Icon( + Icons.arrow_forward, + color: Colors.white, + ), onPressed: () { - ref - .read(chartsTourProvider.notifier) - .state = true; - ref - .read(scaffoldTourProvider.notifier) - .state = false; - tutorialCoachMark.finish(); + if (locale.languageCode == 'ar') { + tutorialCoachMark.previous(); + } else { + ref + .read(chartsTourProvider.notifier) + .state = true; + ref + .read(scaffoldTourProvider.notifier) + .state = false; + tutorialCoachMark.finish(); + } }, ), ), @@ -849,25 +790,13 @@ class _ChartScreen1State extends ConsumerState { align: ContentAlign.right, child: Container( width: screenWidth / 4, - height: screenHeight, + height: screenHeight * 0.2, child: Stack( children: [ Image.asset( 'assets/app_tour/leftDown.png', fit: BoxFit.contain, ), - // Positioned( - // top: 0, - // left: MediaQuery.of(context).size.width* 0.5, - // child: SizedBox( - // width: 50, - // height: 100, - // child: Image.asset( - // 'assets/app_tour/bookmark2.png', - // fit: BoxFit.contain, - // ), - // ), - // ), ], ), ), @@ -890,9 +819,9 @@ class _ChartScreen1State extends ConsumerState { contents: [ createTargetContent( text: AppLocalizations.of(context)!.bookMark, - space: 50, + space: screenWidth * 0.22, alignment: ContentAlign.bottom, - gap: 23, + gap: 53, ), TargetContent( align: ContentAlign.bottom, @@ -934,9 +863,9 @@ class _ChartScreen1State extends ConsumerState { backgroundColor: Colors.transparent, elevation: 0, ), - child: const Text( - 'Skip', - style: TextStyle( + child: Text( + AppLocalizations.of(context)!.skip, + style: const TextStyle( color: Colors.white, fontSize: 14, ), @@ -947,15 +876,34 @@ class _ChartScreen1State extends ConsumerState { Container( decoration: BoxDecoration( shape: BoxShape.circle, + color: locale.languageCode == 'ar' + ? Color(0xFF7DAFBC) + : null, border: Border.all( - color: Colors.white, width: 2.0), + color: locale.languageCode == 'ar' + ? Color(0xFF7DAFBC) + : Colors.white, + width: 2.0, + ), ), child: IconButton( iconSize: 20, - icon: const Icon(Icons.arrow_back, - color: Colors.white), + icon: const Icon( + Icons.arrow_back, + color: Colors.white, + ), onPressed: () { - tutorialCoachMark.next(); + if (locale.languageCode == 'ar') { + ref + .read(chartsTourProvider.notifier) + .state = true; + ref + .read(scaffoldTourProvider.notifier) + .state = false; + tutorialCoachMark.finish(); + } else { + tutorialCoachMark.next(); + } }, ), ), @@ -963,22 +911,32 @@ class _ChartScreen1State extends ConsumerState { Container( decoration: BoxDecoration( shape: BoxShape.circle, - color: Color(0xFF7DAFBC), + color: locale.languageCode == 'ar' + ? null + : Color(0xFF7DAFBC), border: Border.all( - color: Color(0xFF7DAFBC), width: 1.5), + color: locale.languageCode == 'ar' + ? Colors.white + : Color(0xFF7DAFBC), + width: 2.0, + ), ), child: IconButton( iconSize: 20, icon: const Icon(Icons.arrow_forward, color: Colors.white), onPressed: () { - ref - .read(chartsTourProvider.notifier) - .state = true; - ref - .read(scaffoldTourProvider.notifier) - .state = false; - tutorialCoachMark.finish(); + if (locale.languageCode == 'ar') { + tutorialCoachMark.next(); + } else { + ref + .read(chartsTourProvider.notifier) + .state = true; + ref + .read(scaffoldTourProvider.notifier) + .state = false; + tutorialCoachMark.finish(); + } }, ), ), @@ -994,29 +952,17 @@ class _ChartScreen1State extends ConsumerState { ), ), TargetContent( - padding: EdgeInsets.only(left: 0, top: 10), + padding: EdgeInsets.only(left: 0, top: 0), align: ContentAlign.right, - child: Container( + child: SizedBox( width: screenWidth / 4, - height: screenHeight, + height: screenHeight * 0.2, child: Stack( children: [ Image.asset( 'assets/app_tour/leftDown.png', fit: BoxFit.contain, ), - // Positioned( - // top: 0, - // left: MediaQuery.of(context).size.width* 0.5, - // child: SizedBox( - // width: 50, - // height: 100, - // child: Image.asset( - // 'assets/app_tour/bookmark2.png', - // fit: BoxFit.contain, - // ), - // ), - // ), ], ), ), @@ -1034,7 +980,7 @@ class _ChartScreen1State extends ConsumerState { text: AppLocalizations.of(context)!.kpiCards, space: 0, alignment: ContentAlign.top, - gap: 50, + gap: 55, ), TargetContent( align: ContentAlign.bottom, @@ -1076,9 +1022,9 @@ class _ChartScreen1State extends ConsumerState { backgroundColor: Colors.transparent, elevation: 0, ), - child: const Text( - 'Skip', - style: TextStyle( + child: Text( + AppLocalizations.of(context)!.skip, + style: const TextStyle( color: Colors.white, fontSize: 14, ), @@ -1089,23 +1035,36 @@ class _ChartScreen1State extends ConsumerState { Container( decoration: BoxDecoration( shape: BoxShape.circle, + color: locale.languageCode == 'ar' + ? Color(0xFF7DAFBC) + : null, border: Border.all( - color: Colors.white, width: 2.0), + color: locale.languageCode == 'ar' + ? Color(0xFF7DAFBC) + : Colors.white, + width: 2.0, + ), ), child: IconButton( iconSize: 20, - icon: const Icon(Icons.arrow_back, - color: Colors.white), + icon: const Icon( + Icons.arrow_back, + color: Colors.white, + ), onPressed: () { - ref - .read(previousChartsTourProvider - .notifier) - .state = true; - ref - .read( - previousHomeTourProvider.notifier) - .state = false; - tutorialCoachMark.finish(); + if (locale.languageCode == 'ar') { + tutorialCoachMark.previous(); + } else { + ref + .read(previousChartsTourProvider + .notifier) + .state = true; + ref + .read(previousHomeTourProvider + .notifier) + .state = false; + tutorialCoachMark.finish(); + } }, ), ), @@ -1113,16 +1072,35 @@ class _ChartScreen1State extends ConsumerState { Container( decoration: BoxDecoration( shape: BoxShape.circle, - color: Color(0xFF7DAFBC), + color: locale.languageCode == 'ar' + ? null + : Color(0xFF7DAFBC), border: Border.all( - color: Color(0xFF7DAFBC), width: 1.5), + color: locale.languageCode == 'ar' + ? Colors.white + : Color(0xFF7DAFBC), + width: 1), ), child: IconButton( iconSize: 20, - icon: const Icon(Icons.arrow_forward, - color: Colors.white), + icon: const Icon( + Icons.arrow_forward, + color: Colors.white, + ), onPressed: () { - tutorialCoachMark.previous(); + if (locale.languageCode == 'ar') { + ref + .read(previousChartsTourProvider + .notifier) + .state = true; + ref + .read(previousHomeTourProvider + .notifier) + .state = false; + tutorialCoachMark.finish(); + } else { + tutorialCoachMark.previous(); + } }, ), ), @@ -1336,6 +1314,7 @@ class _ChartScreen1State extends ConsumerState { for (var chart in data) { final groupBy = chart['group_by']; List response = chart['response'] ?? []; + final chartHeading = chart['chart_heading']; // Filter the response based on selected filters var chartFilteredData = response.where((responseItem) { @@ -1362,6 +1341,26 @@ class _ChartScreen1State extends ConsumerState { }); }).toList(); + print('chartFilteredData- $chartFilteredData'); + + // If chartFilteredData is empty, print the message + if (chartFilteredData.isEmpty) { + if (kDebugMode) { + print( + "Selected year: ${selectedFilters.firstWhere((f) => f['filter_key'] == 'TIME_PERIOD', orElse: () => { + 'filter_data': ['Unknown'] + })['filter_data']} - No data for chart: : $chartHeading"); + } + + // Add the complete chart data to the filteredData list + filteredData.add({ + ...chart, + 'response': response, // Return full unfiltered response + }); + + continue; + } + // If any data matches the filter, add the whole chart data object // Add filtered chart only once if (chartFilteredData.isNotEmpty && @@ -2115,6 +2114,7 @@ class _ChartScreen1State extends ConsumerState { color: isBookmarked ? Colors.black : Colors.white, + size: 23, ), ], ), @@ -2212,6 +2212,8 @@ class _ChartScreen1State extends ConsumerState { color: Colors.white, ), ), + + SizedBox(width: 10), GestureDetector( onTap: () { showRightSideModal( @@ -2389,6 +2391,12 @@ class _ChartScreen1State extends ConsumerState { right: 16.0, bottom: 1.0, top: 1.0), + decoration: BoxDecoration( + color: Colors + .white, // Move color inside BoxDecoration + borderRadius: BorderRadius.circular( + 12), // Ensure border radius is applied + ), child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: @@ -2432,15 +2440,20 @@ class _ChartScreen1State extends ConsumerState { const SizedBox(height: 5), Flexible( fit: FlexFit.loose, - child: FittedBox( - child: Text( - '(${response[0]['display_value'] ?? 'NA'})', - // '(${data['firstYear'] ?? - // 'NA'} - ${data['lastYear'] ?? - // 'NA'})', - style: const TextStyle( - fontSize: 10, - color: Colors.grey), + child: SizedBox( + height: 20.0, + child: FittedBox( + child: Text( + '(${response[0]['display_value'] ?? 'NA'})', + // '(${data['firstYear'] ?? + // 'NA'} - ${data['lastYear'] ?? + // 'NA'})', + style: + const TextStyle( + fontSize: 10, + color: Colors + .grey), + ), ), ), ), @@ -2451,20 +2464,60 @@ class _ChartScreen1State extends ConsumerState { height: 50.0, child: FittedBox( fit: BoxFit.contain, - child: Text( - response[0] - ['value'] ?? - 'NA', - // '${data['roundedAverage'] ?? - // 'NA'}', - style: - const TextStyle( - fontSize: 20, - fontWeight: - FontWeight.w900, - color: Color( - 0xFF90B0D5), - ), + child: Row( + children: [ + Text( + response[0][ + 'value'] ?? + 'NA', + // '${data['roundedAverage'] ?? + // 'NA'}', + style: TextStyle( + fontSize: 20, + fontWeight: + FontWeight + .w900, + color: response[0] + [ + 'calculation'] == + 'different' + ? _getColorFromHex( + response[0] + [ + 'font_color']) + : const Color( + 0xFF90B0D5), + // color: Color( + // 0xFF90B0D5), + ), + ), + const SizedBox( + width: + 1), // Space between text and icon + if (response[0][ + 'calculation'] == + 'different') ...[ + if (response[0][ + 'font_color'] == + '#D83731') + const Icon( + Icons + .arrow_downward, + color: Colors + .red, + size: 22) + else if (response[ + 0][ + 'font_color'] == + '#11AF22') + const Icon( + Icons + .arrow_upward, + color: Colors + .green, + size: 22), + ], + ], ), ), ), @@ -2500,6 +2553,12 @@ class _ChartScreen1State extends ConsumerState { child: Container( height: cardHeight, padding: const EdgeInsets.all(10.0), + decoration: BoxDecoration( + color: Colors + .white, // Move color inside BoxDecoration + borderRadius: BorderRadius.circular( + 12), // Ensure border radius is applied + ), child: Column( mainAxisSize: MainAxisSize .min, // Adjust card height based on content @@ -2569,12 +2628,18 @@ class _ChartScreen1State extends ConsumerState { // data['lastYearValue']), // apiService.formatAmount( // data['lastYearValue']), - style: const TextStyle( + style: TextStyle( fontSize: 18, fontWeight: FontWeight.w900, - color: - Color(0xFF90B0D5), + color: response[0][ + 'calculation'] == + 'different' + ? _getColorFromHex( + response[0][ + 'font_color']) + : const Color( + 0xFF90B0D5), ), ), ), @@ -2597,12 +2662,18 @@ class _ChartScreen1State extends ConsumerState { 'NA', // apiService.formatAmount( // data['secondLastYearValue']), - style: const TextStyle( + style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, - color: - Color(0xFFD83731), + color: response[1][ + 'calculation'] == + 'different' + ? _getColorFromHex( + response[0][ + 'font_color']) + : const Color( + 0xFFD83731), ), ), ), @@ -2632,29 +2703,48 @@ class _ChartScreen1State extends ConsumerState { 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), - ConstrainedBox( - constraints: const BoxConstraints( - minHeight: - 200, // Minimum height - maxHeight: - 400, // Maximum height + margin: const EdgeInsets.all(10), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color( + int.parse( + (chartScreenData[ + 'border_color'] ?? + '#898C81') + .replaceFirst('#', '0xff'), ), - // child: buildChart(chartsData[index]), - child: ChartWidget( - chartData: - chartsData[index])), - ], - ), - ), - ); + ), // Border color + width: 1, // Border width + ), + color: Colors.white, + borderRadius: BorderRadius.circular( + 8), // Optional: Rounded corners + ), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + // ConstrainedBox + Container( + // constraints: const BoxConstraints( + // minHeight: + // 200, // Minimum height + // maxHeight: + // 400, // Maximum height + // ), + height: 350, + + // child: buildChart(chartsData[index]), + child: ChartWidget( + chartData: + chartsData[index])) + ], + ), + ), + )); }, ), ], @@ -2701,7 +2791,7 @@ class _ChartScreen1State extends ConsumerState { onTap: () { setState(() { _activeTabIndex = _tabsData.indexOf(tab); - }); + }); _scrollToIndex(_activeTabIndex); onTabSelected(tab['id']!); }, @@ -2723,4 +2813,13 @@ class _ChartScreen1State extends ConsumerState { ), ); } -} \ No newline at end of file +} + +// Function to convert hex color string to Color +Color _getColorFromHex(String hexColor) { + hexColor = hexColor.replaceFirst('#', ''); + if (hexColor.length == 6) { + hexColor = 'FF$hexColor'; // Add alpha if not provided + } + return Color(int.parse(hexColor, radix: 16)); +} diff --git a/lib/presentation/Screens/charts/widgets/chart_widget.dart b/lib/presentation/Screens/charts/widgets/chart_widget.dart index 3cf031dd..470ebc97 100644 --- a/lib/presentation/Screens/charts/widgets/chart_widget.dart +++ b/lib/presentation/Screens/charts/widgets/chart_widget.dart @@ -1,3 +1,4 @@ +import 'dart:convert'; import 'dart:math'; import 'package:fl_chart/fl_chart.dart'; @@ -48,27 +49,78 @@ class ChartWidget extends StatelessWidget { List parsePieChartData( dynamic chartData, double totalValue, + // String totalValue, int? touchedIndex, ) { + debugPrint('Chart Data: ${jsonEncode(chartData)}'); + return chartData['response'] .asMap() .entries .map((entry) { int index = entry.key; + + print('piePArse'); + var data = entry.value; - double value = double.tryParse(data['ObsValue']['Value']) ?? 0.0; - double percentage = (value / totalValue) * 100; + // double value = double.tryParse(data['ObsValue']['Value']) ?? 0.0; + // double value = (data['ObsValue']['Value'] is double) + // ? data['ObsValue']['Value'] + // : (data['ObsValue']['Value'] is int) + // ? (data['ObsValue']['Value'] as int).toDouble() + // : 0.0; + + // Handle different types: int, double, and String + double value = 0.0; + + var rawValue = data['ObsValue']['Value']; + + print('Raw Value: $rawValue (Type: ${rawValue.runtimeType})'); + + if (rawValue is String) { + value = double.tryParse(rawValue) ?? 0.0; + } else if (rawValue is int) { + value = rawValue.toDouble(); + } else if (rawValue is double) { + value = rawValue; + } else { + print('Unexpected Type for ObsValue[Value]: ${rawValue.runtimeType}'); + } + + // if (data['ObsValue']['Value'] is String) { + // value = double.tryParse(data['ObsValue']['Value']) ?? 0.0; // Parse string to double + // } else if (data['ObsValue']['Value'] is int) { + // value = (data['ObsValue']['Value'] as int).toDouble(); // Convert int to double + // } else if (data['ObsValue']['Value'] is double) { + // value = data['ObsValue']['Value']; // Already a double + // } + + print('piePArse1 - $value'); + // double percentage = (value / totalValue) * 100; + double percentage = (totalValue > 0) ? (value / totalValue) * 100 : 0.0; + if (kDebugMode) { + print('percentage- $percentage'); + print('Total Value: $totalValue'); + } + + debugPrint('debug Total Value- $totalValue'); + debugPrint('debug percentage- $percentage'); 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 + radius: isTouched ? 60 : 50, + + // Increase size when touched titleStyle: TextStyle( fontSize: isTouched ? 12 : 10, fontWeight: FontWeight.bold, - color: Colors.white, + color: Colors.black, + // color: Colors.white, ), + titlePositionPercentageOffset: 1.3, ); }).toList(); } @@ -94,14 +146,34 @@ class ChartWidget extends StatelessWidget { ), ), SizedBox(width: 8), - Tooltip( - message: title, // Full text on hover - child: Text( - shortTitle, - style: TextStyle(fontSize: 12), - overflow: TextOverflow.ellipsis, // Ensures text doesn't overflow + TooltipTheme( + data: TooltipThemeData( + decoration: BoxDecoration( + color: Colors.blueGrey[800], // Change background color + borderRadius: + BorderRadius.circular(8), // Optional: rounded corners + ), + textStyle: TextStyle(color: Colors.white), // Change text color + ), + child: Tooltip( + message: title, // Full text on hover + child: ConstrainedBox( + // Constrain width to allow wrapping + constraints: BoxConstraints(maxWidth: 100), + child: Text( + title, + style: TextStyle( + fontSize: 12, + ), + softWrap: true, + maxLines: 2, + overflow: + TextOverflow.ellipsis, // Ensures text doesn't overflow + ), + ), ), ), + SizedBox(width: 5), ], ); }).toList(); @@ -123,6 +195,8 @@ class ChartWidget extends StatelessWidget { return Center(child: Text('No chart data available')); } + print(chartData['chart_type_json']['TIME_PERIOD']); + String groupByKey = chartData['group_by'] ?? ''; print('groupByKey $groupByKey'); Set groupByValues = extractGroupByValues(chartData, groupByKey); @@ -213,10 +287,28 @@ class ChartWidget extends StatelessWidget { ), ); case 'pie_chart': - double totalValue = chartData['response'] - .map( - (entry) => double.tryParse(entry['ObsValue']['Value']) ?? 0.0) - .fold(0.0, (prev, element) => prev + element); + double totalValue = chartData['response'].map((entry) { + var value = entry['ObsValue']['Value']; + print( + 'Processing value: $value, type: ${value.runtimeType}'); // Debug each value + print(value is int + ? value.toDouble() + : value is String + ? double.tryParse(value) ?? 0.0 + : 0.0); + return (value is num) + ? value.toDouble() + : value is String + ? double.tryParse(value) ?? 0.0 + : 0.0; + }).fold(0.0, (prev, element) => prev + element); + // List totalValues = chartData['response'] + // .map((entry) { + // var value = entry['ObsValue']['Value']; + // print('Processing value: $value, type: ${value.runtimeType}'); // Debug each value + // + // return value.toString(); // Convert to string + // }).fold(0.0, (prev, element) => prev + element); ValueNotifier touchedIndex = ValueNotifier(null); @@ -231,7 +323,7 @@ class ChartWidget extends StatelessWidget { ), textAlign: TextAlign.center, ), - SizedBox(height: 5), + SizedBox(height: 15), Text( chartData['chart_sub_heading'] ?? '', style: TextStyle( @@ -240,7 +332,7 @@ class ChartWidget extends StatelessWidget { ), textAlign: TextAlign.center, ), - SizedBox(height: 20), + SizedBox(height: 70), Expanded( child: ValueListenableBuilder( valueListenable: touchedIndex, @@ -269,16 +361,19 @@ class ChartWidget extends StatelessWidget { }, ), ), - SizedBox(height: 25), + SizedBox(height: 65), Flexible( + // child: SingleChildScrollView( + // scrollDirection: Axis.horizontal, + // child: SingleChildScrollView( scrollDirection: Axis.vertical, child: Container( constraints: - BoxConstraints(minHeight: 5), // Allow dynamic height + BoxConstraints(minHeight: 3), // Allow dynamic height child: Padding( padding: const EdgeInsets.only( - left: 8.0, right: 8.0, bottom: 8.0, top: 20.0), + left: 0.0, right: 0.0, bottom: 8.0, top: 20.0), child: Wrap( spacing: 12, runSpacing: 8, @@ -288,6 +383,8 @@ class ChartWidget extends StatelessWidget { ), ), ), + + // ), ), ], ); @@ -325,7 +422,7 @@ class ChartWidget extends StatelessWidget { ), textAlign: TextAlign.center, ), - SizedBox(height: 10), + SizedBox(height: 15), AspectRatio( aspectRatio: 1.5, child: BarChart( @@ -336,8 +433,12 @@ class ChartWidget extends StatelessWidget { // tooltipBgColor: Colors.black.withOpacity(0.8), fitInsideHorizontally: true, fitInsideVertically: true, - tooltipPadding: const EdgeInsets.all(8), + // tooltipPadding: const EdgeInsets.all(8), + tooltipPadding: const EdgeInsets.symmetric( + horizontal: 4, vertical: 8), // Optional + tooltipHorizontalAlignment: FLHorizontalAlignment.left, tooltipMargin: 16, + getTooltipItem: (groupData, groupIndex, rodData, rodIndex) { // Get the list of group names dynamically @@ -395,6 +496,7 @@ class ChartWidget extends StatelessWidget { '', TextStyle(color: Colors.white, fontSize: 12), children: tooltipTextSpans, + textAlign: TextAlign.left, ); }, ), @@ -458,7 +560,7 @@ class ChartWidget extends StatelessWidget { waitDuration: Duration(milliseconds: 500), showDuration: Duration(seconds: 2), decoration: BoxDecoration( - color: Colors.black, + color: Colors.blueGrey[900], borderRadius: BorderRadius.circular(4), ), textStyle: TextStyle(color: Colors.white), @@ -494,7 +596,7 @@ class ChartWidget extends StatelessWidget { colorIndex % uniqueColorsLine_trend_2.length]; colorIndex++; } - print('LnTrnd1'); + print('LnTrnd1'); // Extract all years from the chart data List years = (chartData['response'] as List) @@ -531,11 +633,10 @@ class ChartWidget extends StatelessWidget { // (entry) => double.parse(entry['ObsKey']['TIME_PERIOD'])) // .toSet(); - - Set uniqueXValues = filteredData - .map((entry) { - String? timePeriod = entry['ObsKey']['TIME_PERIOD']; // Nullable String - // print('TIME_PERIOD- $timePeriod'); + Set uniqueXValues = filteredData.map((entry) { + String? timePeriod = + entry['ObsKey']['TIME_PERIOD']; // Nullable String + print('TIME_PERIOD- $timePeriod'); if (timePeriod == null) { print('TIME_PERIOD is null'); @@ -556,8 +657,7 @@ class ChartWidget extends StatelessWidget { print('Unknown format: $timePeriod'); return timePeriod; // Keep it as is } - }) - .toSet(); + }).toSet(); print("Unique X Values: $uniqueXValues"); @@ -566,18 +666,30 @@ class ChartWidget extends StatelessWidget { if (RegExp(r'^\d{4}$').hasMatch(timePeriod)) { return double.parse(timePeriod); // Year-only (2019 → 2019.0) } else if (RegExp(r'^\d{4}-\d{2}$').hasMatch(timePeriod)) { - return double.parse(timePeriod.replaceAll('-', '.')); // Year-Month (2019-11 → 2019.11) + return double.parse(timePeriod.replaceAll( + '-', '.')); // Year-Month (2019-11 → 2019.11) } else if (RegExp(r'^\d{4}-[A-Za-z]{3}$').hasMatch(timePeriod)) { // Year-MonthAbbr (2019-Nov) Map monthMap = { - 'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, - 'May': 5, 'Jun': 6, 'Jul': 7, 'Aug': 8, - 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12 + 'Jan': 1, + 'Feb': 2, + 'Mar': 3, + 'Apr': 4, + 'May': 5, + 'Jun': 6, + 'Jul': 7, + 'Aug': 8, + 'Sep': 9, + 'Oct': 10, + 'Nov': 11, + 'Dec': 12 }; List parts = timePeriod.split('-'); - int month = monthMap[parts[1]] ?? 1; // Default to January if unknown - return double.parse('${parts[0]}.$month'); // Convert to format (2019-Nov → 2019.11) + int month = + monthMap[parts[1]] ?? 1; // Default to January if unknown + return double.parse( + '${parts[0]}.$month'); // Convert to format (2019-Nov → 2019.11) } throw FormatException("Invalid TIME_PERIOD format: $timePeriod"); @@ -589,15 +701,12 @@ class ChartWidget extends StatelessWidget { .toSet(); print('Processed X Values: $uniqueXValuesProcessed'); - - print('LnTrnd2.1'); // Generate line bars for the chart List lineBars = lineBarsData(filteredData, groupByValues, groupByKey); - print('LnTrnd3'); return Column(children: [ @@ -631,10 +740,9 @@ class ChartWidget extends StatelessWidget { // minX: uniqueXValues.reduce((a, b) => a < b ? a : b), // maxX: uniqueXValues.reduce((a, b) => a > b ? a : b), - - // minX: uniqueXValuesProcessed.reduce((a, b) => a < b ? a : b), - // maxX: uniqueXValuesProcessed.reduce((a, b) => a > b ? a : b), - ))), + // minX: uniqueXValuesProcessed.reduce((a, b) => a < b ? a : b), + // maxX: uniqueXValuesProcessed.reduce((a, b) => a > b ? a : b), + ))), Padding( padding: const EdgeInsets.all(8.0), child: Wrap( @@ -715,7 +823,7 @@ class ChartWidget extends StatelessWidget { // Generate line bars for the chart List lineBars = lineBarsData(filteredData, groupByValues, groupByKey); - + return Column(children: [ Text( chartData['chart_heading'] ?? '', // Chart title from data @@ -859,7 +967,7 @@ class ChartWidget extends StatelessWidget { Expanded( child: SingleChildScrollView( scrollDirection: Axis.horizontal, // Enable horizontal scrolling - padding: const EdgeInsets.only(right: 40), + padding: const EdgeInsets.only(right: 40, top: 20), child: SizedBox( width: (uniqueXValues.length * 50) + 50, // Adjust width dynamically @@ -884,11 +992,61 @@ class ChartWidget extends StatelessWidget { List xAxisData = []; List yAxisData = []; + var xadditionalgrp = chartData['chart_type_json']['additional_x_group']; + + print('xadditionalgrp-$xadditionalgrp'); + for (var entry in chartData['response']) { var xValue = entry['ObsKey'][groupByKey]; + var xTimePeriod = entry['ObsKey']['TIME_PERIOD']; var yValue = entry['ObsValue']['Value']; + var xadditionalgroup = + chartData['chart_type_json']['additional_x_group']; + + print('chartData response: ${chartData['response']}'); + + print('xValue-$xValue'); + print('Xadditionalt-$xTimePeriod'); + print('xadditionalgroup-$xadditionalgroup'); + print('yValue-$yValue'); + + if (xadditionalgrp == 'TIME_PERIOD') { + chartData['response'].sort((a, b) { + // Convert TIME_PERIOD to int for proper sorting + int timeA = + int.tryParse(a['ObsKey']['TIME_PERIOD'].toString()) ?? 0; + int timeB = + int.tryParse(b['ObsKey']['TIME_PERIOD'].toString()) ?? 0; + + // Extract QUARTER and convert "Q1", "Q2", etc. to numeric values + int quarterA = int.tryParse( + a['ObsKey']['QUARTER'].toString().replaceAll('Q', '')) ?? + 0; + int quarterB = int.tryParse( + b['ObsKey']['QUARTER'].toString().replaceAll('Q', '')) ?? + 0; + + // First, sort by TIME_PERIOD. If equal, sort by QUARTER + if (timeA != timeB) { + return timeA.compareTo(timeB); + } else { + return quarterA.compareTo(quarterB); + } + }); + } + + // if (xValue != null && yValue != null) { + // xAxisData.add(xValue.toString()); + // yAxisData.add(double.tryParse(yValue.toString()) ?? 0.0); + // } if (xValue != null && yValue != null) { - xAxisData.add(xValue.toString()); + // Check if additional_x_group is "Timeperiod" and concatenate + String xLabel = xValue.toString(); + if (xadditionalgroup == 'TIME_PERIOD' && xTimePeriod != null) { + xLabel = '$xTimePeriod-$xValue'; // Format: Label (TimePeriod) + } + + xAxisData.add(xLabel); yAxisData.add(double.tryParse(yValue.toString()) ?? 0.0); } } @@ -919,7 +1077,23 @@ class ChartWidget extends StatelessWidget { maxY: yAxisData.isNotEmpty ? yAxisData.reduce((a, b) => a > b ? a : b) * 1.2 : 10, - barTouchData: BarTouchData(enabled: true), + // barTouchData: BarTouchData(enabled: true), + barTouchData: BarTouchData( + enabled: true, + handleBuiltInTouches: true, + touchTooltipData: BarTouchTooltipData( + // fitInsideHorizontally: true, + // fitInsideVertically: true, + // tooltipPadding: const EdgeInsets.all(8), + // tooltipMargin: 16, + getTooltipItem: (group, groupIndex, rod, rodIndex) { + return BarTooltipItem( + rod.toY.toStringAsFixed(1), + const TextStyle(color: Colors.white), + ); + }, + ), + ), titlesData: FlTitlesData( leftTitles: AxisTitles( sideTitles: SideTitles( @@ -948,23 +1122,57 @@ class ChartWidget extends StatelessWidget { : title; return Padding( - padding: const EdgeInsets.only(top: 8.0), + padding: + const EdgeInsets.only(top: 8.0, left: 55.0), child: SizedBox( width: 60, // Limit width to force wrapping child: Transform.rotate( - angle: -0.5, - child: Tooltip( - message: title, - child: Text( - displayTitle, - softWrap: true, - overflow: TextOverflow.ellipsis, - )), + // angle: -0.5, + angle: -1.5, + + child: TooltipTheme( + data: TooltipThemeData( + decoration: BoxDecoration( + color: Colors.blueGrey[ + 800], // Change background color + borderRadius: BorderRadius.circular( + 8), // Optional: rounded corners + ), + textStyle: TextStyle( + color: Colors + .white), // Change text color + ), + child: TooltipTheme( + data: TooltipThemeData( + decoration: BoxDecoration( + color: Colors.blueGrey[ + 800], // Change background color + borderRadius: BorderRadius.circular( + 8), // Optional: rounded corners + ), + textStyle: TextStyle( + color: Colors + .white), // Change text color + ), + child: Tooltip( + message: title, + child: Text( + // title, + displayTitle, + softWrap: true, + style: TextStyle( + fontSize: 10, + ), + overflow: TextOverflow.ellipsis, + ), + ), + ), + ), ))); } return Container(); }, - reservedSize: 40, + reservedSize: 80, ), ), topTitles: AxisTitles( @@ -1029,102 +1237,104 @@ class ChartWidget extends StatelessWidget { SizedBox(height: 10), // Chart Expanded( - child: BarChart( - BarChartData( - alignment: BarChartAlignment.spaceAround, - maxY: yAxisData.isNotEmpty - ? yAxisData.reduce((a, b) => a > b ? a : b) * 1.2 - : 10, - rotationQuarterTurns: rotationTurns, - barTouchData: BarTouchData( - enabled: true, - handleBuiltInTouches: true, - touchTooltipData: BarTouchTooltipData( - fitInsideHorizontally: true, - fitInsideVertically: true, - tooltipPadding: const EdgeInsets.all(8), - tooltipMargin: 16, - getTooltipItem: (group, groupIndex, rod, rodIndex) { - return BarTooltipItem( - '${rod.toY.toStringAsFixed(1)}', - const TextStyle(color: Colors.white), - ); - }, - ), - ), - titlesData: FlTitlesData( - leftTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: false, - interval: (yAxisData.isNotEmpty - ? yAxisData.reduce((a, b) => a > b ? a : b) / 5 - : 1), - getTitlesWidget: (value, meta) { - return Padding( - padding: const EdgeInsets.only(right: 8.0), - child: Text('${value.toInt()}'), + child: BarChart( + BarChartData( + alignment: BarChartAlignment.spaceAround, + maxY: yAxisData.isNotEmpty + ? yAxisData.reduce((a, b) => a > b ? a : b) * 1.2 + : 10, + rotationQuarterTurns: rotationTurns, + barTouchData: BarTouchData( + enabled: true, + handleBuiltInTouches: true, + touchTooltipData: BarTouchTooltipData( + fitInsideHorizontally: true, + fitInsideVertically: true, + tooltipPadding: const EdgeInsets.all(8), + tooltipMargin: 16, + getTooltipItem: (group, groupIndex, rod, rodIndex) { + return BarTooltipItem( + '${rod.toY.toStringAsFixed(1)}', + const TextStyle(color: Colors.white), ); }, - reservedSize: 60, ), ), - bottomTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: true, - getTitlesWidget: (value, meta) { - if (value.toInt() < xAxisData.length) { + titlesData: FlTitlesData( + leftTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: false, + interval: (yAxisData.isNotEmpty + ? yAxisData.reduce((a, b) => a > b ? a : b) / 5 + : 1), + getTitlesWidget: (value, meta) { return Padding( - padding: const EdgeInsets.only(top: 8.0), - child: Transform.rotate( - angle: -1.58, - // angle: -45 * - // (3.1415927 / 180), // Rotating by -45 degrees - alignment: Alignment.center, - child: Center( - child: SizedBox( - width: 100, - child: Text( - xAxisData[value.toInt()], - style: const TextStyle(fontSize: 12), - softWrap: true, - maxLines: 2, + padding: const EdgeInsets.only(right: 8.0), + child: Text('${value.toInt()}'), + ); + }, + reservedSize: 60, + ), + ), + bottomTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + getTitlesWidget: (value, meta) { + if (value.toInt() < xAxisData.length) { + return Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Transform.rotate( + angle: -1.58, + // angle: -45 * + // (3.1415927 / 180), // Rotating by -45 degrees + alignment: Alignment.center, + child: Center( + child: SizedBox( + width: 100, + child: Text( + xAxisData[value.toInt()], + style: const TextStyle(fontSize: 12), + softWrap: true, + maxLines: 3, + ), ), ), ), - ), - ); - } - return Container(); - }, - reservedSize: 85, + ); + } + return Container(); + }, + reservedSize: 85, + ), + ), + topTitles: AxisTitles( + sideTitles: + SideTitles(showTitles: false), // Hide top titles + ), + rightTitles: AxisTitles( + sideTitles: + SideTitles(showTitles: false), // Hide right titles ), ), - topTitles: AxisTitles( - sideTitles: SideTitles(showTitles: false), // Hide top titles - ), - rightTitles: AxisTitles( - sideTitles: - SideTitles(showTitles: false), // Hide 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, - borderRadius: BorderRadius.circular(4), - width: 20, - ), - ], + 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, + borderRadius: BorderRadius.circular(4), + width: 20, + ), + ], + ), ), ), ), - )) + ), ]); case 'fl_multi_bar': double _calculateChartWidth(dynamic chartData) { @@ -1136,22 +1346,19 @@ class ChartWidget extends StatelessWidget { // Group crops by CROP_TYPE Map> groupedCrops = {}; - int touchedGroupIndex = -1; // Iterate over the chartData to group crops by CROP_TYPE - - for (var item in chartData['response']) { - - // print("MultiBArRaw item: $item"); + print("MultiBArRaw item: $item"); String crop = item['ObsKey'][cropKey]; String cropType = item['ObsKey'][groupByKey]; // Use a Set to avoid duplicates if (groupedCrops.containsKey(cropType)) { - groupedCrops[cropType] = (groupedCrops[cropType]! + [crop]).toSet().toList(); + groupedCrops[cropType] = + (groupedCrops[cropType]! + [crop]).toSet().toList(); } else { groupedCrops[cropType] = [crop]; } @@ -1173,185 +1380,206 @@ class ChartWidget extends StatelessWidget { // // print('groupedCropsflmutli- $groupedCrops'); + return Center( + child: Column(children: [ + Text( + chartData['chart_heading'] ?? '', // Chart title from data + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w400, + ), + textAlign: TextAlign.center, + ), + SizedBox(height: 5), + Text( + chartData['chart_sub_heading'] ?? '', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.w300, + ), + textAlign: TextAlign.center, + ), + SizedBox(height: 10), + // Chart + Expanded( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, // Enable horizontal scrolling + child: SizedBox( + width: _calculateChartWidth( + chartData), // Dynamically calculate the chart width + child: BarChart( + BarChartData( + alignment: BarChartAlignment.spaceAround, + maxY: _calculateMaxY( + chartData), // Dynamically calculate max Y + barGroups: _buildHorizontalRotateBarGroups( + chartData, groupByValues), // Build bar groups + titlesData: FlTitlesData( + leftTitles: AxisTitles( + sideTitles: SideTitles(showTitles: false), + ), + bottomTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + reservedSize: 40, // Added space for rotated titles + getTitlesWidget: (value, meta) { + if (value < groupByValues.length) { + String title = + groupByValues.elementAt(value.toInt()); - return Column(children: [ - Text( - chartData['chart_heading'] ?? '', // Chart title from data - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w400, - ), - textAlign: TextAlign.center, - ), - SizedBox(height: 5), - Text( - chartData['chart_sub_heading'] ?? '', - style: TextStyle( - fontSize: 13, - fontWeight: FontWeight.w300, - ), - textAlign: TextAlign.center, - ), - SizedBox(height: 10), - // Chart - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, // Enable horizontal scrolling - child: SizedBox( - width: _calculateChartWidth( - chartData), // Dynamically calculate the chart width - child: BarChart( - BarChartData( - alignment: BarChartAlignment.spaceAround, - maxY: - _calculateMaxY(chartData), // Dynamically calculate max Y - barGroups: _buildHorizontalRotateBarGroups( - chartData, groupByValues), // Build bar groups - titlesData: FlTitlesData( - leftTitles: AxisTitles( - sideTitles: SideTitles(showTitles: false), + String displayTitle = title.length > 10 + ? title.substring(0, 10) + '...' + : title; + + return Padding( + padding: const EdgeInsets.only(top: 8.0), + child: SizedBox( + width: + 60, // Limit width to force wrapping + child: Transform.rotate( + angle: -0.5, + child: TooltipTheme( + data: TooltipThemeData( + decoration: BoxDecoration( + color: Colors.blueGrey[ + 800], // Change background color + borderRadius: BorderRadius.circular( + 8), // Optional: rounded corners + ), + textStyle: TextStyle( + color: Colors + .white), // Change text color + ), + child: Tooltip( + message: title, + child: Text( + displayTitle, + softWrap: true, + // style: TextStyle(backgroundColor: Colors.blueGrey[800]), + overflow: TextOverflow.ellipsis, + )), + ), + ))); + // return Transform.rotate( + // angle: + // -0.5, // Rotation in radians (~ -30 degrees) + // child: Text( + // title, + // style: const TextStyle(fontSize: 12), + // ), + // ); + } + return const SizedBox.shrink(); + }, + ), + ), + topTitles: + AxisTitles(sideTitles: SideTitles(showTitles: false)), + rightTitles: + AxisTitles(sideTitles: SideTitles(showTitles: false)), ), - bottomTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: true, - reservedSize: 40, // Added space for rotated titles - getTitlesWidget: (value, meta) { - if (value < groupByValues.length) { - String title = - groupByValues.elementAt(value.toInt()); - - String displayTitle = title.length > 10 - ? title.substring(0, 10) + '...' - : title; - - return Padding( - padding: const EdgeInsets.only(top: 8.0), - child: SizedBox( - width: 60, // Limit width to force wrapping - child: Transform.rotate( - angle: -0.5, - child: Tooltip( - message: title, - child: Text( - displayTitle, - softWrap: true, - overflow: TextOverflow.ellipsis, - )), - ))); - // return Transform.rotate( - // angle: - // -0.5, // Rotation in radians (~ -30 degrees) - // child: Text( - // title, - // style: const TextStyle(fontSize: 12), - // ), - // ); + borderData: FlBorderData(show: false), + barTouchData: BarTouchData( + touchTooltipData: BarTouchTooltipData( + tooltipHorizontalAlignment: + FLHorizontalAlignment.center, + tooltipRoundedRadius: 8, + fitInsideHorizontally: + true, // Ensure it fits within the screen + fitInsideVertically: true, + tooltipPadding: EdgeInsets.all(8), + tooltipMargin: 16, + // Only show tooltip when touched + getTooltipItem: (group, groupIndex, rod, rodIndex) { + if (rod.toY == 0 || touchedGroupIndex == -1) { + return null; // Don't show the tooltip if the value is 0 or there's no touch } - return const SizedBox.shrink(); + if (groupIndex == touchedGroupIndex) { + // Get the group label dynamically + String groupLabel = + groupByValues.elementAt(groupIndex); + + // Fetch the crop for the current group from groupedCrops + String cropType = + groupByValues.elementAt(groupIndex); + print('GrpcropType: $cropType'); + // String crop = groupedCrops[cropType]![rodIndex]; + + // Safely fetch crop with null check + List? crops = groupedCrops[cropType]; + String crop; + if (crops != null && rodIndex < crops.length) { + crop = crops[rodIndex]; + } else { + print( + 'Crop is null or index out of bounds for cropType: $cropType and rodIndex: $rodIndex'); + // crop = cropType; // Fallback to cropType + crop = (crops != null && crops.isNotEmpty) + ? crops.first + : cropType; + } + + // print('groupedCrops1: $groupedCrops - $rodIndex'); + // print( + // 'Groupcrop: $crop'); + double value = rod.toY; + + String formattedValue; + if (value >= 1000000) { + formattedValue = + (value / 1000000).toStringAsFixed(1) + 'M'; + } else if (value >= 1000) { + formattedValue = + (value / 1000).toStringAsFixed(1) + 'K'; + } else { + formattedValue = value.toStringAsFixed( + 0); // for values smaller than 1000 + } + // print('Cropvaluevalue: $groupLabel\n$crop $value $formattedValue'); + + return BarTooltipItem( + '$groupLabel\n$crop', + const TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + ), + children: [ + TextSpan( + // text: ' Value: ${rod.toY}', + text: ' Value: $formattedValue', + style: const TextStyle( + color: Colors.yellow, + fontWeight: FontWeight.w500, + ), + ), + ], + ); + } + return null; }, ), - ), - topTitles: - AxisTitles(sideTitles: SideTitles(showTitles: false)), - rightTitles: - AxisTitles(sideTitles: SideTitles(showTitles: false)), - ), - borderData: FlBorderData(show: false), - barTouchData: BarTouchData( - touchTooltipData: BarTouchTooltipData( - tooltipHorizontalAlignment: FLHorizontalAlignment.center, - tooltipRoundedRadius: 8, - fitInsideHorizontally: - true, // Ensure it fits within the screen - fitInsideVertically: true, - tooltipPadding: EdgeInsets.all(8), - tooltipMargin: 16, - // Only show tooltip when touched - getTooltipItem: (group, groupIndex, rod, rodIndex) { - if (rod.toY == 0 || touchedGroupIndex == -1) { - return null; // Don't show the tooltip if the value is 0 or there's no touch + touchCallback: (event, response) { + if (event.isInterestedForInteractions && + response != null && + response.spot != null) { + // setState(() { + touchedGroupIndex = + response.spot!.touchedBarGroupIndex; + // }); + } else { + // setState(() { + touchedGroupIndex = -1; // Reset if no interaction + // }); } - if (groupIndex == touchedGroupIndex) { - // Get the group label dynamically - String groupLabel = - groupByValues.elementAt(groupIndex); - - // Fetch the crop for the current group from groupedCrops - String cropType = groupByValues.elementAt(groupIndex); - print('GrpcropType: $cropType'); - // String crop = groupedCrops[cropType]![rodIndex]; - - // Safely fetch crop with null check - List? crops = groupedCrops[cropType]; - String crop; - if (crops != null && rodIndex < crops.length) { - crop = crops[rodIndex]; - } else { - print( - 'Crop is null or index out of bounds for cropType: $cropType and rodIndex: $rodIndex'); - // crop = cropType; // Fallback to cropType - crop = (crops != null && crops.isNotEmpty) ? crops.first : cropType; - } - - // print('groupedCrops1: $groupedCrops - $rodIndex'); - // print( - // 'Groupcrop: $crop'); - double value = rod.toY; - - String formattedValue; - if (value >= 1000000) { - formattedValue = - (value / 1000000).toStringAsFixed(1) + 'M'; - } else if (value >= 1000) { - formattedValue = - (value / 1000).toStringAsFixed(1) + 'K'; - } else { - formattedValue = value.toStringAsFixed( - 0); // for values smaller than 1000 - } - // print('Cropvaluevalue: $groupLabel\n$crop $value $formattedValue'); - - return BarTooltipItem( - '$groupLabel\n$crop', - const TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - ), - children: [ - TextSpan( - // text: ' Value: ${rod.toY}', - text: ' Value: $formattedValue', - style: const TextStyle( - color: Colors.yellow, - fontWeight: FontWeight.w500, - ), - ), - ], - ); - } - return null; }, ), - touchCallback: (event, response) { - if (event.isInterestedForInteractions && - response != null && - response.spot != null) { - // setState(() { - touchedGroupIndex = response.spot!.touchedBarGroupIndex; - // }); - } else { - // setState(() { - touchedGroupIndex = -1; // Reset if no interaction - // }); - } - }, + gridData: FlGridData(show: false), ), - gridData: FlGridData(show: false), ), ), - ), - )) - ]); + )) + ]), + ); case 'horizontal_rotate': String cropKey = chartData['chart_type_json'] @@ -1855,7 +2083,6 @@ class ChartWidget extends StatelessWidget { return lineBars; } - /// Function to parse TIME_PERIOD into a EXACT value double parseTimePeriod(String timePeriod) { // Match formats @@ -1864,13 +2091,23 @@ class ChartWidget extends StatelessWidget { return double.parse(timePeriod); // Year as a double (2020 → 2020.0) } else if (RegExp(r'^\d{4}-\d{2}$').hasMatch(timePeriod)) { // Format: Year-Month (e.g., "2020-10") - return double.parse(timePeriod.replaceAll('-', '.')); // Convert "2020-10" → 2020.10 + return double.parse( + timePeriod.replaceAll('-', '.')); // Convert "2020-10" → 2020.10 } else if (RegExp(r'^\d{4}-[A-Za-z]{3}$').hasMatch(timePeriod)) { // Format: Year-MonthAbbr (e.g., "2020-Oct") Map monthMap = { - 'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, - 'May': 5, 'Jun': 6, 'Jul': 7, 'Aug': 8, - 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12 + 'Jan': 1, + 'Feb': 2, + 'Mar': 3, + 'Apr': 4, + 'May': 5, + 'Jun': 6, + 'Jul': 7, + 'Aug': 8, + 'Sep': 9, + 'Oct': 10, + 'Nov': 11, + 'Dec': 12 }; List parts = timePeriod.split('-'); @@ -1882,7 +2119,6 @@ class ChartWidget extends StatelessWidget { throw FormatException("Invalid TIME_PERIOD format: $timePeriod"); } - List lineBarsData(List filteredData, Set groupByValues, String groupByKey) { List lineBars = []; @@ -1947,9 +2183,6 @@ class ChartWidget extends StatelessWidget { print('spots - $spots'); - - - // List spots = filteredData // .where((entry) => entry['ObsKey'][groupByKey] == group) // .map((entry) { @@ -1965,8 +2198,6 @@ class ChartWidget extends StatelessWidget { // return FlSpot(xValue, yValue); // }).toList(); - - print('lineGrp2'); // Add a line for this group lineBars.add( @@ -2011,11 +2242,11 @@ class ChartWidget extends StatelessWidget { } FlTitlesData titlesData1(Set xValues) { - print('tileDATa1xvalue - $xValues'); double findClosest(double value, Set values) { - return values.reduce((a, b) => (value - a).abs() < (value - b).abs() ? a : b); + return values + .reduce((a, b) => (value - a).abs() < (value - b).abs() ? a : b); } return FlTitlesData( @@ -2028,8 +2259,14 @@ class ChartWidget extends StatelessWidget { String formattedValue; if (value % 10 == 0) { - // Check if the value is in the millions or thousands range - if (value >= 1000000) { + // Check if the value is in the millions or thousands range + + if (value >= 1000000000000) { + formattedValue = + '${(value / 1000000000000).toStringAsFixed(0)}T'; + } else if (value >= 1000000000) { + formattedValue = '${(value / 1000000000).toStringAsFixed(0)}B'; + } else if (value >= 1000000) { formattedValue = '${(value / 1000000).toStringAsFixed(0)}M'; } else if (value >= 1000) { formattedValue = '${(value / 1000).toStringAsFixed(0)}k'; @@ -2063,21 +2300,22 @@ class ChartWidget extends StatelessWidget { interval: null, // interval: 10, // Ensure each year is shown only once getTitlesWidget: (value, meta) { - print('BtmTiles :-$value'); print('BtmTilesmeta :-$meta'); // if (xValues.contains(value)) double closestValue = findClosest(value, xValues); - if ((closestValue - value).abs() < 0.15) - { - + if ((closestValue - value).abs() < 0.15) { print("Bottomtiles"); print(value); - return Transform.rotate( - angle: -0.5, // Slight rotation to improve readability - child: Text( - value.toInt().toString(), - style: TextStyle(color: Colors.black, fontSize: 12), + return Padding( + padding: const EdgeInsets.only(top: 1.1), + child: Transform.rotate( + angle: 0.0, + // angle: -0.5, // Slight rotation to improve readability + child: Text( + value.toInt().toString(), + style: TextStyle(color: Colors.black, fontSize: 12), + ), ), ); } else { @@ -2405,7 +2643,7 @@ double calculateBarWidth(BuildContext context, int totalBars) { barWidth = availableWidth; } - // Optional: Add a minimum width constraint if needed + // Optional: Add a minimum width constraint if needed double minWidth = 10.0; // Example minimum width if (barWidth < minWidth) { barWidth = minWidth; @@ -2420,4 +2658,4 @@ class ChartData { final DateTime? xDateTime; ChartData({this.x, required this.y, this.xDateTime}); -} \ No newline at end of file +} diff --git a/lib/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart b/lib/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart index 557e9dbf..dbc75a2d 100644 --- a/lib/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart +++ b/lib/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart @@ -273,6 +273,7 @@ class EconomyStatsState extends ConsumerState { late TutorialCoachMark tutorialCoachMark; late List homeTargets; late List previousHomeTargets; + late final Locale locale; void handleSkip() { tutorialCoachMark.skip(); @@ -298,6 +299,7 @@ class EconomyStatsState extends ConsumerState { //Method to Start App Tour void _showHomeTour() { + print('Home tour Arabic Started'); final homeTour = ref.watch(homeTourProvider); final previousHomeTour = ref.watch(previousHomeTourProvider); @@ -305,6 +307,7 @@ class EconomyStatsState extends ConsumerState { if (!homeTour) { // Show Home Tour _initTarget(); + print('Home tour Target Intialized'); tutorialCoachMark = TutorialCoachMark( paddingFocus: 0, useSafeArea: true, @@ -345,7 +348,7 @@ class EconomyStatsState extends ConsumerState { keyTarget: cardTopicKey, shape: ShapeLightFocus.RRect, radius: 8, - paddingFocus: 16, + paddingFocus: 10, contents: [ createTargetContent( text: AppLocalizations.of(context)!.home_topic, @@ -396,9 +399,9 @@ class EconomyStatsState extends ConsumerState { backgroundColor: Colors.transparent, elevation: 0, ), - child: const Text( - 'Skip', - style: TextStyle( + child: Text( + AppLocalizations.of(context)!.skip, + style: const TextStyle( color: Colors.white, fontSize: 14, ), @@ -418,7 +421,8 @@ class EconomyStatsState extends ConsumerState { child: IconButton( padding: EdgeInsets.zero, iconSize: 20, - icon: const Icon(Icons.arrow_forward, + icon:Icon( + locale.languageCode == 'ar' ?Icons.arrow_back : Icons.arrow_forward, color: Colors.white), onPressed: () { tutorialCoachMark.next(); @@ -436,9 +440,13 @@ class EconomyStatsState extends ConsumerState { ), ), TargetContent( - padding: EdgeInsets.only(left: screenWidth * 0.4, bottom: 0), + padding: EdgeInsets.only(left:locale.languageCode == 'ar' + ? 0 + : screenWidth * 0.4, bottom: 0,right:locale.languageCode == 'ar' + ? screenWidth * 0.4 + : 0 ,), align: ContentAlign.bottom, - child: Container( + child: SizedBox( width: 200, height: 77, child: Stack( @@ -458,7 +466,7 @@ class EconomyStatsState extends ConsumerState { keyTarget: cardsKey, shape: ShapeLightFocus.RRect, radius: 7, - paddingFocus: 6, + paddingFocus: 2, // targetPosition:TargetPosition(), contents: [ createTargetContent( @@ -507,9 +515,9 @@ class EconomyStatsState extends ConsumerState { backgroundColor: Colors.transparent, elevation: 0, ), - child: const Text( - 'Skip', - style: TextStyle( + child: Text( + AppLocalizations.of(context)!.skip, + style: const TextStyle( color: Colors.white, fontSize: 14, ), @@ -520,15 +528,16 @@ class EconomyStatsState extends ConsumerState { Container( decoration: BoxDecoration( shape: BoxShape.circle, + color: locale.languageCode=='ar' ? Color(0xFF7DAFBC):null, border: Border.all( - color: Colors.white, width: 2.0), + color:locale.languageCode=='ar' ? Color(0xFF7DAFBC): Colors.white, width: 2.0), ), child: IconButton( iconSize: 20, - icon: const Icon(Icons.arrow_back, - color: Colors.white), + icon: Icon(Icons.arrow_back, + color: Colors.white,), onPressed: () { - tutorialCoachMark.previous(); + locale.languageCode=='ar' ?tutorialCoachMark.next() : tutorialCoachMark.previous(); }, ), ), @@ -536,16 +545,16 @@ class EconomyStatsState extends ConsumerState { Container( decoration: BoxDecoration( shape: BoxShape.circle, - color: Color(0xFF7DAFBC), + color: locale.languageCode=='ar' ? null:Color(0xFF7DAFBC), border: Border.all( - color: Color(0xFF7DAFBC), width: 1), + color:locale.languageCode=='ar' ? Colors.white: Color(0xFF7DAFBC), width: 1), ), child: IconButton( iconSize: 20, - icon: const Icon(Icons.arrow_forward, + icon:Icon(Icons.arrow_forward, color: Colors.white), onPressed: () { - tutorialCoachMark.next(); + locale.languageCode=='ar' ?tutorialCoachMark.previous() : tutorialCoachMark.next(); }, ), ), @@ -561,7 +570,9 @@ class EconomyStatsState extends ConsumerState { ), ), TargetContent( - padding: EdgeInsets.only(left: screenWidth * 0.4, bottom: 0), + padding: EdgeInsets.only(left:locale.languageCode == 'ar' + ? 0: screenWidth * 0.4, bottom: 0, right: locale.languageCode == 'en' + ? 0: screenWidth * 0.4, ), align: ContentAlign.bottom, child: Container( width: 200, @@ -622,8 +633,7 @@ class EconomyStatsState extends ConsumerState { align: ContentAlign.bottom, child: SizedBox( width: double.infinity, - height: MediaQuery.of(context).size.height * - 0.5, // Set an appropriate height for the Stack + height: MediaQuery.of(context).size.height * 0.5, child: Stack( children: [ Positioned( @@ -660,9 +670,9 @@ class EconomyStatsState extends ConsumerState { backgroundColor: Colors.transparent, elevation: 0, ), - child: const Text( - 'Skip', - style: TextStyle( + child: Text( + AppLocalizations.of(context)!.skip, + style: const TextStyle( color: Colors.white, fontSize: 14, ), @@ -675,14 +685,24 @@ class EconomyStatsState extends ConsumerState { Container( decoration: BoxDecoration( shape: BoxShape.circle, + color: locale.languageCode=='ar' ? Color(0xFF7DAFBC):null, border: Border.all( - color: Colors.white, width: 2.0), + color:locale.languageCode=='ar' ? Color(0xFF7DAFBC): Colors.white, width: 2.0,), ), child: IconButton( - icon: const Icon(Icons.arrow_back, - color: Colors.white), + iconSize: 20, + icon: Icon(Icons.arrow_back, + color: Colors.white,), onPressed: () { - tutorialCoachMark.next(); + if (locale.languageCode == 'ar') { + tutorialCoachMark.finish(); + ref.read(previousHomeTourProvider.notifier).state = true; + ref.read(chartsTourProvider.notifier).state = false; + context.go( + '/chartScreen/hotels?bgColor=0xFF90B0D5&mainTopic=ECONOMY&title=Hotel+Establishments',); + } else { + tutorialCoachMark.next(); + } }, ), ), @@ -690,26 +710,24 @@ class EconomyStatsState extends ConsumerState { Container( decoration: BoxDecoration( shape: BoxShape.circle, - color: Color(0xFF7DAFBC), + color: locale.languageCode=='ar' ? null:Color(0xFF7DAFBC), border: Border.all( - color: Color(0xFF7DAFBC), - width: 1.5), + color:locale.languageCode=='ar' ? Colors.white: Color(0xFF7DAFBC), width: 1,), ), child: IconButton( iconSize: 20, icon: const Icon(Icons.arrow_forward, color: Colors.white), onPressed: () { - ref - .read(previousHomeTourProvider - .notifier) - .state = true; - ref - .read(chartsTourProvider.notifier) - .state = false; - context.go( - '/chartScreen/hotels?bgColor=0xFF90B0D5&mainTopic=ECONOMY&title=Hotel+Establishments'); - tutorialCoachMark.finish(); + if (locale.languageCode == 'ar') { + tutorialCoachMark.next(); + } else { + tutorialCoachMark.finish(); + ref.read(previousHomeTourProvider.notifier).state = true; + ref.read(chartsTourProvider.notifier).state = false; + context.go( + '/chartScreen/hotels?bgColor=0xFF90B0D5&mainTopic=ECONOMY&title=Hotel+Establishments'); + } }, ), ), @@ -727,7 +745,9 @@ class EconomyStatsState extends ConsumerState { ), ), TargetContent( - padding: EdgeInsets.only(left: screenWidth * 0.4, bottom: 0), + padding: EdgeInsets.only(left:locale.languageCode == 'ar' + ? 0: screenWidth * 0.4, bottom: 0, right: locale.languageCode == 'en' + ? 0: screenWidth * 0.4, ), align: ContentAlign.bottom, child: Container( width: 200, @@ -788,8 +808,7 @@ class EconomyStatsState extends ConsumerState { children: [ ElevatedButton( onPressed: () { - tutorialCoachMark.skip(); - debugPrint('Skip clicked'); + handleSkip(); }, style: ElevatedButton.styleFrom( shape: RoundedRectangleBorder( @@ -799,9 +818,9 @@ class EconomyStatsState extends ConsumerState { backgroundColor: Colors.transparent, elevation: 0, ), - child: const Text( - 'Skip', - style: TextStyle( + child: Text( + AppLocalizations.of(context)!.skip, + style: const TextStyle( color: Colors.white, fontSize: 14, ), @@ -819,8 +838,8 @@ class EconomyStatsState extends ConsumerState { ), child: IconButton( iconSize: 20, - icon: const Icon(Icons.arrow_forward, - color: Colors.white), + icon: Icon(locale.languageCode == 'ar' ?Icons.arrow_back : Icons.arrow_forward , + color: Colors.white,), onPressed: () { tutorialCoachMark.previous(); }, @@ -838,7 +857,8 @@ class EconomyStatsState extends ConsumerState { ), ), TargetContent( - padding: EdgeInsets.only(left: screenWidth * 0.4, bottom: 0), + padding: EdgeInsets.only(left:locale.languageCode == 'ar' ? 0 : screenWidth * 0.4, bottom: 0, + right:locale.languageCode == 'ar' ? screenWidth * 0.4 : 0 ,), align: ContentAlign.bottom, child: Container( width: 200, @@ -861,7 +881,7 @@ class EconomyStatsState extends ConsumerState { @override void initState() { super.initState(); - final locale = ref.read(localeProvider); + locale = ref.read(localeProvider) ?? const Locale('en'); fetchData(locale?.languageCode ?? 'en'); // _fetchUserData(); _loadLoginCount(); diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/AboutTheApp/AboutFCSC.dart b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/AboutTheApp/AboutFCSC.dart index 7b332537..8f5a8543 100755 --- a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/AboutTheApp/AboutFCSC.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/AboutTheApp/AboutFCSC.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart'; @@ -22,7 +23,7 @@ class aboutFCSC extends StatelessWidget { bottomColor: Colors.white, mycenterTitle: true, title: Text( - 'Getting Started', + context.translate('Getting Started','البدء'), style: TextStyle( fontFamily: 'Roboto', fontSize: 22, @@ -31,63 +32,70 @@ class aboutFCSC extends StatelessWidget { fontWeight: FontWeight.w500, ), ), - body: Container( - width: double.infinity, - color: Colors.white, - padding: EdgeInsets.all(16), - child: Column(children: [ - Align( - alignment: Alignment.topLeft, - child: Text( - 'About FCSC', - style: TextStyle( - fontSize: 20, - color: Color(0xFF414042), - fontWeight: FontWeight.w600, - fontFamily: 'Roboto', + body: SingleChildScrollView( + physics: ClampingScrollPhysics(), + child: Container( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height, + color: Colors.white, + padding: EdgeInsets.all(16), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Align( + alignment: Alignment.topLeft, + child: Text( + context.translate('About FCSC','حول التطبيق'), + style: TextStyle( + fontSize: 20, + color: Color(0xFF414042), + fontWeight: FontWeight.w600, + fontFamily: 'Roboto', + ), ), ), - ), - SizedBox( - width: MediaQuery.of(context).size.width, - height: MediaQuery.of(context).size.height * 0.36, - child: Image.asset( - 'assets/user_guide/AboutFCSC.png', - fit: BoxFit.contain, + SizedBox( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height * 0.36, + child: Image.asset( + 'assets/user_guide/AboutFCSC.png', + fit: BoxFit.contain, + ), ), - ), - SizedBox( - height: 5, - ), - RichText( - text: TextSpan( - text: 'The ', - style: TextStyle( - color: Colors.grey, fontSize: 16, fontFamily: 'Roboto', height: 1.4,), - children: const [ - TextSpan( - text: - ' Federal Competitiveness and Statistics Centre (FCSC),', - style: TextStyle( - fontWeight: FontWeight.bold, - color: Color(0xFF414042), - fontFamily: 'Roboto'), - ), - TextSpan( + SizedBox( + height: 5, + ), + RichText( + text: TextSpan( + text: context.translate('The ', + 'تم تصميم تطبيق المركز الاتحادي للتنافسية والإحصاء (FCSC) لتوفير وصول المستخدمين المسجلين والمعتمدين إلى إحصائيات دقيقة وشاملة حول دولة الإمارات. يعمل التطبيق كمنصة مركزية لاستكشاف البيانات الرئيسية والاتجاهات والرؤى عبر مختلف القطاعات، مما يسهل الوصول إلى المعلومات الضرورية لدعم اتخاذ القرارات والتحليلات.',), + style: TextStyle( + color: Colors.grey, fontSize: 16, fontFamily: 'Roboto', height: 1.4,), + children: [ + TextSpan( text: - ' in your App is designed to provide registered and approved users with access to accurate and comprehensive statistics about the UAE. The app serves as a centralized platform for exploring key datasets, trends, and insights across various sectors.'), - ], + context.translate(' Federal Competitiveness and Statistics Centre (FCSC),',''), + style: const TextStyle( + fontWeight: FontWeight.bold, + color: Color(0xFF414042), + fontFamily: 'Roboto',), + ), + TextSpan( + text: + context.translate(' in your App is designed to provide registered and approved users with access to accurate and comprehensive statistics about the UAE. The app serves as a centralized platform for exploring key datasets, trends, and insights across various sectors.',''),), + ], + ), ), - ), - Spacer(), - Align( - alignment: Alignment.bottomCenter, - child: fcscBanner, - ), - SizedBox( - height: 25, - ), - ]), + SizedBox(height: MediaQuery.of(context).size.height*0.15), + Align( + alignment: Alignment.bottomCenter, + child: fcscBanner, + ), + SizedBox( + height: 25, + ), + ]), + ), ), ); } diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/AboutTheApp/getStarted.dart b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/AboutTheApp/getStarted.dart index 763ba1d7..78835c9d 100755 --- a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/AboutTheApp/getStarted.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/AboutTheApp/getStarted.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart'; @@ -29,7 +30,7 @@ class GetStarted extends StatelessWidget { bottomColor: Colors.white, mycenterTitle: true, title: Text( - 'Getting Started', + context.translate('Getting Started','البدء'), style: TextStyle( fontSize: 22, color: Color(0xFF7DAFBC), @@ -47,7 +48,7 @@ class GetStarted extends StatelessWidget { children: [ Align( alignment: Alignment.topLeft, - child: Text('How to Get Started', + child: Text(context.translate('How to Get Started','كيفية البدء'), style: TextStyle( fontSize:20, @@ -65,13 +66,18 @@ class GetStarted extends StatelessWidget { ), Text( + context.translate( '1. Download the app from the App Store or Google Play Store.', + '1 .قم بتحميل التطبيق من متجر التطبيقات (Appstore) أو متجر جوجل بلاي (Google Play)..', + ), textAlign: TextAlign.justify, // Align the text softWrap: true, ), SizedBox(height: 2,), Text( + context.translate( '2. Log in to access advanced features', + '2 .قم بتسجيل الدخول لفتح الميزات المتقدمة.',), textAlign: TextAlign.justify, // Align the text softWrap: true, ), diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/AppFeatures.dart b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/AppFeatures.dart index b15d522c..3b834f03 100755 --- a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/AppFeatures.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/AppFeatures.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:uae_stat/domain/use_cases/language.dart'; import '../../../../../../infrastructure/services/img_asset_paths/banner_asset_path.dart'; import '../../../custom_drawer_routes.dart'; @@ -27,7 +28,7 @@ class AppFeatures extends StatelessWidget { appbarColor: Colors.white, mycenterTitle: true, title: Text( - 'Key Features', + context.translate('Key Features','الميزات الرئيسية'), style: TextStyle( fontSize: 22, color: Color(0xFF7DAFBC), @@ -45,7 +46,8 @@ class AppFeatures extends StatelessWidget { children: [ Align( alignment: Alignment.topLeft, - child: Text('App Features', + child: Text( + context.translate('App Features','الميزات الرئيسية'), style: TextStyle( fontSize:20, @@ -61,7 +63,8 @@ class AppFeatures extends StatelessWidget { fit: BoxFit.contain, ), ), - Text('1. Comprehensive Statistics:', + Text( + context.translate('1. Comprehensive Statistics:','1. رؤى مستندة إلى البيانات '), style:TextStyle( fontSize:16, color: Color(0xFF414042), @@ -84,20 +87,23 @@ class AppFeatures extends StatelessWidget { Expanded( child: RichText( text: TextSpan( - text: 'Access detailed datasets across categories such as ', + text:context.translate( + 'Access detailed datasets across categories such as ', + 'الوصول إلى مجموعات بيانات تفصيلية عبر فئات مثل الاقتصاد، البيئة، الاجتماعية، وغيرها.',), style: TextStyle( color:Color(0xFF898C81), fontSize: 16, fontFamily: 'Roboto' ), - children: const [ - TextSpan(text: 'Economy, Environment, Social, ', + children: [ + TextSpan(text: + context.translate('Economy, Environment, Social, ',''), style: TextStyle( fontWeight: FontWeight.bold, color: Color(0xFF414042), fontFamily: 'Roboto' ),), - TextSpan(text: 'and more.'), + TextSpan(text:context.translate('and more.','')), ], ), ), @@ -113,8 +119,9 @@ class AppFeatures extends StatelessWidget { ), // Bullet point SizedBox(width: 8), // Space between bullet and text Expanded( - child: Text( + child: Text( context.translate( 'Explore statistics presented as smart metrics, graphs, and charts for better understanding.', + 'استكشاف الإحصائيات المقدمة على هيئة مقاييس ذكية ورسوم بيانية ومخططات لتعزيز الفهم.',), textAlign: TextAlign.justify, // Align the text softWrap: true, ), @@ -127,7 +134,8 @@ class AppFeatures extends StatelessWidget { SizedBox(height: 8), - Text('2. Drilldown Navigation:', + Text( + context.translate('2. Drilldown Navigation:','2. التنقل التفصيلي'), style:TextStyle( fontSize:16, color: Color(0xFF414042), @@ -149,8 +157,10 @@ class AppFeatures extends StatelessWidget { SizedBox(width: 8), // Space between bullet and text Expanded( child: Text( + context.translate( 'Start with high-level categories and drill down to specific KPIs and metrics for deeper insights.', - textAlign: TextAlign.justify, // Align the text + 'البدء بالفئات العامة والتنقل وصولًا إلى مؤشرات الأداء الرئيسية (KPIs) والمقاييس المحددة للحصول على رؤى أعمق.',), + textAlign: TextAlign.justify, // Align the text softWrap: true, ), ), @@ -161,7 +171,8 @@ class AppFeatures extends StatelessWidget { ), SizedBox(height: 8), - Text('3. Interactive Visualizations:', + Text( + context.translate('3. Interactive Visualizations:','3. التصورات التفاعلية:'), style:TextStyle( fontSize:16, color: Color(0xFF414042), @@ -182,8 +193,9 @@ class AppFeatures extends StatelessWidget { ), // Bullet point SizedBox(width: 8), // Space between bullet and text Expanded( - child: Text( + child: Text(context.translate( 'View trends and relationships with interactive graphs and charts, including bar graphs, line charts, and more.', + 'عرض الاتجاهات والعلاقات باستخدام الرسوم البيانية التفاعلية مثل المخططات الشريطية، المخططات الخطية، وغيرها.',), textAlign: TextAlign.justify, // Align the text softWrap: true, ), diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/ChangeMyPassword.dart b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/ChangeMyPassword.dart index 908b26bc..64d20ad8 100755 --- a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/ChangeMyPassword.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/ChangeMyPassword.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:uae_stat/domain/use_cases/language.dart'; import '../../../../../../infrastructure/services/img_asset_paths/banner_asset_path.dart'; import '../../../custom_drawer_routes.dart'; @@ -27,7 +28,7 @@ class ChangeMyPassword extends StatelessWidget { appbarColor: Colors.white, mycenterTitle: true, title: Text( - 'App Features', + context.translate('Key Features','الميزات الرئيسية'), style: TextStyle( fontSize: 22, color: Color(0xFF7DAFBC), @@ -45,9 +46,11 @@ class ChangeMyPassword extends StatelessWidget { children: [ Align( alignment: Alignment.topLeft, - child: Text('How to Change My Password', - style: - TextStyle( + child: Text( + context.translate( + 'How to Change My Password', + 'كيفية تغيير كلمة المرور الخاصة بي',), + style: TextStyle( fontSize:20, color: Color(0xFF414042), fontWeight: FontWeight.w600, @@ -62,10 +65,13 @@ class ChangeMyPassword extends StatelessWidget { ), ), Text( + context.translate( 'Changing your password helps keep your account secure. Follow these steps to update your password:', + 'يُساعد تغيير كلمة المرور في الحفاظ على أمان حسابك. اتبع هذه الخطوات لتحديث كلمة مرور',), ), SizedBox(height: 12), - Text('Steps to Change Password', + Text( + context.translate('Steps to Change Password','خطوات تغيير كلمة المرور '), style:TextStyle( fontSize:22, color: Color(0xFF414042), @@ -73,7 +79,10 @@ class ChangeMyPassword extends StatelessWidget { ), ), SizedBox(height: 8), - Text('1. Access the Change Password Page:', + Text( + context.translate( + '1. Access the Change Password Page:', + '1. الدخول إلى صفحة تغيير كلمة المرور:',), style:TextStyle( fontSize:16, color: Color(0xFF414042), @@ -96,16 +105,23 @@ class ChangeMyPassword extends StatelessWidget { Expanded( child: RichText( text: TextSpan( - text: 'From the Profile page, tap on the ', + text: context.translate( + 'From the Profile page, tap on the ', + 'من صفحة الملف الشخصي، انقر على رابط ',), style: TextStyle(fontSize: 16, color: Color(0xFF898C81), fontFamily: 'Roboto'), - children: const [ - TextSpan(text: '"Change Password"', + children: [ + TextSpan(text: context.translate( + '"Change Password"', + '"تغيير كلمة المرور" ',), style: TextStyle( fontWeight: FontWeight.w600, color: Color(0xFF414042), fontFamily: 'Roboto' ),), - TextSpan(text:' link at the bottom.',) + TextSpan(text:context.translate( + ' link at the bottom.', + 'في الأسفل.',), + ), ], ), ), @@ -117,7 +133,9 @@ class ChangeMyPassword extends StatelessWidget { ), SizedBox(height: 8), - Text('2. Enter Old Password:', + Text(context.translate( + '2. Enter Old Password:', + '2. إدخال كلمة المرور القديمة:',), style:TextStyle( fontSize:16, color: Color(0xFF414042), @@ -139,7 +157,9 @@ class ChangeMyPassword extends StatelessWidget { SizedBox(width: 8), // Space between bullet and text Expanded( child: Text( + context.translate( 'Enter your current password in the first field.', + 'أدخل كلمة المرور الحالية في الحقل الأول.',), textAlign: TextAlign.justify, // Align the text softWrap: true, ), @@ -151,7 +171,9 @@ class ChangeMyPassword extends StatelessWidget { ), SizedBox(height: 8), - Text('3. Set a New Password:', + Text(context.translate( + '3. Set a New Password:', + '3. تعيين كلمة مرور جديدة:',), style:TextStyle( fontSize:16, color: Color(0xFF414042), @@ -172,8 +194,9 @@ class ChangeMyPassword extends StatelessWidget { ), // Bullet point SizedBox(width: 8), // Space between bullet and text Expanded( - child: Text( + child: Text( context.translate( 'Enter your new password in the second field.', + 'أدخل كلمة المرور الجديدة في الحقل الثاني.',), textAlign: TextAlign.justify, // Align the text softWrap: true, ), @@ -190,7 +213,9 @@ class ChangeMyPassword extends StatelessWidget { SizedBox(width: 8), // Space between bullet and text Expanded( child: Text( + context.translate( 'Re-enter the new password in the third field for confirmation.', + 'أعد إدخال كلمة المرور الجديدة في الحقل الثالث للتأكيد.',), textAlign: TextAlign.justify, // Align the text softWrap: true, ), @@ -202,7 +227,8 @@ class ChangeMyPassword extends StatelessWidget { ), SizedBox(height: 8), - Text('4. Password Requirements:', + Text(context.translate( + '4. Password Requirements:','4. متطلبات كلمة المرور:',), style:TextStyle( fontSize:16, color: Color(0xFF414042), @@ -223,8 +249,9 @@ class ChangeMyPassword extends StatelessWidget { ), // Bullet point SizedBox(width: 8), // Space between bullet and text Expanded( - child: Text( + child: Text(context.translate( 'Your new password must be different from the previously used password.', + 'جب أن تكون كلمة المرور الجديدة مختلفة عن كلمة المرور المستخدمة سابقًا',), textAlign: TextAlign.justify, // Align the text softWrap: true, ), @@ -236,7 +263,8 @@ class ChangeMyPassword extends StatelessWidget { ), SizedBox(height: 8), - Text('5. Save Your Password:', + Text( + context.translate('5. Save Your Password:','5. حفظ كلمة المرور '), style:TextStyle( fontSize:16, color: Color(0xFF414042), @@ -259,16 +287,17 @@ class ChangeMyPassword extends StatelessWidget { Expanded( child: RichText( text: TextSpan( - text: 'Tap the ', + text: context.translate('Tap the ','انقرعلى زر '), style: TextStyle(fontSize: 16, color: Color(0xFF898C81), fontFamily: 'Roboto'), - children: const [ - TextSpan(text: 'Save ', + children: [ + TextSpan(text: + context.translate('Save ','"حفظ".'), style: TextStyle( fontWeight: FontWeight.w600, color: Color(0xFF414042), fontFamily: 'Roboto' ),), - TextSpan(text:'button',) + TextSpan(text: context.translate('button',''),) ], ), ), @@ -284,8 +313,9 @@ class ChangeMyPassword extends StatelessWidget { ), // Bullet point SizedBox(width: 8), // Space between bullet and text Expanded( - child: Text( + child: Text(context.translate( 'A confirmation message will appear: “Password has been successfully updated.”', + 'ستظهر رسالة تأكيد: "تم تحديث كلمة المرور بنجاح".',), textAlign: TextAlign.justify, // Align the text softWrap: true, ), @@ -296,7 +326,8 @@ class ChangeMyPassword extends StatelessWidget { ), ), SizedBox(height: 8), - Text('6. Re-Login:', + Text( + context.translate('6. Re-Login:','6. إعادة تسجيل الدخول'), style:TextStyle( fontSize:16, color: Color(0xFF414042), @@ -317,8 +348,9 @@ class ChangeMyPassword extends StatelessWidget { ), // Bullet point SizedBox(width: 8), // Space between bullet and text Expanded( - child: Text( + child: Text(context.translate( 'Log in again using your new password to continue using the app', + 'قم بتسجيل الدخول مرة أخرى باستخدام كلمة المرور الجديدة للاستمرار في استخدام التطبيق.',), textAlign: TextAlign.justify, // Align the text softWrap: true, ), diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/EditMyProfile.dart b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/EditMyProfile.dart index d125fe39..3a8ff898 100755 --- a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/EditMyProfile.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/EditMyProfile.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:uae_stat/domain/use_cases/language.dart'; import '../../../../../../infrastructure/services/img_asset_paths/banner_asset_path.dart'; import '../../../custom_drawer_routes.dart'; @@ -27,7 +28,7 @@ class EditMyProfile extends StatelessWidget { appbarColor: Colors.white, mycenterTitle: true, title: Text( - 'App Features', + context.translate('Key Features','الميزات الرئيسية'), style: TextStyle( fontSize: 22, color: Color(0xFF7DAFBC), @@ -45,7 +46,8 @@ class EditMyProfile extends StatelessWidget { children: [ Align( alignment: Alignment.topLeft, - child: Text('How to Edit My Profile', + child: Text( + context.translate('How to Edit My Profile','كيفية تعديل ملفي الشخصي'), style: TextStyle( fontSize:20, @@ -61,11 +63,13 @@ class EditMyProfile extends StatelessWidget { fit: BoxFit.contain, ), ), - Text( + Text(context.translate( 'Editing your profile allows you to update specific information while ensuring that critical details remain secure. Follow the steps below to update your profile:', + 'يتيح لك تعديل ملف التعريف الخاص بك بتحديث معلومات معينة مع ضمان أن تبقى البيانات الحساسة آمنة. اتبع الخطوات التالية لتحديث ملفك الشخصي:',), ), SizedBox(height: 12), - Text('Steps to Edit Profile', + Text( + context.translate('Steps to Edit Profile','خطوات تعديل الملف الشخصي '), style:TextStyle( fontSize:22, color: Color(0xFF414042), @@ -73,7 +77,9 @@ class EditMyProfile extends StatelessWidget { ), ), SizedBox(height: 8), - Text('1. Access the Profile Page:', + Text(context.translate( + '1. Access the Profile Page:', + '1. الوصول إلى صفحة الملف الشخصي:',), style:TextStyle( fontSize:16, color: Color(0xFF414042), @@ -95,16 +101,16 @@ class EditMyProfile extends StatelessWidget { Expanded( child: RichText( text: TextSpan( - text: 'Tap on the ', + text: context.translate('Tap on the ','انقر على خيار "الملف الشخصي" من شريط التنقل في الزاوية العلوية اليسرى من الشاشة.'), style: TextStyle(fontSize: 16, color: Color(0xFF898C81), fontFamily: 'Roboto'), - children: const [ - TextSpan(text: '"Profile"', + children: [ + TextSpan(text: context.translate('"Profile"',''), style: TextStyle( fontWeight: FontWeight.w600, color: Color(0xFF414042), fontFamily: 'Roboto' ),), - TextSpan(text:' option from the navigation bar at the top left corner of the screen.',) + TextSpan(text: context.translate(' option from the navigation bar at the top left corner of the screen.','')) ], ), ) @@ -115,7 +121,8 @@ class EditMyProfile extends StatelessWidget { ), SizedBox(height: 8), - Text('2. Editable Fields:', + Text( + context.translate('2. Editable Fields:','2. الحقول القابلة للتعديل:'), style:TextStyle( fontSize:16, color: Color(0xFF414042), @@ -139,14 +146,17 @@ class EditMyProfile extends StatelessWidget { child: RichText( text: TextSpan( style: TextStyle(fontSize: 16, color: Color(0xFF898C81), fontFamily: 'Roboto'), - children: const [ - TextSpan(text: 'Full Name:', + children: [ + TextSpan(text: + context.translate('Full Name:','الاسم الكامل: '), style: TextStyle( fontWeight: FontWeight.w600, color: Color(0xFF414042), fontFamily: 'Roboto' ),), - TextSpan(text:' Tap the text box to enter your name (up to 40 alphanumeric characters).',) + TextSpan(text:context.translate( + ' Tap the text box to enter your name (up to 40 alphanumeric characters).', + 'اضغط على مربع النص لإدخال اسمك (حتى 40 حرفًا أبجديًا رقميًا).',),) ], ), ) @@ -166,14 +176,19 @@ class EditMyProfile extends StatelessWidget { child: RichText( text: TextSpan( style: TextStyle(fontSize: 16, color: Color(0xFF898C81), fontFamily: 'Roboto'), - children: const [ - TextSpan(text: 'Date of Birth: ', + children: [ + TextSpan( + text: context.translate('Date of Birth: ','تاريخ الميلاد: '), style: TextStyle( fontWeight: FontWeight.w600, color: Color(0xFF414042), - fontFamily: 'Roboto' + fontFamily: 'Roboto', ),), - TextSpan(text:' Use the calendar dropdown to select your date of birth.',) + TextSpan( + text:context.translate( + ' Use the calendar dropdown to select your date of birth.', + 'استخدم القائمة المنسدلة لاختيار تاريخ ميلادك.',), + ) ], ), ) @@ -193,14 +208,19 @@ class EditMyProfile extends StatelessWidget { child: RichText( text: TextSpan( style: TextStyle(fontSize: 16, color: Color(0xFF898C81), fontFamily: 'Roboto'), - children: const [ - TextSpan(text: 'Country/Region: ', + children: [ + TextSpan(text:context.translate( + 'Country/Region: ', + 'البلد/المنطقة:',), style: TextStyle( fontWeight: FontWeight.w600, color: Color(0xFF414042), fontFamily: 'Roboto' ),), - TextSpan(text:' Choose your current location from the dropdown menu.',), + TextSpan(text:context.translate( + ' Choose your current location from the dropdown menu.', + 'اختر موقعك الحالي من القائمة المنسدلة.',), + ), ], ), ) @@ -220,14 +240,18 @@ class EditMyProfile extends StatelessWidget { child: RichText( text: TextSpan( style: TextStyle(fontSize: 16, color: Color(0xFF898C81), fontFamily: 'Roboto'), - children: const [ - TextSpan(text: 'User Image: ', + children: [ + TextSpan(text: + context.translate('User Image: ', 'الصورة الشخصية:'), style: TextStyle( fontWeight: FontWeight.w600, color: Color(0xFF414042), fontFamily: 'Roboto' ),), - TextSpan(text:'Tap on the avatar icon to upload or change your profile picture.',), + TextSpan(text:context.translate( + 'Tap on the avatar icon to upload or change your profile picture.', + 'اضغط على أيقونة رمزالصورة لتحميل أو تغيير صورة الملف الشخصي.',), + ), ], ), ) @@ -239,7 +263,8 @@ class EditMyProfile extends StatelessWidget { ), SizedBox(height: 8), - Text('3. Non-Editable Fields:', + Text( + context.translate('3. Non-Editable Fields:','3. الحقول غير القابلة للتعديل:'), style:TextStyle( fontSize:16, color: Color(0xFF414042), @@ -263,21 +288,24 @@ class EditMyProfile extends StatelessWidget { child: RichText( text: TextSpan( style: TextStyle(fontSize: 16, color: Color(0xFF898C81), fontFamily: 'Roboto'), - children: const [ - TextSpan(text: 'Username ', + children: [ + TextSpan(text: context.translate('Username ','اسم المستخدم وعنوان البريد الإلكتروني: '), style: TextStyle( fontWeight: FontWeight.w600, color: Color(0xFF414042), fontFamily: 'Roboto' ),), - TextSpan(text:'and ',), - TextSpan(text: 'Email Id: ', + TextSpan(text:context.translate('and ',''),), + TextSpan(text: context.translate('Email Id: ',''), style: TextStyle( fontWeight: FontWeight.w600, color: Color(0xFF414042), fontFamily: 'Roboto' ),), - TextSpan(text:'These fields cannot be edited to ensure the integrity of your account.',), + TextSpan(text:context.translate( + 'These fields cannot be edited to ensure the integrity of your account.', + 'لا يمكن تعديل هذين الحقلين لضمان سلامة حسابك.',), + ), ], ), ) @@ -289,7 +317,8 @@ class EditMyProfile extends StatelessWidget { ), SizedBox(height: 8), - Text('4. Agree to Terms and Conditions:', + Text( + context.translate('4. Agree to Terms and Conditions:','4. الموافقة على الشروط والأحكام:'), style:TextStyle( fontSize:16, color: Color(0xFF414042), @@ -311,7 +340,9 @@ class EditMyProfile extends StatelessWidget { SizedBox(width: 8), // Space between bullet and text Expanded( child: Text( + context.translate( 'Ensure that the checkbox for "I agree to Terms & Conditions and Privacy Policy" is selected before saving changes.', + 'تأكد من تحديد خانة "أوافق على الشروط والأحكام وسياسة الخصوصية" قبل حفظ التغييرات.',), textAlign: TextAlign.justify, // Align the text softWrap: true, ), @@ -323,7 +354,8 @@ class EditMyProfile extends StatelessWidget { ), SizedBox(height: 8), - Text('5. Save Your Changes:', + Text( + context.translate('5. Save Your Changes:','5. حفظ التغييرات:'), style:TextStyle( fontSize:16, color: Color(0xFF414042), @@ -346,16 +378,21 @@ class EditMyProfile extends StatelessWidget { Expanded( child: RichText( text: TextSpan( - text: 'Tap the ', + text: context.translate('Tap the ','اضغط على زر '), style: TextStyle(fontSize: 16, color: Color(0xFF898C81), fontFamily: 'Roboto'), - children: const [ - TextSpan(text: 'Save', + children: [ + TextSpan(text: + context.translate('Save','"حفظ" '), style: TextStyle( fontWeight: FontWeight.w600, color: Color(0xFF414042), fontFamily: 'Roboto' ),), - TextSpan(text:' button at the bottom of the screen.',) + TextSpan(text: + context.translate( + ' button at the bottom of the screen.', + 'أسفل الشاشة.',), + ) ], ), ), @@ -372,8 +409,10 @@ class EditMyProfile extends StatelessWidget { ), // Bullet point SizedBox(width: 8), // Space between bullet and text Expanded( - child: Text( + child: Text(context.translate( 'A confirmation dialog will appear with the message: “Are you sure you want to save this page? Once saved, you will not be able to change your name or date of birth.”', + 'ستظهر نافذة تأكيد برسالة:"هل أنت متأكد أنك تريد حفظ هذه الصفحة؟ بمجرد الحفظ، لن تتمكن من تغيير اسمك أو تاريخ ميلادك."', + ), textAlign: TextAlign.justify, // Align the text softWrap: true, ), @@ -392,23 +431,23 @@ class EditMyProfile extends StatelessWidget { Expanded( child:RichText( text: TextSpan( - text: 'Select ', + text: context.translate('Select ','اختر "تأكيد" لحفظ التغييرات أو "إلغاء" للرجوع.'), style: TextStyle(fontSize: 16, color: Color(0xFF898C81), fontFamily: 'Roboto'), - children: const [ - TextSpan(text: 'Confirm', + children: [ + TextSpan(text: context.translate('Confirm',''), style: TextStyle( fontWeight: FontWeight.w600, color: Color(0xFF414042), fontFamily: 'Roboto' ),), - TextSpan(text:' to save the changes',), - TextSpan(text: ' Cancel', + TextSpan(text:context.translate(' to save the changes',''),), + TextSpan(text:context.translate(' Cancel',''), style: TextStyle( fontWeight: FontWeight.w600, color: Color(0xFF414042), fontFamily: 'Roboto' ),), - TextSpan(text:' to go back.',), + TextSpan(text:context.translate(' to go back.','')), ], ), ), diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/howUseTheApp.dart b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/howUseTheApp.dart index 513871eb..1d61194e 100755 --- a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/howUseTheApp.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/howUseTheApp.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:uae_stat/domain/use_cases/language.dart'; import '../../../../../../infrastructure/services/img_asset_paths/banner_asset_path.dart'; import '../../../custom_drawer_routes.dart'; @@ -27,7 +28,7 @@ class HowUseTheApp extends StatelessWidget { bottomColor: Colors.white, mycenterTitle: true, title: Text( - 'Key Features', + context.translate('Key Features','الميزات الرئيسية'), style: TextStyle( fontSize: 22, color: Color(0xFF7DAFBC), @@ -46,7 +47,7 @@ class HowUseTheApp extends StatelessWidget { Align( alignment: Alignment.topLeft, child: Text( - 'How to Use the App', + context.translate('How to Use the App','كيفية استخدام التطبيق:'), style: TextStyle( fontSize: 20, color: Color(0xFF414042), @@ -63,7 +64,9 @@ class HowUseTheApp extends StatelessWidget { ), ), Text( + context.translate( '1. Registration and Approval:', + '1. التسجيل والموافقة:',), style: TextStyle( fontSize: 16, color: Color(0xFF414042), @@ -85,7 +88,9 @@ class HowUseTheApp extends StatelessWidget { SizedBox(width: 8), // Space between bullet and text Expanded( child: Text( + context.translate( 'Sign up for the app and wait for admin approval.', + 'قم بالتسجيل في التطبيق وانتظر الموافقة من الإدارة.',), textAlign: TextAlign.justify, // Align the text softWrap: true, ), @@ -94,7 +99,9 @@ class HowUseTheApp extends StatelessWidget { ), SizedBox(height: 8), Text( + context.translate( '2. Login and Navigation:', + '2. تسجيل الدخول والتصفح:',), style: TextStyle( fontSize: 16, color: Color(0xFF414042), @@ -116,7 +123,9 @@ class HowUseTheApp extends StatelessWidget { SizedBox(width: 8), // Space between bullet and text Expanded( child: Text( + context.translate( 'Once approved, log in to access the app. Navigate through the categories on the home screen.', + 'بعد الموافقة، قم بتسجيل الدخول للوصول إلى التطبيق. تصفح الفئات المختلفة على الشاشة الرئيسية.',), textAlign: TextAlign.justify, // Align the text softWrap: true, ), @@ -125,7 +134,9 @@ class HowUseTheApp extends StatelessWidget { ), SizedBox(height: 8), Text( + context.translate( '3. Access Data:', + '3. الوصول إلى البيانات:',), style: TextStyle( fontSize: 16, color: Color(0xFF414042), @@ -147,7 +158,9 @@ class HowUseTheApp extends StatelessWidget { SizedBox(width: 8), // Space between bullet and text Expanded( child: Text( + context.translate( 'Drill down into specific categories like "Economy" or "Environment" to view detailed KPIs and visual insights.', + 'قم بالتعمق في الفئات المحددة مثل "الاقتصاد" أو "البيئة" لعرض مؤشرات الأداء الرئيسية والرؤى المرئية بالتفصيل.',), textAlign: TextAlign.justify, // Align the text softWrap: true, ), @@ -156,7 +169,9 @@ class HowUseTheApp extends StatelessWidget { ), SizedBox(height: 8), Text( + context.translate( '4. Bookmark Metrics:', + '4. وضع إشارة مرجعية للمقاييس:',), style: TextStyle( fontSize: 16, color: Color(0xFF414042), @@ -178,7 +193,9 @@ class HowUseTheApp extends StatelessWidget { SizedBox(width: 8), // Space between bullet and text Expanded( child: Text( + context.translate( 'Drill down into specific categories like "Economy" or "Environment" to view detailed KPIs and visual insights.', + 'احفظ الإحصائيات المهمة للرجوع إليها بسهولة.',), textAlign: TextAlign.justify, // Align the text softWrap: true, ), diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/purpose.dart b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/purpose.dart index 85f3de4d..eae4c7cb 100755 --- a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/purpose.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/purpose.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:uae_stat/domain/use_cases/language.dart'; import '../../../../../../infrastructure/services/img_asset_paths/banner_asset_path.dart'; import '../../../custom_drawer_routes.dart'; @@ -30,7 +31,7 @@ class Purpose extends StatelessWidget { bottomColor: Colors.white, mycenterTitle: true, title: Text( - 'Key Features', + context.translate('Key Features','الميزات الرئيسية'), style: TextStyle( fontSize: 22, color: Color(0xFF7DAFBC), @@ -49,7 +50,7 @@ class Purpose extends StatelessWidget { Align( alignment: Alignment.topLeft, child: Text( - 'Purpose of the App', + context.translate('Purpose of the App','الغرض من التطبيق'), style: TextStyle( fontSize: 20, color: Color(0xFF414042), @@ -81,21 +82,22 @@ class Purpose extends StatelessWidget { Expanded( child: RichText( text: TextSpan( - text: 'Provide ', + text: context.translate('Provide ', + 'توفير الإحصائيات الرسمية لدولة الإمارات بشكل سهل الوصول.',), style: TextStyle( color: Color(0xFF898C81), fontSize: 16, fontFamily: 'Roboto'), - children: const [ + children: [ TextSpan( - text: 'official statistics ', + text: context.translate('official statistics ',''), style: TextStyle( fontWeight: FontWeight.bold, color: Color(0xFF414042), fontFamily: 'Roboto'), ), TextSpan( - text: 'on the UAE in an accessible format.'), + text: context.translate('on the UAE in an accessible format.',''),), ], ), ), @@ -116,7 +118,9 @@ class Purpose extends StatelessWidget { SizedBox(width: 8), // Space between bullet and text Expanded( child: Text( + context.translate( 'Support decision-making and research with reliable, up-to-date data.', + 'دعم اتخاذ القرارات والبحوث من خلال بيانات موثوقة ومحدثة.',), textAlign: TextAlign.justify, // Align the text softWrap: true, ), @@ -137,7 +141,9 @@ class Purpose extends StatelessWidget { SizedBox(width: 8), // Space between bullet and text Expanded( child: Text( + context.translate( 'Enable users to interact with data visually through graphs and metrics.', + 'تمكين المستخدمين من التفاعل مع البيانات بصريًا من خلال الرسوم البيانية والمقاييس.',), textAlign: TextAlign.justify, // Align the text softWrap: true, ), diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/stayUpdate.dart b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/stayUpdate.dart index a7333e0b..85ec7ce7 100755 --- a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/stayUpdate.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/stayUpdate.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:uae_stat/domain/use_cases/language.dart'; import '../../../../../../infrastructure/services/img_asset_paths/banner_asset_path.dart'; import '../../../custom_drawer_routes.dart'; @@ -30,7 +31,7 @@ class StayUpdate extends StatelessWidget { bottomColor: Colors.white, mycenterTitle: true, title: Text( - 'Key Features', + context.translate('Key Features','الميزات الرئيسية'), style: TextStyle( fontSize: 22, color: Color(0xFF7DAFBC), @@ -49,7 +50,7 @@ class StayUpdate extends StatelessWidget { Align( alignment: Alignment.topLeft, child: Text( - 'Stay Updated', + context.translate('Stay Updated','ابقَ على اطلاع'), style: TextStyle( fontSize: 20, color: Color(0xFF414042), @@ -80,7 +81,9 @@ class StayUpdate extends StatelessWidget { SizedBox(width: 8), // Space between bullet and text Expanded( child: Text( + context.translate( 'The app regularly updates datasets and features to reflect the latest information. Notifications will alert you about new data or improvements.', + 'يتم تحديث مجموعات البيانات وميزات التطبيق بانتظام لتعكس أحدث المعلومات. ستتلقى إشعارات تنبهك حول البيانات الجديدة والتحسينات.',), textAlign: TextAlign.justify, // Align the text softWrap: true, ), diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/useTheApp.dart b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/useTheApp.dart index f34258b0..b2720689 100755 --- a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/useTheApp.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/KeyFeatures/useTheApp.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:uae_stat/domain/use_cases/language.dart'; import '../../../../../../infrastructure/services/img_asset_paths/banner_asset_path.dart'; import '../../../custom_drawer_routes.dart'; @@ -27,7 +28,7 @@ class WhoUseTheApp extends StatelessWidget { bottomColor: Colors.white, mycenterTitle: true, title: Text( - 'Key Features', + context.translate('Key Features','الميزات الرئيسية'), style: TextStyle( fontSize: 22, color: Color(0xFF7DAFBC), @@ -46,7 +47,7 @@ class WhoUseTheApp extends StatelessWidget { Align( alignment: Alignment.topLeft, child: Text( - 'Who can use the App?', + context.translate('Who can use the App?','من يمكنه استخدام التطبيق؟'), style: TextStyle( fontSize: 20, color: Color(0xFF414042), @@ -63,7 +64,7 @@ class WhoUseTheApp extends StatelessWidget { ), ), Text( - 'This app is intended for:', + context.translate('This app is intended for:','يستهدف هذا التطبيق:'), style: TextStyle( fontSize: 16, color: Color(0xFF414042), @@ -85,8 +86,10 @@ class WhoUseTheApp extends StatelessWidget { SizedBox(width: 8), // Space between bullet and text Expanded( child: Text( + context.translate( 'Government officials requiring UAE statistics for decision-making.', - textAlign: TextAlign.justify, // Align the text + 'المسؤولين الحكوميين الذين يحتاجون إلى إحصاءات دولة الإمارات العربية المتحدة لاتخاذ القرارات.',), + textAlign: TextAlign.justify, // Align the text softWrap: true, ), ), @@ -106,7 +109,9 @@ class WhoUseTheApp extends StatelessWidget { SizedBox(width: 8), // Space between bullet and text Expanded( child: Text( + context.translate( 'Business professionals and researchers analyzing market trends.', + 'المتخصصين في مجال الأعمال والباحثين الذين يقومون بتحليل اتجاهات السوق.',), textAlign: TextAlign.justify, // Align the text softWrap: true, ), @@ -127,7 +132,9 @@ class WhoUseTheApp extends StatelessWidget { SizedBox(width: 8), // Space between bullet and text Expanded( child: Text( + context.translate( 'Students and educators needing reliable data for study and teaching.', + 'الطلاب والمعلمين الذين يحتاجون إلى بيانات موثوقة للدراسة والتعليم.',), textAlign: TextAlign.justify, // Align the text softWrap: true, ), diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/aboutApp.dart b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/aboutApp.dart index 98eb4cd9..fa53a0b8 100755 --- a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/aboutApp.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/aboutApp.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart'; import 'package:uae_stat/infrastructure/services/img_asset_paths/banner_asset_path.dart'; @@ -22,7 +23,7 @@ class aboutTheApp extends StatelessWidget { appbarColor: Colors.white, mycenterTitle: true, title: Text( - 'Getting Started', + context.translate('Getting Started','البدء'), style: TextStyle( fontSize: 22, fontFamily: 'Roboto', @@ -41,7 +42,7 @@ class aboutTheApp extends StatelessWidget { border: Border( bottom: BorderSide( color: Colors.grey.shade300, - width: 0.5), // Grey bottom line + width: 0.5,), // Grey bottom line ), ), child: ListTile( @@ -50,7 +51,7 @@ class aboutTheApp extends StatelessWidget { }, tileColor: Colors.white, title: Text( - 'About FCSC', + context.translate('About FCSC','حول التطبيق'), style: TextStyle( fontSize: 16, color: Color(0xFF414042), @@ -75,7 +76,7 @@ class aboutTheApp extends StatelessWidget { }, // tileColor: Colors.white, title: Text( - 'How to Get Started?', + context.translate('How to Get Started?','كيفية البدء'), style: TextStyle( fontSize: 16, color: Color(0xFF414042), diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/faq_page.dart b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/faq_page.dart index 633666ff..6511c91a 100755 --- a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/faq_page.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/faq_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/infrastructure/services/img_asset_paths/banner_asset_path.dart'; import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart'; @@ -25,7 +26,7 @@ class _FAQPageState extends State { bottomColor: Colors.white, mycenterTitle: true, title: Text( - ' FAQs', + context.translate(' FAQs','الأسئلة الشائعة'), style: TextStyle( fontSize: 22, color: Color(0xFF7DAFBC), @@ -67,11 +68,14 @@ class QuestionAnswerScrollView extends StatelessWidget { final List> questionsAndAnswers = [ { 'question': 'What is the purpose of this app?', + 'question-ar': 'ما هو الغرض من هذا التطبيق؟', 'answer': - 'The app provides official UAE statistics across categories like Economy, Environment, and Social. It allows users to explore datasets, view trends, and access detailed metrics to make informed decisions.' + 'The app provides official UAE statistics across categories like Economy, Environment, and Social. It allows users to explore datasets, view trends, and access detailed metrics to make informed decisions.', + 'answer-ar':'يوفر التطبيق الإحصائيات الرسمية لدولة الإمارات العربية المتحدة عبر فئات مثل الاقتصاد والبيئة والاجتماعية . يتيح للمستخدمين استكشاف مجموعات البيانات، عرض الاتجاهات، والوصول إلى المقاييس التفصيلية لاتخاذ قرارات مستنيرة.', }, { 'question': 'Do I need to create an account to use the app?', + 'question-ar': 'هل أحتاج إلى إنشاء حساب لاستخدام التطبيق؟ ', 'answer': RichText( text: TextSpan( children: [ @@ -101,14 +105,46 @@ class QuestionAnswerScrollView extends StatelessWidget { ], ), ), + 'answer-ar':RichText( + text: TextSpan( + children: [ + TextSpan( + text: + 'نعم، التطبيق مخصص فقط للمستخدمين المسجلين والمعتمدين. للوصول إلى البيانات:\n\n', + style: TextStyle( + color: Colors.grey, fontSize: 16, fontFamily: 'Roboto'), + ), + TextSpan( + text: + ' 1. يجب عليك التسجيل باستخدام خيار "التسجيل الآن" في شاشة تسجيل الدخول.\n', + style: TextStyle( + color: Colors.grey, fontSize: 16, fontFamily: 'Roboto'), + ), + TextSpan( + text: ' 2. يجب أن يتم الموافقة على تسجيلك من قبل المسؤول.\n', + style: TextStyle( + color: Colors.grey, fontSize: 16, fontFamily: 'Roboto'), + ), + TextSpan( + text: + " بعد الموافقة، يمكنك تسجيل الدخول للوصول إلى ميزات التطبيق وبياناته.\n\n لا يتوفر الوصول للزوار في هذا التطبيق.\n", + style: TextStyle( + color: Colors.grey, fontSize: 16, fontFamily: 'Roboto'), + ), + ], + ), + ), }, { 'question': 'How can I navigate through the app?', + 'question-ar': 'كيف يمكنني التنقل عبر التطبيق؟', 'answer': - '• Use the main categories on the homepage (e.g., Economy, Environment) to access subcategories and detailed KPIs.\n• Drill down into specific metrics or graphical views by tapping on a KPI.\n• Access additional features like Bookmarks or Profile through the navigation bar.\n' + '• Use the main categories on the homepage (e.g., Economy, Environment) to access subcategories and detailed KPIs.\n• Drill down into specific metrics or graphical views by tapping on a KPI.\n• Access additional features like Bookmarks or Profile through the navigation bar.\n', + 'answer-ar': '•استخدم الفئات الرئيسية الموجودة على الصفحة الرئيسية (مثل: الاقتصاد، البيئة) للوصول إلى الفئات الفرعية ومؤشرات الأداء الرئيسية التفصيلية •\n\ قم بالتعمق في مؤشرات معينة أو عرض الرسوم البيانية من خلال النقر على مؤشر الأداء الرئيسي (KPI). \n • للوصول إلى ميزات إضافية مثل الإشارات المرجعية أو الملف الشخصي، استخدم شريط التنقل.\n', }, { 'question': 'What types of data are available?', + 'question-ar':'ما أنواع البيانات المتوفرة؟ ', 'answer': RichText( text: TextSpan( children: [ @@ -118,7 +154,7 @@ class QuestionAnswerScrollView extends StatelessWidget { color: Colors.grey, fontSize: 16, fontFamily: 'Roboto'), ), TextSpan( - text: ' • Economy', + text: ' • Economy:', style: TextStyle( color: Color(0xFF414042), fontWeight: FontWeight.w500, @@ -157,9 +193,58 @@ class QuestionAnswerScrollView extends StatelessWidget { ], ), ), + 'answer-ar':RichText( + text: TextSpan( + children: [ + TextSpan( + text: 'يوفر التطبيق بيانات عن:\n\n', + style: TextStyle( + color: Colors.grey, fontSize: 16, fontFamily: 'Roboto'), + ), + TextSpan( + text: ' • الاقتصاد:', + style: TextStyle( + color: Color(0xFF414042), + fontWeight: FontWeight.w500, + fontSize: 16), + ), + TextSpan( + text: ' الناتج المحلي الإجمالي (GDP)، معدلات النمو، والاتجاهات الاقتصادية.\n', + style: TextStyle( + color: Colors.grey, fontSize: 16, fontFamily: 'Roboto'), + ), + TextSpan( + text: ' • البيئة:', + style: TextStyle( + color: Color(0xFF414042), + fontWeight: FontWeight.w500, + fontSize: 16), + ), + TextSpan( + text: ' إنتاج الكهرباء، استهلاك المياه، وغيرها.\n', + style: TextStyle( + color: Colors.grey, fontSize: 16, fontFamily: 'Roboto'), + ), + TextSpan( + text: ' • الاجتماعية:', + style: TextStyle( + color: Color(0xFF414042), + fontWeight: FontWeight.w500, + fontSize: 16), + ), + TextSpan( + text: + ' توزيع القوى العاملة، معدلات المشاركة، والبيانات الديموغرافية.\n', + style: TextStyle( + color: Colors.grey, fontSize: 16, fontFamily: 'Roboto'), + ), + ], + ), + ), }, { 'question': 'How do I bookmark a metric?', + 'question-ar': 'كيف يمكنني وضع مؤشر في الإشارات المرجعية؟', 'answer': RichText( text: TextSpan( children: [ @@ -195,9 +280,22 @@ class QuestionAnswerScrollView extends StatelessWidget { ], ), ), + 'answer-ar':RichText( + text: TextSpan( + children: [ + TextSpan( + text: 'عند عرض المؤشر، اضغط على أيقونة الإشارة المرجعية. يمكنك الوصول إلى الإشارات المرجعية الخاصة بك من قسم "إشاراتي المرجعية" في شريط التنقل.', + style: TextStyle( + color: Colors.grey, fontSize: 16, fontFamily: 'Roboto'), + ), + + ], + ), + ), }, { 'question': 'Can I view the app in another language?', + 'question-ar':'هل يمكنني عرض التطبيق بلغة أخرى؟', 'answer': RichText( text: TextSpan( children: [ @@ -234,29 +332,49 @@ class QuestionAnswerScrollView extends StatelessWidget { ], ), ), + 'answer-ar':RichText( + text: TextSpan( + children: [ + TextSpan( + text: 'نعم، التطبيق يدعم اللغتين الإنجليزية والعربية. يمكنك تبديل اللغة باستخدام المفتاح الموجود في الزاوية العلوية اليمنى من التطبيق.', + style: TextStyle( + color: Colors.grey, fontSize: 16, fontFamily: 'Roboto'), + ), + ], + ), + ), }, { 'question': 'What happens if I forget my password?', + 'question-ar':'ماذا يحدث إذا نسيت كلمة المرور الخاصة بي؟', 'answer': - 'Tap on the Forgot Password? link on the login page. Follow the steps to reset your password via your registered email address.\n' + 'Tap on the Forgot Password? link on the login page. Follow the steps to reset your password via your registered email address.\n', + 'answer-ar':'انقر على رابط "نسيت كلمة المرور؟" في صفحة تسجيل الدخول. اتبع الخطوات لإعادة تعيين كلمة المرور الخاصة بك عبر عنوان بريدك الإلكتروني المسجل.', }, { 'question': 'Can I edit my profile details?', + 'question-ar':'هل يمكنني تعديل تفاصيل الملف الشخصي؟', 'answer': - 'Yes, you can edit specific fields such as Date of Birth and User Image. However, certain fields like Username and Email are non-editable for security reasons.\n' + 'Yes, you can edit specific fields such as Date of Birth and User Image. However, certain fields like Username and Email are non-editable for security reasons.\n', + 'answer-ar':'يتم تحديث مجموعات البيانات في التطبيق بشكل منتظم لضمان وصول المستخدمين إلى أحدث الإحصاءات. يتم إرسال إشعارات عند إجراء تحديثات مهمة.', }, { 'question': 'How often is the data updated?', + 'question-ar':'كم مرة يتم تحديث البيانات؟ ', 'answer': - 'The app updates its datasets regularly to ensure users have access to the latest statistics. Notifications are sent whenever significant updates are made.\n' + 'The app updates its datasets regularly to ensure users have access to the latest statistics. Notifications are sent whenever significant updates are made.\n', + 'answer-ar':'يتم تحديث مجموعات البيانات في التطبيق بشكل منتظم لضمان وصول المستخدمين إلى أحدث الإحصاءات. يتم إرسال إشعارات عند إجراء تحديثات مهمة.', }, { 'question': 'What types of graphs and charts are available?', + 'question-ar':'ما أنواع الرسوم البيانية والمخططات المتوفرة؟ ', 'answer': - 'The app provides a variety of visualizations, including:\n • Line charts for trends.\n • Bar and column charts for comparisons.\n • Stacked charts for multi-layered data views.\n' + 'The app provides a variety of visualizations, including:\n • Line charts for trends.\n • Bar and column charts for comparisons.\n • Stacked charts for multi-layered data views.\n', + 'answer-ar':'يوفر التطبيق مجموعة متنوعة من التصورات البيانية، بما في ذلك:\n• المخططات الخطية لعرض الاتجاهات.\n• المخططات الشريطية والعمودية للمقارنات.\n• المخططات المكدسة لعرض البيانات متعددة الطبقات.\n', }, { 'question': 'Can I share the data or charts?', + 'question-ar':'هل يمكنني مشاركة البيانات أو الرسوم البيانية؟', 'answer': RichText( text: TextSpan( children: [ @@ -281,9 +399,22 @@ class QuestionAnswerScrollView extends StatelessWidget { ], ), ), + 'answer-ar':RichText( + text: TextSpan( + children: [ + TextSpan( + text: + 'نعم، يمكنك مشاركة البيانات أو الرسوم البيانية مباشرة من التطبيق من خلال النقر على زر "مشاركة" المتوفر في معظم الصفحات.', + style: TextStyle( + color: Colors.grey, fontSize: 16, fontFamily: 'Roboto'), + ), + ], + ), + ), }, { 'question': 'What should I do if I encounter an issue?', + 'question-ar':'ماذا يجب أن أفعل إذا واجهت مشكلة؟ ', 'answer': RichText( text: TextSpan( children: [ @@ -307,9 +438,21 @@ class QuestionAnswerScrollView extends StatelessWidget { ], ), ), + 'answer-ar': RichText( + text: TextSpan( + children: [ + TextSpan( + text: 'للحصول على الدعم الفني أو تقديم ملاحظات، انتقل إلى قسم "المساعدة" في التطبيق وتواصل مع فريق الدعم.\n', + style: TextStyle( + color: Colors.grey, fontSize: 16, fontFamily: 'Roboto'), + ), + ], + ), + ), }, { 'question': 'How do I log out of the app?', + 'question-ar':'كيف يمكنني تسجيل الخروج من التطبيق؟', 'answer': RichText( text: TextSpan( children: [ @@ -345,6 +488,17 @@ class QuestionAnswerScrollView extends StatelessWidget { ], ), ), + 'answer-ar':RichText( + text: TextSpan( + children: [ + TextSpan( + text: 'انتقل إلى قسم "الملف الشخصي" واضغط على خيار "تسجيل الخروج" في الزاوية العلوية اليسرى.\n', + style: TextStyle( + color: Colors.grey, fontSize: 16, fontFamily: 'Roboto'), + ) + ], + ), + ), }, ]; @@ -388,7 +542,7 @@ class _QuestionAnswerCardState extends State { dense: true, textColor: Color(0xFF414042), title: Text( - widget.qa['question']!, + context.translate(widget.qa['question'],widget.qa['question-ar'])!, style: TextStyle(fontWeight: FontWeight.w500, fontSize: 16), ), trailing: Icon(isExpanded @@ -404,10 +558,10 @@ class _QuestionAnswerCardState extends State { Padding( padding: const EdgeInsets.only( left: 16, right: 16, bottom: 16, top: 0), - child: widget.qa['answer'] is RichText - ? widget.qa['answer'] + child:widget.qa['answer'] is RichText + ? context.translate(widget.qa['answer'],widget.qa['answer-ar']) : Text( - widget.qa['answer'] ?? '', + context.translate(widget.qa['answer'] ?? '',widget.qa['answer-ar']), style: TextStyle( color: Colors.grey, fontSize: 16, diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/features.dart b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/features.dart index 9743c868..216d3bb8 100755 --- a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/features.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/features.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; +import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart'; import 'package:uae_stat/infrastructure/services/img_asset_paths/banner_asset_path.dart'; @@ -23,7 +24,7 @@ class UsingFeatures extends StatelessWidget { appbarColor: Colors.white, mycenterTitle: true, title: Text( - 'Key Features', + context.translate('Key Features','الميزات الرئيسية'), style: TextStyle( fontSize: 22, fontFamily: 'Roboto', @@ -51,7 +52,7 @@ class UsingFeatures extends StatelessWidget { }, tileColor: Colors.white, title: Text( - 'App Features', + context.translate('App Features','الميزات الرئيسية '), style: TextStyle( fontSize: 16, color: Color(0xFF414042), @@ -76,7 +77,7 @@ class UsingFeatures extends StatelessWidget { }, // tileColor: Colors.white, title: Text( - 'Who can use The App?', + context.translate('Who can use The App?','يمكنه استخدام التطبيق?'), style: TextStyle( fontSize: 16, color: Color(0xFF414042), @@ -105,7 +106,7 @@ class UsingFeatures extends StatelessWidget { }, // tileColor: Colors.white, title: Text( - 'Purpose of the App', + context.translate('Purpose of the App','ض من التطبيق'), style: TextStyle( fontSize: 16, color: Color(0xFF414042), @@ -134,7 +135,7 @@ class UsingFeatures extends StatelessWidget { }, // tileColor: Colors.white, title: Text( - 'How to Use the App', + context.translate('How to Use the App','كيفية استخدام التطبيق'), style: TextStyle( fontSize: 16, color: Color(0xFF414042), @@ -163,7 +164,7 @@ class UsingFeatures extends StatelessWidget { }, // tileColor: Colors.white, title: Text( - 'Stay Updated', + context.translate('Stay Updated','ابق على اطلاع'), style: TextStyle( fontSize: 16, color: Color(0xFF414042), @@ -192,7 +193,7 @@ class UsingFeatures extends StatelessWidget { }, // tileColor: Colors.white, title: Text( - 'How to Change My Password', + context.translate('How to Change My Password','كيفية تغيير كلمة المرور الخاصة بي'), style: TextStyle( fontSize: 16, color: Color(0xFF414042), @@ -221,7 +222,7 @@ class UsingFeatures extends StatelessWidget { }, // tileColor: Colors.white, title: Text( - 'How to Edit My Profile', + context.translate('How to Edit My Profile','كيفية تعديل ملفي الشخصي'), style: TextStyle( fontSize: 16, color: Color(0xFF414042), diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/userguide.dart b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/userguide.dart index 14966edb..b6372bcb 100755 --- a/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/userguide.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/user_guide/userguide.dart @@ -1,10 +1,13 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart'; import 'package:iconify_design/iconify_design.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + class Userguide extends StatefulWidget { - Userguide({super.key}); + const Userguide({super.key}); @override State createState() => _UserguideState(); @@ -12,12 +15,11 @@ class Userguide extends StatefulWidget { class _UserguideState extends State { final List> guideList = [ - {'routePath':'aboutApp','color': Color(0xFF90B0D5), 'text': 'Getting Started', 'icon': 'cbi:start-tv', }, - {'routePath':'features','color': Color(0xFFAA8E83), 'text': 'Using Features', 'icon': 'pajamas:issue-type-feature',}, - {'routePath':'faq','color': Color(0xFF7296BE), 'text': 'FAQs', 'icon': 'mdi:faq',}, + {'routePath':'aboutApp','color': Color(0xFF90B0D5), 'text': 'Getting Started', 'icon': 'cbi:start-tv', 'text-ar': 'البدء' }, + {'routePath':'features','color': Color(0xFFAA8E83), 'text': 'Using Features', 'icon': 'pajamas:issue-type-feature', 'text-ar' : 'استخدام الميزات'}, + {'routePath':'faq','color': Color(0xFF7296BE), 'text': 'FAQs', 'icon': 'mdi:faq', 'text-ar': 'لأسئلة الشائعة'}, ]; - @override Widget buildDynamicWidget(dynamic icons, Color color) { if (icons is IconData) { return Icon( @@ -44,6 +46,7 @@ class _UserguideState extends State { } } + @override Widget build(BuildContext context) { return PopScope( canPop: false, @@ -56,7 +59,7 @@ class _UserguideState extends State { bottomColor: Colors.white, dividerColor: Colors.grey[300], appbarColor: Colors.white, - title: Text('User Guide') , + title: Text(AppLocalizations.of(context)!.guide_title) , body: Container( color: Colors.white, padding: const EdgeInsets.symmetric(horizontal: 16 , vertical: 20), @@ -71,7 +74,7 @@ class _UserguideState extends State { itemBuilder: (context, index) { return HoverContainer( iconName: guideList[index]['icon'], - title: guideList[index]['text'], + title: context.translate(guideList[index]['text'], guideList[index]['text-ar']), routePath: guideList[index]['routePath'], ); }, @@ -118,7 +121,7 @@ class _HoverContainerState extends State { boxShadow: isHovered ? [ BoxShadow( - color: Colors.black.withOpacity(0.2), + color: Colors.black.withValues(alpha:0.2), blurRadius:2, spreadRadius: 1, offset: Offset(0, 4), @@ -127,7 +130,7 @@ class _HoverContainerState extends State { : [], border: Border.all( color: Color(0xFF7DAFBC), - width: 1.0 + width: 1.0, ), ), alignment: Alignment.center, @@ -151,7 +154,7 @@ class _HoverContainerState extends State { decoration: BoxDecoration( color: Color(0xFF7DAFBC), borderRadius: BorderRadius.circular(5), - border: Border.all(color: Color(0xFF7DAFBC)) + border: Border.all(color: Color(0xFF7DAFBC)), ), child: Text( widget.title, @@ -164,7 +167,7 @@ class _HoverContainerState extends State { ), ], ); - }) + },), ), diff --git a/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart b/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart index 0811419e..28f1152c 100644 --- a/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart +++ b/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart @@ -81,11 +81,13 @@ class _BaseScaffoldState extends ConsumerState { bool isLoggedOut = false; final FlutterSecureStorage _secureStorage = const FlutterSecureStorage(); static final _repo = getIt.call(); + late final Locale locale; @override void initState() { super.initState(); _checkUserId(); + locale = ref.read(localeProvider)?? const Locale('en'); WidgetsBinding.instance.addPostFrameCallback((_) { _startAppbarTour(); }); @@ -200,23 +202,24 @@ class _BaseScaffoldState extends ConsumerState { Container( decoration: BoxDecoration( shape: BoxShape.circle, + color: locale.languageCode=='ar' ? Color(0xFF7DAFBC):null, border: Border.all( - color: Colors.white, width: 2.0), + color:locale.languageCode=='ar' ? Color(0xFF7DAFBC): Colors.white, width: 2.0), ), child: IconButton( icon: const Icon(Icons.arrow_back, - color: Colors.white), + color: Colors.white,), onPressed: () { - tutorialCoachMark.finish(); - ref - .read(scaffoldTourProvider.notifier) - .state = true; - ref - .read(previousChartsTourProvider - .notifier) - .state = false; - context.go( - '/chartScreen/hotels?bgColor=0xFF90B0D5&mainTopic=ECONOMY&title=Hotel+Establishments'); + if (locale.languageCode == 'ar') { + tutorialCoachMark.next(); + } else { + tutorialCoachMark.finish(); + ref.read(scaffoldTourProvider.notifier).state = true; + ref.read(previousChartsTourProvider.notifier).state = false; + context.go( + '/chartScreen/hotels?bgColor=0xFF90B0D5&mainTopic=ECONOMY&title=Hotel+Establishments',); + } + }, ), ), @@ -224,15 +227,23 @@ class _BaseScaffoldState extends ConsumerState { Container( decoration: BoxDecoration( shape: BoxShape.circle, - color: Color(0xFF7DAFBC), + color: locale.languageCode=='ar' ? null:Color(0xFF7DAFBC), border: Border.all( - color: Color(0xFF7DAFBC), width: 1.5), + color:locale.languageCode=='ar' ? Colors.white: Color(0xFF7DAFBC), width: 1), ), child: IconButton( icon: const Icon(Icons.arrow_forward, color: Colors.white), onPressed: () { - tutorialCoachMark.next(); + if (locale.languageCode == 'ar') { + tutorialCoachMark.finish(); + ref.read(scaffoldTourProvider.notifier).state = true; + ref.read(previousChartsTourProvider.notifier).state = false; + context.go( + '/chartScreen/hotels?bgColor=0xFF90B0D5&mainTopic=ECONOMY&title=Hotel+Establishments',); + } else { + tutorialCoachMark.next(); + } }, ), ), @@ -260,7 +271,7 @@ class _BaseScaffoldState extends ConsumerState { text: AppLocalizations.of(context)!.mainMenu, alignment: ContentAlign.bottom, gap: 55, - space: 0, + space:locale.languageCode=='ar' ? 20: 20, ), TargetContent( align: ContentAlign.bottom, @@ -316,14 +327,15 @@ class _BaseScaffoldState extends ConsumerState { Container( decoration: BoxDecoration( shape: BoxShape.circle, + color: locale.languageCode=='ar' ? Color(0xFF7DAFBC):null, border: Border.all( - color: Colors.white, width: 2.0), + color:locale.languageCode=='ar' ? Color(0xFF7DAFBC): Colors.white, width: 2.0,), ), child: IconButton( icon: const Icon(Icons.arrow_back, - color: Colors.white), + color: Colors.white,), onPressed: () { - tutorialCoachMark.previous(); + locale.languageCode=='ar' ?tutorialCoachMark.next() : tutorialCoachMark.previous(); }, ), ), @@ -331,15 +343,15 @@ class _BaseScaffoldState extends ConsumerState { Container( decoration: BoxDecoration( shape: BoxShape.circle, - color: Color(0xFF7DAFBC), + color: locale.languageCode=='ar' ? null:Color(0xFF7DAFBC), border: Border.all( - color: Color(0xFF7DAFBC), width: 1), + color:locale.languageCode=='ar' ? Colors.white: Color(0xFF7DAFBC), width: 1), ), child: IconButton( icon: const Icon(Icons.arrow_forward, - color: Colors.white), + color: Colors.white,), onPressed: () { - tutorialCoachMark.next(); + locale.languageCode=='ar' ?tutorialCoachMark.previous() : tutorialCoachMark.next(); }, ), ), @@ -355,15 +367,17 @@ class _BaseScaffoldState extends ConsumerState { ), ), TargetContent( - padding: EdgeInsets.only(right: screenWidth * 0.7, top: 30), - align: ContentAlign.right, + padding: EdgeInsets.only(right:locale.languageCode=='ar' ? 0: screenWidth * 0.7, top: locale.languageCode=='ar' ?20 : 20, left: locale.languageCode=='ar' ? screenWidth * 0.7:0,), + align: locale.languageCode=='ar' ? ContentAlign.left : ContentAlign.right, child: Container( width: 200, height: screenHeight / 4, child: Stack( children: [ Image.asset( - 'assets/app_tour/leftDown.png', + locale.languageCode == 'ar' + ? 'assets/app_tour/down_right.png' // Arabic locale image + : 'assets/app_tour/leftDown.png', // Default image fit: BoxFit.contain, ), // Positioned( @@ -438,7 +452,7 @@ class _BaseScaffoldState extends ConsumerState { elevation: 0, ), child: Text( - // 'Skip', + AppLocalizations.of(context)!.skip, style: TextStyle( color: Colors.white, @@ -455,8 +469,8 @@ class _BaseScaffoldState extends ConsumerState { color: Colors.white, width: 2.0), ), child: IconButton( - icon: const Icon(Icons.arrow_back, - color: Colors.white), + icon: Icon(locale.languageCode=='ar' ? Icons.arrow_forward: Icons.arrow_back, + color: Colors.white,), onPressed: () { tutorialCoachMark.previous(); }, @@ -466,25 +480,12 @@ class _BaseScaffoldState extends ConsumerState { ElevatedButton( onPressed: () { debugPrint('Got it clicked'); - ref - .read(chartsTourProvider.notifier) - .state = true; - ref - .read( - previousChartsTourProvider.notifier) - .state = true; - ref.read(homeTourProvider.notifier).state = - true; - ref - .read(previousHomeTourProvider.notifier) - .state = true; - ref - .read(scaffoldTourProvider.notifier) - .state = true; - ref - .read(previousScaffoldTourProvider - .notifier) - .state = true; + ref.read(chartsTourProvider.notifier).state = true; + ref.read(previousChartsTourProvider.notifier).state = true; + ref.read(homeTourProvider.notifier).state = true; + ref.read(previousHomeTourProvider.notifier).state = true; + ref.read(scaffoldTourProvider.notifier).state = true; + ref.read(previousScaffoldTourProvider.notifier).state = true; tutorialCoachMark.finish(); }, style: ElevatedButton.styleFrom( @@ -515,30 +516,22 @@ class _BaseScaffoldState extends ConsumerState { ), ), TargetContent( - padding: - EdgeInsets.only(left: screenWidth * 0.7, top: toggleHeight), - align: ContentAlign.left, + padding: EdgeInsets.only(left: locale.languageCode=='ar' ? 0: screenWidth * 0.7, + top: toggleHeight, + right: locale.languageCode=='ar' ? screenWidth * 0.7 : 0, + ), + align : locale.languageCode=='ar' ? ContentAlign.right :ContentAlign.left, child: Container( width: 200, height: screenHeight / 4, child: Stack( children: [ Image.asset( - 'assets/app_tour/down_right.png', + locale.languageCode == 'ar' + ? 'assets/app_tour/leftDown.png' // Arabic locale image + : 'assets/app_tour/down_right.png', // Default image fit: BoxFit.contain, - ), - // Positioned( - // top: 0, - // left: MediaQuery.of(context).size.width* 0.5, - // child: SizedBox( - // width: 50, - // height: 100, - // child: Image.asset( - // 'assets/app_tour/bookmark2.png', - // fit: BoxFit.contain, - // ), - // ), - // ), + ) ], ), ), diff --git a/pubspec.yaml b/pubspec.yaml index b5dfb3ce..f6ff96fd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: uae_stat description: "View statistics about the UAE from the Federal Center for Statistics and Competitiveness." publish_to: "none" -version: 1.0.19+20 +version: 1.0.23+24 environment: sdk: ">=3.2.3 <4.0.0"