import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../../../shared/providers/auth_provider.dart'; class LoginScreen extends ConsumerStatefulWidget { const LoginScreen({super.key}); @override ConsumerState createState() => _LoginScreenState(); } class _LoginScreenState extends ConsumerState { final _formKey = GlobalKey(); final _emailController = TextEditingController(); final _passwordController = TextEditingController(); bool _isLoading = false; String? _error; @override void dispose() { _emailController.dispose(); _passwordController.dispose(); super.dispose(); } Future _handleLogin() async { if (!_formKey.currentState!.validate()) return; setState(() { _isLoading = true; _error = null; }); try { await ref.read(authStateProvider.notifier).signIn( email: _emailController.text.trim(), password: _passwordController.text, ); if (mounted) { context.go('/'); } } catch (e) { setState(() { _error = 'Invalid email or password'; }); } finally { if (mounted) { setState(() { _isLoading = false; }); } } } @override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: Center( child: SingleChildScrollView( padding: const EdgeInsets.all(24), child: Form( key: _formKey, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // Logo/Title Icon( Icons.hub, size: 64, color: Theme.of(context).colorScheme.primary, ), const SizedBox(height: 16), Text( 'Network App', style: Theme.of(context).textTheme.headlineMedium?.copyWith( fontWeight: FontWeight.bold, ), textAlign: TextAlign.center, ), const SizedBox(height: 8), Text( 'Sign in to your account', style: Theme.of(context).textTheme.bodyLarge?.copyWith( color: Colors.grey, ), textAlign: TextAlign.center, ), const SizedBox(height: 48), // Error message if (_error != null) ...[ Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.red.shade50, borderRadius: BorderRadius.circular(8), ), child: Text( _error!, style: TextStyle(color: Colors.red.shade700), textAlign: TextAlign.center, ), ), const SizedBox(height: 16), ], // Email field TextFormField( controller: _emailController, keyboardType: TextInputType.emailAddress, textInputAction: TextInputAction.next, decoration: const InputDecoration( labelText: 'Email', prefixIcon: Icon(Icons.email_outlined), ), validator: (value) { if (value == null || value.isEmpty) { return 'Please enter your email'; } if (!value.contains('@')) { return 'Please enter a valid email'; } return null; }, ), const SizedBox(height: 16), // Password field TextFormField( controller: _passwordController, obscureText: true, textInputAction: TextInputAction.done, onFieldSubmitted: (_) => _handleLogin(), decoration: const InputDecoration( labelText: 'Password', prefixIcon: Icon(Icons.lock_outlined), ), validator: (value) { if (value == null || value.isEmpty) { return 'Please enter your password'; } return null; }, ), const SizedBox(height: 24), // Login button FilledButton( onPressed: _isLoading ? null : _handleLogin, child: _isLoading ? const SizedBox( height: 20, width: 20, child: CircularProgressIndicator(strokeWidth: 2), ) : const Text('Sign In'), ), const SizedBox(height: 16), // Register link Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text("Don't have an account?"), TextButton( onPressed: () => context.go('/register'), child: const Text('Sign Up'), ), ], ), ], ), ), ), ), ), ); } }