From d83130b01d63f05146bd3c7d2ba3c7e38376f57c Mon Sep 17 00:00:00 2001 From: Juan Felipe Duarte <70235683+DuarteJFelipe@users.noreply.github.com> Date: Thu, 6 Apr 2023 11:26:22 -0500 Subject: [PATCH] update --- .../authentication_repository.dart | 13 + lib/src/components/photo_view.dart | 37 ++ lib/src/screens/profile.dart | 372 ++++++++++++++---- lib/src/services/select_image_profile.dart | 13 + lib/src/services/upload_image.dart | 24 ++ macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 80 ++++ pubspec.yaml | 2 + 8 files changed, 472 insertions(+), 71 deletions(-) create mode 100644 lib/src/components/photo_view.dart create mode 100644 lib/src/services/select_image_profile.dart create mode 100644 lib/src/services/upload_image.dart diff --git a/lib/src/authentication/authentication_repository.dart b/lib/src/authentication/authentication_repository.dart index d45b713..e338e4c 100644 --- a/lib/src/authentication/authentication_repository.dart +++ b/lib/src/authentication/authentication_repository.dart @@ -143,4 +143,17 @@ class AuthenticationRepository extends GetxController { } return city; } + + Future getPhoto(String uid) async { + String photo = ''; + try { + final snapshot = + await FirebaseFirestore.instance.collection('users').doc(uid).get(); + final Map? data = snapshot.data(); + photo = data?['photo'] ?? ''; + } catch (e) { + print('Error getting photo: $e'); + } + return photo; + } } diff --git a/lib/src/components/photo_view.dart b/lib/src/components/photo_view.dart new file mode 100644 index 0000000..5b830fc --- /dev/null +++ b/lib/src/components/photo_view.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; + +class PhotoViewWidget extends StatelessWidget { + Bytes imageData; + PhotoViewWidget({required this.imageData}); + + @override + Widget build(BuildContext context) { + return Container( + margin: EdgeInsets.symmetric(vertical: 50), + child: ClipOval( + child: Image.memory( + imageData, + width: 60, + height: 60, + fit: BoxFit.cover, + ), + ), + ); + } +} + + +// Container( +// margin: EdgeInsets.symmetric(vertical: 50), +// width: 100, +// height: 100, +// decoration: BoxDecoration( +// color: Color(0xFF2BA4EC), +// borderRadius: BorderRadius.circular(50), +// ), +// child: Icon( +// Icons.person, +// color: Colors.white, +// size: 90, +// ), +// ); \ No newline at end of file diff --git a/lib/src/screens/profile.dart b/lib/src/screens/profile.dart index 372f91b..b1b0b8e 100644 --- a/lib/src/screens/profile.dart +++ b/lib/src/screens/profile.dart @@ -1,11 +1,13 @@ import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; +import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:intl_phone_field/countries.dart'; +import 'dart:io'; import 'package:prosappco/src/authentication/authentication_repository.dart'; import 'package:prosappco/src/controllers/add_name_email_city.dart'; -import 'package:prosappco/src/screens/welcome.dart'; +import 'package:prosappco/src/services/select_image_profile.dart'; +import 'package:prosappco/src/services/upload_image.dart'; class ProfileScreen extends StatefulWidget { ProfileScreen({Key? key}) : super(key: key); @@ -15,6 +17,10 @@ class ProfileScreen extends StatefulWidget { } class _ProfileScreenState extends State { + File? imagen_to_upload; + + bool _mostrarMenuDesplegable = true; + final uid = AuthenticationRepository.instance.getCurrentUserUid(); final _formKey = GlobalKey(); final controller = Get.put(NameEmailCityController()); @@ -22,13 +28,16 @@ class _ProfileScreenState extends State { final _nameController = TextEditingController(); final _emailController = TextEditingController(); late final FirebaseAuth _auth; - + final FirebaseStorage storage = FirebaseStorage.instance; + var photoTemp = ''; var _ciudad = '...'; + var _photo = '...'; @override void initState() { super.initState(); _auth = FirebaseAuth.instance; + final Reference ref = storage.ref().child(_photo); final currentUser = _auth.currentUser; @@ -50,9 +59,148 @@ class _ProfileScreenState extends State { _ciudad = s; })); } + + if (_photo == '...') { + AuthenticationRepository.instance + .getPhoto(uid.toString()) + .then((String s) => setState(() { + _photo = s; + })); + } + } + + Future 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 uploadImage(File image) async { + final String namefile = image.path.split('/').last; + + Reference ref = storage.ref().child('profile').child(namefile); + + final UploadTask uploadTask = ref.putFile(image); + + final TaskSnapshot snapshot = await uploadTask.whenComplete(() => true); + + photoTemp = ref.fullPath; + + if (snapshot.state == TaskState.success) { + return true; + } else { + return false; + } + } + + Future downloadImage(Reference ref) async { + try { + if (_photo == '...' || _photo.isEmpty) { + return GestureDetector( + onTap: () { + _showChoiceDialog(context); + }, + child: Container( + margin: EdgeInsets.symmetric(vertical: 50), + width: 100, + height: 100, + decoration: BoxDecoration( + color: Color(0xFF2BA4EC), + borderRadius: BorderRadius.circular(50), + ), + child: Icon( + Icons.person, + color: Colors.white, + size: 90, + ), + ), + ); + } else { + final imageData = await ref.getData(); + if (imageData != null) { + // final widgetImage = Image.memory(imageData); + final widgetImage = GestureDetector( + onTap: () { + _showChoiceDialog(context); + }, + child: Container( + margin: EdgeInsets.symmetric(vertical: 50), + child: ClipOval( + child: Image.memory( + imageData, + width: 60, + height: 60, + fit: BoxFit.cover, + ), + ), + ), + ); + return widgetImage; + } else { + return GestureDetector( + onTap: () { + _showChoiceDialog(context); + }, + child: Container( + margin: EdgeInsets.symmetric(vertical: 50), + width: 100, + height: 100, + decoration: BoxDecoration( + color: Color(0xFF2BA4EC), + borderRadius: BorderRadius.circular(50), + ), + child: Icon( + Icons.person, + color: Colors.white, + size: 90, + ), + ), + ); + } + } + } catch (e) { + print('XD $e'); + return GestureDetector( + onTap: () { + _showChoiceDialog(context); + }, + child: Container( + margin: EdgeInsets.symmetric(vertical: 50), + width: 100, + height: 100, + decoration: BoxDecoration( + color: Color(0xFF2BA4EC), + borderRadius: BorderRadius.circular(50), + ), + child: Icon( + Icons.person, + color: Colors.white, + size: 90, + ), + ), + ); + } } Future updateInfo() async { + final currentUser = _auth.currentUser; + String newName = _nameController.text.trim(); String newEmail = _emailController.text.trim(); @@ -71,46 +219,99 @@ class _ProfileScreenState extends State { return; } - try { - await FirebaseAuth.instance.currentUser!.updateDisplayName(newName); - await FirebaseFirestore.instance.collection('users').doc(uid).update({ - 'name': newName, - }); - print('Nombre actualizado correctamente'); - } catch (e) { - print('Error al actualizar el nombre: $e'); + if (currentUser?.displayName != newName) { + try { + await FirebaseAuth.instance.currentUser!.updateDisplayName(newName); + await FirebaseFirestore.instance.collection('users').doc(uid).update({ + 'name': newName, + }); + print('Nombre actualizado correctamente'); + } catch (e) { + print('Error al actualizar el nombre: $e'); + } + } + + if (currentUser?.email != newEmail) { + AuthCredential credential = + EmailAuthProvider.credential(email: newEmail, password: '654321'); + try { + await FirebaseAuth.instance.currentUser!.updateEmail(newEmail); + await FirebaseFirestore.instance.collection('users').doc(uid).update({ + 'email': newEmail, + }); + print('Correo electrónico actualizado correctamente'); + + // Reautentica al usuario con las credenciales proporcionadas + await FirebaseAuth.instance.currentUser! + .reauthenticateWithCredential(credential); + + // Actualiza el correo electrónico del usuario + await FirebaseAuth.instance.currentUser!.updateEmail(newEmail); + + // Actualiza los datos del usuario en tu base de datos + await FirebaseFirestore.instance.collection('users').doc(uid).update({ + 'email': newEmail, + }); + + print('Correo electrónico actualizado correctamente'); + } catch (e) { + print('Error al actualizar el correo electrónico: $e'); + } } try { - await FirebaseAuth.instance.currentUser!.updateEmail(newEmail); - await FirebaseFirestore.instance.collection('users').doc(uid).update({ - 'email': newEmail, - }); - print('Correo electrónico actualizado correctamente'); + if (imagen_to_upload == null) { + return; + } else { + final uploaded = await uploadImage(imagen_to_upload!); + updateImage(photoTemp); + } } catch (e) { - print('Error al actualizar el correo electrónico: $e'); + print('Error al actualizar la imagen de perfil $e'); } + } - AuthCredential credential = - EmailAuthProvider.credential(email: newEmail, password: '654321'); - - try { - // Reautentica al usuario con las credenciales proporcionadas - await FirebaseAuth.instance.currentUser! - .reauthenticateWithCredential(credential); - - // Actualiza el correo electrónico del usuario - await FirebaseAuth.instance.currentUser!.updateEmail(newEmail); - - // Actualiza los datos del usuario en tu base de datos - await FirebaseFirestore.instance.collection('users').doc(uid).update({ - 'email': newEmail, - }); - - print('Correo electrónico actualizado correctamente'); - } catch (e) { - print('Error al actualizar el correo electrónico: $e'); - } + Future _showChoiceDialog(BuildContext context) async { + return showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + content: SingleChildScrollView( + child: ListBody( + children: [ + GestureDetector( + child: Text( + textAlign: TextAlign.center, + "Tomar foto", + style: TextStyle(color: Color(0xFF2BA4EC)), + ), + onTap: () async { + final imagen = await getImage(1); + setState(() { + imagen_to_upload = File(imagen!.path); + }); + }, + ), + Divider(color: Colors.black54), + GestureDetector( + child: Text( + textAlign: TextAlign.center, + "Abrir Galería", + style: TextStyle(color: Color(0xFF2BA4EC)), + ), + onTap: () async { + final imagen = await getImage(2); + setState(() { + imagen_to_upload = File(imagen!.path); + }); + }, + ), + ], + ), + ), + ); + }, + ); } @override @@ -123,16 +324,17 @@ class _ProfileScreenState extends State { child: Scaffold( resizeToAvoidBottomInset: false, appBar: AppBar( - backgroundColor: Colors.white, - iconTheme: IconThemeData( + backgroundColor: Colors.white, + iconTheme: IconThemeData( + color: Colors.black, + ), + title: Text( + 'Perfil', + style: TextStyle( color: Colors.black, ), - title: Text( - 'Perfil', - style: TextStyle( - color: Colors.black, - ), - )), + ), + ), drawer: Drawer( child: ListView( padding: EdgeInsets.zero, @@ -162,18 +364,31 @@ class _ProfileScreenState extends State { ), ], ), - leading: Container( - width: 60, - height: 60, - decoration: BoxDecoration( - color: Color(0xFF2BA4EC), - borderRadius: BorderRadius.circular(50), - ), - child: Icon( - Icons.person, - color: Colors.white, - size: 55, - ), + leading: FutureBuilder( + future: + downloadImage(storage.ref().child(_photo)), + builder: (BuildContext context, + AsyncSnapshot snapshot) { + if (snapshot.connectionState == + ConnectionState.done && + snapshot.hasData) { + return snapshot.data!; + } else { + return Container( + width: 60, + height: 60, + decoration: BoxDecoration( + color: Color(0xFF2BA4EC), + borderRadius: BorderRadius.circular(50), + ), + child: Icon( + Icons.person, + color: Colors.white, + size: 55, + ), + ); + } + }, ), trailing: Icon(Icons.keyboard_arrow_right, color: Colors.black), @@ -340,20 +555,35 @@ class _ProfileScreenState extends State { body: Center( child: Column( children: [ - Container( - margin: EdgeInsets.symmetric(vertical: 50), - width: 100, - height: 100, - decoration: BoxDecoration( - color: Color(0xFF2BA4EC), - borderRadius: BorderRadius.circular(50), - ), - child: Icon( - Icons.person, - color: Colors.white, - size: 90, - ), - ), + imagen_to_upload != null + ? GestureDetector( + onTap: () { + _showChoiceDialog(context); + }, + child: Container( + margin: EdgeInsets.symmetric(vertical: 50), + child: ClipOval( + child: Image.file( + imagen_to_upload!, + width: 100, + height: 100, + fit: BoxFit.cover, + ), + ), + ), + ) + : FutureBuilder( + future: downloadImage(storage.ref().child(_photo)), + builder: (BuildContext context, + AsyncSnapshot snapshot) { + if (snapshot.connectionState == ConnectionState.done && + snapshot.hasData) { + return snapshot.data!; + } else { + return const CircularProgressIndicator(); + } + }, + ), Container( width: 300, padding: EdgeInsets.only(top: 0), diff --git a/lib/src/services/select_image_profile.dart b/lib/src/services/select_image_profile.dart new file mode 100644 index 0000000..a6f1dac --- /dev/null +++ b/lib/src/services/select_image_profile.dart @@ -0,0 +1,13 @@ +import 'package:image_picker/image_picker.dart'; + +Future getImage(opc) async { + final ImagePicker picker = ImagePicker(); + + if (opc == 1) { + XFile? image = await picker.pickImage(source: ImageSource.camera); + return image; + } else { + XFile? image = await picker.pickImage(source: ImageSource.gallery); + return image; + } +} diff --git a/lib/src/services/upload_image.dart b/lib/src/services/upload_image.dart new file mode 100644 index 0000000..3d5471f --- /dev/null +++ b/lib/src/services/upload_image.dart @@ -0,0 +1,24 @@ +import 'dart:io'; + +import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_storage/firebase_storage.dart'; + +// final FirebaseStorage storage = FirebaseStorage.instance; + +// Future uploadImage(File image) async { +// final String namefile = image.path.split('/').last; + +// Reference ref = storage.ref().child('profile').child(namefile); + +// final UploadTask uploadTask = ref.putFile(image); + +// final TaskSnapshot snapshot = await uploadTask.whenComplete(() => true); + +// final String url = await snapshot.ref.getDownloadURL(); + +// if (snapshot.state == TaskState.success) { +// return true; +// } else { +// return false; +// } +// } diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 804ef2f..2db5f1b 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -8,9 +8,11 @@ import Foundation import cloud_firestore import firebase_auth import firebase_core +import firebase_storage func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FLTFirebaseFirestorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseFirestorePlugin")) FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin")) FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) + FLTFirebaseStoragePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseStoragePlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 1841910..2453e6f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -73,6 +73,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.17.0" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "0b0036e8cccbfbe0555fd83c1d31a6f30b77a96b598b35a5d36dd41f718695e9" + url: "https://pub.dev" + source: hosted + version: "0.3.3+4" cupertino_icons: dependency: "direct main" description: @@ -145,6 +153,30 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.0" + firebase_storage: + dependency: "direct main" + description: + name: firebase_storage + sha256: a27909491c25acef90acc932be4d87bafb9d33fb98678edd2f81eaec9568a109 + url: "https://pub.dev" + source: hosted + version: "11.1.0" + firebase_storage_platform_interface: + dependency: transitive + description: + name: firebase_storage_platform_interface + sha256: f254e064890df4ee588f10bea06d679e047018910451a4bc3c529b9791adb0a9 + url: "https://pub.dev" + source: hosted + version: "4.2.0" + firebase_storage_web: + dependency: transitive + description: + name: firebase_storage_web + sha256: b6d3c104fecafdce5fe1795306d33856c9a11fa76f73fe7eb062430fc151d686 + url: "https://pub.dev" + source: hosted + version: "3.4.0" flutter: dependency: "direct main" description: flutter @@ -166,6 +198,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: c224ac897bed083dabf11f238dd11a239809b446740be0c2044608c50029ffdf + url: "https://pub.dev" + source: hosted + version: "2.0.9" flutter_test: dependency: "direct dev" description: flutter @@ -256,6 +296,46 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + image_picker: + dependency: "direct main" + description: + name: image_picker + sha256: cb25f04595a88450970dbe727243ba8cd21b6f7e0d7d1fc5b789fc6f52e95494 + url: "https://pub.dev" + source: hosted + version: "0.8.7+1" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: dfb5b0f28b8786fcc662b7ed42bfb4b82a6cbbd74da1958384b10d40bdf212a7 + url: "https://pub.dev" + source: hosted + version: "0.8.6+6" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: "98f50d6b9f294c8ba35e25cc0d13b04bfddd25dbc8d32fa9d566a6572f2c081c" + url: "https://pub.dev" + source: hosted + version: "2.1.12" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: d4cb8ab04f770dab9d04c7959e5f6d22e8c5280343d425f9344f93832cf58445 + url: "https://pub.dev" + source: hosted + version: "0.8.7+2" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + sha256: "1991219d9dbc42a99aff77e663af8ca51ced592cd6685c9485e3458302d3d4f8" + url: "https://pub.dev" + source: hosted + version: "2.6.3" intl: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index aed8155..ce59801 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -47,6 +47,8 @@ dependencies: intl_phone_field: ^3.1.0 cloud_firestore: ^4.5.0 diacritic: ^0.1.3 + firebase_storage: ^11.1.0 + image_picker: ^0.8.7+1 dev_dependencies: flutter_test: