import 'dart:convert'; import 'dart:io'; import 'package:wanisdriver/Provider/utils_provider.dart'; import 'package:wanisdriver/Provider/utils_singleton.dart'; import 'package:wanisdriver/config/AppSnackbar.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:get_it/get_it.dart'; import 'dart:developer'; import 'package:http/http.dart' as http; import '../Screen/location_screen.dart'; import '../config/api_response.dart'; import '../models/users.dart'; import '../services/auth_services.dart'; import '../utils/connection.dart'; import 'language_provider.dart'; import '../response/login_response.dart'; class AuthProvider extends ChangeNotifier { AuthServices get authService => GetIt.I(); bool loader = false; bool loaderImage = false; String deviceId = ""; String deviceModel = ""; String ipAddress = ""; String deviceType = ""; users? profile; VoidCallback? onValidate; String dToken = ""; String? _email; String? _password; String get emailAddress => _email ?? ''; String get password => _password ?? ""; // SharedPreferences instance cached for reuse late final SharedPreferences _prefs; AuthProvider() { _init(); } Future _init() async { _prefs = await SharedPreferences.getInstance(); } Future getLoginData(BuildContext context) async { final utilProvider = context.read(); if (Platform.isIOS) { deviceId = utilProvider.deviceInfo['name']; deviceModel = utilProvider.deviceInfo['model']; ipAddress = utilProvider.ipAddress; } else { deviceId = utilProvider.deviceInfo['id']; deviceModel = utilProvider.deviceInfo['model']; ipAddress = utilProvider.ipAddress; } } Future getToken() async { var token = _prefs.getString('token'); log("token check: $token"); return token != null && token.isNotEmpty && token != 'InvalidToken'; } void showErrorSnackbar(String message) { Get.showSnackbar( GetSnackBar( title: languageSingleton.translate("Error"), message: languageSingleton.translate(message), duration: const Duration(seconds: 3), ), ); } Future updateProfile({String? name, String? phone, String? email,String? password}) async { if (!await Connection.checkConnection()) { log("No Internet Connection"); return false; } print("password---------------------------- $password"); final Map data = {}; if (name != null) data['name'] = name; if (phone != null) data['phone'] = phone; if (email != null) data['email'] = email; if (password != null) data['password'] = password; print("data---------------------------- $data"); if (data.isEmpty) false; _updateLoaderStatus(true); try { final updateResult = await authService.updateProfile(name: name, phonenumber: phone,email:email,password:password); if (updateResult.statusCode == 200 || updateResult.statusCode == 201) { utils.updateCurrentUser(users.fromJson(updateResult.data)); notifyListeners(); AppSnackbar.showSuccess("Success","Profile updated successfully"); // ✅ NEW: ADDED LOGIC TO SAVE UPDATED CREDENTIALS if (email != null && email.isNotEmpty) { await _prefs.setString('Email', email); } if (password != null && password.isNotEmpty) { await _prefs.setString('Password', password); } // ✅ END OF NEW LOGIC return true; } else { log("Failed to update profile with status code: ${updateResult.statusCode}"); AppSnackbar.showError("Error","Failed to update profile"); return false; } } catch (e, stackTrace) { log("Provider updateProfile caught error: $e"); log("Error stack trace: $stackTrace"); return false; }finally{ _updateLoaderStatus(false); } } Future login(String email, String password) async { // Check for internet connection before proceeding if (!(await Connection.checkConnection())) { _showErrorSnackbar("Error", "No Internet Connection"); log("No Internet Connection"); _updateLoaderStatus(false); return false; } _updateLoaderStatus(true); try { // Attempt user sign in through the service final authResult = await authService.signIn( email.trim(), password.trim(), deviceId, deviceModel, ipAddress, ); // Handle successful login if ((authResult.statusCode == 200 || authResult.statusCode == 201) && authResult.data != null) { await _handleSuccessfulLogin(authResult, email, password); _updateLoaderStatus(false); return true; } // Handle different types of errors switch (authResult.statusCode) { case 401: _showErrorSnackbar("Sign in Error", "Wrong credentials."); break; case 400: _handleLoginErrors(authResult.errorMessage); break; default: _showErrorSnackbar("Error", "Sign in Error"); } _updateLoaderStatus(false); return false; } catch (e, stackTrace) { // Generic catch for unexpected errors _showErrorSnackbar("Error", "Server Error. Please try again later."); log("Login provider caught error: $e"); log("Login provider error stack trace: $stackTrace"); _updateLoaderStatus(false); return false; } } // Helper to update the loader state and notify listeners void _updateLoaderStatus(bool status) { loader = status; notifyListeners(); } void _updateLoaderImageStatus(bool status) { loaderImage = status; notifyListeners(); } // Helper to handle successful login process and SharedPreferences updates Future _handleSuccessfulLogin(APIResponse authResult, String email, String password) async { await fetchProfile(); // Batch update SharedPreferences await Future.wait([ _prefs.setString('Email', email), _prefs.setString('Password', password), _prefs.setBool("isLoggedIn", true), _prefs.setString("Role", authResult.data!.roles!), ]); } // Helper to handle error messages during login void _handleLoginErrors(String? errorMessage) { final translatedTitle = languageSingleton.translate("Sign in Error"); String translatedMessage; switch (errorMessage?.trim()) { case "Wrong userName": translatedMessage = languageSingleton.translate( "Oops, this account does not exist in our records"); break; case "Wrong Password": translatedMessage = languageSingleton.translate("Oops, Wrong password"); break; default: translatedMessage = languageSingleton.translate("Wrong credentials."); } _showErrorSnackbar(translatedTitle, translatedMessage); } // Helper to display snack bar messages void _showErrorSnackbar(String title, String message) { Get.showSnackbar( GetSnackBar( title: languageSingleton.translate(title), message: languageSingleton.translate(message), duration: const Duration(seconds: 3), ), ); } Future getIpAddress() async { try { final response = await http.get(Uri.parse('https://api.ipify.org?format=json')); if (response.statusCode == 200) { final jsonResponse = json.decode(response.body); ipAddress = jsonResponse['ip']; return jsonResponse['ip']; // IP Address } } catch (e) { print('Failed to get IP address: $e'); } return ''; } Future> getDeviceInfo() async { DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); if (Platform.isAndroid) { AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; deviceId = androidInfo.id ?? ""; // Device ID deviceType = "Android"; // Device Type } else if (Platform.isIOS) { IosDeviceInfo iosInfo = await deviceInfo.iosInfo; deviceId = iosInfo.identifierForVendor ?? ""; // Device ID deviceType = "iOS"; // Device Type } return { 'deviceId': deviceId, 'deviceType': deviceType, }; } Future getDeviceToken() async { FirebaseMessaging messaging = FirebaseMessaging.instance; String? token = await messaging.getToken(); dToken = token ?? ""; return token ?? ""; } Future fetchProfile() async { if (!await Connection.checkConnection()) { log("No Internet Connection"); _updateLoaderStatus(false); return false; } _updateLoaderStatus(true); try { final fetchProfileResult = await authService.getCurrentUser(); // Check for successful response if (fetchProfileResult.statusCode == 200 || fetchProfileResult.statusCode == 201) { if (fetchProfileResult.data == null) { log("No data found in the response"); return false; } profile = fetchProfileResult.data; utils.updateCurrentUser(profile!); log("my profile +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ : $profile"); // Check role validity if (profile?.role == null || profile?.role != "ROLE_DRIVER") { log("This is not a driver --------------------------------"); return false; } await utils.getToken(); log("Profile loaded successfully: Email: ${utils.user?.email}, User ID: ${utils.user?.id}"); return true; } else { log("Failed to load profile with status code: ${fetchProfileResult.statusCode}"); return false; } } catch (e, stackTrace) { log("Provider fetchProfile caught error: $e"); log("Error stack trace: $stackTrace"); return false; } finally { _updateLoaderStatus(false); } } // New method to update the profile picture Future updateProfilePicture(File image) async { if (!await Connection.checkConnection()) { log("No Internet Connection"); return; } _updateLoaderImageStatus(true); try { final response = await authService.updateProfilePicture(image, utils.user!.id!); if (response.statusCode == 200 || response.statusCode == 201) { log("Profile picture updated successfully"); final updatedUser = users.fromJson(response.data); utils.updateCurrentUser(updatedUser); profile = updatedUser; notifyListeners(); _updateLoaderImageStatus(false); } else { showErrorSnackbar("Failed to update profile picture"); } _updateLoaderImageStatus(false); } catch (e, stackTrace) { log("Error updating profile picture: $e"); log("Error stack trace: $stackTrace"); showErrorSnackbar("An error occurred while updating the profile picture"); } finally { _updateLoaderImageStatus(false); } } Future logOut() async { await _prefs.remove('token'); } }