import 'dart:io'; import 'package:flutter/material.dart'; import 'package:injector/injector.dart'; import 'package:intl/intl.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:image_picker/image_picker.dart'; import 'package:prosappco/blocs/auth_bloc/auth_bloc.dart'; import 'package:prosappco/blocs/my_user_bloc/my_user_bloc.dart'; import 'package:prosappco/blocs/profile_bloc/profile_bloc.dart'; import 'package:prosappco/components/birthday_picker.dart'; import 'package:prosappco/components/gender_dropdown.dart'; import 'package:prosappco/screens/lists/city_list_screen.dart'; import 'package:prosappco/screens/profile/components/profile_item.dart'; import 'package:prosappco/screens/profile/profile_register_email_screen.dart'; import 'package:prosappco/screens/profile/profile_register_phone_screen.dart'; import 'package:prosappco/screens/profile/profile_update_password_screen.dart'; class ProfileScreen extends StatefulWidget { const ProfileScreen({super.key}); @override State createState() => _ProfileScreenState(); } class _ProfileScreenState extends State { final TextEditingController _nameController = TextEditingController(); final TextEditingController _cityController = TextEditingController(); final TextEditingController _emailController = TextEditingController(); final TextEditingController _newEmailController = TextEditingController(); final TextEditingController _phoneController = TextEditingController(); final TextEditingController _birthdayController = TextEditingController(); final TextEditingController _genderController = TextEditingController(); final TextEditingController _passwordController = TextEditingController(); XFile? _imageFile; bool isLoading = false; late final AuthBloc authBloc; @override void initState() { super.initState(); authBloc = Injector.appInstance.get(); } @override void dispose() { _nameController.dispose(); _cityController.dispose(); _emailController.dispose(); _newEmailController.dispose(); _phoneController.dispose(); _birthdayController.dispose(); _genderController.dispose(); _passwordController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return BlocProvider( create: (context) => authBloc, child: BlocListener( listener: (context, state) { if (state is UpdateUserInfoLoading) { setState(() { isLoading = true; }); } else if (state is UpdateUserInfoSuccess) { ScaffoldMessenger.of(context).showSnackBar(const SnackBar( content: Text('Información actualizada'), )); setState(() { isLoading = false; }); } else if (state is UpdateUserInfoFailure) { ScaffoldMessenger.of(context).showSnackBar(const SnackBar( content: Text('Error al actualizar la información'), )); setState(() { isLoading = false; }); } }, child: Scaffold( appBar: AppBar( title: const Text('Perfil'), ), body: BlocBuilder( builder: (context, state) { if (state.status == MyUserStatus.success) { _nameController.text = state.user!.name ?? ''; _cityController.text = state.user!.city ?? ''; _emailController.text = state.user!.email ?? ''; _phoneController.text = state.user!.phone ?? ''; _birthdayController.text = state.user!.birthday ?? ''; _genderController.text = state.user!.gender ?? ''; return Column( children: [ Expanded( child: SingleChildScrollView( child: Padding( padding: const EdgeInsets.symmetric( horizontal: 40, vertical: 10), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ pictureWidget(state, context), const SizedBox(height: 30), TextFormField( controller: _nameController, decoration: const InputDecoration( labelText: 'Nombre', prefixIcon: Icon(Icons.person), hintText: 'Nombre (obligatorio)', border: OutlineInputBorder( borderRadius: BorderRadius.all( Radius.circular(10.0), )), errorBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.red), ), focusedErrorBorder: OutlineInputBorder( borderSide: BorderSide( color: Colors.red, width: 2.0), ), ), validator: (value) { if (value == null || value.isEmpty) { return 'Por favor, ingrese su nombre'; } return null; }, ), const SizedBox(height: 20.0), TextFormField( controller: _cityController, readOnly: true, onTap: () async { final cityName = await Navigator.push( context, CupertinoPageRoute( builder: (BuildContext context) { return const CityListScreen(); }, ), ); if (cityName != null) { _cityController.text = cityName; } }, decoration: const InputDecoration( labelText: 'Ciudad', prefixIcon: Icon(Icons.near_me_rounded), hintText: 'Selecciona tu ciudad', border: OutlineInputBorder( borderRadius: BorderRadius.all( Radius.circular(10.0), )), errorBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.red), ), focusedErrorBorder: OutlineInputBorder( borderSide: BorderSide( color: Colors.red, width: 2.0), ), ), validator: (value) { if (value == null || value.isEmpty) { return 'Por favor, ingrese su nombre'; } return null; }, ), _birthdayController.text.isEmpty && _genderController.text.isEmpty ? Column( children: [ const SizedBox(height: 20.0), BirthdayPicker( onDateSelected: (birthDay) { _birthdayController.text = DateFormat('dd/MM/yyyy') .format(birthDay); }, controller: _birthdayController, ), const SizedBox(height: 20.0), GenderDropdown( controller: _genderController, ), ], ) : const SizedBox(), const SizedBox(height: 20), ProfileItem( title: 'Configurar inicio de sesión con correo', subtitle: _emailController.text, leading: Icons.email_rounded, onTap: () { if (state.user!.name == null || state.user!.name == '') { ScaffoldMessenger.of(context) .clearSnackBars(); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text( 'Por favor, ingrese su nombre'))); return; } if (state.user!.city == null || state.user!.city == '') { ScaffoldMessenger.of(context) .clearSnackBars(); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text( 'Por favor, ingrese su ciudad'))); return; } Navigator.push( context, CupertinoPageRoute( builder: (context) => _emailController .text.isEmpty ? ProfileRegisterEmailScreen() : ProfileUpdatePasswordScreen( email: _emailController.text)), ); }, ), const SizedBox(height: 20), ProfileItem( title: 'Configurar inicio de sesión con celular', subtitle: _phoneController.text, leading: Icons.phone_iphone_rounded, onTap: () { if (state.user!.name == null || state.user!.name == '') { ScaffoldMessenger.of(context) .clearSnackBars(); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text( 'Por favor, ingrese su nombre'))); return; } if (state.user!.city == null || state.user!.city == '') { ScaffoldMessenger.of(context) .clearSnackBars(); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text( 'Por favor, ingrese su nombre'))); return; } if (_phoneController.text.isEmpty) { Navigator.push( context, CupertinoPageRoute( builder: (context) => const ProfileRegisterPhoneScreen(), ), ); } }, ), const SizedBox(height: 10), ], ), ), ), ), const Divider( height: 1, thickness: 0.5, ), Padding( padding: const EdgeInsets.symmetric( vertical: 10, horizontal: 15, ), child: saveButton(state, context), ), ], ); } else { return const Center(child: CircularProgressIndicator()); } }, ), ), ), ); } Widget saveButton(MyUserState state, BuildContext context) { return ElevatedButton( onPressed: () { if (isLoading) { return; } if (_nameController.text.isEmpty) { ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Por favor, ingrese su nombre'))); return; } if (_cityController.text.isEmpty) { ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Por favor, ingrese su ciudad'))); return; } final myUser = state.user!.copyWith( name: _nameController.text, city: _cityController.text, nickname: _nameController.text.trim().toLowerCase(), email: _emailController.text, phone: _phoneController.text, birthday: _birthdayController.text, gender: _genderController.text, ); context .read() .add(UpdateUserInfo(myUser: myUser, filePicture: _imageFile?.path)); ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Información actualizada...')), ); Navigator.pop(context); }, style: FilledButton.styleFrom( backgroundColor: Theme.of(context).colorScheme.primary, padding: const EdgeInsets.symmetric(vertical: 15), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), ), child: Container( alignment: Alignment.center, child: isLoading ? const CircularProgressIndicator( color: Colors.white, ) : const Text( 'Actualizar', style: TextStyle( color: Colors.white, fontSize: 18, ), ), ), ); } Widget pictureWidget(MyUserState state, BuildContext context) { final pictureUrl = state.user?.picture; final pathImageFile = _imageFile?.path; ImageProvider? imageProvider; if (pathImageFile != null && pathImageFile.isNotEmpty) { imageProvider = FileImage(File(pathImageFile)); } else if (pictureUrl != null && pictureUrl.isNotEmpty) { imageProvider = NetworkImage(pictureUrl); } return GestureDetector( onTap: () async { final ImagePicker picker = ImagePicker(); final XFile? image = await picker.pickImage( source: ImageSource.gallery, maxHeight: 500, maxWidth: 500, imageQuality: 40, ); if (image != null) { setState(() { _imageFile = image; }); } }, child: Hero( tag: 'picture-profile', child: pictureContainerWidget(imageProvider), ), ); } Widget pictureContainerWidget(ImageProvider? imageProvider) { final image = imageProvider == null ? null : DecorationImage( image: imageProvider, fit: BoxFit.contain, ); final widget = image == null ? Icon( CupertinoIcons.person, color: Colors.grey.shade400, size: 40, ) : null; return Container( width: 120, height: 120, decoration: BoxDecoration( color: Colors.grey.shade300, shape: BoxShape.circle, image: image, ), child: widget, ); } }