import 'dart:developer'; import 'dart:io' as io; import 'package:wanisclient/config/AppSnackbar.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_svg/svg.dart'; import 'package:get/get.dart'; import 'package:http/http.dart' as http; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:sign_in_button/sign_in_button.dart'; import 'package:sign_in_with_apple/sign_in_with_apple.dart'; import '../config/constants/app_constant.dart'; import '../config/custom_text.dart'; import '../config/language/language_enum.dart'; import '../providers/authentification_provider.dart'; import '../providers/language_provider.dart'; import '../providers/public_keys_provider.dart'; import '../providers/utils_singleton.dart'; import '../routes/app_routes.dart'; import '../services/Sockets/PubNubManager.dart'; import '../utils/colors.dart'; import '../widgets/change_lang_drop_down.dart'; import '../widgets/custom_button.dart'; import '../widgets/missing_keys_banner.dart'; import '../widgets/phone_input_field.dart'; import 'package:beemwidget/beem_buttons_styles/beem_button_styles.dart'; import 'package:beemwidget/text_styles/beem_text_styles.dart'; import 'AddPhoneNumber.dart'; import 'NewUiScreen/PasswordInputWidget.dart'; import 'SignUpScreen.dart'; import 'oauth_screen.dart'; class LoginScreen extends StatefulWidget { const LoginScreen({super.key}); @override State createState() => _LoginScreenState(); } class _LoginScreenState extends State{ final TextEditingController phoneController = TextEditingController(); String _phoneNumber = ''; String _countryCode = ''; String completePhoneNumber = ''; final _formKey = GlobalKey(); late final AuthProvider authProvider; bool _credentialsLoaded = false; @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) async { authProvider = context.read(); Provider.of(context, listen: false).getLanguage(); await _loadSavedCredentials(); }); } @override void didChangeDependencies() { super.didChangeDependencies(); // Only load credentials if not already loaded and route is current if (!_credentialsLoaded && ModalRoute.of(context)?.isCurrent == true) { WidgetsBinding.instance.addPostFrameCallback((_) async { await _loadSavedCredentials(); }); } } Future _loadSavedCredentials() async { if (_credentialsLoaded) return; // Prevent multiple calls try { final prefs = await SharedPreferences.getInstance(); print("=== Loading saved credentials ==="); // Check all saved values final allKeys = prefs.getKeys(); print("All SharedPreferences keys: $allKeys"); // Load saved phone number final savedPhone = prefs.getString("clientphonenumberlogin"); final clientphonenumberlogincountrycode = prefs.getString("clientphonenumberlogincountrycode"); final clientphonenumberlogincompletephonenumber = prefs.getString("clientphonenumberlogincompletephonenumber"); print("Saved phone: '$savedPhone'"); print("Saved Complete phone: '$clientphonenumberlogincompletephonenumber'"); print("Saved Country code: '$clientphonenumberlogincountrycode'"); // Load saved password final savedPassword = prefs.getString("clientpassword"); print("Saved password: '${savedPassword != null ? '[EXISTS]' : 'null'}'"); // Load saved remember me state final savedRememberMe = prefs.getBool("rememberMe") ?? false; print("Saved remember me: $savedRememberMe"); if (mounted) { bool shouldUpdate = false; // Update phone number if exists and different if (savedPhone != null && savedPhone.isNotEmpty && _phoneNumber != savedPhone) { _phoneNumber = savedPhone; phoneController.text = savedPhone; shouldUpdate = true; print("Phone number will be updated to: $savedPhone"); } if (clientphonenumberlogincountrycode != null && clientphonenumberlogincountrycode.isNotEmpty && _countryCode != clientphonenumberlogincountrycode) { _countryCode=clientphonenumberlogincountrycode; shouldUpdate = true; print("Phone number will be updated to: $savedPhone"); } if (clientphonenumberlogincompletephonenumber != null && clientphonenumberlogincompletephonenumber.isNotEmpty && completePhoneNumber != clientphonenumberlogincompletephonenumber) { completePhoneNumber=clientphonenumberlogincompletephonenumber; shouldUpdate = true; print("Phone number will be updated to: $savedPhone"); } if (shouldUpdate) { setState(() { print("=== State updated with saved credentials ==="); }); } else { print("=== No updates needed ==="); } } _credentialsLoaded = true; } catch (e) { print("Error loading saved credentials: $e"); } } @override void dispose() { super.dispose(); } Future _saveCredentials() async { try { final prefs = await SharedPreferences.getInstance(); if (_phoneNumber.isNotEmpty) { await prefs.setString("clientphonenumberlogin", _phoneNumber); await prefs.setString("clientphonenumberlogincountrycode", _countryCode); await prefs.setString("clientphonenumberlogincompletephonenumber", completePhoneNumber); print("Phone saved successfully"); } if (_countryCode.isNotEmpty) { await prefs.setString("clientphonenumberlogincountrycode", _countryCode); print("Phone saved successfully"); } if (completePhoneNumber.isNotEmpty) { await prefs.setString("clientphonenumberlogincompletephonenumber", completePhoneNumber); print("Phone saved successfully"); } await prefs.setBool("rememberMe", true); print("Remember me saved as true"); // Verify the save worked final verifyPhone = prefs.getString("clientphonenumberlogin"); final verifyPassword = prefs.getString("clientpassword"); final verifyRemember = prefs.getBool("rememberMe"); print("Verification - Phone: $verifyPhone, Password exists: ${verifyPassword != null}, Remember: $verifyRemember"); } catch (e) { print("Error saving credentials: $e"); } } Future _isUserTokenValid() async { final prefs = await SharedPreferences.getInstance(); var tokenData = prefs.getString("token"); bool tokenverif = tokenData != null && tokenData.isNotEmpty && tokenData != "InvalidToken"; utils.updatetoken(tokenData ?? "InvalidToken"); bool fetchprofile = await authProvider.fetchProfile(); return fetchprofile && tokenverif; } @override Widget build(BuildContext context) { final languageProvider = context.watch(); bool isArabic = languageProvider.currentLangCode == Language.ar; final signUpProvider = context.watch(); return SafeArea( child: Scaffold( resizeToAvoidBottomInset: false, backgroundColor: AppNewColors.whiteBackGround, body: Column( children: [ // ── test banners at very top ────────────────────────── const MissingKeysBanner(), // ── test mode info panel ────────────────────────────── if (publickeys.isTestEnvironment) Container( width: double.infinity, color: Colors.orange.shade50, padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Row( children: [ Icon(Icons.science, color: Colors.orange, size: 16), SizedBox(width: 6), Text( 'Test Mode — Dev Info', style: TextStyle( color: Colors.orange, fontWeight: FontWeight.bold, fontSize: 13, ), ), ], ), const SizedBox(height: 4), // test phone hint GestureDetector( onTap: () { setState(() { _phoneNumber = '99991111'; _countryCode = '+216'; completePhoneNumber = '+21699991111'; phoneController.text = '99991111'; }); }, child: Container( padding: const EdgeInsets.symmetric( vertical: 4, horizontal: 8), decoration: BoxDecoration( color: Colors.orange.shade100, borderRadius: BorderRadius.circular(6), ), child: const Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.touch_app, size: 14, color: Colors.orange), SizedBox(width: 4), Text( 'Tap to use test number: +216 9999 1111', style: TextStyle( color: Colors.deepOrange, fontSize: 12, fontWeight: FontWeight.w500, ), ), ], ), ), ), // missing keys list if (publickeys.missingPublicKeys.isNotEmpty) ...[ const SizedBox(height: 4), Text( '🔑 Not configured: ${publickeys.missingPublicKeys.join(', ')}', style: TextStyle( color: Colors.red.shade700, fontSize: 11, ), ), ], if (publickeys.missingPublicKeys.isEmpty) const Text( '✅ All public keys configured', style: TextStyle( color: Colors.green, fontSize: 11, ), ), ], ), ), // ── main content ────────────────────────────────────── Expanded( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ const SizedBox(height: 60), Txt( text: 'Welcome back', style: TextStyle( color: AppNewColors.titleTextColor, fontSize: 26, fontFamily: isArabic ? "Readex_Pro" : 'Inter', fontWeight: FontWeight.w600, height: 1.23, ), ), const SizedBox(height: 8), Txt( text: 'Enter your phone number to receive a one-time verification code', style: TextStyle( color: AppNewColors.grayTxtColor, fontSize: 18, fontFamily: isArabic ? "Readex_Pro" : 'Inter', fontWeight: FontWeight.w500, height: 1.33, ), ), const SizedBox(height: 32), Directionality( textDirection: isArabic ? TextDirection.rtl : TextDirection.ltr, child: PhoneInputField( controller: phoneController, onNumberChange: (phoneNumber) { if (phoneNumber.number.isEmpty || phoneNumber.number.trim().isEmpty) return; setState(() { _phoneNumber = phoneNumber.number; _countryCode = phoneNumber.countryCode; completePhoneNumber = _countryCode + _phoneNumber; }); }, validator: (phoneNumber) { if (phoneNumber == null || phoneNumber.number.isEmpty || phoneNumber.number.length < 8) { return languageProvider .translate('Please enter a valid phone number'); } return null; }, ), ), const SizedBox(height: 22), CustomButton( onClick: () async { if (signUpProvider.loader) return; if (_phoneNumber.isEmpty) { AppSnackbar.showError( "Error", "Phone-number is required!"); return; } if (_formKey.currentState!.validate()) { print('Complete Phone Number: $completePhoneNumber'); var res = await signUpProvider .phoneTextLogin(completePhoneNumber); _saveCredentials(); if (res) { if (await _isUserTokenValid()) { final userContext = UserContext( username: utils.user!.username!); context .read() .init(userContext); await publickeys.loadSecretKeys(); Get.toNamed(AppRoutes.home); return; } else { Get.toNamed( AppRoutes.verifOtp, arguments: { 'phoneNumber': completePhoneNumber, 'isForgetPassword': false, 'isLogin': true, }, ); } } } }, fontSize: 18, width: double.infinity, height: 40.sp, borderRadius: 10, txtColor: AppNewColors.white, title: 'Continue', backgroundColor: AppNewColors.primaryBtnColor, borderColor: AppNewColors.primaryBtnColor, isloading: signUpProvider.loader, loadercolor: AppNewColors.white, ), ], ), ), ), ), ], ), ), ); } }