login_screen.dart 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. import 'package:flutter/material.dart';
  2. import 'package:provider/provider.dart';
  3. import '../../../core/models/models.dart';
  4. import '../../../utils/themes.dart';
  5. import '../../viewmodels/viewmodels.dart';
  6. import '../../../utils/widgets/widgets.dart';
  7. import '../home/home_screen.dart';
  8. class LoginScreen extends StatefulWidget {
  9. const LoginScreen({Key? key}) : super(key: key);
  10. @override
  11. State<LoginScreen> createState() => _LoginScreenState();
  12. }
  13. class _LoginScreenState extends State<LoginScreen> {
  14. final _correo = TextEditingController();
  15. final _contrasena = TextEditingController();
  16. Sucursal? _selectedSucursal;
  17. @override
  18. void dispose() {
  19. super.dispose();
  20. _correo.dispose();
  21. _contrasena.dispose();
  22. }
  23. @override
  24. void initState() {
  25. super.initState();
  26. // Verifica la sesión almacenada
  27. WidgetsBinding.instance.addPostFrameCallback((_) {
  28. final loginViewModel =
  29. Provider.of<LoginViewModel>(context, listen: false);
  30. Provider.of<PermisoViewModel>(context, listen: false)
  31. .sincronizarPermisos();
  32. Provider.of<UsuarioViewModel>(context, listen: false)
  33. .sincronizarUsuarios();
  34. // Verificar la sesión
  35. loginViewModel.checkSession().then((_) {
  36. if (loginViewModel.status == Status.authenticated) {
  37. print("Sesión activa detectada, redirigiendo al HomeScreen.");
  38. Navigator.pushReplacement(
  39. context,
  40. MaterialPageRoute(builder: (context) => const HomeScreen()),
  41. );
  42. } else {
  43. print("No se detectó sesión, mostrando la pantalla de login.");
  44. final sucursalViewModel =
  45. Provider.of<SucursalViewModel>(context, listen: false);
  46. sucursalViewModel.sincronizarSucursales().then((_) {
  47. setState(() {
  48. final sucursales = sucursalViewModel.sucursales;
  49. _selectedSucursal = sucursales.firstWhere(
  50. (sucursal) => sucursal.seleccionado == 1,
  51. orElse: () =>
  52. sucursales.isNotEmpty ? sucursales[0] : Sucursal(),
  53. );
  54. });
  55. });
  56. }
  57. });
  58. });
  59. }
  60. @override
  61. Widget build(BuildContext context) {
  62. final loginViewModel = Provider.of<LoginViewModel>(context);
  63. // Mostrar la pantalla de carga `Cargando` mientras verifica la sesión
  64. if (loginViewModel.isLoading) {
  65. return const Cargando();
  66. }
  67. final size = MediaQuery.sizeOf(context);
  68. final sucursalViewModel = Provider.of<SucursalViewModel>(context);
  69. final sucursales = sucursalViewModel.sucursales;
  70. final obscureText = loginViewModel.obscureText;
  71. final errores = loginViewModel.errores;
  72. return Scaffold(
  73. backgroundColor: const Color.fromRGBO(245, 245, 245, 1),
  74. body: SingleChildScrollView(
  75. child: Padding(
  76. padding: const EdgeInsets.all(8.0),
  77. child: Column(
  78. mainAxisAlignment: MainAxisAlignment.center,
  79. children: [
  80. SizedBox(height: size.width < 1200 ? 20 : 100),
  81. const Image(
  82. image: AssetImage('assets/logo.png'),
  83. height: 250,
  84. ),
  85. const Text(
  86. 'Inicie sesión para acceder al sistema',
  87. style: TextStyle(fontSize: 26, fontWeight: FontWeight.bold),
  88. textAlign: TextAlign.center,
  89. ),
  90. const SizedBox(height: 20),
  91. // Campo de correo
  92. SizedBox(
  93. width: size.width < 1200 ? size.width : size.width * .35,
  94. child: Card(
  95. elevation: 5,
  96. shape: RoundedRectangleBorder(
  97. borderRadius: BorderRadius.circular(15)),
  98. child: Padding(
  99. padding: const EdgeInsets.all(15),
  100. child: Column(
  101. children: [
  102. AppDropdownModel<Sucursal>(
  103. etiqueta: 'Seleccione una sucursal',
  104. hint: 'Elija una sucursal',
  105. selectedValue: _selectedSucursal,
  106. onChanged: (Sucursal? newValue) {
  107. setState(() {
  108. _selectedSucursal = newValue;
  109. });
  110. },
  111. items: sucursales.map((Sucursal sucursal) {
  112. return DropdownMenuItem<Sucursal>(
  113. value: sucursal,
  114. child: Text(
  115. sucursal.nombre ?? '',
  116. style: const TextStyle(color: Colors.black),
  117. ),
  118. );
  119. }).toList(),
  120. ),
  121. const SizedBox(height: 5),
  122. AppTextField(
  123. autofillHints: [AutofillHints.username],
  124. prefixIcon: const Icon(Icons.mail),
  125. etiqueta: 'Correo electrónico',
  126. hintText: 'Introduzca su correo electrónico',
  127. errorText: errores?['correo'],
  128. controller: _correo,
  129. keyboardType: TextInputType.emailAddress,
  130. ),
  131. const SizedBox(height: 5),
  132. AppTextField(
  133. prefixIcon: const Icon(Icons.lock),
  134. obscureText: obscureText,
  135. etiqueta: 'Contraseña',
  136. hintText: 'Introduzca su contraseña',
  137. errorText: errores?['contrasena'],
  138. controller: _contrasena,
  139. suffixIcon: IconButton(
  140. onPressed: () {
  141. loginViewModel.showPassword();
  142. },
  143. icon: obscureText
  144. ? const Icon(Icons.remove_red_eye_outlined)
  145. : const Icon(Icons.remove_red_eye),
  146. ),
  147. ),
  148. ],
  149. ),
  150. ),
  151. ),
  152. ),
  153. const SizedBox(height: 20),
  154. // Botón de login
  155. Align(
  156. alignment: Alignment.center,
  157. child: SizedBox(
  158. height: 75,
  159. width: 380,
  160. child: ElevatedButton(
  161. style: ButtonStyle(
  162. shape: MaterialStatePropertyAll(
  163. RoundedRectangleBorder(
  164. borderRadius: BorderRadius.circular(10),
  165. ),
  166. ),
  167. backgroundColor:
  168. MaterialStatePropertyAll(AppTheme.secondary),
  169. ),
  170. onPressed: () async {
  171. await loginViewModel.login(
  172. _correo.text, _contrasena.text);
  173. if (loginViewModel.status == Status.authenticated) {
  174. if (_selectedSucursal != null) {
  175. await sucursalViewModel
  176. .setSelectedSucursal(_selectedSucursal!);
  177. }
  178. Navigator.pushReplacement(
  179. context,
  180. MaterialPageRoute(
  181. builder: (context) => const HomeScreen()),
  182. );
  183. } else {
  184. String mensaje = "";
  185. if (loginViewModel.errores?["correo"] != null) {
  186. mensaje += "\n${loginViewModel.errores!["correo"]}";
  187. }
  188. if (mensaje.isNotEmpty && context.mounted) {
  189. return showDialog(
  190. context: context,
  191. builder: (context) {
  192. return AlertDialog(
  193. title: const Text("Alerta"),
  194. content: Text(mensaje),
  195. actions: [
  196. Row(children: [
  197. Expanded(
  198. child: TextButton(
  199. onPressed: () async {
  200. Navigator.pop(context);
  201. },
  202. child: const Text('Continuar'),
  203. ))
  204. ])
  205. ],
  206. );
  207. },
  208. );
  209. }
  210. }
  211. },
  212. child: const Row(
  213. mainAxisAlignment: MainAxisAlignment.center,
  214. children: [
  215. Text(
  216. 'Iniciar Sesión',
  217. style: TextStyle(fontSize: 18, color: Colors.white),
  218. ),
  219. ],
  220. ),
  221. ),
  222. ),
  223. ),
  224. const SizedBox(height: 20),
  225. ],
  226. ),
  227. ),
  228. ),
  229. );
  230. }
  231. }