import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:gen_service/Notifiers/AuthProvider.dart'; import 'package:provider/provider.dart'; import '../../Utility/AdvancedSnackbar.dart'; import '../../Utility/AppColors.dart'; import '../../Utility/CustomSnackbar.dart'; import '../../Utility/SharedpreferencesService.dart'; import 'OTP_Screen.dart'; class LoginScreen extends StatefulWidget { const LoginScreen({super.key}); @override State createState() => _LoginScreenState(); } class _LoginScreenState extends State { final TextEditingController _mobileController = TextEditingController(); final _formKey = GlobalKey(); bool _isValid = false; bool _showError = false; bool _hasUserInteracted = false; final prefs = SharedPreferencesService.instance; void _validatePhone(String value) { setState(() { _isValid = RegExp(r'^[0-9]{10}$').hasMatch(value); // Reset error when user clears the field or starts typing if (value.isEmpty) { _showError = false; } }); } void _checkValidation() { setState(() { _hasUserInteracted = true; // Only show error if field is not empty and invalid _showError = _mobileController.text.isNotEmpty && !_isValid; }); } Future _login(BuildContext context) async { // Check validation when button is pressed _checkValidation(); // If invalid, don't proceed if (!_isValid) return; final authProvider = Provider.of(context, listen: false); final mob = _mobileController.text.trim(); await authProvider.fetchMobile(mob); // Handle response - Check if error is "0" (string comparison) if (authProvider.mobileResponse != null && authProvider.mobileResponse!.error == "0") { AnimatedSnackBar.success( context: context, title: "OTP Sent", message: authProvider.mobileResponse?.message ?? "OTP sent to your registered mobile number!", ); // Navigate to OTP screen after a short delay Future.delayed(const Duration(milliseconds: 500), () { if (mounted) { Navigator.push( context, MaterialPageRoute( builder: (context) => OtpScreen(mob: mob), ), ); } }); } else { CustomSnackBar.showWarning( context: context, title: "Login Failed", message: authProvider.mobileResponse?.message.toString() ?? "Mobile number not registered or invalid", ); } } @override Widget build(BuildContext context) { final authProvider = Provider.of(context); final size = MediaQuery.of(context).size; return Scaffold( resizeToAvoidBottomInset: true, backgroundColor: Colors.blue, body: Stack( children: [ /// 🔹 Background image Container(// here is fixed same we need to do for profile here width: double.infinity, height: double.infinity, decoration: const BoxDecoration( image: DecorationImage( image: AssetImage("assets/images/background_png.png"), fit: BoxFit.cover, ), ), ), /// 🔹 Main content (scrollable & keyboard-safe) SafeArea(// here is scrollable child: LayoutBuilder( builder: (context, constraints) { return SingleChildScrollView( padding: EdgeInsets.only( bottom: MediaQuery.of(context).viewInsets.bottom, // moves up with keyboard ), child: ConstrainedBox( constraints: BoxConstraints( minHeight: constraints.maxHeight, ), child: IntrinsicHeight( child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const SizedBox(height: 80), /// 🔹 Logo Row( mainAxisAlignment: MainAxisAlignment.start, children: [ SizedBox(width: 30,), SvgPicture.asset( "assets/svg/genesis_logo_2io.svg", height: 50, color: Colors.white, ), ] ), const SizedBox(height: 12), const Spacer(), Row( mainAxisAlignment: MainAxisAlignment.start, children: [ SizedBox(width: 6,), Padding( padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Login to", style: TextStyle( fontSize: 48, height: 1, fontFamily: "PoppinsThin", fontWeight: FontWeight.w200, color: Colors.white, ), ), Text( "continue", style: TextStyle( fontSize: 48, fontWeight: FontWeight.w500, color: Colors.white, ), ), ], ), ), ], ), const SizedBox(height: 20), /// 🔹 Bottom Sheet style area Container( width: double.infinity, padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 30), decoration: const BoxDecoration( color: Colors.white, borderRadius: BorderRadius.only( topLeft: Radius.circular(24), topRight: Radius.circular(24), ), ), child: Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text( "Enter Registered Mobile No.", style: TextStyle( fontSize: 14, color: AppColors.normalText, fontWeight: FontWeight.w500, ), ), const SizedBox(height: 10), /// 🔹 Mobile Field TextField( controller: _mobileController, keyboardType: TextInputType.phone, onChanged: _validatePhone, maxLength: 10, style: const TextStyle(color: Colors.black, fontFamily: "Poppins",fontSize: 14), decoration: InputDecoration( hintText: "Enter Mobile No.", hintStyle: const TextStyle(color: Colors.grey,fontFamily: "Poppins", fontSize: 14), filled: true, fillColor: AppColors.backgroundRegular, counterText: "", // Remove character counter contentPadding: const EdgeInsets.symmetric( vertical: 16, horizontal: 20), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(30), borderSide: BorderSide( color: Colors.white.withOpacity(0.5), width: 0.5, ), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(30), borderSide: BorderSide( color: _showError ? Colors.red : Colors.blue, width: 1 ), ), ), ), // ⚠ Validation message - Only show after button press and if invalid if (_showError) const Padding( padding: EdgeInsets.only(left: 12, top: 8), child: Align( alignment: Alignment.centerLeft, child: Text( "*Invalid number. Enter your registered number.", style: TextStyle( fontFamily: "Poppins", color: Colors.redAccent, fontSize: 12, ), ), ), ), const SizedBox(height: 20), /// 🔹 Continue Button (Always visible) SizedBox( width: double.infinity, height: 50, child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF0086F1), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30), ), ), onPressed: (authProvider.isLoading) ? null : () => _login(context), child: const Text( "Continue", style: TextStyle( fontSize: 16, color: Colors.white, fontWeight: FontWeight.w600, ), ), ), ), ], ), ), ), ], ), ), ), ); }, ), ), ], ), ); } }