Primera app funcional
This commit is contained in:
106
lib/screens/login_screen.dart
Normal file
106
lib/screens/login_screen.dart
Normal file
@@ -0,0 +1,106 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../core/app_colors.dart';
|
||||
import '../services/auth_service.dart';
|
||||
|
||||
class LoginScreen extends StatefulWidget {
|
||||
const LoginScreen({super.key});
|
||||
@override State<LoginScreen> createState() => _LoginScreenState();
|
||||
}
|
||||
|
||||
class _LoginScreenState extends State<LoginScreen> {
|
||||
final _emailCtrl = TextEditingController();
|
||||
final _passCtrl = TextEditingController();
|
||||
bool _loading = false, _obscure = true;
|
||||
|
||||
Future<void> _login() async {
|
||||
if (_emailCtrl.text.isEmpty || _passCtrl.text.isEmpty) {
|
||||
_snack('Llena todos los campos', isError: true); return;
|
||||
}
|
||||
setState(() => _loading = true);
|
||||
final err = await context.read<AuthService>().login(_emailCtrl.text, _passCtrl.text);
|
||||
if (!mounted) return;
|
||||
setState(() => _loading = false);
|
||||
if (err != null) { _snack(err, isError: true); return; }
|
||||
final rol = context.read<AuthService>().rol;
|
||||
switch (rol) {
|
||||
case 'ADMINISTRADOR': Navigator.pushReplacementNamed(context, '/admin'); break;
|
||||
case 'CONDUCTOR': Navigator.pushReplacementNamed(context, '/driver'); break;
|
||||
default: Navigator.pushReplacementNamed(context, '/home'); break;
|
||||
}
|
||||
}
|
||||
|
||||
void _snack(String msg, {bool isError = false}) => ScaffoldMessenger.of(context)
|
||||
.showSnackBar(SnackBar(content:Text(msg),
|
||||
backgroundColor: isError ? AppColors.rojoError : AppColors.verdeExito));
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Scaffold(
|
||||
backgroundColor: AppColors.grisFondo,
|
||||
body: SingleChildScrollView(child: Column(children: [
|
||||
Container(width:double.infinity, color:AppColors.guindaPrimary,
|
||||
padding:const EdgeInsets.only(top:60,bottom:28),
|
||||
child:Column(children:[
|
||||
Container(width:84,height:84,
|
||||
decoration:BoxDecoration(color:Colors.white12,shape:BoxShape.circle,
|
||||
border:Border.all(color:AppColors.dorado,width:2.5)),
|
||||
child:const Icon(Icons.delete_sweep_rounded,size:44,color:AppColors.dorado)),
|
||||
const SizedBox(height:14),
|
||||
const Text('H. AYUNTAMIENTO DE CELAYA',
|
||||
style:TextStyle(color:Colors.white,fontSize:13,fontWeight:FontWeight.bold,letterSpacing:1.2)),
|
||||
const SizedBox(height:4),
|
||||
const Text('Sistema de Recolección de Residuos',
|
||||
style:TextStyle(color:AppColors.dorado,fontSize:13)),
|
||||
])),
|
||||
Container(height:4,color:AppColors.dorado),
|
||||
Padding(padding:const EdgeInsets.all(24), child:Card(elevation:4,
|
||||
shape:RoundedRectangleBorder(borderRadius:BorderRadius.circular(12)),
|
||||
child:Padding(padding:const EdgeInsets.all(24), child:Column(
|
||||
crossAxisAlignment:CrossAxisAlignment.start, children:[
|
||||
const Text('Iniciar Sesión',style:TextStyle(fontSize:20,
|
||||
fontWeight:FontWeight.bold,color:AppColors.guindaPrimary)),
|
||||
const SizedBox(height:16),
|
||||
// Accesos rápidos demo
|
||||
Container(padding:const EdgeInsets.all(10),
|
||||
decoration:BoxDecoration(color:Colors.blue.shade50,borderRadius:BorderRadius.circular(8)),
|
||||
child:const Column(crossAxisAlignment:CrossAxisAlignment.start, children:[
|
||||
Text('Demo rápido:',style:TextStyle(fontWeight:FontWeight.bold,fontSize:12,color:AppColors.azulInfo)),
|
||||
Text('Admin: admin@celaya.gob.mx / admin123',style:TextStyle(fontSize:11)),
|
||||
Text('Conductor: conductor@celaya.gob.mx / conductor123',style:TextStyle(fontSize:11)),
|
||||
])),
|
||||
const SizedBox(height:16),
|
||||
TextField(controller:_emailCtrl,keyboardType:TextInputType.emailAddress,
|
||||
decoration:const InputDecoration(labelText:'Correo electrónico',
|
||||
prefixIcon:Icon(Icons.email_outlined,color:AppColors.guindaPrimary),
|
||||
border:OutlineInputBorder())),
|
||||
const SizedBox(height:12),
|
||||
TextField(controller:_passCtrl,obscureText:_obscure,
|
||||
decoration:InputDecoration(labelText:'Contraseña',
|
||||
prefixIcon:const Icon(Icons.lock_outline,color:AppColors.guindaPrimary),
|
||||
border:const OutlineInputBorder(),
|
||||
suffixIcon:IconButton(icon:Icon(_obscure?Icons.visibility_off:Icons.visibility),
|
||||
onPressed:()=>setState(()=>_obscure=!_obscure)))),
|
||||
const SizedBox(height:20),
|
||||
SizedBox(width:double.infinity,height:50,
|
||||
child:ElevatedButton(onPressed:_loading?null:_login,
|
||||
style:ElevatedButton.styleFrom(backgroundColor:AppColors.guindaPrimary,
|
||||
foregroundColor:Colors.white,shape:RoundedRectangleBorder(borderRadius:BorderRadius.circular(8))),
|
||||
child:_loading?const CircularProgressIndicator(color:Colors.white,strokeWidth:2)
|
||||
:const Text('ENTRAR',style:TextStyle(fontWeight:FontWeight.bold,letterSpacing:1)))),
|
||||
const SizedBox(height:12),
|
||||
const Divider(),
|
||||
const SizedBox(height:12),
|
||||
SizedBox(width:double.infinity,height:50,
|
||||
child:OutlinedButton(onPressed:()=>Navigator.pushNamed(context,'/register'),
|
||||
style:OutlinedButton.styleFrom(foregroundColor:AppColors.guindaPrimary,
|
||||
side:const BorderSide(color:AppColors.guindaPrimary),
|
||||
shape:RoundedRectangleBorder(borderRadius:BorderRadius.circular(8))),
|
||||
child:const Text('CREAR CUENTA CIUDADANO',style:TextStyle(fontWeight:FontWeight.bold)))),
|
||||
])))),
|
||||
const Padding(padding:EdgeInsets.only(bottom:20),
|
||||
child:Text('Gobierno Municipal de Celaya • Guanajuato',
|
||||
style:TextStyle(color:AppColors.grisTexto,fontSize:11))),
|
||||
])),
|
||||
);
|
||||
@override void dispose() { _emailCtrl.dispose(); _passCtrl.dispose(); super.dispose(); }
|
||||
}
|
||||
Reference in New Issue
Block a user