From 7c902696b6c9837c1d484640e020d72a4aebc371 Mon Sep 17 00:00:00 2001 From: Felipe Date: Mon, 30 Oct 2023 10:25:46 -0500 Subject: [PATCH] update y uso de provider --- lib/main.dart | 62 ++++++++------ lib/src/components/drawer_menu.dart | 115 +++++++++++++------------ lib/src/models/user_model.dart | 24 ++++++ lib/src/providers/user_provider.dart | 23 +++++ lib/src/screens/configuracion.dart | 122 +++++++++++++++++++++++---- lib/src/screens/profile.dart | 91 ++------------------ lib/src/screens/service.dart | 2 +- 7 files changed, 256 insertions(+), 183 deletions(-) create mode 100644 lib/src/providers/user_provider.dart diff --git a/lib/main.dart b/lib/main.dart index aeefee7..83da3a6 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,6 +3,7 @@ import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:intl/date_symbol_data_local.dart'; import 'package:prosappco/src/authentication/authentication_repository.dart'; +import 'package:prosappco/src/providers/user_provider.dart'; import 'package:prosappco/src/screens/calendar.dart'; import 'package:prosappco/src/screens/city.dart'; import 'package:prosappco/src/screens/login.dart'; @@ -25,6 +26,7 @@ import 'package:prosappco/src/services/local_notifications.dart'; import 'firebase_options.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/foundation.dart' show kIsWeb; +import 'package:provider/provider.dart'; Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async { await Firebase.initializeApp(); @@ -79,34 +81,38 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { - return GetMaterialApp( - theme: ThemeData(fontFamily: 'Poppins'), - debugShowCheckedModeBanner: false, - title: 'ProsApp', - initialRoute: '/', - routes: { - '/': (context) => const LoginScreen(), - '/splash': (context) => const SplashScreen(), - '/login': (context) => const LoginEmailScreen(), - '/profile': (context) => const ProfileScreen(), - '/register': (context) => const RegisterScreen(), - '/city': (context) => const CityScreen(), - '/profession': (context) => const ProfessionScreen(), - '/newNumber': (context) => const NewNumberScreen(), - '/profesionalRevision': (context) => const ProfessionalRevisionScreen(), - '/profesionalProfile': (context) => const ProfessionalProfileScreen(), - '/solicitudEnviada': (context) => const RequestSentScreen(), - '/nuevaPassword': (context) => NewPasswordScreen(), - '/servicio': (context) => const ServiceScreen(), - '/profilePro': (context) => const ProfileProScreen(), - '/calendar': (context) => const CalendarScreen(), - '/solicitud': (context) => SolicitudScreen(), - '/misserviciospro': (context) => const MyServicesProScreen(), - '/misservicios': (context) => MyServicesScreen(), - }, - onGenerateRoute: (settings) { - throw Exception('Ruta desconocida: ${settings.name}'); - }, + return MultiProvider( + providers: [ChangeNotifierProvider(create: (_) => UserProvider())], + child: GetMaterialApp( + theme: ThemeData(fontFamily: 'Poppins'), + debugShowCheckedModeBanner: false, + title: 'ProsApp', + initialRoute: '/', + routes: { + '/': (context) => const LoginScreen(), + '/splash': (context) => const SplashScreen(), + '/login': (context) => const LoginEmailScreen(), + '/profile': (context) => const ProfileScreen(), + '/register': (context) => const RegisterScreen(), + '/city': (context) => const CityScreen(), + '/profession': (context) => const ProfessionScreen(), + '/newNumber': (context) => const NewNumberScreen(), + '/profesionalRevision': (context) => + const ProfessionalRevisionScreen(), + '/profesionalProfile': (context) => const ProfessionalProfileScreen(), + '/solicitudEnviada': (context) => const RequestSentScreen(), + '/nuevaPassword': (context) => NewPasswordScreen(), + '/servicio': (context) => const ServiceScreen(), + '/profilePro': (context) => const ProfileProScreen(), + '/calendar': (context) => const CalendarScreen(), + '/solicitud': (context) => SolicitudScreen(), + '/misserviciospro': (context) => const MyServicesProScreen(), + '/misservicios': (context) => MyServicesScreen(), + }, + onGenerateRoute: (settings) { + throw Exception('Ruta desconocida: ${settings.name}'); + }, + ), ); } } diff --git a/lib/src/components/drawer_menu.dart b/lib/src/components/drawer_menu.dart index b1ba821..70508c6 100644 --- a/lib/src/components/drawer_menu.dart +++ b/lib/src/components/drawer_menu.dart @@ -7,6 +7,7 @@ import 'package:prosappco/src/authentication/authentication_repository.dart'; import 'package:prosappco/src/components/photo_view.dart'; import 'package:prosappco/src/models/scores_model.dart'; import 'package:prosappco/src/models/user_model.dart'; +import 'package:prosappco/src/providers/user_provider.dart'; import 'package:prosappco/src/screens/configuracion.dart'; import 'package:prosappco/src/screens/messages_user.dart'; import 'package:prosappco/src/screens/professional_profile_web.dart'; @@ -17,6 +18,7 @@ import 'package:prosappco/src/screens/support.dart'; import 'package:prosappco/src/screens/web_view.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:get/get.dart'; +import 'package:provider/provider.dart'; class DrawerMenu extends StatefulWidget { @override @@ -31,13 +33,6 @@ class _DrawerMenuState extends State { @override void initState() { super.initState(); - - if (user == null) { - UserModel.getUser(uid.toString()).then( - (UserModel s) => setState(() => user = s), - ); - } - if (scoresModel == null) { ScoresModel.scoreTo(uid.toString(), false, false).then( (ScoresModel s) => setState(() => scoresModel = s), @@ -57,7 +52,9 @@ class _DrawerMenuState extends State { @override Widget build(BuildContext context) { - final User? currentUser = FirebaseAuth.instance.currentUser; + final userProvider = Provider.of(context); + + // final UserModel? user = userProvider.user; return Drawer( child: Column( @@ -66,52 +63,18 @@ class _DrawerMenuState extends State { color: Colors.white, child: Column( children: [ - ListTile( - onTap: () { - if (kIsWeb) { - Navigator.push( - context, - CupertinoPageRoute( - builder: (BuildContext context) { - return const ProfileWebScreen(); - }, - ), - ); + StreamBuilder( + stream: userProvider.itemsStream, + builder: (BuildContext context, + AsyncSnapshot snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return Center(child: CircularProgressIndicator()); + } else if (snapshot.hasError) { + return Center(child: Text('Error: ${snapshot.error}')); } else { - Navigator.push( - context, - CupertinoPageRoute( - builder: (BuildContext context) { - return const ProfileScreen(); - }, - ), - ); + return infoUser(context, snapshot.data); } }, - title: Text(user?.name ?? '', - style: const TextStyle(fontWeight: FontWeight.bold)), - subtitle: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - currentUser?.phoneNumber ?? '', - style: const TextStyle(fontSize: 12), - ), - Text( - user?.city ?? '', - style: const TextStyle(fontSize: 12), - ), - ], - ), - leading: ReferencePhoto( - ref: user?.photo, - size: 55, - sizeCircle: 60, - ), - trailing: const Icon(Icons.keyboard_arrow_right, - color: Colors.black), - contentPadding: - const EdgeInsets.symmetric(vertical: 20, horizontal: 16), ), ], // ), @@ -392,7 +355,7 @@ class _DrawerMenuState extends State { snackPosition: SnackPosition.BOTTOM, ); } else { - if (currentUser?.phoneNumber != user?.phoneNumber) { + if (user?.phoneNumber != user?.phoneNumber) { Get.snackbar( 'Tu número de teléfono sigue sin cambios.', 'Para guardar esta información, dirígete a tu perfil y selecciona la opción Guardar', @@ -461,4 +424,52 @@ class _DrawerMenuState extends State { ), ); } + + ListTile infoUser(BuildContext context, UserModel? user) { + return ListTile( + onTap: () { + if (kIsWeb) { + Navigator.push( + context, + CupertinoPageRoute( + builder: (BuildContext context) { + return const ProfileWebScreen(); + }, + ), + ); + } else { + Navigator.push( + context, + CupertinoPageRoute( + builder: (BuildContext context) { + return const ProfileScreen(); + }, + ), + ); + } + }, + title: Text(user?.name ?? '', + style: const TextStyle(fontWeight: FontWeight.bold)), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + user?.phoneNumber ?? '', + style: const TextStyle(fontSize: 12), + ), + Text( + user?.city ?? '', + style: const TextStyle(fontSize: 12), + ), + ], + ), + leading: ReferencePhoto( + ref: user?.photo, + size: 55, + sizeCircle: 60, + ), + trailing: const Icon(Icons.keyboard_arrow_right, color: Colors.black), + contentPadding: const EdgeInsets.symmetric(vertical: 20, horizontal: 16), + ); + } } diff --git a/lib/src/models/user_model.dart b/lib/src/models/user_model.dart index 15cecb9..b7b5d31 100644 --- a/lib/src/models/user_model.dart +++ b/lib/src/models/user_model.dart @@ -37,6 +37,30 @@ class UserModel { } } + @override + String toString() { + return 'UserModel(name: $name, city: $city, profession: $profession, state: $state, tarifa: $tarifa, phoneNumber: $phoneNumber, token: $token)'; + } + + static UserModel fromFirestore(Map firestoreMap) { + try { + String? avatar = firestoreMap['photo']; + return UserModel( + firestoreMap['name'] ?? 'Sin nombre', + firestoreMap['city'] ?? 'Sin ciudad', + firestoreMap['profesion'], + firestoreMap['estado'], + avatar != null ? storage.ref().child(avatar) : null, + firestoreMap['tarifa'] ?? 0, + firestoreMap['phoneNumber'] ?? 'Sin numero', + firestoreMap['token'], + ); + } catch (e) { + print('DesdeProvider $e'); + return UserModel('', '', '', null, null, 0, '', ''); + } + } + static Future getUser(String uid) async { try { final snapshot = diff --git a/lib/src/providers/user_provider.dart b/lib/src/providers/user_provider.dart new file mode 100644 index 0000000..d219d81 --- /dev/null +++ b/lib/src/providers/user_provider.dart @@ -0,0 +1,23 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter/material.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:prosappco/src/models/user_model.dart'; + +class UserProvider extends ChangeNotifier { + final FirebaseFirestore _firestore = FirebaseFirestore.instance; + Stream? _itemsStream; + + UserProvider() { + _itemsStream = _firestore + .collection('users') + .doc(FirebaseAuth.instance.currentUser?.uid) + .snapshots() + .map((event) { + final data = event.data() as Map; + + return UserModel.fromFirestore(data); + }); + } + + Stream? get itemsStream => _itemsStream; +} diff --git a/lib/src/screens/configuracion.dart b/lib/src/screens/configuracion.dart index a3e92f9..7dd08d0 100644 --- a/lib/src/screens/configuracion.dart +++ b/lib/src/screens/configuracion.dart @@ -1,11 +1,88 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:get/get.dart'; import 'package:prosappco/src/components/pop_appbar.dart'; import 'package:prosappco/src/screens/about.dart'; -class ConfiguracionScreen extends StatelessWidget { +class ConfiguracionScreen extends StatefulWidget { const ConfiguracionScreen({super.key}); + @override + State createState() => _ConfiguracionScreenState(); +} + +class _ConfiguracionScreenState extends State { + late final FirebaseAuth _auth; + + @override + void initState() { + super.initState(); + _auth = FirebaseAuth.instance; + } + + Future deleteAccount() async { + try { + final currentUser = _auth.currentUser; + + if (currentUser != null) { + final uid = currentUser.uid; + + await FirebaseFirestore.instance.collection('users').doc(uid).delete(); + + await currentUser.delete(); + + await _auth.signOut(); + + Get.snackbar( + 'Cuenta Eliminada', + 'Tu cuenta ha sido eliminada con éxito.', + snackPosition: SnackPosition.BOTTOM, + ); + } + } catch (e) { + Get.snackbar( + 'Error al Eliminar Cuenta', + 'Hubo un error al eliminar tu cuenta. Por favor, inténtalo de nuevo más tarde.', + snackPosition: SnackPosition.BOTTOM, + ); + } + } + + Future _showDeleteAccountConfirmationDialog( + BuildContext context) async { + return showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Eliminar Cuenta'), + content: const Text( + '¿Estás seguro de que deseas eliminar tu cuenta? Esta acción no se puede deshacer.'), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: const Text('Cancelar'), + ), + TextButton( + onPressed: () { + deleteAccount(); + Navigator.of(context).pop(); + }, + child: const Text( + 'Eliminar', + style: + TextStyle(color: Colors.red, fontWeight: FontWeight.w600), + ), + ), + ], + ); + }, + ); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -14,22 +91,35 @@ class ConfiguracionScreen extends StatelessWidget { Navigator.pop(context); }, label: 'Configuración'), - body: ListTile( - onTap: () { - Navigator.push( - context, - CupertinoPageRoute( - builder: (BuildContext context) { - return const AboutScreen(); - }, + body: ListView( + children: [ + ListTile( + onTap: () { + Navigator.push( + context, + CupertinoPageRoute( + builder: (BuildContext context) { + return const AboutScreen(); + }, + ), + ); + }, + title: const Text('Acerca de la aplicación'), + trailing: const Icon( + Icons.keyboard_arrow_right, + color: Colors.black, ), - ); - }, - title: const Text('Acerca de la aplicación'), - trailing: const Icon( - Icons.keyboard_arrow_right, - color: Colors.black, - ), + ), + ListTile( + onTap: () { + _showDeleteAccountConfirmationDialog(context); + }, + title: const Text( + 'Eliminar cuenta', + style: TextStyle(color: Colors.red), + ), + ), + ], ), ); } diff --git a/lib/src/screens/profile.dart b/lib/src/screens/profile.dart index a3fb9e5..cf90fa6 100644 --- a/lib/src/screens/profile.dart +++ b/lib/src/screens/profile.dart @@ -9,11 +9,12 @@ import 'package:intl/intl.dart'; import 'package:prosappco/src/authentication/authentication_repository.dart'; import 'package:prosappco/src/components/pop_appbar.dart'; import 'package:prosappco/src/controllers/add_name_email_city.dart'; +import 'package:prosappco/src/providers/user_provider.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:prosappco/src/services/select_image_profile.dart'; - +import 'package:provider/provider.dart'; import '../components/photo_view.dart'; class ProfileScreen extends StatefulWidget { @@ -293,6 +294,8 @@ class _ProfileScreenState extends State { } catch (e) { print('Error al actualizar la imagen de perfil $e'); } + + // notifyListeners(); } Future _updateEmail(String newEmail) async { @@ -376,67 +379,6 @@ class _ProfileScreenState extends State { } } - Future deleteAccount() async { - try { - final currentUser = _auth.currentUser; - - if (currentUser != null) { - final uid = currentUser.uid; - - await FirebaseFirestore.instance.collection('users').doc(uid).delete(); - - await currentUser.delete(); - - await _auth.signOut(); - - Get.snackbar( - 'Cuenta Eliminada', - 'Tu cuenta ha sido eliminada con éxito.', - snackPosition: SnackPosition.BOTTOM, - ); - } - } catch (e) { - Get.snackbar( - 'Error al Eliminar Cuenta', - 'Hubo un error al eliminar tu cuenta. Por favor, inténtalo de nuevo más tarde.', - snackPosition: SnackPosition.BOTTOM, - ); - } - } - - Future _showDeleteAccountConfirmationDialog( - BuildContext context) async { - return showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Eliminar Cuenta'), - content: const Text( - '¿Estás seguro de que deseas eliminar tu cuenta? Esta acción no se puede deshacer.'), - actions: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(); - }, - child: const Text('Cancelar'), - ), - TextButton( - onPressed: () { - deleteAccount(); - Navigator.of(context).pop(); - }, - child: const Text( - 'Eliminar', - style: - TextStyle(color: Colors.red, fontWeight: FontWeight.w600), - ), - ), - ], - ); - }, - ); - } - Future _showChoiceDialog(BuildContext context) async { return showDialog( context: context, @@ -484,6 +426,7 @@ class _ProfileScreenState extends State { @override Widget build(BuildContext context) { + final userProvider = Provider.of(context); String city = _ciudad.toString(); return Scaffold( @@ -675,30 +618,6 @@ class _ProfileScreenState extends State { ), ), ), - const SizedBox(height: 15), - ElevatedButton( - onPressed: () { - _showDeleteAccountConfirmationDialog(context); - }, - style: ElevatedButton.styleFrom( - backgroundColor: - Colors.red, // Puedes elegir un color adecuado - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(50), - ), - elevation: 0, - minimumSize: const Size(300, 45), - ), - child: const Text( - 'Eliminar Cuenta', - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - fontSize: 17, - ), - ), - ), - const SizedBox(height: 40), ElevatedButton( onPressed: () async { if (_formKey.currentState!.validate()) { diff --git a/lib/src/screens/service.dart b/lib/src/screens/service.dart index f955299..52792c5 100644 --- a/lib/src/screens/service.dart +++ b/lib/src/screens/service.dart @@ -252,7 +252,7 @@ class _ServiceScreenState extends State { setState(() { appVersion = version; - print('Version de app $appVersion - version de firebase $settings'); + // print('Version de app $appVersion - version de firebase $settings'); }); if (settings != null) {