From cbe243ea1d9d547d8077f2f9fd780cf7e750961f Mon Sep 17 00:00:00 2001 From: venbaittech Date: Tue, 11 Mar 2025 18:00:20 +0530 Subject: [PATCH] bug fix and notification --- android/app/build.gradle | 4 +- lib/config/connectivity_provider.dart | 15 + lib/config/my_router.dart | 5 +- .../UAE_Numbers/uae_numbers.dart | 50 +- .../auth_verification/registration.dart | 1729 +++++++++-------- .../Screens/charts/screens/chart_screen.dart | 40 +- .../Screens/charts/widgets/chart_widget.dart | 2 + .../internet_check.dart | 103 +- lib/presentation/Screens/profilepage.dart | 9 + .../routes/auth_routes/login_route.dart | 20 +- .../tab_routes/home_route.dart | 11 + .../drawer_routes/Drawer Items/bookmark.dart | 411 ++-- .../notification/notification.dart | 163 +- pubspec.lock | 40 +- pubspec.yaml | 3 +- 15 files changed, 1433 insertions(+), 1172 deletions(-) create mode 100644 lib/config/connectivity_provider.dart diff --git a/android/app/build.gradle b/android/app/build.gradle index 8aacea94..61c7579b 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -20,12 +20,12 @@ if (project.hasProperty('google-services.json')) { def flutterVersionCode = localProperties.getProperty("flutter.versionCode") if (flutterVersionCode == null) { - flutterVersionCode = "33" + flutterVersionCode = "34" } def flutterVersionName = localProperties.getProperty("flutter.versionName") if (flutterVersionName == null) { - flutterVersionName = "1.0.32" + flutterVersionName = "1.0.33" } def keystorePropertiesFile = rootProject.file("key.properties") diff --git a/lib/config/connectivity_provider.dart b/lib/config/connectivity_provider.dart new file mode 100644 index 00000000..1c1f2e5a --- /dev/null +++ b/lib/config/connectivity_provider.dart @@ -0,0 +1,15 @@ +import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:internet_connection_checker/internet_connection_checker.dart'; + +final connectivityProvider = StreamProvider((ref) async* { + await for (var result in Connectivity().onConnectivityChanged) { + bool isConnected = result != ConnectivityResult.none; + + if (isConnected) { + isConnected = await InternetConnectionChecker.instance.hasConnection; + } + + yield isConnected; + } +}); diff --git a/lib/config/my_router.dart b/lib/config/my_router.dart index 9d3ad5f7..d6f4b2b9 100644 --- a/lib/config/my_router.dart +++ b/lib/config/my_router.dart @@ -377,7 +377,7 @@ final GoRouter router = GoRouter( // ), GoRoute( path: '/internetcheck', - builder: (context, state) => InternetCheck(), + builder: (context, state) => InternetCheckScreen(), ), GoRoute( path: '/login', @@ -653,7 +653,8 @@ final GoRouter router = GoRouter( ], redirect: (context, state) async { if (state.uri.path == '/SessionCheckScreen' || - state.uri.path == '/login') { + state.uri.path == '/login' || + state.uri.path == '/register') { return null; } diff --git a/lib/presentation/Screens/Bottom Navigation Pages/UAE_Numbers/uae_numbers.dart b/lib/presentation/Screens/Bottom Navigation Pages/UAE_Numbers/uae_numbers.dart index b81677dd..683576d3 100644 --- a/lib/presentation/Screens/Bottom Navigation Pages/UAE_Numbers/uae_numbers.dart +++ b/lib/presentation/Screens/Bottom Navigation Pages/UAE_Numbers/uae_numbers.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:go_router/go_router.dart'; +import 'package:uae_stat/config/connectivity_provider.dart'; import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/infrastructure/services/img_asset_paths/icons/misc_icon_asset_path.dart'; import 'package:uae_stat/presentation/components/indicators/locale_provider.dart'; @@ -170,10 +171,20 @@ class _UaenumberWidgetState extends ConsumerState { } Widget build(BuildContext context) { + final isConnected = ref.watch(connectivityProvider); + + // If no internet, redirect to InternetCheckScreen + ref.listen>(connectivityProvider, (previous, hasInternet) { + if (hasInternet.value == false) { + context.go('/internetcheck'); + } + }); + ref.listen(localeProvider, (previous, next) { final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null fetchData(localeCode); }); + double myheight = MediaQuery.of(context).size.height; double mywidth = MediaQuery.of(context).size.width; @@ -362,6 +373,16 @@ class _UaenumberWidgetState extends ConsumerState { colorPattern, double mywidth, String mainTopic) { + print('UAE Numbers $value , $title'); + // Check if title is "Population Growth" + bool isPopulationGrowth = title == "Population Growth"; + + // Convert value to double for checking positive or negative (only for Population Growth) + double parsedValue = isPopulationGrowth + ? double.tryParse(value.replaceAll('%', '')) ?? 0.0 + : 0.0; + bool isPositive = parsedValue >= 0; + return GestureDetector( onTap: () { // print('checking data'); @@ -403,13 +424,28 @@ class _UaenumberWidgetState extends ConsumerState { SizedBox(height: 0.1), Text(subtitle, textAlign: TextAlign.center, style: subtitleStyle), SizedBox(height: 0.3), - Text( - value, - style: TextStyle( - fontSize: 20, - color: boldColor, - fontWeight: FontWeight.bold, - ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + value, + style: TextStyle( + fontSize: 20, + color: isPopulationGrowth + ? (isPositive ? Colors.green : Colors.red) + : boldColor, + fontWeight: FontWeight.bold, + ), + ), + if (isPopulationGrowth) ...[ + const SizedBox(width: 5), + Icon( + isPositive ? Icons.arrow_upward : Icons.arrow_downward, + color: isPositive ? Colors.green : Colors.red, + size: 20, + ), + ], + ], ), ], ), diff --git a/lib/presentation/Screens/auth_verification/registration.dart b/lib/presentation/Screens/auth_verification/registration.dart index 90e4aceb..9df0657b 100644 --- a/lib/presentation/Screens/auth_verification/registration.dart +++ b/lib/presentation/Screens/auth_verification/registration.dart @@ -176,21 +176,22 @@ class _RegisterScreenState extends ConsumerState { List missingConstraints = []; if (!hasUppercase.hasMatch(value)) { - missingConstraints.add(context.translate('uppercase letter','حرف كبير')); + missingConstraints.add(context.translate('uppercase letter', 'حرف كبير')); } if (!hasLowercase.hasMatch(value)) { - missingConstraints.add(context.translate('lowercase letter','حرف صغير')); + missingConstraints.add(context.translate('lowercase letter', 'حرف صغير')); } if (!hasDigit.hasMatch(value)) { - missingConstraints.add(context.translate('numeric digit','رقم')); + missingConstraints.add(context.translate('numeric digit', 'رقم')); } if (!hasSpecialCharacter.hasMatch(value)) { - missingConstraints.add(context.translate('special character','رمز خاص')); + missingConstraints.add(context.translate('special character', 'رمز خاص')); } // If there are missing constraints, return a consolidated message if (missingConstraints.isNotEmpty) { - return context.translate('At least one ${missingConstraints.join(', ')}','${missingConstraints.join(', ')}على الأقل واحد '); + return context.translate('At least one ${missingConstraints.join(', ')}', + '${missingConstraints.join(', ')}على الأقل واحد '); } _password = value; // Store the password for confirm password validation @@ -273,33 +274,38 @@ class _RegisterScreenState extends ConsumerState { builder: (context) { return AlertDialog( backgroundColor: Colors.white, - title: Text(context.translate( 'Email Exists','البريد الإلكتروني موجود'),), + title: Text( + context.translate( + 'Email Exists', 'البريد الإلكتروني موجود'), + ), content: Text( - context.translate( 'Email ID already exists. Please use a different email.', - 'معرف البريد الإلكتروني موجود بالفعل. يرجى استخدام بريد إلكتروني آخر.' - ),), + context.translate( + 'Email ID already exists. Please use a different email.', + 'معرف البريد الإلكتروني موجود بالفعل. يرجى استخدام بريد إلكتروني آخر.'), + ), actions: [ TextButton( onPressed: () { Navigator.pop(context); setState(() { isRegistering = - false; // Re-enable the button after error + false; // Re-enable the button after error }); }, style: TextButton.styleFrom( - backgroundColor: Color(0xFFAA8E83), // Set background color + backgroundColor: + Color(0xFFAA8E83), // Set background color foregroundColor: Colors.white, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10.0), // Set text color + borderRadius: + BorderRadius.circular(10.0), // Set text color ), ), child: Text( - context.translate('Ok','حسنًا'), + context.translate('Ok', 'حسنًا'), style: TextStyle(color: Colors.white, fontSize: 16), ), ), - ], ); }, @@ -376,10 +382,11 @@ class _RegisterScreenState extends ConsumerState { Align( alignment: AlignmentDirectional.topEnd, child: Padding( - padding: EdgeInsets.only(top: 16.0, right :16.0), + padding: EdgeInsets.only(top: 16.0, right: 16.0), child: Consumer( builder: (context, ref, _) { - final locale = ref.watch(localeProvider); // Current locale + final locale = + ref.watch(localeProvider); // Current locale return MyToggle( isOn: locale?.languageCode == 'en', knobTextWhenOn: 'ع', @@ -390,7 +397,8 @@ class _RegisterScreenState extends ConsumerState { final formState = _formKey.currentState; ref.read(localeProvider.notifier).toggleLocale(); Future.delayed(Duration(milliseconds: 100), () { - if (hasValidated && formState?.validate() == false) { + if (hasValidated && + formState?.validate() == false) { formState?.validate(); } }); @@ -403,864 +411,881 @@ class _RegisterScreenState extends ConsumerState { Column(children: [ registrationSuccess ? Padding( - padding: const EdgeInsets.all(20.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox(height: screenheight / 4), - buildIconContainer( - Icons.report, Color(0xFF7DAFBC)), - SizedBox(height: 20), - Text( - context.translate( - 'Your registration is pending for verification.', - 'تسجيلك في انتظار التحقق.'), - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: Color(0xFF414042)), - ), - SizedBox(height: 10), - Text( - context.translate( - 'Kindly verify your mail to proceed further.', - 'يرجى التحقق من البريد الخاص بك للمضي قدما.'), - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14, - color: Color(0xFF898C81), - ), - ), - SizedBox(height: 10), - ElevatedButton( - onPressed: () => {context.go('/login')}, - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFFAA8E83), // Background color - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), // Border radius - ), - ), - child: Text( - context.translate('Go to Login', 'اذهب إلى تسجيل الدخول'), - style: TextStyle( - color: Colors.white, // Text color - ), - ), - ), - - SizedBox(height: screenheight / 5), - Center( - child: Container( - height: screenheight / 16, - width: screenwidth / 2.5, - decoration: BoxDecoration( - image: DecorationImage( - image: AssetImage( - "assets/splash_screen/logo.png"), // Background image asset - fit: BoxFit.fill, + padding: const EdgeInsets.all(20.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox(height: screenheight / 4), + buildIconContainer( + Icons.report, Color(0xFF7DAFBC)), + SizedBox(height: 20), + Text( + context.translate( + 'Your registration is pending for verification.', + 'تسجيلك في انتظار التحقق.'), + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Color(0xFF414042)), + ), + SizedBox(height: 10), + Text( + context.translate( + 'Kindly verify your mail to proceed further.', + 'يرجى التحقق من البريد الخاص بك للمضي قدما.'), + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, + color: Color(0xFF898C81), ), ), - )) - ], - ), - ) + SizedBox(height: 10), + ElevatedButton( + onPressed: () => {context.go('/login')}, + style: ElevatedButton.styleFrom( + backgroundColor: + Color(0xFFAA8E83), // Background color + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular( + 12), // Border radius + ), + ), + child: Text( + context.translate( + 'Go to Login', 'اذهب إلى تسجيل الدخول'), + style: TextStyle( + color: Colors.white, // Text color + ), + ), + ), + SizedBox(height: screenheight / 5), + Center( + child: Container( + height: screenheight / 16, + width: screenwidth / 2.5, + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage( + "assets/splash_screen/logo.png"), // Background image asset + fit: BoxFit.fill, + ), + ), + )) + ], + ), + ) : registrationFailed - ? Padding( - padding: const EdgeInsets.all(20.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox(height: screenheight / 8), - buildIconContainer(Icons.report, Colors.red), - SizedBox(height: 20), - Text( - context.translate( - 'Sorry ${_usernameController.text}!', - 'آسف ${_usernameController.text}!'), - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: Color(0xFF414042)), - ), - SizedBox(height: 10), - Text( - context.translate( - 'Your registration process failed. For further assistance, please contact support.', - 'فشلت عملية التسجيل الخاصة بك. لمزيد من المساعدة، يرجى الاتصال بالدعم.'), - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14, - color: Color(0xFF898C81), - ), - ), - SizedBox(height: 10), - ElevatedButton( - onPressed: () => { - setState(() { - registrationFailed = false; - registrationSuccess = false; - _usernameController.clear(); - _emailController.clear(); - _passwordController.clear(); - _confirmpasswordController.clear(); - isChecked = false; - }) - }, - child: Text( - context.translate( - 'Retry', 'أعد المحاولة'), - ), - ), - SizedBox(height: screenheight / 5), - Center( - child: Container( - height: screenheight / 16, - width: screenwidth / 2.5, - decoration: BoxDecoration( - image: DecorationImage( - image: AssetImage( - "assets/splash_screen/logo.png"), // Background image asset - fit: BoxFit.fill, - ), + ? Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox(height: screenheight / 8), + buildIconContainer(Icons.report, Colors.red), + SizedBox(height: 20), + Text( + context.translate( + 'Sorry ${_usernameController.text}!', + 'آسف ${_usernameController.text}!'), + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Color(0xFF414042)), + ), + SizedBox(height: 10), + Text( + context.translate( + 'Your registration process failed. For further assistance, please contact support.', + 'فشلت عملية التسجيل الخاصة بك. لمزيد من المساعدة، يرجى الاتصال بالدعم.'), + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, + color: Color(0xFF898C81), + ), + ), + SizedBox(height: 10), + ElevatedButton( + onPressed: () => { + setState(() { + registrationFailed = false; + registrationSuccess = false; + _usernameController.clear(); + _emailController.clear(); + _passwordController.clear(); + _confirmpasswordController.clear(); + isChecked = false; + }) + }, + child: Text( + context.translate( + 'Retry', 'أعد المحاولة'), + ), + ), + SizedBox(height: screenheight / 5), + Center( + child: Container( + height: screenheight / 16, + width: screenwidth / 2.5, + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage( + "assets/splash_screen/logo.png"), // Background image asset + fit: BoxFit.fill, + ), + ), + )) + ], ), - )) - ], - ), - ) - : Form( - key: _formKey, - child: SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox(height: screenheight / 60), - Text( - // 'Register', - AppLocalizations.of(context)! - .register_title, - style: TextStyle( - fontSize: 32, - fontWeight: FontWeight.w400), - ), - SizedBox(height: 10), - Text(AppLocalizations.of(context)! - .register_details, - style: TextStyle( - fontSize: context.translate(18.0, 14.0), - color: const Color(0xff898C81), - fontWeight: FontWeight.w600, - ), - ), - - SizedBox(height: 20), - // Display this if registration is pending approval - Padding( - padding: const EdgeInsets.only( - top: 5.0, - bottom: 10, - left: 30, - right: 30), - child: TextFormField( - controller: _usernameController, - // focusNode: _focusNodes[0], - decoration: InputDecoration( - // hintText: _showHints[0] ? 'Username' : null, - hintText: _showHints[0] - ? AppLocalizations.of(context)! - .register_name - : null, - prefixIconConstraints: - const BoxConstraints( - maxWidth: 25 + 16 + 10, - maxHeight: 25 + (8 * 2), - ), - prefixIcon: Padding( - padding: const EdgeInsetsDirectional - .only( - start: 16, - end: 10, - ), - child: Image.asset( - MiscIconAssetPath.person, - fit: BoxFit.fitHeight, - height: 25, - width: 25, - color: MyTheme.topicColor( - IndicatorTopic.economy) - .shade300, - ), - ), + ) + : Form( + key: _formKey, + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox(height: screenheight / 60), + Text( + // 'Register', + AppLocalizations.of(context)! + .register_title, + style: TextStyle( + fontSize: 32, + fontWeight: FontWeight.w400), + ), + SizedBox(height: 10), + Text( + AppLocalizations.of(context)! + .register_details, + style: TextStyle( + fontSize: context.translate(18.0, 14.0), + color: const Color(0xff898C81), + fontWeight: FontWeight.w600, + ), + ), - // prefixIcon: Icon( - // Icons.person, - // color: Color(0xFF90B0D5), - // - // ), - // border: OutlineInputBorder(), - enabledBorder: OutlineInputBorder( - borderRadius: - BorderRadius.circular(10), - borderSide: BorderSide( - color: MyTheme.topicColor( - IndicatorTopic.economy) - .shade400, - width: 1), // Enabled border - ), - focusedBorder: OutlineInputBorder( - borderRadius: - BorderRadius.circular(10), - borderSide: BorderSide( - color: Colors.deepPurple, - width: 2), // Focused border - ), - errorBorder: OutlineInputBorder( - borderRadius: - BorderRadius.circular(10), - borderSide: BorderSide( - color: Color(0xFFb22222), - width: 1), // Error border - ), - focusedErrorBorder: - OutlineInputBorder( - borderRadius: - BorderRadius.circular(10), - borderSide: BorderSide( - color: Color(0xFFb22222), - width: - 1), // Match the error color - ), - counterText: '', - hintStyle: TextStyle( - color: Color(0xFFC3C6CB), - fontSize: - registerLocale?.languageCode == - 'ar' - ? 14 - : 16, - ), - ), - validator: _validateUsername, - maxLength: - 40, // Set the maximum length to 20 characters - maxLengthEnforcement: - MaxLengthEnforcement.enforced, - ), - ), - SizedBox(height: 15), - Padding( - padding: const EdgeInsets.only( - top: 5.0, - bottom: 10, - left: 30, - right: 30), - child: TextFormField( - controller: _emailController, - // focusNode: _focusNodes[1], - decoration: InputDecoration( - // hintText: 'Enter your email', - hintText: _showHints[1] - ? AppLocalizations.of(context)! - .enter_your_email - : null, - // _showHints[1] ? 'Enter your email' : null, - prefixIconConstraints: - const BoxConstraints( - maxWidth: 25 + 16 + 10, - maxHeight: 25 + (8 * 2), - ), - prefixIcon: Padding( - padding: const EdgeInsetsDirectional - .only( - start: 16, - end: 10, - ), - child: Image.asset( - MiscIconAssetPath.vector, - fit: BoxFit.fitHeight, - height: 20, - width: 25, - color: MyTheme.topicColor( - IndicatorTopic.economy) - .shade100, - ), - ), - - // border: OutlineInputBorder(), - enabledBorder: OutlineInputBorder( - borderRadius: - BorderRadius.circular(10), - borderSide: BorderSide( - color: MyTheme.topicColor( - IndicatorTopic.economy) - .shade400, - width: 1), - ), - focusedBorder: OutlineInputBorder( - borderRadius: - BorderRadius.circular(10), - borderSide: BorderSide( - color: Colors.deepPurple, - width: 2), // Focused border - ), - errorBorder: OutlineInputBorder( - borderRadius: - BorderRadius.circular(10), - borderSide: BorderSide( - color: Color(0xFFb22222), - width: 1), // Error border - ), - focusedErrorBorder: - OutlineInputBorder( - borderRadius: - BorderRadius.circular(10), - borderSide: BorderSide( - color: Color(0xFFb22222), - width: - 1), // Match the error color - ), - counterText: '', - hintStyle: TextStyle( - color: Color(0xFFC3C6CB), - fontSize: - registerLocale?.languageCode == - 'ar' - ? 14 - : 16, - ), - ), - validator: _validateEmail, - maxLength: 320, - maxLengthEnforcement: - MaxLengthEnforcement.enforced, - inputFormatters: [ - LengthLimitingTextInputFormatter( - 320), // Limit to 320 characters - ], - ), - ), - SizedBox(height: 15), - Padding( - padding: const EdgeInsets.only( - top: 5.0, - bottom: 10, - left: 30, - right: 30), - child: TextFormField( - controller: _passwordController, - // focusNode: _focusNodes[2], - obscureText: _obscurePassword, - decoration: InputDecoration( - hintText: _showHints[2] - ? AppLocalizations.of(context)! - .enter_your_password - : null, - // _showHints[2] ? 'Enter your password' : null, - prefixIconConstraints: - const BoxConstraints( - maxWidth: 25 + 16 + 10, - maxHeight: 25 + (8 * 2), - ), - prefixIcon: Padding( - padding: const EdgeInsetsDirectional - .only( - start: 16, - end: 10, - ), - child: Image.asset( - MiscIconAssetPath.lock, - fit: BoxFit.fitHeight, - height: 25, - width: 25, - color: MyTheme.topicColor( - IndicatorTopic.economy) - .shade300, - ), - ), - - // prefixIcon: Icon( - // Icons.lock, - // color: Color(0xFF90B0D5), - // ), - suffixIcon: IconButton( - // icon: Icon( - // _obscurePassword - // ? Icons.visibility_off - // : Icons.visibility, - // color: Color(0xFF9EA2A9), - // ), - - icon: Image.asset( - _obscurePassword - ? MiscIconAssetPath - .visibilityOff - : MiscIconAssetPath.visibleOn, - - color: Color( - 0xFF9EA2A9), // Apply color if needed, but keep in mind `Image.asset` might not support color directly. - width: 24, - height: 24, - ), - - onPressed: () { - setState(() { - _obscurePassword = - !_obscurePassword; - }); - }, - ), - // border: OutlineInputBorder(), - enabledBorder: OutlineInputBorder( - borderRadius: - BorderRadius.circular(10), - borderSide: BorderSide( - color: MyTheme.topicColor( - IndicatorTopic.economy) - .shade400, - width: 1), - ), - focusedBorder: OutlineInputBorder( - borderRadius: - BorderRadius.circular(10), - borderSide: BorderSide( - color: Colors.deepPurple, - width: 2), // Focused border - ), - errorBorder: OutlineInputBorder( - borderRadius: - BorderRadius.circular(10), - borderSide: BorderSide( - color: Color(0xFFb22222), - width: 1), // Error border - ), - focusedErrorBorder: - OutlineInputBorder( - borderRadius: - BorderRadius.circular(10), - borderSide: BorderSide( - color: Color(0xFFb22222), - width: - 1), // Match the error color - ), - - counterText: '', - hintStyle: TextStyle( - color: Color(0xFFC3C6CB), - fontSize: - registerLocale?.languageCode == - 'ar' - ? 14 - : 16, - ), - ), - validator: _validatePassword, - maxLength: 40, - maxLengthEnforcement: - MaxLengthEnforcement.enforced, - ), - ), - SizedBox(height: 15), - Padding( - padding: const EdgeInsets.only( - top: 5.0, - bottom: 10, - left: 30, - right: 30), - child: TextFormField( - controller: _confirmpasswordController, - // focusNode: _focusNodes[3], - obscureText: _obscureConfirmPassword, - decoration: InputDecoration( - hintText: _showHints[3] - ? AppLocalizations.of(context)! - .register_Confirm_password - : null, - // _showHints[3] ? 'Confirm password' : null, - prefixIconConstraints: - const BoxConstraints( - maxWidth: 25 + 16 + 10, - maxHeight: 25 + (8 * 2), - ), - prefixIcon: Padding( - padding: const EdgeInsetsDirectional - .only( - start: 16, - end: 10, - ), - child: Image.asset( - MiscIconAssetPath.lock, - fit: BoxFit.fitHeight, - height: 25, - width: 25, - color: MyTheme.topicColor( - IndicatorTopic.economy) - .shade300, - ), - ), - - suffixIcon: IconButton( - icon: Image.asset( - _obscureConfirmPassword - ? MiscIconAssetPath - .visibilityOff - : MiscIconAssetPath.visibleOn, - - color: Color( - 0xFF9EA2A9), // Apply color if needed, but keep in mind `Image.asset` might not support color directly. - width: 24, - height: 24, - ), - onPressed: () { - setState(() { - _obscureConfirmPassword = - !_obscureConfirmPassword; - }); - }, - ), - // border: OutlineInputBorder( - // borderSide: BorderSide(color: Colors.blue, width: 2), // Default border color - // ), - enabledBorder: OutlineInputBorder( - borderRadius: - BorderRadius.circular(10), - borderSide: BorderSide( - color: MyTheme.topicColor( - IndicatorTopic.economy) - .shade400, - width: 1), - ), - focusedBorder: OutlineInputBorder( - borderRadius: - BorderRadius.circular(10), - borderSide: BorderSide( - color: Colors.deepPurple, - width: 2), // Focused border - ), - errorBorder: OutlineInputBorder( - borderRadius: - BorderRadius.circular(10), - borderSide: BorderSide( - color: Color(0xFFb22222), - width: 1), // Error border - ), - focusedErrorBorder: - OutlineInputBorder( - borderRadius: - BorderRadius.circular(10), - borderSide: BorderSide( - color: Color(0xFFb22222), - width: - 1), // Match the error color - ), - counterText: '', - hintStyle: TextStyle( - color: Color(0xFFC3C6CB), - fontSize: - registerLocale?.languageCode == - 'ar' - ? 14 - : 16, - ), - ), - validator: _validateConfirmPassword, - maxLength: 40, - maxLengthEnforcement: - MaxLengthEnforcement.enforced, - inputFormatters: [ - LengthLimitingTextInputFormatter( - 64), // Limit to 40 characters - ], - ), - ), - SizedBox(height: 10), - Padding( - padding: const EdgeInsets.only( - top: 0, - bottom: 10, - left: 15.5, - right: 30), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Checkbox( - value: isChecked, - onChanged: (value) { - setState(() { - isChecked = value ?? false; - showError = false; - }); - }, - side: BorderSide( - color: showError - ? Color(0xFFb22222) - : MyTheme.topicColor( - IndicatorTopic.economy) - .shade400, - width: 1, - ), - ), - Expanded( - child: Padding( - padding: const EdgeInsets.only( - top: 14.0,), - child: Text.rich( - TextSpan( - text: AppLocalizations.of( - context,)! - .agree, - // text: 'I agree to ', - style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: registerLocale - ?.languageCode == - 'ar' - ? 12 - : 14, - color: Color( - 0xFF898C81,), // Change to your desired color - ), - children: [ - TextSpan( - recognizer:TapGestureRecognizer() - ..onTap = () => context.push('/terms&conditions'), - text: AppLocalizations.of( - context)! - .terms_conditions, - // text: 'Terms & Conditions', - style: TextStyle( - fontSize: registerLocale - ?.languageCode == - 'ar' - ? 12 - : 14, - fontWeight: - FontWeight.bold, - color: - Color(0xFF985400), - // Makes the text bold - // decoration: - // TextDecoration.underline, - decorationColor: - Color(0xFF985400), - decorationThickness: - 1), + SizedBox(height: 20), + // Display this if registration is pending approval + Padding( + padding: const EdgeInsets.only( + top: 5.0, + bottom: 10, + left: 30, + right: 30), + child: TextFormField( + controller: _usernameController, + // focusNode: _focusNodes[0], + decoration: InputDecoration( + // hintText: _showHints[0] ? 'Username' : null, + hintText: _showHints[0] + ? AppLocalizations.of(context)! + .register_name + : null, + prefixIconConstraints: + const BoxConstraints( + maxWidth: 25 + 16 + 10, + maxHeight: 25 + (8 * 2), ), - TextSpan( - text: AppLocalizations.of( - context)! - .t_and, - style: TextStyle( - color: Color( - 0xFF898C81), // Change to your desired color + prefixIcon: Padding( + padding: const EdgeInsetsDirectional + .only( + start: 16, + end: 10, + ), + child: Image.asset( + MiscIconAssetPath.person, + fit: BoxFit.fitHeight, + height: 25, + width: 25, + color: MyTheme.topicColor( + IndicatorTopic.economy) + .shade300, ), ), - TextSpan( - recognizer: TapGestureRecognizer() - ..onTap = () => context.push('/privacy_policy'), - text: AppLocalizations.of( - context)! - .privacy_policy, - style: TextStyle( - fontWeight: - FontWeight.bold, - fontSize: registerLocale - ?.languageCode == - 'ar' - ? 12 - : 14, - fontFamily: 'Roboto', - color: - Color(0xFF985400), - // decoration: - // TextDecoration.underline, - decorationColor: - Color(0xFF648CBA), - decorationThickness: - 1), + + // prefixIcon: Icon( + // Icons.person, + // color: Color(0xFF90B0D5), + // + // ), + // border: OutlineInputBorder(), + enabledBorder: OutlineInputBorder( + borderRadius: + BorderRadius.circular(10), + borderSide: BorderSide( + color: MyTheme.topicColor( + IndicatorTopic.economy) + .shade400, + width: 1), // Enabled border ), - TextSpan( - text: AppLocalizations.of( - context)! - .conditions, - style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: registerLocale - ?.languageCode == - 'ar' - ? 12 - : 14, + focusedBorder: OutlineInputBorder( + borderRadius: + BorderRadius.circular(10), + borderSide: BorderSide( + color: Colors.deepPurple, + width: 2), // Focused border + ), + errorBorder: OutlineInputBorder( + borderRadius: + BorderRadius.circular(10), + borderSide: BorderSide( + color: Color(0xFFb22222), + width: 1), // Error border + ), + focusedErrorBorder: + OutlineInputBorder( + borderRadius: + BorderRadius.circular(10), + borderSide: BorderSide( + color: Color(0xFFb22222), + width: + 1), // Match the error color + ), + counterText: '', + hintStyle: TextStyle( + color: Color(0xFFC3C6CB), + fontSize: + registerLocale?.languageCode == + 'ar' + ? 14 + : 16, + ), + ), + validator: _validateUsername, + maxLength: + 40, // Set the maximum length to 20 characters + maxLengthEnforcement: + MaxLengthEnforcement.enforced, + ), + ), + SizedBox(height: 15), + Padding( + padding: const EdgeInsets.only( + top: 5.0, + bottom: 10, + left: 30, + right: 30), + child: TextFormField( + controller: _emailController, + // focusNode: _focusNodes[1], + decoration: InputDecoration( + // hintText: 'Enter your email', + hintText: _showHints[1] + ? AppLocalizations.of(context)! + .enter_your_email + : null, + // _showHints[1] ? 'Enter your email' : null, + prefixIconConstraints: + const BoxConstraints( + maxWidth: 25 + 16 + 10, + maxHeight: 25 + (8 * 2), + ), + prefixIcon: Padding( + padding: const EdgeInsetsDirectional + .only( + start: 16, + end: 10, + ), + child: Image.asset( + MiscIconAssetPath.vector, + fit: BoxFit.fitHeight, + height: 20, + width: 25, + color: MyTheme.topicColor( + IndicatorTopic.economy) + .shade100, + ), + ), + + // border: OutlineInputBorder(), + enabledBorder: OutlineInputBorder( + borderRadius: + BorderRadius.circular(10), + borderSide: BorderSide( + color: MyTheme.topicColor( + IndicatorTopic.economy) + .shade400, + width: 1), + ), + focusedBorder: OutlineInputBorder( + borderRadius: + BorderRadius.circular(10), + borderSide: BorderSide( + color: Colors.deepPurple, + width: 2), // Focused border + ), + errorBorder: OutlineInputBorder( + borderRadius: + BorderRadius.circular(10), + borderSide: BorderSide( + color: Color(0xFFb22222), + width: 1), // Error border + ), + focusedErrorBorder: + OutlineInputBorder( + borderRadius: + BorderRadius.circular(10), + borderSide: BorderSide( + color: Color(0xFFb22222), + width: + 1), // Match the error color + ), + counterText: '', + hintStyle: TextStyle( + color: Color(0xFFC3C6CB), + fontSize: + registerLocale?.languageCode == + 'ar' + ? 14 + : 16, + ), + ), + validator: _validateEmail, + maxLength: 320, + maxLengthEnforcement: + MaxLengthEnforcement.enforced, + inputFormatters: [ + LengthLimitingTextInputFormatter( + 320), // Limit to 320 characters + ], + ), + ), + SizedBox(height: 15), + Padding( + padding: const EdgeInsets.only( + top: 5.0, + bottom: 10, + left: 30, + right: 30), + child: TextFormField( + controller: _passwordController, + // focusNode: _focusNodes[2], + obscureText: _obscurePassword, + decoration: InputDecoration( + hintText: _showHints[2] + ? AppLocalizations.of(context)! + .enter_your_password + : null, + // _showHints[2] ? 'Enter your password' : null, + prefixIconConstraints: + const BoxConstraints( + maxWidth: 25 + 16 + 10, + maxHeight: 25 + (8 * 2), + ), + prefixIcon: Padding( + padding: const EdgeInsetsDirectional + .only( + start: 16, + end: 10, + ), + child: Image.asset( + MiscIconAssetPath.lock, + fit: BoxFit.fitHeight, + height: 25, + width: 25, + color: MyTheme.topicColor( + IndicatorTopic.economy) + .shade300, + ), + ), + + // prefixIcon: Icon( + // Icons.lock, + // color: Color(0xFF90B0D5), + // ), + suffixIcon: IconButton( + // icon: Icon( + // _obscurePassword + // ? Icons.visibility_off + // : Icons.visibility, + // color: Color(0xFF9EA2A9), + // ), + + icon: Image.asset( + _obscurePassword + ? MiscIconAssetPath + .visibilityOff + : MiscIconAssetPath.visibleOn, + color: Color( - 0xFF898C81), // Change to your desired color + 0xFF9EA2A9), // Apply color if needed, but keep in mind `Image.asset` might not support color directly. + width: 24, + height: 24, + ), + + onPressed: () { + setState(() { + _obscurePassword = + !_obscurePassword; + }); + }, + ), + // border: OutlineInputBorder(), + enabledBorder: OutlineInputBorder( + borderRadius: + BorderRadius.circular(10), + borderSide: BorderSide( + color: MyTheme.topicColor( + IndicatorTopic.economy) + .shade400, + width: 1), + ), + focusedBorder: OutlineInputBorder( + borderRadius: + BorderRadius.circular(10), + borderSide: BorderSide( + color: Colors.deepPurple, + width: 2), // Focused border + ), + errorBorder: OutlineInputBorder( + borderRadius: + BorderRadius.circular(10), + borderSide: BorderSide( + color: Color(0xFFb22222), + width: 1), // Error border + ), + focusedErrorBorder: + OutlineInputBorder( + borderRadius: + BorderRadius.circular(10), + borderSide: BorderSide( + color: Color(0xFFb22222), + width: + 1), // Match the error color + ), + + counterText: '', + hintStyle: TextStyle( + color: Color(0xFFC3C6CB), + fontSize: + registerLocale?.languageCode == + 'ar' + ? 14 + : 16, + ), + ), + validator: _validatePassword, + maxLength: 40, + maxLengthEnforcement: + MaxLengthEnforcement.enforced, + ), + ), + SizedBox(height: 15), + Padding( + padding: const EdgeInsets.only( + top: 5.0, + bottom: 10, + left: 30, + right: 30), + child: TextFormField( + controller: _confirmpasswordController, + // focusNode: _focusNodes[3], + obscureText: _obscureConfirmPassword, + decoration: InputDecoration( + hintText: _showHints[3] + ? AppLocalizations.of(context)! + .register_Confirm_password + : null, + // _showHints[3] ? 'Confirm password' : null, + prefixIconConstraints: + const BoxConstraints( + maxWidth: 25 + 16 + 10, + maxHeight: 25 + (8 * 2), + ), + prefixIcon: Padding( + padding: const EdgeInsetsDirectional + .only( + start: 16, + end: 10, + ), + child: Image.asset( + MiscIconAssetPath.lock, + fit: BoxFit.fitHeight, + height: 25, + width: 25, + color: MyTheme.topicColor( + IndicatorTopic.economy) + .shade300, + ), + ), + + suffixIcon: IconButton( + icon: Image.asset( + _obscureConfirmPassword + ? MiscIconAssetPath + .visibilityOff + : MiscIconAssetPath.visibleOn, + + color: Color( + 0xFF9EA2A9), // Apply color if needed, but keep in mind `Image.asset` might not support color directly. + width: 24, + height: 24, + ), + onPressed: () { + setState(() { + _obscureConfirmPassword = + !_obscureConfirmPassword; + }); + }, + ), + // border: OutlineInputBorder( + // borderSide: BorderSide(color: Colors.blue, width: 2), // Default border color + // ), + enabledBorder: OutlineInputBorder( + borderRadius: + BorderRadius.circular(10), + borderSide: BorderSide( + color: MyTheme.topicColor( + IndicatorTopic.economy) + .shade400, + width: 1), + ), + focusedBorder: OutlineInputBorder( + borderRadius: + BorderRadius.circular(10), + borderSide: BorderSide( + color: Colors.deepPurple, + width: 2), // Focused border + ), + errorBorder: OutlineInputBorder( + borderRadius: + BorderRadius.circular(10), + borderSide: BorderSide( + color: Color(0xFFb22222), + width: 1), // Error border + ), + focusedErrorBorder: + OutlineInputBorder( + borderRadius: + BorderRadius.circular(10), + borderSide: BorderSide( + color: Color(0xFFb22222), + width: + 1), // Match the error color + ), + counterText: '', + hintStyle: TextStyle( + color: Color(0xFFC3C6CB), + fontSize: + registerLocale?.languageCode == + 'ar' + ? 14 + : 16, + ), + ), + validator: _validateConfirmPassword, + maxLength: 40, + maxLengthEnforcement: + MaxLengthEnforcement.enforced, + inputFormatters: [ + LengthLimitingTextInputFormatter( + 64), // Limit to 40 characters + ], + ), + ), + SizedBox(height: 10), + Padding( + padding: const EdgeInsets.only( + top: 0, + bottom: 10, + left: 15.5, + right: 30), + child: Row( + mainAxisAlignment: + MainAxisAlignment.center, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Checkbox( + value: isChecked, + onChanged: (value) { + setState(() { + isChecked = value ?? false; + showError = false; + }); + }, + side: BorderSide( + color: showError + ? Color(0xFFb22222) + : MyTheme.topicColor( + IndicatorTopic + .economy) + .shade400, + width: 1, + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.only( + top: 0, + ), + child: Text.rich( + TextSpan( + text: AppLocalizations.of( + context, + )! + .agree, + // text: 'I agree to ', + style: TextStyle( + fontWeight: FontWeight.w500, + fontSize: registerLocale + ?.languageCode == + 'ar' + ? 12 + : 14, + color: Color( + 0xFF898C81, + ), // Change to your desired color + ), + children: [ + TextSpan( + recognizer: + TapGestureRecognizer() + ..onTap = () => + context.push( + '/terms&conditions'), + text: AppLocalizations.of( + context)! + .terms_conditions, + // text: 'Terms & Conditions', + style: TextStyle( + fontSize: registerLocale + ?.languageCode == + 'ar' + ? 12 + : 14, + fontWeight: + FontWeight.bold, + color: + Color(0xFF985400), + // Makes the text bold + // decoration: + // TextDecoration.underline, + decorationColor: + Color(0xFF985400), + decorationThickness: + 1), + ), + TextSpan( + text: AppLocalizations.of( + context)! + .t_and, + style: TextStyle( + color: Color( + 0xFF898C81), // Change to your desired color + ), + ), + TextSpan( + recognizer: + TapGestureRecognizer() + ..onTap = () => + context.push( + '/privacy_policy'), + text: AppLocalizations.of( + context)! + .privacy_policy, + style: TextStyle( + fontWeight: + FontWeight.bold, + fontSize: registerLocale + ?.languageCode == + 'ar' + ? 12 + : 14, + fontFamily: 'Roboto', + color: + Color(0xFF985400), + // decoration: + // TextDecoration.underline, + decorationColor: + Color(0xFF648CBA), + decorationThickness: + 1), + ), + TextSpan( + text: AppLocalizations.of( + context)! + .conditions, + style: TextStyle( + fontWeight: + FontWeight.w500, + fontSize: registerLocale + ?.languageCode == + 'ar' + ? 12 + : 14, + color: Color( + 0xFF898C81), // Change to your desired color + ), + ), + ], + ), + ), ), ), ], ), ), - ), - ), - ], - ), - ), - if (showError) - Row( - mainAxisAlignment: - MainAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.only( - left:registerLocale - ?.languageCode == - 'ar' - ? 0 - : 40.0, - right: registerLocale - ?.languageCode == - 'ar' - ? 45 - : 0.0,), - child: Text( - context.translate('Required', 'مطلوب'), - style: TextStyle( - color: Color(0xFFb22222), - fontSize: registerLocale - ?.languageCode == - 'ar' - ? 12 - : 12, + if (showError) + Row( + mainAxisAlignment: + MainAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only( + left: registerLocale + ?.languageCode == + 'ar' + ? 0 + : 40.0, + right: registerLocale + ?.languageCode == + 'ar' + ? 45 + : 0.0, + ), + child: Text( + context.translate( + 'Required', 'مطلوب'), + style: TextStyle( + color: Color(0xFFb22222), + fontSize: registerLocale + ?.languageCode == + 'ar' + ? 12 + : 12, + ), + ), + ), + ], + ), + SizedBox(height: 20), + Padding( + padding: const EdgeInsets.only( + top: 5.0, + bottom: 10, + left: 30, + right: 30), + child: SizedBox( + width: screenwidth / 1, + child: ElevatedButton( + onPressed: isRegistering + ? null + : _registerUser, + style: ElevatedButton.styleFrom( + backgroundColor: Color( + 0xFFA7887A), // Brownish color for Register + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.circular(10), + ), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + // "Register", + AppLocalizations.of(context)! + .register_title, + style: TextStyle( + fontSize: registerLocale + ?.languageCode == + 'ar' + ? 14 + : 16, + color: Colors.white), + ), + SizedBox(width: 8), + const Icon( + Icons.chevron_right_outlined, + color: Colors + .white, // Set your desired color here + ) + ], + ), + ), + ), ), - ), - ), - ], - ), - SizedBox(height: 20), - Padding( - padding: const EdgeInsets.only( - top: 5.0, - bottom: 10, - left: 30, - right: 30), - child: SizedBox( - width: screenwidth / 1, - child: ElevatedButton( - onPressed: isRegistering - ? null - : _registerUser, - style: ElevatedButton.styleFrom( - backgroundColor: Color( - 0xFFA7887A), // Brownish color for Register - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(10), - ), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ + SizedBox(height: 15), Text( - // "Register", AppLocalizations.of(context)! - .register_title, + .account_confirmation, style: TextStyle( - fontSize: registerLocale - ?.languageCode == - 'ar' - ? 14 - : 16, - color: Colors.white), + fontWeight: FontWeight.w500, + fontSize: + registerLocale?.languageCode == 'ar' + ? 12 + : 14, + color: Color(0xFF898C81), + ), + ), + SizedBox(height: 15), + Padding( + padding: const EdgeInsets.only( + top: 5.0, + bottom: 10, + left: 30, + right: 30), + child: SizedBox( + width: screenwidth / 1, + child: ElevatedButton( + onPressed: () { + context.pop(); + }, + style: ElevatedButton.styleFrom( + backgroundColor: Color( + 0xFF82AFCB), // Blueish color for Login + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.circular(10), + ), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + AppLocalizations.of(context)! + .login_title, + style: TextStyle( + fontSize: 16, + color: Colors.white), + ), + SizedBox(width: 8), + const Icon( + Icons.chevron_right_outlined, + color: Colors + .white, // Set your desired color here + ) + ], + ), + ), + ), + ), + SizedBox( + height: 10, + ), + Center( + // child: Container( + // height: screenheight / 16, + // width: screenwidth / 3, + // decoration: BoxDecoration( + // image: DecorationImage( + // image: AssetImage( + // "assets/splash_screen/logo.png"), // Background image asset + // fit: BoxFit.fill, + // ), + // ), + // ) + child: fcscBanner, + ), + SizedBox( + height: 20, ), - SizedBox(width: 8), - const Icon( - Icons.chevron_right_outlined, - color: Colors - .white, // Set your desired color here - ) ], ), ), ), - ), - SizedBox(height: 15), - Text( - AppLocalizations.of(context)! - .account_confirmation, - style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: - registerLocale?.languageCode == - 'ar' - ? 12 - : 14, - color: Color(0xFF898C81), - ), - ), - SizedBox(height: 15), - Padding( - padding: const EdgeInsets.only( - top: 5.0, - bottom: 10, - left: 30, - right: 30), - child: SizedBox( - width: screenwidth / 1, - child: ElevatedButton( - onPressed: () { - context.pop(); - }, - style: ElevatedButton.styleFrom( - backgroundColor: Color( - 0xFF82AFCB), // Blueish color for Login - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(10), - ), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - AppLocalizations.of(context)! - .login_title, - style: TextStyle( - fontSize: 16, - color: Colors.white), - ), - SizedBox(width: 8), - const Icon( - Icons.chevron_right_outlined, - color: Colors - .white, // Set your desired color here - ) - ], - ), - ), - ), - ), - SizedBox( - height: 10, - ), - Center( - // child: Container( - // height: screenheight / 16, - // width: screenwidth / 3, - // decoration: BoxDecoration( - // image: DecorationImage( - // image: AssetImage( - // "assets/splash_screen/logo.png"), // Background image asset - // fit: BoxFit.fill, - // ), - // ), - // ) - child: fcscBanner, - ), - SizedBox( - height: 20, - ), - ], - ), - ), - ), ]), // Container( // height: MediaQuery.of(context).size.height / 1.2, @@ -1273,4 +1298,4 @@ class _RegisterScreenState extends ConsumerState { ), ); } -} \ No newline at end of file +} diff --git a/lib/presentation/Screens/charts/screens/chart_screen.dart b/lib/presentation/Screens/charts/screens/chart_screen.dart index 5c14c40b..8603820d 100644 --- a/lib/presentation/Screens/charts/screens/chart_screen.dart +++ b/lib/presentation/Screens/charts/screens/chart_screen.dart @@ -11,6 +11,7 @@ import 'package:screenshot/screenshot.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:tutorial_coach_mark/tutorial_coach_mark.dart'; import 'package:uae_stat/config/api_config.dart'; +import 'package:uae_stat/config/connectivity_provider.dart'; import 'package:uae_stat/config/toast_util.dart'; import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/infrastructure/services/img_asset_paths/icons/uae_numbers_asset_path.dart'; @@ -2098,6 +2099,15 @@ class _ChartScreen1State extends ConsumerState { final locale = ref.watch(localeProvider); final localeNotifier = ref.read(localeProvider.notifier); + final isConnected = ref.watch(connectivityProvider); + + // If no internet, redirect to InternetCheckScreen + ref.listen>(connectivityProvider, (previous, hasInternet) { + if (hasInternet.value == false) { + context.go('/internetcheck'); + } + }); + ref.listen(localeProvider, (previous, next) { final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null @@ -2330,7 +2340,8 @@ class _ChartScreen1State extends ConsumerState { Row( children: [ GestureDetector( - onTap: () => shareCurrentPage(context, _isSharing), + onTap: () => + shareCurrentPage(context, _isSharing), child: Row( children: [ Text( @@ -2343,19 +2354,20 @@ class _ChartScreen1State extends ConsumerState { SizedBox(width: 5), _isSharing ? SizedBox( - width: 24, - height: 24, - child: CircularProgressIndicator( - color: Colors.white, - strokeWidth: 2, - ), - ) // Show loading spinner + width: 24, + height: 24, + child: + CircularProgressIndicator( + color: Colors.white, + strokeWidth: 2, + ), + ) // Show loading spinner : SvgPicture.asset( - UaeNumbersAssetPath.share, - semanticsLabel: 'share', - width: 24, - height: 24, - ), + UaeNumbersAssetPath.share, + semanticsLabel: 'share', + width: 24, + height: 24, + ), ], ), ), @@ -2664,7 +2676,7 @@ Future shareCurrentPage(BuildContext context, bool _isSharing) async { height: 200, ); final Uint8List? capturedImage = - await screenshotController.captureFromWidget( + await screenshotController.captureFromWidget( Material(child: svgWidget), ); diff --git a/lib/presentation/Screens/charts/widgets/chart_widget.dart b/lib/presentation/Screens/charts/widgets/chart_widget.dart index 29e0616f..62e1b33f 100644 --- a/lib/presentation/Screens/charts/widgets/chart_widget.dart +++ b/lib/presentation/Screens/charts/widgets/chart_widget.dart @@ -2684,6 +2684,8 @@ class ChartWidget extends StatelessWidget { print('spots - $spots'); + // lineChartLabel = spots; + // List spots = filteredData // .where((entry) => entry['ObsKey'][groupByKey] == group) // .map((entry) { diff --git a/lib/presentation/Screens/online_offline_verification/internet_check.dart b/lib/presentation/Screens/online_offline_verification/internet_check.dart index 745f31d3..351767a5 100644 --- a/lib/presentation/Screens/online_offline_verification/internet_check.dart +++ b/lib/presentation/Screens/online_offline_verification/internet_check.dart @@ -1,54 +1,75 @@ import 'package:flutter/material.dart'; -import 'package:uae_stat/presentation/components/constant/constant.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; +import 'package:internet_connection_checker/internet_connection_checker.dart'; +import 'package:uae_stat/config/connectivity_provider.dart'; -class InternetCheck extends StatelessWidget { - const InternetCheck({super.key}); +class InternetCheckScreen extends ConsumerWidget { + const InternetCheckScreen({super.key}); @override - Widget build(BuildContext context) { - double myheight = MediaQuery.of(context).size.height; - double mywidth = MediaQuery.of(context).size.width; + Widget build(BuildContext context, WidgetRef ref) { + // Listen to changes in connectivity and navigate back to Home if online + ref.listen>(connectivityProvider, (previous, hasInternet) { + if (hasInternet.value == true) { + Navigator.pop(context); + // context.go('/myhomepage'); + } + }); + + double myHeight = MediaQuery.of(context).size.height; + return Scaffold( body: Padding( padding: const EdgeInsets.all(8.0), - child: Container( - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image(image: AssetImage('assets/logos/no-internet.png')), - SizedBox(height: myheight/40,), - Text("No Internet Connection",style: TextStyle(fontSize: 25,fontWeight: FontWeight.bold)), - Text("Please check with your Wi-Fi or Mobile",style: TextStyle(fontSize: 15,fontWeight: FontWeight.w500)), - Text("Data connection and try again",style: TextStyle(fontSize: 15,fontWeight: FontWeight.w500)), - SizedBox(height: myheight/40,), - ElevatedButton( - onPressed: (){ - Navigator.pop(context); - }, - style: ElevatedButton.styleFrom( - backgroundColor: Color( - 0xFFA7887A), // Brownish color for Register - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(10)), - ), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "Retry", - style: TextStyle( - fontSize: 16, color: Colors.white), + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset('assets/logos/no-internet.png', width: 150), + SizedBox(height: myHeight / 40), + Text("No Internet Connection", + style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold)), + Text("Please check your Wi-Fi or Mobile Data", + style: TextStyle(fontSize: 15, fontWeight: FontWeight.w500)), + Text("connection and try again", + style: TextStyle(fontSize: 15, fontWeight: FontWeight.w500)), + SizedBox(height: myHeight / 40), + ElevatedButton( + onPressed: () async { + bool hasInternet = + await InternetConnectionChecker.instance.hasConnection; + + if (hasInternet) { + Navigator.pop( + context); // Redirect to home if internet is available + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: + Text("No internet connection. Please try again."), + backgroundColor: Colors.red, ), - SizedBox(width: 8), - Icon(Icons.arrow_forward_ios_outlined,size: 12, - color: Colors.white), - ], + ); + } + }, + style: ElevatedButton.styleFrom( + backgroundColor: Color(0xFFA7887A), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(10)), ), ), - ], - ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text("Retry", + style: TextStyle(fontSize: 16, color: Colors.white)), + SizedBox(width: 8), + Icon(Icons.refresh, size: 16, color: Colors.white), + ], + ), + ), + ], ), ), ), diff --git a/lib/presentation/Screens/profilepage.dart b/lib/presentation/Screens/profilepage.dart index e70c4ee6..5e988cbc 100644 --- a/lib/presentation/Screens/profilepage.dart +++ b/lib/presentation/Screens/profilepage.dart @@ -13,6 +13,7 @@ import 'package:intl/intl.dart'; import 'package:pocketbase/pocketbase.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:uae_stat/config/api_config.dart'; +import 'package:uae_stat/config/connectivity_provider.dart'; import 'package:uae_stat/config/my_theme.dart'; import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/infrastructure/data/p_auth_repo.dart'; @@ -467,6 +468,14 @@ class _ProfileScreenState extends ConsumerState { @override Widget build(BuildContext context) { + final isConnected = ref.watch(connectivityProvider); + + // If no internet, redirect to InternetCheckScreen + ref.listen>(connectivityProvider, (previous, hasInternet) { + if (hasInternet.value == false) { + context.go('/internetcheck'); + } + }); final profileLocale = ref.watch(localeProvider); return PopScope( canPop: false, // Allow back navigation only if not login screen diff --git a/lib/presentation/routes/auth_routes/login_route.dart b/lib/presentation/routes/auth_routes/login_route.dart index 41c3b4e4..6c171ecd 100644 --- a/lib/presentation/routes/auth_routes/login_route.dart +++ b/lib/presentation/routes/auth_routes/login_route.dart @@ -209,6 +209,21 @@ class LoginRoute extends HookConsumerWidget { // } // } + emailValidation({String? message, String? requiredMessage}) { + return (fieldValue) { + if (fieldValue == null || fieldValue.trim().isEmpty) { + return requiredMessage ?? "Email is required"; + } + if (!Validator.isEmail(fieldValue)) { + if (fieldValue.contains(" ")) { + return "Space is present, email is not correct"; + } + return message ?? "Email is not correct"; + } + return null; // Validation passed + }; + } + @override Widget build(BuildContext context, WidgetRef ref) { final hasValidated = useState(false); @@ -241,7 +256,7 @@ class LoginRoute extends HookConsumerWidget { content: Form( key: forgotPwFormKey, child: TextFormField( - validator: FieldValidator.email(), + validator: emailValidation(), controller: emailCtl, decoration: InputDecoration( labelText: context.translate( @@ -456,7 +471,8 @@ class LoginRoute extends HookConsumerWidget { print("Is Profile Complete: $isProfileComplete"); // Extract intendedPath from query parameters (if coming from redirect) - final String? intendedPath = GoRouterState.of(context).uri.queryParameters['intendedPath']; + final String? intendedPath = + GoRouterState.of(context).uri.queryParameters['intendedPath']; print("Extracted intendedPath after login: $intendedPath"); if (!context.mounted) return; 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 8e142b0a..81e69753 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 @@ -168,6 +168,7 @@ import 'package:go_router/go_router.dart'; import 'package:pocketbase/pocketbase.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:uae_stat/config/api_config.dart'; +import 'package:uae_stat/config/connectivity_provider.dart'; import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/infrastructure/data/p_auth_repo.dart'; import 'package:uae_stat/presentation/components/indicators/locale_provider.dart'; @@ -1134,6 +1135,16 @@ class EconomyStatsState extends ConsumerState { final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null fetchData(localeCode); }); + + final isConnected = ref.watch(connectivityProvider); + + // If no internet, redirect to InternetCheckScreen + ref.listen>(connectivityProvider, (previous, hasInternet) { + if (hasInternet.value == false) { + context.go('/internetcheck'); + } + }); + double myheight = MediaQuery.of(context).size.height; double mywidth = MediaQuery.of(context).size.width; diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/bookmark.dart b/lib/presentation/routes/drawer_routes/Drawer Items/bookmark.dart index a3c79491..a3dcd3fd 100644 --- a/lib/presentation/routes/drawer_routes/Drawer Items/bookmark.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/bookmark.dart @@ -7,13 +7,13 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:pocketbase/pocketbase.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:uae_stat/config/api_config.dart'; +import 'package:uae_stat/config/connectivity_provider.dart'; import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/infrastructure/services/img_asset_paths/icons/bookmark_asset_path.dart'; import 'package:uae_stat/infrastructure/services/img_asset_paths/icons/uae_numbers_asset_path.dart'; import 'package:uae_stat/presentation/components/indicators/locale_provider.dart'; import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart'; - class BookMark extends ConsumerStatefulWidget { const BookMark({super.key}); @@ -35,7 +35,6 @@ class _BookMarkState extends ConsumerState { super.initState(); final locale = ref.read(localeProvider); fetchBookmarks(locale?.languageCode ?? 'en'); - } String colorToHex(Color color) { @@ -43,6 +42,7 @@ class _BookMarkState extends ConsumerState { '${color.green.toRadixString(16).padLeft(2, '0').toUpperCase()}' '${color.blue.toRadixString(16).padLeft(2, '0').toUpperCase()}'; } + // Function to convert hex color string to int Color _parseColor(String? colorString) { if (colorString == null || colorString.isEmpty) { @@ -105,26 +105,26 @@ class _BookMarkState extends ConsumerState { String? mainTopic = item['main_topic']; String subtitle = item['subtitle']; - // Ignore if main_topic is null if (mainTopic == null) continue; // If main_topic doesn't exist in groupedMap, create a new entry if (!groupedMap.containsKey(mainTopic)) { - groupedMap[mainTopic] = {'main_topic': mainTopic, + groupedMap[mainTopic] = { + 'main_topic': mainTopic, 'valueColor': item['valueColor'], 'SubTopic': [] }; } // Add subtitle as a key with its corresponding map value - groupedMap[mainTopic]!['SubTopic'].add ({ + groupedMap[mainTopic]!['SubTopic'].add({ 'subtitle': subtitle, 'isBookmark': item['isBookmark'], 'value': item['value'], - 'title':item['title'], - 'value_source':item['value_source'], - 'data_set':item['data_set'], + 'title': item['title'], + 'value_source': item['value_source'], + 'data_set': item['data_set'], 'id': item['id'], }); } @@ -170,7 +170,7 @@ class _BookMarkState extends ConsumerState { content: Text( 'Unable to remove from bookmarks. Please try again', style: - TextStyle(color: Color(0xFFEB5F24), fontWeight: FontWeight.w600), + TextStyle(color: Color(0xFFEB5F24), fontWeight: FontWeight.w600), ), backgroundColor: Color(0xFFD6E9C6), duration: Duration(seconds: 2), @@ -253,7 +253,8 @@ class _BookMarkState extends ConsumerState { backgroundColor: Color(0xFFAA8E83), // Set background color foregroundColor: Colors.white, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10.0), // Set text color + borderRadius: + BorderRadius.circular(10.0), // Set text color ), ), child: Text( @@ -264,7 +265,6 @@ class _BookMarkState extends ConsumerState { ), ], ) - ], ), ); @@ -272,12 +272,32 @@ class _BookMarkState extends ConsumerState { @override Widget build(BuildContext context) { + final isConnected = ref.watch(connectivityProvider); + + // If no internet, redirect to InternetCheckScreen + ref.listen>(connectivityProvider, (previous, hasInternet) { + if (hasInternet.value == false) { + context.go('/internetcheck'); + } + }); final List> tabs = [ - { 'title':AppLocalizations.of(context)!.all_bookmarks, 'color': Colors.black}, - { 'title': AppLocalizations.of(context)!.economy_title, 'color': Color(0xFF90B0D5)}, - { 'title':AppLocalizations.of(context)!.social_title, 'color': Color(0xFFAA8E83)}, - { 'title': AppLocalizations.of(context)!.environment_title, 'color': Color(0xFF7DAFBC)}, + { + 'title': AppLocalizations.of(context)!.all_bookmarks, + 'color': Colors.black + }, + { + 'title': AppLocalizations.of(context)!.economy_title, + 'color': Color(0xFF90B0D5) + }, + { + 'title': AppLocalizations.of(context)!.social_title, + 'color': Color(0xFFAA8E83) + }, + { + 'title': AppLocalizations.of(context)!.environment_title, + 'color': Color(0xFF7DAFBC) + }, ]; ref.listen(localeProvider, (previous, next) { @@ -285,23 +305,26 @@ class _BookMarkState extends ConsumerState { fetchBookmarks(localeCode); }); - List> bookmarks = dataList.where((item) => item['isBookmark'] == true).toList(); - List> filteredBookmarks = dataList - .where((bookmark) { + List> bookmarks = + dataList.where((item) => item['isBookmark'] == true).toList(); + List> filteredBookmarks = dataList.where((bookmark) { String mainTopic = bookmark['main_topic'].toString().trim().toLowerCase(); - String selectedTabTitle = tabs[selectedTabIndex]['title'].toString().trim().toLowerCase(); + String selectedTabTitle = + tabs[selectedTabIndex]['title'].toString().trim().toLowerCase(); // Debugging prints - print("main_topic: '$mainTopic', selected_tab_title: '$selectedTabTitle'"); + print( + "main_topic: '$mainTopic', selected_tab_title: '$selectedTabTitle'"); return mainTopic == selectedTabTitle; - }) - .toList(); + }).toList(); // print( 'filtered one :${filteredBookmarks['main_topic']} , Tabs : ${tabs[selectedTabIndex]["title"]}'); List> transformedList = groupedMap.values.toList(); // print('filtered $filteredBookmarks'); return BaseScaffold( - title: Text(AppLocalizations.of(context)!.bookmarks,), + title: Text( + AppLocalizations.of(context)!.bookmarks, + ), body: Column( children: [ TabBarHeader( @@ -316,134 +339,143 @@ class _BookMarkState extends ConsumerState { Expanded( child: selectedTabIndex == 0 ? (bookmarks.isNotEmpty - ? SingleChildScrollView( - child: Column( - children: List.generate(transformedList.length, (i) { - final mainTopic = transformedList[i]; - print('oustside1 $mainTopic'); - final list=List.from(mainTopic['SubTopic'] ?? []); - print('oustside2 $list'); - return CustomExpandableTile( - index: i, - isExpanded: expandedIndex == i, - onTap: (int index) { // 🔹 Expecting an index - setState(() { - expandedIndex = (expandedIndex == index) ? null : index; - }); - }, - title: mainTopic['main_topic'] ?? 'No Topic', - childWidget: - Container( - decoration: BoxDecoration( - color: Colors.white, - // borderRadius: BorderRadius.all(Radius.circular(20)) - ), - padding: const EdgeInsets.all(16), - child: GridView.builder( - shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), - gridDelegate: - const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - crossAxisSpacing: 10.0, - mainAxisSpacing: 10.0, - mainAxisExtent: 100, + ? SingleChildScrollView( + child: Column( + children: List.generate(transformedList.length, (i) { + final mainTopic = transformedList[i]; + print('oustside1 $mainTopic'); + final list = List.from(mainTopic['SubTopic'] ?? []); + print('oustside2 $list'); + return CustomExpandableTile( + index: i, + isExpanded: expandedIndex == i, + onTap: (int index) { + // 🔹 Expecting an index + setState(() { + expandedIndex = + (expandedIndex == index) ? null : index; + }); + }, + title: mainTopic['main_topic'] ?? 'No Topic', + childWidget: Container( + decoration: BoxDecoration( + color: Colors.white, + // borderRadius: BorderRadius.all(Radius.circular(20)) + ), + padding: const EdgeInsets.all(16), + child: GridView.builder( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + gridDelegate: + const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + crossAxisSpacing: 10.0, + mainAxisSpacing: 10.0, + mainAxisExtent: 100, + ), + itemCount: list.length, + itemBuilder: (context, index) { + return _buildBoxes( + mainTopic['SubTopic'][index], + context, + mainTopic['valueColor']); + }, + ), + ), + filteredBookmarks: + List.from(mainTopic['SubTopic'] ?? []), + titleBackgroundColor: mainTopic['valueColor'], + // Ensure it's a new list + ); + }), + ), + ) + : Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.info_outline, + size: 100, color: Colors.grey[400]), + SizedBox(height: 16), + Text( + context.translate('No BookMark Added', + 'لم يتم إضافة أي علامة مرجعية'), + style: + TextStyle(fontSize: 16, color: Colors.grey), + ), + ], + ), + )) + : filteredBookmarks.isEmpty + ? Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.info_outline, + size: 100, color: Colors.grey[400]), + SizedBox(height: 16), + Text( + 'No Bookmark is added', + style: + TextStyle(fontSize: 16, color: Colors.grey), + ), + ], + ), + ) + : Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + children: [ + Container( + decoration: BoxDecoration( + color: tabs[selectedTabIndex]['color'], + borderRadius: + BorderRadius.all(Radius.circular(35))), + padding: const EdgeInsets.only( + left: 16, bottom: 5, top: 5, right: 10), + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + tabs[selectedTabIndex]['title'], + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.w600, + fontSize: 20, + ), + ), + ], + ), + ), + SizedBox( + height: 20, + ), + Expanded( + child: GridView.builder( + gridDelegate: + const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + crossAxisSpacing: 10.0, + mainAxisSpacing: 10.0, + mainAxisExtent: 100, + ), + itemCount: filteredBookmarks.length, + itemBuilder: (context, index) { + return _buildBox( + filteredBookmarks[index], context); + }, + ), + ), + ], ), - itemCount:list.length, - itemBuilder: (context, index) { - return _buildBoxes(mainTopic['SubTopic'][index], context,mainTopic['valueColor']); - }, ), - ), - filteredBookmarks: List.from(mainTopic['SubTopic'] ?? []), titleBackgroundColor: mainTopic['valueColor'], - // Ensure it's a new list - ); - }), - ), - ) - : Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.info_outline, - size: 100, color: Colors.grey[400]), - SizedBox(height: 16), - Text( - context.translate('No BookMark Added','لم يتم إضافة أي علامة مرجعية'), - style: - TextStyle(fontSize: 16, color: Colors.grey), - ), - ], - ), - )) - :filteredBookmarks.isEmpty - ? Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.info_outline, - size: 100, color: Colors.grey[400]), - SizedBox(height: 16), - Text( - 'No Bookmark is added', - style: - TextStyle(fontSize: 16, color: Colors.grey), - ), - ], - ), - ) - : Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - children: [ - Container( - decoration: BoxDecoration( - color: tabs[selectedTabIndex]['color'], - borderRadius: BorderRadius.all(Radius.circular(35)) - ), - padding: const EdgeInsets.only( - left: 16, bottom: 5, top: 5, right: 10), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - tabs[selectedTabIndex]['title'], - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.w600, - fontSize: 20, - ), - ), - ], - ), - ), - SizedBox(height: 20,), - Expanded( - child: GridView.builder( - gridDelegate: - const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - crossAxisSpacing: 10.0, - mainAxisSpacing: 10.0, - mainAxisExtent: 100, - ), - itemCount: filteredBookmarks.length, - itemBuilder: (context, index) { - return _buildBox(filteredBookmarks[index], context); - }, - ), ), ], ), - ), - ), - ], - - ), - - ); } + Widget _buildBox(Map data, BuildContext context) { // Color borderColor = data['valueColor']; return GestureDetector( @@ -501,10 +533,9 @@ class _BookMarkState extends ConsumerState { child: SvgPicture.asset( BookmarkAssetPath.delete, semanticsLabel: 'share', - width:23, + width: 23, height: 20, - ) - ), + )), // GestureDetector( // onTap: () { @@ -543,7 +574,8 @@ class _BookMarkState extends ConsumerState { ); } - Widget _buildBoxes(Map data, BuildContext context, Color styleColor) { + Widget _buildBoxes( + Map data, BuildContext context, Color styleColor) { // Color borderColor = data['valueColor']; print('inside function $data'); return GestureDetector( @@ -555,7 +587,8 @@ class _BookMarkState extends ConsumerState { final encodedTitle = data['title']; String hexColor = colorToHex(styleColor); - debugPrint( '/chartScreen/$data_set?bgColor=$hexColor&mainTopic=$encodedMainTopic&title=$encodedTitle'); + debugPrint( + '/chartScreen/$data_set?bgColor=$hexColor&mainTopic=$encodedMainTopic&title=$encodedTitle'); // String hexColor = colorToHex(colorPattern); // Get hex string // print(hexColor); // Prints: 0xFFAA8E83 @@ -573,8 +606,7 @@ class _BookMarkState extends ConsumerState { borderRadius: BorderRadius.circular(10), border: Border.all(color: styleColor), ), - child: - Align( + child: Align( alignment: Alignment.center, child: Column( mainAxisSize: MainAxisSize.min, @@ -603,10 +635,9 @@ class _BookMarkState extends ConsumerState { child: SvgPicture.asset( BookmarkAssetPath.delete, semanticsLabel: 'share', - width:23, + width: 23, height: 20, - ) - ), + )), ], ), Text( @@ -630,11 +661,10 @@ class _BookMarkState extends ConsumerState { ), ); } - } class TabBarHeader extends StatelessWidget { - final List> tabs; + final List> tabs; final int selectedIndex; final ValueChanged onTabSelected; @@ -662,7 +692,7 @@ class TabBarHeader extends StatelessWidget { onPressed: () => onTabSelected(index), style: ButtonStyle( foregroundColor: - MaterialStateProperty.resolveWith((states) { + MaterialStateProperty.resolveWith((states) { return selectedIndex == index ? entry.value['color'] : Colors.grey[700]; @@ -715,7 +745,6 @@ class CustomExpandableTile extends StatefulWidget { } class _CustomExpandableTileState extends State { - @override void initState() { super.initState(); // Initialize isExpanded based on widget's property @@ -733,13 +762,13 @@ class _CustomExpandableTileState extends State { onTap: () => widget.onTap(widget.index), child: Container( decoration: BoxDecoration( - color: Colors.white, // Ensuring the background outside the rounded container is white + color: Colors + .white, // Ensuring the background outside the rounded container is white ), child: Container( decoration: BoxDecoration( color: widget.titleBackgroundColor, - borderRadius: BorderRadius.all(Radius.circular(35)) - ), + borderRadius: BorderRadius.all(Radius.circular(35))), padding: const EdgeInsets.only( left: 16, bottom: 5, top: 5, right: 10), child: Row( @@ -771,37 +800,37 @@ class _CustomExpandableTileState extends State { curve: Curves.easeInOut, width: double.infinity, color: Colors.white, - height:widget.isExpanded ? myheight * 0.4 : 0, - child:widget.isExpanded + // height: widget.isExpanded ? myheight * 0.4 : 0, + child: widget.isExpanded ? SingleChildScrollView( - child: Column( - children: [ - widget.childWidget, - // Container( - // decoration: BoxDecoration( - // color: Colors.white, - // // borderRadius: BorderRadius.all(Radius.circular(20)) - // ), - // padding: const EdgeInsets.all(16), - // child: GridView.builder( - // shrinkWrap: true, - // physics: NeverScrollableScrollPhysics(), - // gridDelegate: - // const SliverGridDelegateWithFixedCrossAxisCount( - // crossAxisCount: 2, - // crossAxisSpacing: 10.0, - // mainAxisSpacing: 10.0, - // mainAxisExtent: 100, - // ), - // itemCount: widget.filteredBookmarks.length, - // itemBuilder: (context, index) { - // return _buildBox(widget.filteredBookmarks[index], context,widget.titleBackgroundColor); - // }, - // ), - // ), - ], - ), - ) + child: Column( + children: [ + widget.childWidget, + // Container( + // decoration: BoxDecoration( + // color: Colors.white, + // // borderRadius: BorderRadius.all(Radius.circular(20)) + // ), + // padding: const EdgeInsets.all(16), + // child: GridView.builder( + // shrinkWrap: true, + // physics: NeverScrollableScrollPhysics(), + // gridDelegate: + // const SliverGridDelegateWithFixedCrossAxisCount( + // crossAxisCount: 2, + // crossAxisSpacing: 10.0, + // mainAxisSpacing: 10.0, + // mainAxisExtent: 100, + // ), + // itemCount: widget.filteredBookmarks.length, + // itemBuilder: (context, index) { + // return _buildBox(widget.filteredBookmarks[index], context,widget.titleBackgroundColor); + // }, + // ), + // ), + ], + ), + ) : null, ), ), diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/notification/notification.dart b/lib/presentation/routes/drawer_routes/Drawer Items/notification/notification.dart index 6f8c3470..e3febcac 100644 --- a/lib/presentation/routes/drawer_routes/Drawer Items/notification/notification.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/notification/notification.dart @@ -5,6 +5,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:intl/intl.dart'; import 'package:pocketbase/pocketbase.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:uae_stat/config/api_config.dart'; import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/presentation/components/indicators/locale_provider.dart'; @@ -21,28 +22,67 @@ class _NotificationPageState extends ConsumerState { // Example notification data final _pb = PocketBase(apiUrl); List> notifications = []; + List pushedNotification = []; // Current selected tab index int selectedTabIndex = 0; late final Locale locale; + dynamic userID; // Tab categories - final List tabs = [ - "All updates", - "App updates", - "Social", - "Economy", - "Environment", - "Favourites" - ]; + // final List tabs = [ + // "All updates", + // "App updates", + // "Social", + // "Economy", + // "Environment", + // "Favourites" + // ]; @override void initState() { super.initState(); locale = ref.read(localeProvider) ?? const Locale('en'); + _fetchUserData(); fetchNotifications(locale?.languageCode ?? 'en'); } + Future getUserId() async { + final prefs = await SharedPreferences.getInstance(); + return prefs.getString('userId'); // Retrieve the userId + } + + Future _fetchUserData() async { + try { + String? fetchedUserId = await getUserId(); + userID = fetchedUserId; + final adminAuth = await _pb.admins + .authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com'); + final adminToken = adminAuth.token; + print('adminToken- ${adminToken}'); + final userDetailsResponse = await _pb.collection('users').getOne( + fetchedUserId!, + headers: { + 'Authorization': 'Bearer $adminToken', + }, + ); + print('userDetails: $userDetailsResponse'); + setState(() { + print('In'); + // Extract pushed_notification from response + List notifications = + userDetailsResponse.data['pushed_notification']; + + // Convert to List + pushedNotification = List.from(notifications); + + print('pushedNotification: $pushedNotification'); + }); + } catch (e) { + print('Error fetching user details: $e'); + } + } + String formatDate(String dateString) { try { DateTime dateTime = @@ -81,21 +121,6 @@ class _NotificationPageState extends ConsumerState { } } - // Future fetchNotifications() async {/api/getNotification?language=ar - // try { - // await _pb.admins - // .authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com'); - // - // final result = await _pb.collection('notification').getFullList(); - // - // setState(() { - // notifications = result.map((record) => record.toJson()).toList(); - // }); - // } catch (e) { - // print('Error fetching notifications: $e'); - // } - // } - @override Widget build(BuildContext context) { ref.listen(localeProvider, (previous, next) { @@ -177,6 +202,8 @@ class _NotificationPageState extends ConsumerState { category: notification['category'] ?? 'Unknown', message: notification['message'] ?? '', id: notification['id'], + pushedNotification: pushedNotification, + userID: userID, ), ); }, @@ -253,6 +280,8 @@ class NotificationTile extends StatelessWidget { final String date; final String category; final String id; + final String userID; + final List pushedNotification; const NotificationTile({ required this.title, @@ -260,37 +289,83 @@ class NotificationTile extends StatelessWidget { required this.date, required this.category, required this.id, + required this.userID, + required this.pushedNotification, }); @override Widget build(BuildContext context) { + bool isPushed = pushedNotification.contains(id); + print('isPushed $isPushed , $id'); + return GestureDetector( - onTap: () { - final encodedKey = Uri.encodeQueryComponent('notification'); - context.go('/notification_details', extra: { - 'title': title, - 'message': message, - 'date': date, - 'category': category, - 'id': id, - 'backNavigation': encodedKey - }); - }, + onTap: isPushed + ? () { + readedNotification(userID, id); + final encodedKey = Uri.encodeQueryComponent('notification'); + context.go('/notification_details', extra: { + 'title': title, + 'message': message, + 'date': date, + 'category': category, + 'id': id, + 'backNavigation': encodedKey + }); + } + : null, child: ListTile( - // leading: Icon(Icons.circle, - // size: 12, color: category == "Social" ? Colors.red : Colors.grey), - leading: Icon(Icons.circle, size: 12, color: Colors.red), - title: Text(title, style: const TextStyle(fontWeight: FontWeight.bold)), + leading: isPushed + ? const Icon(Icons.circle, size: 12, color: Color(0xFFFF274E)) + : const Icon(Icons.circle, size: 12, color: Color(0x99414042)), + title: Text( + title, + style: TextStyle( + color: isPushed ? const Color(0xFF414042) : const Color(0x99414042), + fontWeight: FontWeight.bold, + ), + ), subtitle: Text( date, - style: const TextStyle( - color: Color(0xFF8E8E8E), - fontSize: 12, - fontWeight: FontWeight.w400), + style: TextStyle( + color: isPushed ? const Color(0xFF8E8E8E) : const Color(0x998E8E8E), + fontSize: 12, + fontWeight: FontWeight.w400, + ), ), - trailing: const Icon(Icons.arrow_forward_ios, - size: 16, color: Color(0xFF898C81)), + trailing: isPushed + ? const Icon(Icons.arrow_forward_ios, + size: 16, color: Color(0xFF898C81)) + : null, ), ); } } + +final pb = PocketBase(apiUrl); +Future readedNotification(String userId, String notificationId) async { + await pb.admins.authWithPassword( + 'pb@venbainfotech.com', + 'pb@venbainfotech.com', + ); + + final url = + "${pb.baseUrl}api/removeNotification?user_id=$userId¬ification_id=$notificationId"; + + try { + final response = await http.get( + Uri.parse(url), + headers: { + 'Content-Type': 'application/json', // Add this + 'Authorization': pb.authStore.token, // Correct way to send auth token + }, + ); + + if (response.statusCode == 200) { + print("✅ updated successfully!"); + } else { + print("❌ Failed to update : ${response.body}"); + } + } catch (e) { + print("🚨 Error updating : $e"); + } +} diff --git a/pubspec.lock b/pubspec.lock index a9e54001..2e8e5ba6 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -173,10 +173,10 @@ packages: dependency: transitive description: name: built_value - sha256: "8b158ab94ec6913e480dc3f752418348b5ae099eb75868b5f4775f0572999c61" + sha256: ea90e81dc4a25a043d9bee692d20ed6d1c4a1662a28c03a96417446c093ed6b4 url: "https://pub.dev" source: hosted - version: "8.9.4" + version: "8.9.5" characters: dependency: transitive description: @@ -824,10 +824,10 @@ packages: dependency: transitive description: name: image_picker_android - sha256: "82652a75e3dd667a91187769a6a2cc81bd8c111bbead698d8e938d2b63e5e89a" + sha256: "8bd392ba8b0c8957a157ae0dc9fcf48c58e6c20908d5880aea1d79734df090e9" url: "https://pub.dev" source: hosted - version: "0.8.12+21" + version: "0.8.12+22" image_picker_for_web: dependency: transitive description: @@ -892,6 +892,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.7.0" + internet_connection_checker: + dependency: "direct main" + description: + name: internet_connection_checker + sha256: ee08f13d8b13b978affe226e9274ca3ba7a9bed07c9479e8ae245f785b7a488a + url: "https://pub.dev" + source: hosted + version: "3.0.1" intl: dependency: "direct main" description: @@ -1104,10 +1112,10 @@ packages: dependency: transitive description: name: path_provider_android - sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2" + sha256: "0ca7359dad67fd7063cb2892ab0c0737b2daafd807cf1acecd62374c8fae6c12" url: "https://pub.dev" source: hosted - version: "2.2.15" + version: "2.2.16" path_provider_foundation: dependency: transitive description: @@ -1192,10 +1200,10 @@ packages: dependency: transitive description: name: pub_semver - sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd" + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" url: "https://pub.dev" source: hosted - version: "2.1.5" + version: "2.2.0" pubspec_parse: dependency: transitive description: @@ -1311,10 +1319,10 @@ packages: dependency: transitive description: name: shared_preferences_android - sha256: a768fc8ede5f0c8e6150476e14f38e2417c0864ca36bb4582be8e21925a03c22 + sha256: "3ec7210872c4ba945e3244982918e502fa2bfb5230dff6832459ca0e1879b7ad" url: "https://pub.dev" source: hosted - version: "2.4.6" + version: "2.4.8" shared_preferences_foundation: dependency: transitive description: @@ -1539,10 +1547,10 @@ packages: dependency: transitive description: name: url_launcher_android - sha256: "6fc2f56536ee873eeb867ad176ae15f304ccccc357848b351f6f0d8d4a40d193" + sha256: "1d0eae19bd7606ef60fe69ef3b312a437a16549476c42321d5dc1506c9ca3bf4" url: "https://pub.dev" source: hosted - version: "6.3.14" + version: "6.3.15" url_launcher_ios: dependency: transitive description: @@ -1643,10 +1651,10 @@ packages: dependency: transitive description: name: video_player_android - sha256: "7018dbcb395e2bca0b9a898e73989e67c0c4a5db269528e1b036ca38bcca0d0b" + sha256: d949a83d1a333178eb3a9683f70afa41b7771c2bfa4cedd894fe836942de06b1 url: "https://pub.dev" source: hosted - version: "2.7.17" + version: "2.8.1" video_player_avfoundation: dependency: transitive description: @@ -1723,10 +1731,10 @@ packages: dependency: transitive description: name: webview_flutter_android - sha256: "512c26ccc5b8a571fd5d13ec994b7509f142ff6faf85835e243dde3538fdc713" + sha256: "631093a7fbd93e9690ac61d8c8f3e857efbc189fc33f712b9ad6c01a623517ef" url: "https://pub.dev" source: hosted - version: "4.3.2" + version: "4.3.3" webview_flutter_platform_interface: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 6283d2ae..a9a4e990 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.32+33 +version: 1.0.33+34 environment: sdk: ">=3.2.3 <4.0.0" @@ -68,6 +68,7 @@ dependencies: flutter_svg: ^2.0.17 boxy: ^2.2.1 firebase_messaging: ^15.2.4 + internet_connection_checker: ^3.0.1 dependency_overrides: fading_edge_scrollview: ^4.1.1