|
|
@ -35,18 +35,6 @@ class _LoginPageState extends State<LoginPage> { |
|
|
try { |
|
|
try { |
|
|
final userCount = await AppDatabase.instance.getUserCount(); |
|
|
final userCount = await AppDatabase.instance.getUserCount(); |
|
|
print('Nombre d\'utilisateurs trouvés: $userCount'); // Debug |
|
|
print('Nombre d\'utilisateurs trouvés: $userCount'); // Debug |
|
|
|
|
|
|
|
|
// Commentez cette partie pour permettre le login même sans utilisateurs |
|
|
|
|
|
/* |
|
|
|
|
|
if (userCount == 0) { |
|
|
|
|
|
if (mounted) { |
|
|
|
|
|
Navigator.pushReplacement( |
|
|
|
|
|
context, |
|
|
|
|
|
MaterialPageRoute(builder: (context) => const AccueilPage()), |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
*/ |
|
|
|
|
|
} catch (error) { |
|
|
} catch (error) { |
|
|
print('Erreur lors de la vérification du nombre d\'utilisateurs: $error'); |
|
|
print('Erreur lors de la vérification du nombre d\'utilisateurs: $error'); |
|
|
setState(() { |
|
|
setState(() { |
|
|
@ -65,11 +53,9 @@ class _LoginPageState extends State<LoginPage> { |
|
|
|
|
|
|
|
|
Future<void> saveUserData(Users user, String role, int userId) async { |
|
|
Future<void> saveUserData(Users user, String role, int userId) async { |
|
|
try { |
|
|
try { |
|
|
// ✅ CORRECTION : Utiliser la nouvelle méthode du contrôleur |
|
|
|
|
|
// Le contrôleur se charge maintenant de tout (observable + SharedPreferences) |
|
|
|
|
|
userController.setUserWithCredentials(user, role, userId); |
|
|
userController.setUserWithCredentials(user, role, userId); |
|
|
|
|
|
print( |
|
|
print('Utilisateur sauvegardé: ${user.username}, rôle: $role, id: $userId'); |
|
|
'Utilisateur sauvegardé: ${user.username}, rôle: $role, id: $userId'); |
|
|
} catch (error) { |
|
|
} catch (error) { |
|
|
print('Erreur lors de la sauvegarde: $error'); |
|
|
print('Erreur lors de la sauvegarde: $error'); |
|
|
throw Exception('Erreur lors de la sauvegarde des données utilisateur'); |
|
|
throw Exception('Erreur lors de la sauvegarde des données utilisateur'); |
|
|
@ -82,10 +68,10 @@ class _LoginPageState extends State<LoginPage> { |
|
|
final String username = _usernameController.text.trim(); |
|
|
final String username = _usernameController.text.trim(); |
|
|
final String password = _passwordController.text.trim(); |
|
|
final String password = _passwordController.text.trim(); |
|
|
|
|
|
|
|
|
// Validation basique |
|
|
|
|
|
if (username.isEmpty || password.isEmpty) { |
|
|
if (username.isEmpty || password.isEmpty) { |
|
|
setState(() { |
|
|
setState(() { |
|
|
_errorMessage = 'Veuillez saisir le nom d\'utilisateur et le mot de passe'; |
|
|
_errorMessage = |
|
|
|
|
|
'Veuillez saisir le nom d\'utilisateur et le mot de passe'; |
|
|
_isErrorVisible = true; |
|
|
_isErrorVisible = true; |
|
|
}); |
|
|
}); |
|
|
return; |
|
|
return; |
|
|
@ -97,45 +83,22 @@ class _LoginPageState extends State<LoginPage> { |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
try { |
|
|
try { |
|
|
print('Tentative de connexion pour: $username'); |
|
|
|
|
|
|
|
|
|
|
|
// Vérification de la connexion à la base de données |
|
|
|
|
|
final dbInstance = AppDatabase.instance; |
|
|
final dbInstance = AppDatabase.instance; |
|
|
|
|
|
|
|
|
// Test de connexion à la base |
|
|
|
|
|
try { |
|
|
|
|
|
final userCount = await dbInstance.getUserCount(); |
|
|
|
|
|
print('Base de données accessible, $userCount utilisateurs trouvés'); |
|
|
|
|
|
} catch (dbError) { |
|
|
|
|
|
throw Exception('Impossible d\'accéder à la base de données: $dbError'); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Vérifier les identifiants |
|
|
// Vérifier les identifiants |
|
|
bool isValidUser = await dbInstance.verifyUser(username, password); |
|
|
bool isValidUser = await dbInstance.verifyUser(username, password); |
|
|
print('Résultat de la vérification: $isValidUser'); |
|
|
|
|
|
|
|
|
|
|
|
if (isValidUser) { |
|
|
if (isValidUser) { |
|
|
// Récupérer les informations complètes de l'utilisateur |
|
|
|
|
|
Users user = await dbInstance.getUser(username); |
|
|
Users user = await dbInstance.getUser(username); |
|
|
print('Utilisateur récupéré: ${user.username}'); |
|
|
|
|
|
|
|
|
|
|
|
// Récupérer les credentials |
|
|
|
|
|
Map<String, dynamic>? userCredentials = |
|
|
Map<String, dynamic>? userCredentials = |
|
|
await dbInstance.getUserCredentials(username, password); |
|
|
await dbInstance.getUserCredentials(username, password); |
|
|
|
|
|
|
|
|
if (userCredentials != null) { |
|
|
if (userCredentials != null) { |
|
|
print('Connexion réussie pour: ${user.username}'); |
|
|
|
|
|
print('Rôle: ${userCredentials['role']}'); |
|
|
|
|
|
print('ID: ${userCredentials['id']}'); |
|
|
|
|
|
|
|
|
|
|
|
// ✅ CORRECTION : Sauvegarder ET mettre à jour le contrôleur |
|
|
|
|
|
await saveUserData( |
|
|
await saveUserData( |
|
|
user, |
|
|
user, |
|
|
userCredentials['role'] as String, |
|
|
userCredentials['role'] as String, |
|
|
userCredentials['id'] as int, |
|
|
userCredentials['id'] as int, |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
// Navigation |
|
|
|
|
|
if (mounted) { |
|
|
if (mounted) { |
|
|
Navigator.pushReplacement( |
|
|
Navigator.pushReplacement( |
|
|
context, |
|
|
context, |
|
|
@ -146,137 +109,189 @@ class _LoginPageState extends State<LoginPage> { |
|
|
throw Exception('Erreur lors de la récupération des credentials'); |
|
|
throw Exception('Erreur lors de la récupération des credentials'); |
|
|
} |
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
print('Identifiants invalides pour: $username'); |
|
|
|
|
|
setState(() { |
|
|
setState(() { |
|
|
_errorMessage = 'Nom d\'utilisateur ou mot de passe invalide'; |
|
|
_errorMessage = 'Nom d\'utilisateur ou mot de passe invalide'; |
|
|
_isErrorVisible = true; |
|
|
_isErrorVisible = true; |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
} catch (error) { |
|
|
} catch (error) { |
|
|
print('Erreur lors de la connexion: $error'); |
|
|
|
|
|
setState(() { |
|
|
setState(() { |
|
|
_errorMessage = 'Erreur de connexion: ${error.toString()}'; |
|
|
_errorMessage = 'Erreur de connexion: ${error.toString()}'; |
|
|
_isErrorVisible = true; |
|
|
_isErrorVisible = true; |
|
|
}); |
|
|
}); |
|
|
} finally { |
|
|
} finally { |
|
|
if (mounted) { |
|
|
if (mounted) setState(() => _isLoading = false); |
|
|
setState(() { |
|
|
|
|
|
_isLoading = false; |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@override |
|
|
@override |
|
|
Widget build(BuildContext context) { |
|
|
Widget build(BuildContext context) { |
|
|
|
|
|
final Color primaryBlue = const Color(0xFF0033A1); |
|
|
|
|
|
final Color accentRed = const Color(0xFFD70000); |
|
|
|
|
|
final Color secondaryBlue = const Color(0xFF1976D2); |
|
|
|
|
|
final Color primaryColor = primaryBlue; |
|
|
|
|
|
final Color accentColor = secondaryBlue; |
|
|
|
|
|
final Color cardColor = Colors.white; |
|
|
|
|
|
|
|
|
return Scaffold( |
|
|
return Scaffold( |
|
|
appBar: AppBar( |
|
|
backgroundColor: primaryColor, |
|
|
title: const Text( |
|
|
|
|
|
'Login', |
|
|
|
|
|
style: TextStyle(color: Colors.white), |
|
|
|
|
|
), |
|
|
|
|
|
backgroundColor: const Color.fromARGB(255, 4, 54, 95), |
|
|
|
|
|
centerTitle: true, |
|
|
|
|
|
), |
|
|
|
|
|
body: ParticleBackground( |
|
|
body: ParticleBackground( |
|
|
child: Center( |
|
|
child: Center( |
|
|
|
|
|
child: SingleChildScrollView( |
|
|
child: Container( |
|
|
child: Container( |
|
|
width: MediaQuery.of(context).size.width * 0.5, |
|
|
width: MediaQuery.of(context).size.width < 500 |
|
|
height: MediaQuery.of(context).size.height * 0.8, |
|
|
? double.infinity |
|
|
padding: const EdgeInsets.all(16.0), |
|
|
: 400, |
|
|
|
|
|
padding: |
|
|
|
|
|
const EdgeInsets.symmetric(horizontal: 24.0, vertical: 32.0), |
|
|
decoration: BoxDecoration( |
|
|
decoration: BoxDecoration( |
|
|
color: Colors.white, |
|
|
color: cardColor.withOpacity(0.98), |
|
|
shape: BoxShape.rectangle, |
|
|
|
|
|
borderRadius: BorderRadius.circular(30.0), |
|
|
borderRadius: BorderRadius.circular(30.0), |
|
|
|
|
|
boxShadow: [ |
|
|
|
|
|
BoxShadow( |
|
|
|
|
|
color: primaryColor.withOpacity(0.2), |
|
|
|
|
|
blurRadius: 16, |
|
|
|
|
|
spreadRadius: 4, |
|
|
|
|
|
offset: const Offset(0, 8), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
), |
|
|
), |
|
|
child: Column( |
|
|
child: Column( |
|
|
crossAxisAlignment: CrossAxisAlignment.stretch, |
|
|
crossAxisAlignment: CrossAxisAlignment.stretch, |
|
|
children: [ |
|
|
children: [ |
|
|
Container( |
|
|
Center( |
|
|
padding: const EdgeInsets.symmetric(vertical: 16.0), |
|
|
child: Column( |
|
|
child: const Icon( |
|
|
children: [ |
|
|
|
|
|
CircleAvatar( |
|
|
|
|
|
radius: 38, |
|
|
|
|
|
backgroundColor: accentColor.withOpacity(0.15), |
|
|
|
|
|
child: Icon( |
|
|
Icons.lock_outline, |
|
|
Icons.lock_outline, |
|
|
size: 100.0, |
|
|
color: accentColor, |
|
|
color: Color.fromARGB(255, 4, 54, 95), |
|
|
size: 50, |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
|
|
|
const SizedBox(height: 14), |
|
|
|
|
|
Text( |
|
|
|
|
|
'GUYCOM', |
|
|
|
|
|
style: TextStyle( |
|
|
|
|
|
color: primaryColor, |
|
|
|
|
|
fontWeight: FontWeight.bold, |
|
|
|
|
|
fontSize: 28, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
const SizedBox(height: 4), |
|
|
|
|
|
Text( |
|
|
|
|
|
'Connectez-vous à votre compte', |
|
|
|
|
|
style: TextStyle( |
|
|
|
|
|
color: primaryColor.withOpacity(.8), |
|
|
|
|
|
fontSize: 16, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
const SizedBox(height: 24), |
|
|
TextField( |
|
|
TextField( |
|
|
controller: _usernameController, |
|
|
controller: _usernameController, |
|
|
enabled: !_isLoading, |
|
|
enabled: !_isLoading, |
|
|
decoration: InputDecoration( |
|
|
decoration: InputDecoration( |
|
|
labelText: 'Username', |
|
|
labelText: 'Nom d\'utilisateur', |
|
|
prefixIcon: const Icon(Icons.person, color: Colors.blueAccent), |
|
|
labelStyle: TextStyle( |
|
|
|
|
|
color: primaryColor.withOpacity(0.7), |
|
|
|
|
|
), |
|
|
|
|
|
prefixIcon: Icon(Icons.person, color: accentColor), |
|
|
|
|
|
filled: true, |
|
|
|
|
|
fillColor: accentColor.withOpacity(0.045), |
|
|
border: OutlineInputBorder( |
|
|
border: OutlineInputBorder( |
|
|
borderRadius: BorderRadius.circular(30.0), |
|
|
borderRadius: BorderRadius.circular(30.0), |
|
|
|
|
|
borderSide: BorderSide(color: accentColor, width: 2), |
|
|
|
|
|
), |
|
|
|
|
|
focusedBorder: OutlineInputBorder( |
|
|
|
|
|
borderRadius: BorderRadius.circular(30.0), |
|
|
|
|
|
borderSide: BorderSide(color: accentColor, width: 2), |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
const SizedBox(height: 16.0), |
|
|
const SizedBox(height: 18.0), |
|
|
TextField( |
|
|
TextField( |
|
|
controller: _passwordController, |
|
|
controller: _passwordController, |
|
|
enabled: !_isLoading, |
|
|
enabled: !_isLoading, |
|
|
|
|
|
obscureText: true, |
|
|
decoration: InputDecoration( |
|
|
decoration: InputDecoration( |
|
|
labelText: 'Password', |
|
|
labelText: 'Mot de passe', |
|
|
prefixIcon: const Icon(Icons.lock, color: Colors.redAccent), |
|
|
labelStyle: TextStyle( |
|
|
|
|
|
color: primaryColor.withOpacity(0.7), |
|
|
|
|
|
), |
|
|
|
|
|
prefixIcon: Icon(Icons.lock, color: accentColor), |
|
|
|
|
|
filled: true, |
|
|
|
|
|
fillColor: accentColor.withOpacity(0.045), |
|
|
border: OutlineInputBorder( |
|
|
border: OutlineInputBorder( |
|
|
borderRadius: BorderRadius.circular(30.0), |
|
|
borderRadius: BorderRadius.circular(30.0), |
|
|
), |
|
|
), |
|
|
|
|
|
focusedBorder: OutlineInputBorder( |
|
|
|
|
|
borderRadius: BorderRadius.circular(30.0), |
|
|
|
|
|
borderSide: BorderSide(color: accentColor, width: 2), |
|
|
|
|
|
), |
|
|
), |
|
|
), |
|
|
obscureText: true, |
|
|
|
|
|
onSubmitted: (_) => _login(), |
|
|
onSubmitted: (_) => _login(), |
|
|
), |
|
|
), |
|
|
const SizedBox(height: 16.0), |
|
|
if (_isErrorVisible) ...[ |
|
|
Visibility( |
|
|
const SizedBox(height: 12.0), |
|
|
visible: _isErrorVisible, |
|
|
Text( |
|
|
child: Text( |
|
|
|
|
|
_errorMessage, |
|
|
_errorMessage, |
|
|
style: const TextStyle( |
|
|
style: const TextStyle( |
|
|
color: Colors.red, |
|
|
color: Colors.redAccent, |
|
|
fontSize: 14, |
|
|
fontSize: 15, |
|
|
|
|
|
fontWeight: FontWeight.w600, |
|
|
), |
|
|
), |
|
|
textAlign: TextAlign.center, |
|
|
textAlign: TextAlign.center, |
|
|
), |
|
|
), |
|
|
), |
|
|
], |
|
|
const SizedBox(height: 16.0), |
|
|
const SizedBox(height: 26.0), |
|
|
ElevatedButton( |
|
|
ElevatedButton( |
|
|
onPressed: _isLoading ? null : _login, |
|
|
onPressed: _isLoading ? null : _login, |
|
|
style: ElevatedButton.styleFrom( |
|
|
style: ElevatedButton.styleFrom( |
|
|
backgroundColor: const Color(0xFF0015B7), |
|
|
backgroundColor: accentColor, |
|
|
elevation: 5.0, |
|
|
disabledBackgroundColor: accentColor.withOpacity(0.3), |
|
|
|
|
|
foregroundColor: Colors.white, |
|
|
|
|
|
elevation: 7.0, |
|
|
shape: RoundedRectangleBorder( |
|
|
shape: RoundedRectangleBorder( |
|
|
borderRadius: BorderRadius.circular(30.0), |
|
|
borderRadius: BorderRadius.circular(30.0), |
|
|
), |
|
|
), |
|
|
minimumSize: const Size(double.infinity, 48), |
|
|
minimumSize: const Size(double.infinity, 52), |
|
|
), |
|
|
), |
|
|
child: _isLoading |
|
|
child: _isLoading |
|
|
? const SizedBox( |
|
|
? const SizedBox( |
|
|
height: 20, |
|
|
height: 24, |
|
|
width: 20, |
|
|
width: 24, |
|
|
child: CircularProgressIndicator( |
|
|
child: CircularProgressIndicator( |
|
|
color: Colors.white, |
|
|
color: Colors.white, |
|
|
strokeWidth: 2, |
|
|
strokeWidth: 2.5, |
|
|
), |
|
|
), |
|
|
) |
|
|
) |
|
|
: const Text( |
|
|
: const Text( |
|
|
'Se connecter', |
|
|
'Se connecter', |
|
|
style: TextStyle( |
|
|
style: TextStyle( |
|
|
color: Colors.white, |
|
|
color: Colors.white, |
|
|
fontSize: 16, |
|
|
fontSize: 18, |
|
|
|
|
|
fontWeight: FontWeight.bold, |
|
|
|
|
|
letterSpacing: .4, |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
// Bouton de debug (à supprimer en production) |
|
|
// Option debug, à enlever en prod |
|
|
if (_isErrorVisible) |
|
|
if (_isErrorVisible) ...[ |
|
|
TextButton( |
|
|
TextButton( |
|
|
onPressed: () async { |
|
|
onPressed: () async { |
|
|
try { |
|
|
try { |
|
|
final count = await AppDatabase.instance.getUserCount(); |
|
|
final count = |
|
|
print('Debug: $count utilisateurs dans la base'); |
|
|
await AppDatabase.instance.getUserCount(); |
|
|
ScaffoldMessenger.of(context).showSnackBar( |
|
|
ScaffoldMessenger.of(context).showSnackBar( |
|
|
SnackBar(content: Text('$count utilisateurs trouvés')), |
|
|
SnackBar( |
|
|
|
|
|
content: Text('$count utilisateurs trouvés')), |
|
|
); |
|
|
); |
|
|
} catch (e) { |
|
|
} catch (e) { |
|
|
print('Debug error: $e'); |
|
|
|
|
|
ScaffoldMessenger.of(context).showSnackBar( |
|
|
ScaffoldMessenger.of(context).showSnackBar( |
|
|
SnackBar(content: Text('Erreur: $e')), |
|
|
SnackBar(content: Text('Erreur: $e')), |
|
|
); |
|
|
); |
|
|
@ -285,6 +300,8 @@ class _LoginPageState extends State<LoginPage> { |
|
|
child: const Text('Debug: Vérifier BDD'), |
|
|
child: const Text('Debug: Vérifier BDD'), |
|
|
), |
|
|
), |
|
|
], |
|
|
], |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
|