import 'dart:developer'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:get_it/get_it.dart'; import 'package:muaawana/config/provider.dart'; import 'package:muaawana/providers/navbar_provider/bottom_navigation_provider.dart'; import 'package:muaawana/providers/utils_provider.dart'; import 'package:persistent_bottom_nav_bar/persistent_bottom_nav_bar.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../models/auth/current_user_response.dart'; import '../services/auth_services.dart'; import '../services/chat_v2/chat_socket.dart'; import '../services/navigation_service.dart'; import '../utils/connection.dart'; import '../utils/image_picker.dart'; import '../utils/utils_singleton.dart'; import '../views/auth/login_view.dart'; import '../views/auth/second_step_fortgot.dart'; import '../views/auth/third_step_forgot.dart'; import '../views/client_view/main_screen.dart'; import '../views/splash/splash_screen.dart'; import '../views/technicien_view/home_tech_screen.dart'; import '../widgets/popup_widget.dart'; import 'chat_v2/chat_socket_stream_provider.dart'; import 'language_provider.dart'; import 'navbar_provider/client_bottom_nav_provider.dart'; import 'notif/notification_socket.dart'; class AuthProvider with ChangeNotifier { AuthServices get service => GetIt.I(); bool authorized = false; bool profileLoader = false; String? email; String? password; bool loader = false; bool socialLoader = false; bool logoutLoader = false; Map? userData; bool isLoading = false; bool isBusy = false; bool isLoggedIn = false; CurrentUser? profile; String deviceId = ""; String deviceModel = ""; String ipAddress = ""; bool remember = false; File? _image; File? get image => _image; /// Server roles this app has a UI for. The backend also issues roles such as /// ROLE_ADMIN and ROLE_CORPORATE; its endpoints are guarded with /// `hasRole('ADMIN') or hasRole('USER')` and friends, so an account holding /// any other role would reach the home screen and then get 403 on every /// action. Such accounts are kept out at login instead. static const Set allowedAppRoles = {"ROLE_USER", "ROLE_TECHNICIAN"}; static bool isRoleAllowed(String? role) => allowedAppRoles.contains(role); /// The role issued by the server for the signed-in account, or null when no /// profile has been loaded (guest browsing). This is the authoritative role — /// the "Role" preference written by the role picker holds a local-only value /// ("ROLE_CLIENT") that the backend never issues. String? get serverRole => profile?.role?.role ?? util.user?.role?.role; /// Tears down a session belonging to an account whose role the app does not /// support, so the user is left logged out on the login screen. /// /// Deliberately takes no BuildContext: it awaits, and clearing the connection /// state swaps the client shell over to its logged-out screens, which can /// unmount whatever widget called this. Future denyUnauthorizedRole( String? role, { bool redirectToLogin = false, }) async { log("-----> Login refused, unsupported role: $role"); final prefs = await SharedPreferences.getInstance(); await prefs.remove('token'); await prefs.remove('refreshToken'); await prefs.remove('Role'); await prefs.setBool("isLoggedIn", false); profile = null; isLoggedIn = false; authorized = false; util.user = null; util.isValidToken = false; // Singleton, so this is the same instance the widget tree listens to. ClientBottomNavigationProvider().setUserConnectionState(false); loader = false; socialLoader = false; notifyListeners(); Get.showSnackbar( GetSnackBar( title: LanguageProvider().translate("Access denied"), message: LanguageProvider() .translate("You're not authorized to use this application"), duration: const Duration(seconds: 3), ), ); if (redirectToLogin) { NavigatorService.navigatorKey.currentState?.pushReplacement( MaterialPageRoute( builder: (context) => const LoginScreen(isFromSplash: true)), ); } } Future deleteAccount(BuildContext context) async { final prefs = await SharedPreferences.getInstance(); loader = true; notifyListeners(); var _apiResponseprofile = await service.deleteAccount(); if (_apiResponseprofile.statusCode == 200 || _apiResponseprofile.statusCode == 201) { await logout(context, isDelete: true); await prefs.clear(); if (util.prefs != null) { await util.prefs!.clear(); } util.user = null; clientNavProvider.setUserConnectionState(false); log("cleared prefs !!!!!"); Navigator.pushReplacement(NavigatorService.navigatorKey.currentContext!, MaterialPageRoute(builder: (context) => const Splash())); log("navigated to home screen !!!!!"); loader = false; notifyListeners(); return true; } else { //print("deleteAccount"); //print(_apiResponseprofile.statusCode); loader = false; notifyListeners(); return false; } } getLogin() async { var sh = await SharedPreferences.getInstance(); if (sh.getString("Email") != null) { email = sh.getString("Email")!; } if (sh.getString("Password") != null) { password = sh.getString("Password")!; } notifyListeners(); } Future pickPicture(String source,context) async { final imagePicker = ImagePick(); final image = await imagePicker.pick(source,context); if (image != null) { _image = image; notifyListeners(); } } rememberMe() { remember = !remember; notifyListeners(); } getLoginData(BuildContext context) { if (Platform.isIOS) { deviceId = context.read().deviceInfo['name']; deviceModel = context.read().deviceInfo['model']; ipAddress = context.read().ipAddress; } else { deviceId = context.read().deviceInfo['id']; deviceModel = context.read().deviceInfo['model']; ipAddress = context.read().ipAddress; } } goToHomeScreen(BuildContext context, String role, bool isFromSplash) { // `role` may be the role picker's local value ("ROLE_CLIENT"), which is not // a server role. Whenever a profile has been loaded its role wins, so a // technician cannot end up driving the client UI (and vice versa) — that // mismatch is what makes the backend answer 403 on role-guarded endpoints. final effectiveRole = serverRole ?? role; // No profile means nobody is signed in (guest browsing) — nothing to guard. if (serverRole != null && !isRoleAllowed(serverRole)) { denyUnauthorizedRole(serverRole, redirectToLogin: isFromSplash); return; } if (effectiveRole == "ROLE_TECHNICIAN") { Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => const HomeTechView()), ); return; } Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => const HomeClientView()), ); } bool checkId(BuildContext context, int? id) { if (id == null) { Popup(context, "Ok", title: "Error", description: "A problem has occurred Try again !"); } else { if (profile != null) { if (id == profile!.id) { return true; } else { return false; } } else { Popup(context, "Login", title: "Error", description: "Please sign in first", confirmFunction: () { Navigator.pop(context); PersistentNavBarNavigator.pushNewScreen( context, screen: const LoginScreen( isFromSplash: false, ), withNavBar: false, // OPTIONAL VALUE. True by default. pageTransitionAnimation: PageTransitionAnimation.slideUp, ); }); return false; } } return false; } loginApple(String token, BuildContext context, bool isFromSplash, bool isSignUp) async { final prefs = await SharedPreferences.getInstance(); await prefs.setString("token", token); if (isSignUp) { await addMissingDataApple(context, token, isFromSplash); } else { if (await fetchProfile(context)) { await prefs.setBool("isLoggedIn", true); util.updateUserInfo(profile!); util.setUser(profile); ChatSocket chatSocket = ChatSocket(); NotificationSocket notificationSocket = NotificationSocket(); await chatSocket.connectSock(); await notificationSocket.connectSock(); await context .read() .setChatSocketStream(chatSocket); await context .read() .setNotificationSocketStream(notificationSocket); context .read() .setUserConnectionState(true); loader = false; notifyListeners(); // ignore: use_build_context_synchronously goToHomeScreen(context, util.user!.role!.role!, isFromSplash); } } // final missingDataUpdated = // await addMissingDataApple(context, token, isFromSplash); // final profileFetched = await fetchProfile(context); // if (profileFetched) { // isLoggedIn = true; // await prefs.setBool("isLoggedIn", true); // util.updateUserInfo(profile!); // Get.showSnackbar( // const GetSnackBar( // title: "Success", // message: 'User Signed In Successfully', // // icon: const Icon(Icons.refresh), // duration: Duration(seconds: 2), // ), // ); // } else { // Get.showSnackbar( // const GetSnackBar( // title: "Error", // message: 'User Sign In error occurred! Try again.', // // icon: const Icon(Icons.refresh), // duration: Duration(seconds: 2), // ), // ); // } } addMissingDataApple( BuildContext context, String token, bool isFromSplash) async { log(token); try { final prefs = await SharedPreferences.getInstance(); prefs.setString('token', token.toString()); //print("I was here 33333"); await prefs.setBool("isLoggedIn", true); final initPlatformState = await context.read().initPlatformState(); log(context.read().deviceInfo.toString()); final ipAddressFetched = await context.read().getIpAddress(); if (await Connection.checkConnection()) { loader = true; notifyListeners(); //loading log("connection step done"); if (initPlatformState && ipAddressFetched) { final authresult = await service.socialLoginMissingData( context.read().deviceInfo['identifierForVendor'] ?? context.read().deviceInfo['id'], "phone", context.read().ipAddress); log(authresult.statusCode.toString()); log(authresult.data.toString()); if (authresult.statusCode == 200 || authresult.statusCode == 201) { if (authresult.data!.user!.role != null && authresult.data!.user!.role!.role == "ROLE_USER") { if (await fetchProfile(context)) { util.updateUserInfo(profile!); util.setUser(profile); ChatSocket chatSocket = ChatSocket(); NotificationSocket notificationSocket = NotificationSocket(); await chatSocket.connectSock(); await notificationSocket.connectSock(); await context .read() .setChatSocketStream(chatSocket); await context .read() .setNotificationSocketStream(notificationSocket); context .read() .setUserConnectionState(true); loader = false; notifyListeners(); // ignore: use_build_context_synchronously goToHomeScreen( context, authresult.data!.user!.role!.role!, isFromSplash); } else { log("Error occured"); } } else { if (await fetchProfile(context)) { util.updateUserInfo(profile!); util.setUser(profile); ChatSocket chatSocket = ChatSocket(); NotificationSocket notificationSocket = NotificationSocket(); await chatSocket.connectSock(); await notificationSocket.connectSock(); await context .read() .setChatSocketStream(chatSocket); await context .read() .setNotificationSocketStream(notificationSocket); context .read() .setUserConnectionState(true); loader = false; notifyListeners(); // ignore: use_build_context_synchronously goToHomeScreen( context, authresult.data!.user!.role!.role!, isFromSplash); } else { log("Error occured"); } } } else { log(authresult.statusCode.toString()); //stop loading if (authresult.statusCode == 409) { loader = false; notifyListeners(); // popup(context, "Ok", // title: "Error", // description: // "This email is already used , please try another"); } if (authresult.statusCode == 400 || authresult.statusCode == 402 || authresult.statusCode == 403) { loader = false; notifyListeners(); // popup(context, "Ok", // title: "Error", description: "Please check all the fields"); } if (authresult.statusCode == 401) { loader = false; notifyListeners(); // popup(context, "Ok", // title: "Error", // description: // "You are not authorized to log in , Please try later!"); } if (authresult.statusCode! >= 500) { loader = false; notifyListeners(); // popup(context, "Ok", // title: "Error", // description: "A problem has occurred Try again !"); } } } else { loader = false; notifyListeners(); // popup(context, "Ok", // title: "Error", // description: "A problem has occurred Try again !"); } } else { loader = false; notifyListeners(); // popup(context, "Ok", // title: "No internet connection", // description: "Please check your internet connection"); } } catch (e) { log(e.toString()); // popup(context, "Ok", // title: "Error", // description: "You are not authorized to log in , Please try later!"); } } userLogin(BuildContext context, String email, String password, bool isFromSplash) async { final prefs = await SharedPreferences.getInstance(); if (await Connection.checkConnection()) { //print("1"); loader = true; notifyListeners(); try { // ignore: use_build_context_synchronously getLoginData(context); final authResult = await service.signIn( email.trim(), password.trim(), deviceId, deviceModel, ipAddress, ); //print("2"); if ((authResult.statusCode == 200 || authResult.statusCode == 201) && authResult.data != null) { //print("3"); await fetchProfile(context); if (profile == null) { loader = false; notifyListeners(); Get.showSnackbar( const GetSnackBar( title: "Error", message: 'Could not fetch user profile', duration: Duration(seconds: 2), ), ); return; } // Refused before any session state is written or sockets opened. if (!isRoleAllowed(profile!.role?.role)) { await denyUnauthorizedRole(profile!.role?.role); return; } util.updateUserInfo(profile!); util.setUser(profile); ChatSocket chatSocket = ChatSocket(); NotificationSocket notificationSocket = NotificationSocket(); await chatSocket.connectSock(); await notificationSocket.connectSock(); await context .read() .setChatSocketStream(chatSocket); await context .read() .setNotificationSocketStream(notificationSocket); await prefs.setString('Email', email); await prefs.setString('Password', password); await prefs.setBool("isLoggedIn", true); await prefs.setString("Role", authResult.data!.roles!); context .read() .setUserConnectionState(true); Get.showSnackbar( const GetSnackBar( title: "Success", message: 'User Signed In Successfully', // icon: const Icon(Icons.refresh), duration: Duration(seconds: 2), ), ); loader = false; notifyListeners(); // ignore: use_build_context_synchronously goToHomeScreen(context, authResult.data!.roles!, isFromSplash); } else { //print("4"); loader = false; notifyListeners(); Get.showSnackbar( const GetSnackBar( title: "Error", message: 'Sign In Error', duration: Duration(seconds: 2), ), ); } } catch (e, stackTrace) { //print(stackTrace); //print("5"); loader = false; notifyListeners(); Get.showSnackbar( const GetSnackBar( title: "Error", message: 'Sign In Error', duration: Duration(seconds: 2), ), ); log("-----> Login Caught Error : "); log(e.toString()); log("-----> Login Caught Error StackTrace : "); log(stackTrace.toString()); } } else { Get.showSnackbar( const GetSnackBar( title: "Connection Error", message: 'No internet connection.', duration: Duration(seconds: 2), ), ); //print("6"); /// No Internet Connection log("-----> No Internet Connection"); loader = false; notifyListeners(); } } Future socialLoginHandling( BuildContext context, String token, bool isFromSplash) async { try { final prefs = await SharedPreferences.getInstance(); await prefs.setString('token', token); await prefs.setBool("isLoggedIn", true); if (!await Connection.checkConnection()) { Get.showSnackbar(const GetSnackBar( title: "Connection Error", message: 'No internet connection available', duration: Duration(seconds: 2), )); return null; } socialLoader = true; notifyListeners(); if (!await context.read().initPlatformState() || !await context.read().getIpAddress()) { socialLoader = false; notifyListeners(); Get.showSnackbar( const GetSnackBar( title: "Device Error", message: 'Could not retrieve device information', duration: Duration(seconds: 2), ), ); return null; } final deviceId = Platform.isIOS ? context.read().deviceInfo['identifierForVendor'] : context.read().deviceInfo['androidId'] ?? context.read().deviceInfo['id']; final authresult = await service.socialLoginMissingData( deviceId, "user", context.read().ipAddress); log("Auth result: ${authresult.statusCode}"); log("User data: ${authresult.data?.user?.toJson()}"); if ((authresult.statusCode != 200 && authresult.statusCode != 201) || authresult.data?.user == null) { socialLoader = false; notifyListeners(); Get.showSnackbar(const GetSnackBar( title: "Authentication Failed", message: 'Could not authenticate with Google', duration: Duration(seconds: 2), )); return null; } await fetchProfile(context); if (profile == null) { socialLoader = false; notifyListeners(); Get.showSnackbar(const GetSnackBar( title: "Profile Error", message: 'Could not fetch user profile', duration: Duration(seconds: 2), )); return null; } // This path navigates on its own instead of going through // goToHomeScreen, so it needs the same role guard. Returning null keeps // the caller on the login screen. if (!isRoleAllowed(profile!.role?.role)) { await denyUnauthorizedRole(profile!.role?.role); return null; } // Update user info like in userLogin() util.updateUserInfo(profile!); util.setUser(profile); context .read() .setUserConnectionState(true); // Connect sockets (but don't block navigation if they fail) try { final chatSocket = ChatSocket(); final notificationSocket = NotificationSocket(); await Future.wait( [chatSocket.connectSock(), notificationSocket.connectSock()]); await context .read() .setChatSocketStream(chatSocket); await context .read() .setNotificationSocketStream(notificationSocket); } catch (e) { log('Socket connection error: $e'); Get.showSnackbar( GetSnackBar( title: "Connection Warning", message: 'Real-time features might not work properly', duration: const Duration(seconds: 2), ), ); } socialLoader = false; notifyListeners(); return authresult.data!.user!.role!.role; } catch (e) { socialLoader = false; notifyListeners(); log('Error in socialLoginHandling: $e'); Get.showSnackbar( GetSnackBar( title: "Error", message: 'An unexpected error occurred: ${e.toString()}', duration: const Duration(seconds: 3), ), ); return null; } } signUp(BuildContext context, String email, String password, String fullName, String phoneNumber, bool isFromSplash) async { log("here"); if (await Connection.checkConnection()) { final prefs = await SharedPreferences.getInstance(); loader = true; notifyListeners(); try { final signUpResult = await service.singUp( email.trim(), password.trim(), fullName.trim(), phoneNumber.trim(), ); log("${signUpResult.statusCode}"); if ((signUpResult.statusCode == 200 || signUpResult.statusCode == 201) && signUpResult.data != null) { await prefs.setString('Email', email); await prefs.setString('Password', password); await prefs.setBool("isLoggedIn", true); await userLogin(context, email, password, isFromSplash); loader = false; notifyListeners(); Get.showSnackbar( const GetSnackBar( title: "Success", message: 'User Signed Up Successfully', // icon: const Icon(Icons.refresh), duration: Duration(seconds: 2), ), ); // ignore: use_build_context_synchronously //Navigator.pushReplacement( // context, // MaterialPageRoute(builder: (context) => const HomeClientView()), //); } else { Get.showSnackbar( const GetSnackBar( title: "Error", message: 'Sign up Error', duration: Duration(seconds: 2), ), ); loader = false; notifyListeners(); } } catch (e, stackTrace) { loader = false; notifyListeners(); Get.showSnackbar( const GetSnackBar( title: "Error", message: 'Sign up Error', duration: Duration(seconds: 2), ), ); log("-----> Login Caught Error : "); log(e.toString()); log("-----> Login Caught Error StackTrace : "); log(stackTrace.toString()); } } else { /// No Internet Connection Get.showSnackbar( const GetSnackBar( title: "Connection Error", message: 'No internet connection.', duration: Duration(seconds: 2), ), ); log("-----> No Internet Connection"); loader = false; notifyListeners(); } } updatePassword(String newPassword, String oldPassword) async { if (await Connection.checkConnection()) { loader = true; notifyListeners(); try { final updatePasswordResult = await service.updatePassword( newPassword.trim(), oldPassword.trim()); if ((updatePasswordResult.statusCode == 200 || updatePasswordResult.statusCode == 201) && updatePasswordResult.data != null) { Get.showSnackbar( const GetSnackBar( title: "Success", message: 'Password updated Successfully', // icon: const Icon(Icons.refresh), duration: Duration(seconds: 2), ), ); loader = false; notifyListeners(); } else { Get.showSnackbar( const GetSnackBar( title: "Error", message: 'An error occurred.', // icon: const Icon(Icons.refresh), duration: Duration(seconds: 2), ), ); loader = false; notifyListeners(); } } catch (e, stackTrace) { Get.showSnackbar( const GetSnackBar( title: "Error", message: 'An error occurred.', // icon: const Icon(Icons.refresh), duration: Duration(seconds: 2), ), ); loader = false; notifyListeners(); log("-----> Login Caught Error : "); log(e.toString()); log("-----> Login Caught Error StackTrace : "); log(stackTrace.toString()); } } else { Get.showSnackbar( const GetSnackBar( title: "Connection Error", message: 'No internet connection.', duration: Duration(seconds: 2), ), ); /// No Internet Connection log("-----> No Internet Connection"); loader = false; notifyListeners(); } } Future fetchProfile(BuildContext context) async { if (await Connection.checkConnection()) { loader = true; notifyListeners(); try { final fetchProfileResult = await service.getCurrentUser(); if ((fetchProfileResult.statusCode == 200 || fetchProfileResult.statusCode == 201) && fetchProfileResult.data != null) { profile = fetchProfileResult.data; util.updateUserInfo(fetchProfileResult.data!); util.setUser(profile); var roleCheck = profile!.role!.role!; if (roleCheck == "ROLE_USER") { clientNavProvider .updateMessageNotificationState(profile!.messageCount! > 0); } else if (roleCheck == "ROLE_TECHNICIAN") { techNavProvider .updateMessageNotificationState(profile!.messageCount! > 0); } loader = false; notifyListeners(); return true; } else { loader = false; notifyListeners(); return false; } } catch (e, stackTrace) { loader = false; notifyListeners(); log("-----> Login Caught Error : "); log(e.toString()); log("-----> Login Caught Error StackTrace : "); log(stackTrace.toString()); return false; } } else { /// No Internet Connection log("-----> No Internet Connection"); loader = false; notifyListeners(); return false; } } refreshToken() async { if (await Connection.checkConnection()) { loader = true; notifyListeners(); try { final refreshTokenResult = await service.refreshToken(); if ((refreshTokenResult.statusCode == 200 || refreshTokenResult.statusCode == 201) && refreshTokenResult.data != null) { loader = false; notifyListeners(); } else { loader = false; notifyListeners(); } } catch (e, stackTrace) { loader = false; notifyListeners(); log("-----> Login Caught Error : "); log(e.toString()); log("-----> Login Caught Error StackTrace : "); log(stackTrace.toString()); } } else { /// No Internet Connection log("-----> No Internet Connection"); loader = false; notifyListeners(); } } Future resetPasswordStepOne(String email, BuildContext context) async { if (await Connection.checkConnection()) { loader = true; notifyListeners(); try { final resetPasswordStepOneResult = await service.resetPassword(email.trim()); if (resetPasswordStepOneResult.statusCode == 200 || resetPasswordStepOneResult.statusCode == 201) { Navigator.push( context, MaterialPageRoute( builder: (context) => VerificationCodeScreen( email: email, ))); loader = false; notifyListeners(); Get.showSnackbar( const GetSnackBar( title: "Success", message: 'Check your email for reset code.', duration: Duration(seconds: 2), ), ); return true; } else { Get.showSnackbar( const GetSnackBar( title: "Error", message: 'An error occurred. Try again.', duration: Duration(seconds: 2), ), ); loader = false; notifyListeners(); return false; } } catch (e, stackTrace) { Get.showSnackbar( const GetSnackBar( title: "Error", message: 'An error occurred.', duration: Duration(seconds: 2), ), ); loader = false; notifyListeners(); log("-----> Login Caught Error : "); log(e.toString()); log("-----> Login Caught Error StackTrace : "); log(stackTrace.toString()); return false; } } else { Get.showSnackbar( const GetSnackBar( title: "Connection Error", message: 'No internet connection.', duration: Duration(seconds: 2), ), ); /// No Internet Connection log("-----> No Internet Connection"); loader = false; notifyListeners(); return false; } } resetPasswordStepTwo( BuildContext context, String email, String resetCode) async { if (await Connection.checkConnection()) { loader = true; notifyListeners(); try { final resetPasswordStepTwoResult = await service.validateResetCode(email.trim(), resetCode.trim()); if ((resetPasswordStepTwoResult.statusCode == 200 || resetPasswordStepTwoResult.statusCode == 201) && resetPasswordStepTwoResult.data != null) { loader = false; notifyListeners(); Get.showSnackbar( const GetSnackBar( title: "Success", message: 'Reset code check successful.', duration: Duration(seconds: 2), ), ); Navigator.pushReplacement( context, MaterialPageRoute( builder: (context) => ChangeForgotPasswordScreen( email: email.trim(), code: resetCode.trim(), )), ); } else { Get.showSnackbar( const GetSnackBar( title: "Error", message: 'An error occurred when checking the reset code.', duration: Duration(seconds: 2), ), ); loader = false; notifyListeners(); } } catch (e, stackTrace) { Get.showSnackbar( const GetSnackBar( title: "Error", message: 'An error occurred when checking the reset code.', duration: Duration(seconds: 2), ), ); loader = false; notifyListeners(); log("-----> Login Caught Error : "); log(e.toString()); log("-----> Login Caught Error StackTrace : "); log(stackTrace.toString()); } } else { Get.showSnackbar( const GetSnackBar( title: "Connection Error", message: 'No internet connection.', duration: Duration(seconds: 2), ), ); /// No Internet Connection log("-----> No Internet Connection"); loader = false; notifyListeners(); } } resetPasswordStepFinal(BuildContext context, String email, String password, String resetCode) async { if (await Connection.checkConnection()) { loader = true; notifyListeners(); try { final resetPasswordStepFinalResult = await service.changePasswordFinal( email.trim(), password.trim(), resetCode.trim()); if ((resetPasswordStepFinalResult.statusCode == 200 || resetPasswordStepFinalResult.statusCode == 201) && resetPasswordStepFinalResult.data != null) { loader = false; notifyListeners(); Get.showSnackbar( const GetSnackBar( title: "Success", message: 'Password reset Successfully', duration: Duration(seconds: 2), ), ); Navigator.pushReplacement( context, MaterialPageRoute( builder: (context) => const LoginScreen( isFromSplash: true, )), ); } else { Get.showSnackbar( const GetSnackBar( title: "Error", message: 'An error occurred.', duration: Duration(seconds: 2), ), ); loader = false; notifyListeners(); } } catch (e, stackTrace) { Get.showSnackbar( const GetSnackBar( title: "Error", message: 'An error occurred.', duration: Duration(seconds: 2), ), ); loader = false; notifyListeners(); log("-----> Login Caught Error : "); log(e.toString()); log("-----> Login Caught Error StackTrace : "); log(stackTrace.toString()); } } else { Get.showSnackbar( const GetSnackBar( title: "Connection Error", message: 'No internet connection.', duration: Duration(seconds: 2), ), ); /// No Internet Connection log("-----> No Internet Connection"); loader = false; notifyListeners(); } } Future logout(BuildContext context, {bool isDelete = false}) async { final prefss = await SharedPreferences.getInstance(); if (await Connection.checkConnection()) { context.read().setUserConnectionState(false); getLoginData(context); logoutLoader = true; notifyListeners(); try { final logoutResult = await service.logout(deviceId, deviceModel, ipAddress); // Log the API response status code log("-----> Logout API Response Status Code: ${logoutResult.statusCode}"); if (logoutResult.statusCode == 200 || logoutResult.statusCode == 201) { if (remember) { email = prefss.getString("Email")!; password = prefss.getString("Password")!; } logoutLoader = false; notifyListeners(); prefss.clear(); util.prefs?.clear(); util.userId = 0; util.user = null; if (email != null && password != null) { prefss.setString("Email", email!); prefss.setString("Password", password!); } if (!isDelete) { Get.showSnackbar( const GetSnackBar( title: "Success", message: 'Logout Successful', duration: Duration(seconds: 2), ), ); } // Not `Navigator.of(context)`: setUserConnectionState(false) above // swapped the client shell over to _screensDisconnected, which // unmounts the profile screen this was called from. Its context is // defunct by the time the logout request returns. NavigatorService.navigatorKey.currentState?.pushReplacement( MaterialPageRoute( builder: (context) => const LoginScreen(isFromSplash: true)), ); return true; } else { // Log the specific error message from the API log("-----> Logout Failed. API returned status code: ${logoutResult.statusCode}"); prefss.clear(); util.prefs?.clear(); util.userId = 0; util.user = null; if (email != null && password != null) { prefss.setString("Email", email!); prefss.setString("Password", password!); } if (!isDelete && logoutResult.statusCode != 404) { Get.showSnackbar( const GetSnackBar( title: "Error", message: 'An error occurred.', duration: Duration(seconds: 2), ), ); } logoutLoader = false; notifyListeners(); return false; } } catch (e, stackTrace) { // Log the caught exception and stack trace for more details log("-----> Logout Caught an Exception: ${e.toString()}"); log("-----> StackTrace: ${stackTrace.toString()}"); prefss.clear(); util.prefs?.clear(); util.userId = 0; util.user = null; if (email != null && password != null) { prefss.setString("Email", email!); prefss.setString("Password", password!); } if (!isDelete) { Get.showSnackbar( const GetSnackBar( title: "Error", message: 'An error occurred.', duration: Duration(seconds: 2), ), ); } logoutLoader = false; notifyListeners(); return false; } } else { // This part handles the "No internet connection" case // No changes needed here, as it's already well-handled. // ... (rest of the else block remains the same) // ... log("-----> No Internet Connection"); logoutLoader = false; notifyListeners(); return false; } } updateProfile(String? name, String? phoneNumber, String? country) async { if (await Connection.checkConnection()) { loader = true; notifyListeners(); try { final updateUserDataResult = await service.updateUserData(name, phoneNumber, country); if ((updateUserDataResult.statusCode == 200 || updateUserDataResult.statusCode == 201) && updateUserDataResult.data != null) { profile = updateUserDataResult.data; loader = false; notifyListeners(); Get.showSnackbar( const GetSnackBar( title: "Success", message: 'Profile updated Successfully', duration: Duration(seconds: 2), ), ); } else { loader = false; notifyListeners(); } } catch (e, stackTrace) { loader = false; notifyListeners(); log("-----> Login Caught Error : "); log(e.toString()); log("-----> Login Caught Error StackTrace : "); log(stackTrace.toString()); } } else { /// No Internet Connection log("-----> No Internet Connection"); loader = false; notifyListeners(); } } updateProfilePicture() async { if (await Connection.checkConnection()) { loader = true; notifyListeners(); try { if (_image != null) { final updatePasswordResult = await service.addProfilePicture(_image!); if ((updatePasswordResult.statusCode == 200 || updatePasswordResult.statusCode == 201) && updatePasswordResult.data != null) { loader = false; notifyListeners(); } else { loader = false; notifyListeners(); }} else { // Handle the case where _image is null (e.g., log a message) log("-----> Image is null, cannot update profile picture"); } } catch (e, stackTrace) { loader = false; notifyListeners(); log("-----> Login Caught Error : "); log(e.toString()); log("-----> Login Caught Error StackTrace : "); log(stackTrace.toString()); } } else { /// No Internet Connection log("-----> No Internet Connection"); loader = false; notifyListeners(); } } addAddress(String newAddress) async { if (await Connection.checkConnection()) { loader = true; notifyListeners(); try { final addAddressResult = await service.addAddress(newAddress.trim()); if ((addAddressResult.statusCode == 200 || addAddressResult.statusCode == 201) && addAddressResult.data != null) { loader = false; notifyListeners(); } else { loader = false; notifyListeners(); } } catch (e, stackTrace) { loader = false; notifyListeners(); log(e.toString()); log(stackTrace.toString()); } } else { /// No Internet Connection log("-----> No Internet Connection"); loader = false; notifyListeners(); } } }