478 lines
17 KiB
Dart
478 lines
17 KiB
Dart
import 'package:cloud_firestore/cloud_firestore.dart';
|
|
import 'package:firebase_auth/firebase_auth.dart';
|
|
import 'package:flutter/cupertino.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:intl/intl.dart';
|
|
import 'package:firebase_storage/firebase_storage.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:file_picker/file_picker.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:image_picker/image_picker.dart';
|
|
import 'package:prosappco/src/authentication/authentication_repository.dart';
|
|
import 'package:prosappco/src/components/photo_view_web.dart';
|
|
import 'package:prosappco/src/components/pop_appbar.dart';
|
|
import 'package:prosappco/src/screens/city.dart';
|
|
import 'package:prosappco/src/screens/new_number.dart';
|
|
import 'package:prosappco/src/screens/new_password.dart';
|
|
import 'package:universal_html/html.dart' as html;
|
|
|
|
class ProfileWebScreen extends StatefulWidget {
|
|
const ProfileWebScreen({super.key});
|
|
|
|
@override
|
|
State<ProfileWebScreen> createState() => _ProfileWebScreenState();
|
|
}
|
|
|
|
class _ProfileWebScreenState extends State<ProfileWebScreen> {
|
|
final uid = AuthenticationRepository.instance.getCurrentUserUid();
|
|
final FirebaseStorage storage = FirebaseStorage.instance;
|
|
late final FirebaseAuth _auth;
|
|
|
|
// variables imagen
|
|
String selectedImage = '';
|
|
XFile? file;
|
|
Uint8List? selectedImagInBytes;
|
|
String photoTemp = '';
|
|
|
|
// controladores
|
|
final _formKey = GlobalKey<FormState>();
|
|
final TextEditingController _nameController = TextEditingController();
|
|
final TextEditingController _emailController = TextEditingController();
|
|
final TextEditingController _phoneNumberController = TextEditingController();
|
|
final TextEditingController _passwordController = TextEditingController();
|
|
bool _obscureText = true;
|
|
|
|
// variables
|
|
String _ciudad = '...';
|
|
String _photo = '...';
|
|
String? _email = '';
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
|
|
final uid = AuthenticationRepository.instance.getCurrentUserUid();
|
|
_auth = FirebaseAuth.instance;
|
|
|
|
final currentUser = _auth.currentUser;
|
|
|
|
if (currentUser != null && currentUser.phoneNumber != null) {
|
|
_phoneNumberController.text = currentUser.phoneNumber!;
|
|
}
|
|
|
|
if (currentUser != null && currentUser.displayName != null) {
|
|
_nameController.text = currentUser.displayName!;
|
|
}
|
|
if (currentUser != null && currentUser.email != null) {
|
|
_emailController.text = currentUser.email!;
|
|
}
|
|
|
|
_email = currentUser?.email;
|
|
|
|
if (_ciudad == '...') {
|
|
AuthenticationRepository.instance
|
|
.getCity(uid.toString())
|
|
.then((String s) => setState(() {
|
|
_ciudad = s;
|
|
}));
|
|
}
|
|
|
|
if (_photo == '...') {
|
|
AuthenticationRepository.instance
|
|
.getPhoto(uid.toString())
|
|
.then((String s) => setState(() {
|
|
_photo = s;
|
|
}));
|
|
}
|
|
}
|
|
|
|
_selectFile(bool imageFrom) async {
|
|
FilePickerResult? fileResult = await FilePicker.platform.pickFiles();
|
|
|
|
if (fileResult != null) {
|
|
setState(() {
|
|
selectedImage = fileResult.files.first.name;
|
|
selectedImagInBytes = fileResult.files.first.bytes;
|
|
});
|
|
}
|
|
}
|
|
|
|
_uploadFile() async {
|
|
try {
|
|
final now = DateTime.now();
|
|
final formattedDate = DateFormat('HHmmssddMMyyyy').format(now);
|
|
final milliseconds = (now.microsecondsSinceEpoch / 1000).round();
|
|
final random = '$formattedDate$milliseconds';
|
|
|
|
final Reference ref = FirebaseStorage.instance
|
|
.ref()
|
|
.child('users')
|
|
.child(uid!)
|
|
.child('profile')
|
|
.child(random);
|
|
|
|
final metaData = SettableMetadata(contentType: 'image/jpeg');
|
|
|
|
final UploadTask uploadTask = ref.putData(selectedImagInBytes!, metaData);
|
|
|
|
final TaskSnapshot snapshot = await uploadTask.whenComplete(() => true);
|
|
|
|
photoTemp = ref.fullPath;
|
|
|
|
if (snapshot.state == TaskState.success) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
} catch (e) {
|
|
print('web image error - $e');
|
|
}
|
|
}
|
|
|
|
Future<void> updateInfo() async {
|
|
final currentUser = _auth.currentUser;
|
|
final currentPhoneNumber = _auth.currentUser!.phoneNumber;
|
|
|
|
String newName = _nameController.text.trim();
|
|
String newEmail = _emailController.text.trim();
|
|
String newPassword = _passwordController.text.trim();
|
|
|
|
if (newName.isEmpty) {
|
|
// Si el nuevo nombre está vacío, no lo actualizamos y mostramos un mensaje al usuario
|
|
Get.snackbar(
|
|
'Nombre Invalido',
|
|
'Ingrese un nombre válido.',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
);
|
|
return;
|
|
} else {
|
|
try {
|
|
await FirebaseAuth.instance.currentUser!.updateDisplayName(newName);
|
|
await FirebaseFirestore.instance.collection('users').doc(uid).update({
|
|
'name': newName,
|
|
'lowerName': newName.toLowerCase(),
|
|
});
|
|
print('Nombre actualizado correctamente');
|
|
} catch (e) {
|
|
print('Error al actualizar el nombre: $e');
|
|
}
|
|
}
|
|
if (newEmail.isEmpty) {
|
|
// Si el nuevo nombre está vacío, no lo actualizamos y mostramos un mensaje al usuario
|
|
Get.snackbar(
|
|
'Correo Invalido',
|
|
'Ingrese un email válido.',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
);
|
|
return;
|
|
}
|
|
if (currentUser?.displayName != newName) {
|
|
try {
|
|
await FirebaseAuth.instance.currentUser!.updateDisplayName(newName);
|
|
await FirebaseFirestore.instance.collection('users').doc(uid).update({
|
|
'name': newName,
|
|
'lowerName': newName.toLowerCase(),
|
|
});
|
|
print('Nombre actualizado correctamente');
|
|
} catch (e) {
|
|
print('Error al actualizar el nombre: $e');
|
|
}
|
|
}
|
|
|
|
if (currentUser?.email != newEmail) {
|
|
if (newPassword.isNotEmpty) {
|
|
await FirebaseFirestore.instance.collection('users').doc(uid).update({
|
|
'email': newEmail,
|
|
});
|
|
updateEmailAndPassword(newEmail, newPassword);
|
|
} else {
|
|
Get.snackbar(
|
|
'Contraseña Invalida',
|
|
'Porfavor ingrese una contraseña.',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
);
|
|
}
|
|
}
|
|
|
|
try {
|
|
await FirebaseFirestore.instance
|
|
.collection('users')
|
|
.doc(uid)
|
|
.update({'phoneNumber': currentPhoneNumber});
|
|
} catch (e) {
|
|
print('e');
|
|
}
|
|
|
|
try {
|
|
await FirebaseFirestore.instance
|
|
.collection('users')
|
|
.doc(uid)
|
|
.update({'email': newEmail});
|
|
} catch (e) {
|
|
print('e');
|
|
}
|
|
|
|
try {
|
|
if (selectedImagInBytes == null) {
|
|
return;
|
|
} else {
|
|
await _uploadFile();
|
|
updateImage(photoTemp);
|
|
}
|
|
} catch (e) {
|
|
print('Error al actualizar la imagen de perfil $e');
|
|
}
|
|
}
|
|
|
|
Future<void> updateImage(image) async {
|
|
try {
|
|
await FirebaseFirestore.instance
|
|
.collection('users')
|
|
.doc(uid)
|
|
.update({'photo': image});
|
|
|
|
print('imagen actualizada correctamente');
|
|
} catch (e) {
|
|
try {
|
|
await FirebaseFirestore.instance
|
|
.collection('users')
|
|
.doc(uid)
|
|
.set({'photo': image});
|
|
} catch (e) {
|
|
print('Error al agregar la imagen de perfil: $e');
|
|
}
|
|
|
|
print('Error al actualizar la imagen de perfil: $e');
|
|
}
|
|
}
|
|
|
|
Future<void> updateEmailAndPassword(String email, String password) async {
|
|
final User? user = FirebaseAuth.instance.currentUser;
|
|
if (user != null) {
|
|
try {
|
|
await user.updateEmail(email);
|
|
await user.updatePassword(password);
|
|
} catch (e) {
|
|
Get.snackbar(
|
|
'Agregar correo',
|
|
'Inicie sesión para asegurarnos de que seas tú .',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
);
|
|
AuthenticationRepository.instance.logout(uid!);
|
|
}
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
String city = _ciudad.toString();
|
|
|
|
return Scaffold(
|
|
backgroundColor: const Color(0xFFD6F4FF),
|
|
appBar: PopAppbar(
|
|
onPressed: () {
|
|
Navigator.pop(context);
|
|
},
|
|
label: 'Perfil'),
|
|
body: Center(
|
|
child: SizedBox(
|
|
width: 300,
|
|
height: 600,
|
|
child: Card(
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(10),
|
|
),
|
|
color: Colors.white,
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 20.0),
|
|
child: Form(
|
|
key: _formKey,
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Container(
|
|
padding: const EdgeInsets.only(top: 20, bottom: 20),
|
|
child: (selectedImagInBytes != null)
|
|
? LocalPhotoWeb(file: selectedImagInBytes)
|
|
: ReferencePhotoWeb(ref: storage.ref().child(_photo)),
|
|
),
|
|
TextFormField(
|
|
controller: _nameController,
|
|
maxLength: 50,
|
|
validator: (value) {
|
|
if (value == null || value.isEmpty) {
|
|
return 'Porfavor ingrese un nombre.';
|
|
}
|
|
if (value.length < 5) {
|
|
return 'Debe tener al menos 5 caracteres.';
|
|
}
|
|
return null;
|
|
},
|
|
decoration: const InputDecoration(
|
|
prefixIcon: Icon(Icons.person_outline),
|
|
hintText: 'Nombre (Obligatorio)',
|
|
),
|
|
),
|
|
_email != null
|
|
? TextFormField(
|
|
onTap: () {
|
|
Navigator.push(context, CupertinoPageRoute(
|
|
builder: (BuildContext context) {
|
|
return NewPasswordScreen();
|
|
},
|
|
));
|
|
},
|
|
readOnly: true,
|
|
controller: _emailController,
|
|
decoration: const InputDecoration(
|
|
prefixIcon: Icon(Icons.email_outlined),
|
|
hintText: 'Email (Obligatorio)',
|
|
),
|
|
)
|
|
: TextFormField(
|
|
controller: _emailController,
|
|
validator: (String? value) {
|
|
if (value == null || value.isEmpty) {
|
|
return 'Por favor ingrese un email';
|
|
}
|
|
final RegExp emailRegExp =
|
|
RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
|
|
if (!emailRegExp.hasMatch(value)) {
|
|
return 'Por favor ingrese un email válido';
|
|
}
|
|
return null;
|
|
},
|
|
decoration: const InputDecoration(
|
|
prefixIcon: Icon(Icons.email_outlined),
|
|
hintText: 'Email (Obligatorio)',
|
|
),
|
|
),
|
|
const SizedBox(height: 20.0),
|
|
_email != null
|
|
? const SizedBox.shrink()
|
|
: TextFormField(
|
|
controller: _passwordController,
|
|
obscureText: _obscureText,
|
|
validator: (value) {
|
|
if (value == null || value.isEmpty) {
|
|
return 'Porfavor ingrese una contraseña.';
|
|
}
|
|
if (value.length < 5) {
|
|
return 'Debe tener al menos 5 caracteres.';
|
|
}
|
|
return null;
|
|
},
|
|
decoration: InputDecoration(
|
|
prefixIcon: const Icon(Icons.lock_outline),
|
|
suffixIcon: IconButton(
|
|
icon: Icon(
|
|
_obscureText
|
|
? Icons.visibility
|
|
: Icons.visibility_off,
|
|
color: Colors.grey,
|
|
),
|
|
onPressed: () {
|
|
setState(() {
|
|
_obscureText = !_obscureText;
|
|
});
|
|
},
|
|
),
|
|
hintText: 'Contraseña (Obligatorio)',
|
|
),
|
|
),
|
|
_email != null
|
|
? const SizedBox.shrink()
|
|
: const SizedBox(height: 20.0),
|
|
TextFormField(
|
|
readOnly: true,
|
|
onTap: () async {
|
|
final String? ciudad = await Navigator.push(
|
|
context,
|
|
CupertinoPageRoute(
|
|
builder: (BuildContext context) {
|
|
return const CityScreen();
|
|
},
|
|
),
|
|
) as String?;
|
|
|
|
if (ciudad != null) {
|
|
setState(() {
|
|
_ciudad = ciudad;
|
|
});
|
|
}
|
|
},
|
|
decoration: InputDecoration(
|
|
prefixIcon: const Icon(Icons.near_me),
|
|
suffixIcon: const Icon(Icons.arrow_drop_down),
|
|
hintStyle: city == ''
|
|
? const TextStyle()
|
|
: const TextStyle(color: Colors.black87),
|
|
hintText: city == '' ? 'Ciudad' : city,
|
|
),
|
|
),
|
|
const SizedBox(height: 20.0),
|
|
TextFormField(
|
|
controller: _phoneNumberController,
|
|
readOnly: true,
|
|
onTap: () {
|
|
Navigator.of(context).push(
|
|
CupertinoPageRoute(
|
|
builder: (BuildContext context) {
|
|
return const NewNumberScreen();
|
|
},
|
|
),
|
|
);
|
|
},
|
|
decoration: const InputDecoration(
|
|
prefixIcon: Icon(Icons.phone_android),
|
|
suffixIcon: Icon(Icons.edit_outlined),
|
|
hintText: '+57'),
|
|
),
|
|
Container(
|
|
alignment: Alignment.bottomCenter,
|
|
margin: const EdgeInsets.only(top: 30),
|
|
padding: const EdgeInsets.only(bottom: 30),
|
|
child: ElevatedButton(
|
|
onPressed: () async {
|
|
if (_formKey.currentState!.validate()) {
|
|
await updateInfo().whenComplete(() {
|
|
html.window.location.reload();
|
|
|
|
Get.snackbar(
|
|
'Perfil',
|
|
'Información actualizada correctamente.',
|
|
snackPosition: SnackPosition.TOP,
|
|
);
|
|
});
|
|
}
|
|
},
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: const Color(0xFF2BA4EC),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(50),
|
|
),
|
|
elevation: 0,
|
|
minimumSize: const Size(200, 50),
|
|
),
|
|
child: const Text(
|
|
'Guardar',
|
|
style: TextStyle(
|
|
color: Colors.white,
|
|
fontWeight: FontWeight.bold,
|
|
fontSize: 17,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|