import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; import '../../shared/providers/auth_provider.dart'; import '../../core/constants/app_spacing.dart'; import '../../core/enums/auth_state.dart'; class EnhancedAuthScreen extends StatefulWidget { const EnhancedAuthScreen({super.key}); @override State createState() => _EnhancedAuthScreenState(); } class _EnhancedAuthScreenState extends State { final _formKey = GlobalKey(); final _baseUrlController = TextEditingController(); final _usernameController = TextEditingController(); final _passwordController = TextEditingController(); final _qrCodeController = TextEditingController(); bool _isPasswordVisible = false; bool _isLoading = false; bool _isQrMode = false; String? _errorMessage; @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { Provider.of(context, listen: false).initialize(); }); } @override void dispose() { _baseUrlController.dispose(); _usernameController.dispose(); _passwordController.dispose(); _qrCodeController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Theme.of(context).colorScheme.surface, body: SafeArea( child: SingleChildScrollView( padding: AppSpacing.paddingLG, child: Column( children: [ // Logo and Title _buildHeader(context), const SizedBox(height: 32), // Auth Mode Toggle _buildAuthModeToggle(context), const SizedBox(height: 32), // Auth Form _buildAuthForm(context), const SizedBox(height: 24), // Error Message if (_errorMessage != null) _buildErrorMessage(context), ], ), ), ), ); } Widget _buildHeader(BuildContext context) { return Column( children: [ Icon( Icons.music_note, size: 80, color: Theme.of(context).colorScheme.primary, ), const SizedBox(height: 16), Text( 'SwingMusic', style: Theme.of(context).textTheme.headlineLarge?.copyWith( fontWeight: FontWeight.bold, color: Theme.of(context).colorScheme.onSurface, ), ), const SizedBox(height: 8), Text( 'Connect to your music library', style: Theme.of(context).textTheme.bodyLarge?.copyWith( color: Theme.of(context).colorScheme.onSurface.withOpacity(0.7), ), textAlign: TextAlign.center, ), ], ); } Widget _buildAuthModeToggle(BuildContext context) { return Container( decoration: BoxDecoration( color: Theme.of(context).colorScheme.surfaceVariant, borderRadius: BorderRadius.circular(12), ), child: Row( children: [ Expanded( child: GestureDetector( onTap: () => setState(() => _isQrMode = false), child: Container( padding: const EdgeInsets.symmetric(vertical: 16), decoration: BoxDecoration( color: _isQrMode ? Theme.of(context).colorScheme.surface : Theme.of(context).colorScheme.primary, borderRadius: const BorderRadius.only( topLeft: Radius.circular(12), bottomLeft: Radius.circular(12), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.person, color: _isQrMode ? Theme.of(context).colorScheme.onSurfaceVariant : Theme.of(context).colorScheme.onPrimary, ), const SizedBox(width: 8), Text( 'Username & Password', style: TextStyle( color: _isQrMode ? Theme.of(context).colorScheme.onSurfaceVariant : Theme.of(context).colorScheme.onPrimary, fontWeight: FontWeight.w500, ), ), ], ), ), ), ), Expanded( child: GestureDetector( onTap: () => setState(() => _isQrMode = true), child: Container( padding: const EdgeInsets.symmetric(vertical: 16), decoration: BoxDecoration( color: _isQrMode ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.surface, borderRadius: const BorderRadius.only( topRight: Radius.circular(12), bottomRight: Radius.circular(12), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.qr_code_scanner, color: _isQrMode ? Theme.of(context).colorScheme.onPrimary : Theme.of(context).colorScheme.onSurfaceVariant, ), const SizedBox(width: 8), Text( 'QR Code', style: TextStyle( color: _isQrMode ? Theme.of(context).colorScheme.onPrimary : Theme.of(context).colorScheme.onSurfaceVariant, fontWeight: FontWeight.w500, ), ), ], ), ), ), ), ], ), ); } Widget _buildAuthForm(BuildContext context) { return Consumer( builder: (context, authProvider, child) { return Form( key: _formKey, child: Column( children: [ if (_isQrMode) ...[ // QR Code Input TextFormField( controller: _qrCodeController, decoration: InputDecoration( labelText: 'QR Code', hintText: 'Enter or scan QR code', prefixIcon: const Icon(Icons.qr_code_scanner), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide( color: Theme.of(context).colorScheme.outline, ), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide( color: Theme.of(context).colorScheme.primary, ), ), ), readOnly: true, onTap: () => _scanQrCode(context), ), ] else ...[ // Server URL Input TextFormField( controller: _baseUrlController, decoration: InputDecoration( labelText: 'Server URL', hintText: 'https://your-server.com', prefixIcon: const Icon(Icons.link), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide( color: Theme.of(context).colorScheme.outline, ), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide( color: Theme.of(context).colorScheme.primary, ), ), ), validator: (value) { if (value == null || value!.isEmpty) { return 'Server URL is required'; } if (!_isValidUrl(value)) { return 'Please enter a valid URL'; } return null; }, ), const SizedBox(height: 16), // Username Input TextFormField( controller: _usernameController, decoration: InputDecoration( labelText: 'Username', hintText: 'Enter your username', prefixIcon: const Icon(Icons.person), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide( color: Theme.of(context).colorScheme.outline, ), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide( color: Theme.of(context).colorScheme.primary, ), ), ), validator: (value) { if (value == null || value!.isEmpty) { return 'Username is required'; } return null; }, ), const SizedBox(height: 16), // Password Input TextFormField( controller: _passwordController, obscureText: !_isPasswordVisible, decoration: InputDecoration( labelText: 'Password', hintText: 'Enter your password', prefixIcon: const Icon(Icons.lock), suffixIcon: IconButton( onPressed: () => setState(() => _isPasswordVisible = !_isPasswordVisible), icon: Icon( _isPasswordVisible ? Icons.visibility : Icons.visibility_off, ), ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide( color: Theme.of(context).colorScheme.outline, ), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide( color: Theme.of(context).colorScheme.primary, ), ), ), validator: (value) { if (value == null || value!.isEmpty) { return 'Password is required'; } return null; }, ), ], const SizedBox(height: 24), // Login Button SizedBox( width: double.infinity, height: 50, child: ElevatedButton( onPressed: _isLoading ? null : () => _handleLogin(context), style: ElevatedButton.styleFrom( backgroundColor: Theme.of(context).colorScheme.primary, foregroundColor: Theme.of(context).colorScheme.onPrimary, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: _isLoading ? const SizedBox( width: 20, height: 20, child: CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation(Colors.white), ), ) : Text( _isQrMode ? 'Login with QR' : 'Login', style: const TextStyle( fontSize: 16, fontWeight: FontWeight.w600, ), ), ), ), ], ), ); }, ); } Widget _buildErrorMessage(BuildContext context) { return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Theme.of(context).colorScheme.errorContainer, borderRadius: BorderRadius.circular(8), ), child: Row( children: [ Icon( Icons.error_outline, color: Theme.of(context).colorScheme.error, size: 20, ), const SizedBox(width: 8), Expanded( child: Text( _errorMessage!, style: TextStyle( color: Theme.of(context).colorScheme.error, fontSize: 14, ), ), ), IconButton( onPressed: () => setState(() => _errorMessage = null), icon: const Icon(Icons.close), iconSize: 16, color: Theme.of(context).colorScheme.error, ), ], ), ); } bool _isValidUrl(String url) { try { final uri = Uri.parse(url); return uri.hasScheme && (uri.scheme == 'http' || uri.scheme == 'https'); } catch (e) { return false; } } Future _handleLogin(BuildContext context) async { if (!_formKey.currentState!.validate()) { return; } setState(() { _isLoading = true; _errorMessage = null; }); try { final authProvider = Provider.of(context, listen: false); if (_isQrMode) { await authProvider.loginWithQrCode(_qrCodeController.text.trim()); } else { await authProvider.loginWithUsernameAndPassword( _baseUrlController.text.trim(), _usernameController.text.trim(), _passwordController.text, ); } if (mounted) { Navigator.of(context).pushReplacementNamed('/home'); } } catch (e) { setState(() { _isLoading = false; _errorMessage = e.toString(); }); } } Future _scanQrCode(BuildContext context) async { try { final qrCode = await Navigator.pushNamed('/qr'); if (qrCode != null && mounted) { _qrCodeController.text = qrCode!; } } catch (e) { setState(() { _errorMessage = 'Failed to scan QR code: $e'; }); } } }