This commit is contained in:
lizandrogd
2023-09-15 15:52:59 -05:00
43 changed files with 1692 additions and 1357 deletions
+1 -1
View File
@@ -46,7 +46,7 @@ android {
defaultConfig { defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.prosappco" applicationId "com.prosapp.prosapp"
// You can update the following values to match your application needs. // You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion "21".toInteger() minSdkVersion "21".toInteger()
+5 -5
View File
@@ -8,18 +8,18 @@
"client": [ "client": [
{ {
"client_info": { "client_info": {
"mobilesdk_app_id": "1:245204384533:android:12920d0fe3ec9b999f871c", "mobilesdk_app_id": "1:245204384533:android:e01772831d86f5c79f871c",
"android_client_info": { "android_client_info": {
"package_name": "com.example.prosappco" "package_name": "com.prosapp.prosapp"
} }
}, },
"oauth_client": [ "oauth_client": [
{ {
"client_id": "245204384533-7p2j0go97da4gp062s7enop0ab8q7a7p.apps.googleusercontent.com", "client_id": "245204384533-23bm14294ctm728nd9u83eiapsjfebhu.apps.googleusercontent.com",
"client_type": 1, "client_type": 1,
"android_info": { "android_info": {
"package_name": "com.example.prosappco", "package_name": "com.prosapp.prosapp",
"certificate_hash": "e0e88a66931385d2626f8531e7cbbb5722df7b4b" "certificate_hash": "29ac5d7d1b88c755a084a0ad5d561dd62d795eb5"
} }
}, },
{ {
+4
View File
@@ -14,6 +14,7 @@
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
ADF3D9B31D73179ECCE7D3BB /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 47D29BFFEE062A72D9E6E12A /* GoogleService-Info.plist */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */ /* Begin PBXCopyFilesBuildPhase section */
@@ -33,6 +34,7 @@
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
47D29BFFEE062A72D9E6E12A /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
@@ -88,6 +90,7 @@
97C146EF1CF9000F007C117D /* Products */, 97C146EF1CF9000F007C117D /* Products */,
E5C876AEF0D01DE572D83FC4 /* Pods */, E5C876AEF0D01DE572D83FC4 /* Pods */,
5F3EBDC617D1ACB18B4906E0 /* Frameworks */, 5F3EBDC617D1ACB18B4906E0 /* Frameworks */,
47D29BFFEE062A72D9E6E12A /* GoogleService-Info.plist */,
); );
sourceTree = "<group>"; sourceTree = "<group>";
}; };
@@ -192,6 +195,7 @@
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
ADF3D9B31D73179ECCE7D3BB /* GoogleService-Info.plist in Resources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
+3 -3
View File
@@ -5,15 +5,15 @@
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string> <string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key> <key>CFBundleDisplayName</key>
<string>Prosappco</string> <string>Prosapp</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string> <string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <string>com.prosapp.prosapp</string>
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundleName</key> <key>CFBundleName</key>
<string>prosappco</string> <string>prosapp</string>
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"file_generated_by": "FlutterFire CLI", "file_generated_by": "FlutterFire CLI",
"purpose": "FirebaseAppID & ProjectID for this Firebase app in this directory", "purpose": "FirebaseAppID & ProjectID for this Firebase app in this directory",
"GOOGLE_APP_ID": "1:245204384533:ios:aeb233e55c5ddf7a9f871c", "GOOGLE_APP_ID": "1:245204384533:ios:1d58f5624d0df4859f871c",
"FIREBASE_PROJECT_ID": "prosapp-5747a", "FIREBASE_PROJECT_ID": "prosapp-5747a",
"GCM_SENDER_ID": "245204384533" "GCM_SENDER_ID": "245204384533"
} }
+10 -5
View File
@@ -49,35 +49,40 @@ class DefaultFirebaseOptions {
messagingSenderId: '245204384533', messagingSenderId: '245204384533',
projectId: 'prosapp-5747a', projectId: 'prosapp-5747a',
authDomain: 'prosapp-5747a.firebaseapp.com', authDomain: 'prosapp-5747a.firebaseapp.com',
databaseURL: 'https://prosapp-5747a-default-rtdb.firebaseio.com',
storageBucket: 'prosapp-5747a.appspot.com', storageBucket: 'prosapp-5747a.appspot.com',
measurementId: 'G-EVBEQRZEDY',
); );
static const FirebaseOptions android = FirebaseOptions( static const FirebaseOptions android = FirebaseOptions(
apiKey: 'AIzaSyBp7vsJvD6oXz0FORBLEeIELwId4a2onHQ', apiKey: 'AIzaSyBp7vsJvD6oXz0FORBLEeIELwId4a2onHQ',
appId: '1:245204384533:android:12920d0fe3ec9b999f871c', appId: '1:245204384533:android:e01772831d86f5c79f871c',
messagingSenderId: '245204384533', messagingSenderId: '245204384533',
projectId: 'prosapp-5747a', projectId: 'prosapp-5747a',
databaseURL: 'https://prosapp-5747a-default-rtdb.firebaseio.com',
storageBucket: 'prosapp-5747a.appspot.com', storageBucket: 'prosapp-5747a.appspot.com',
); );
static const FirebaseOptions ios = FirebaseOptions( static const FirebaseOptions ios = FirebaseOptions(
apiKey: 'AIzaSyDUhnkNkeEPkqcwVo5EWr63q3oEX6bDGic', apiKey: 'AIzaSyDUhnkNkeEPkqcwVo5EWr63q3oEX6bDGic',
appId: '1:245204384533:ios:aeb233e55c5ddf7a9f871c', appId: '1:245204384533:ios:1d58f5624d0df4859f871c',
messagingSenderId: '245204384533', messagingSenderId: '245204384533',
projectId: 'prosapp-5747a', projectId: 'prosapp-5747a',
databaseURL: 'https://prosapp-5747a-default-rtdb.firebaseio.com',
storageBucket: 'prosapp-5747a.appspot.com', storageBucket: 'prosapp-5747a.appspot.com',
androidClientId: '245204384533-7p2j0go97da4gp062s7enop0ab8q7a7p.apps.googleusercontent.com', androidClientId: '245204384533-04oabs744hp8fjbdreijp4h16nvfmeti.apps.googleusercontent.com',
iosClientId: '245204384533-nv7e2n7d4vj5kfkc55mlmiiju0ch2qhn.apps.googleusercontent.com', iosClientId: '245204384533-nv7e2n7d4vj5kfkc55mlmiiju0ch2qhn.apps.googleusercontent.com',
iosBundleId: 'com.example.prosappco', iosBundleId: 'com.example.prosappco',
); );
static const FirebaseOptions macos = FirebaseOptions( static const FirebaseOptions macos = FirebaseOptions(
apiKey: 'AIzaSyDUhnkNkeEPkqcwVo5EWr63q3oEX6bDGic', apiKey: 'AIzaSyDUhnkNkeEPkqcwVo5EWr63q3oEX6bDGic',
appId: '1:245204384533:ios:aeb233e55c5ddf7a9f871c', appId: '1:245204384533:ios:1d58f5624d0df4859f871c',
messagingSenderId: '245204384533', messagingSenderId: '245204384533',
projectId: 'prosapp-5747a', projectId: 'prosapp-5747a',
databaseURL: 'https://prosapp-5747a-default-rtdb.firebaseio.com',
storageBucket: 'prosapp-5747a.appspot.com', storageBucket: 'prosapp-5747a.appspot.com',
androidClientId: '245204384533-7p2j0go97da4gp062s7enop0ab8q7a7p.apps.googleusercontent.com', androidClientId: '245204384533-04oabs744hp8fjbdreijp4h16nvfmeti.apps.googleusercontent.com',
iosClientId: '245204384533-nv7e2n7d4vj5kfkc55mlmiiju0ch2qhn.apps.googleusercontent.com', iosClientId: '245204384533-nv7e2n7d4vj5kfkc55mlmiiju0ch2qhn.apps.googleusercontent.com',
iosBundleId: 'com.example.prosappco', iosBundleId: 'com.example.prosappco',
); );
+23 -24
View File
@@ -1,4 +1,4 @@
import 'package:animated_splash_screen/animated_splash_screen.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
@@ -25,8 +25,9 @@ import 'package:prosappco/src/screens/solicitudes.dart';
import 'package:prosappco/src/services/local_notifications.dart'; import 'package:prosappco/src/services/local_notifications.dart';
import 'firebase_options.dart'; import 'firebase_options.dart';
import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_web_plugins/url_strategy.dart'; //import 'package:flutter_web_plugins/url_strategy.dart';
import 'package:flutter/foundation.dart' show kIsWeb; // Importa kIsWeb import 'package:flutter/foundation.dart' show kIsWeb; // Importa kIsWeb
//import 'dart:html' as html;
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async { Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp(); await Firebase.initializeApp();
@@ -40,30 +41,28 @@ void main() async {
options: DefaultFirebaseOptions.currentPlatform, options: DefaultFirebaseOptions.currentPlatform,
).then((value) => Get.put(AuthenticationRepository())); ).then((value) => Get.put(AuthenticationRepository()));
FirebaseMessaging.onBackgroundMessage((_firebaseMessagingBackgroundHandler)); // Evitar la solicitud de permiso en la versión web
if (!kIsWeb) {
FirebaseMessaging messaging = FirebaseMessaging.instance;
FirebaseMessaging messaging = FirebaseMessaging.instance; NotificationSettings settings = await messaging.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
NotificationSettings settings = await messaging.requestPermission( print('User granted permission: ${settings.authorizationStatus}');
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
FirebaseMessaging.onMessage.listen((RemoteMessage message) { FirebaseMessaging.onBackgroundMessage((_firebaseMessagingBackgroundHandler));
print('Got a message whilst in the foreground!');
print('Message data: ${message.data}');
if (message.notification != null) { FirebaseMessaging.onMessage.listen((RemoteMessage message) {
print('Message also contained a notification: ${message.notification}'); // Tu código para manejar las notificaciones aquí
} });
}); }
print('User granted permission: ${settings.authorizationStatus}');
await initNotifications(); await initNotifications();
@@ -73,7 +72,7 @@ void main() async {
DeviceOrientation.portraitUp, DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown, DeviceOrientation.portraitDown,
]); ]);
usePathUrlStrategy();
runApp(const MyApp()); runApp(const MyApp());
} }
@@ -88,8 +87,8 @@ class MyApp extends StatelessWidget {
title: 'ProsApp', title: 'ProsApp',
initialRoute: '/', initialRoute: '/',
routes: { routes: {
'/splash': (context) => const SplashScreen(),
'/': (context) => const LoginScreen(), '/': (context) => const LoginScreen(),
'/splash': (context) => const SplashScreen(),
'/login': (context) => const LoginEmailScreen(), '/login': (context) => const LoginEmailScreen(),
'/profile': (context) => const ProfileScreen(), '/profile': (context) => const ProfileScreen(),
'/register': (context) => const RegisterScreen(), '/register': (context) => const RegisterScreen(),
+21 -5
View File
@@ -14,6 +14,7 @@ import 'package:prosappco/src/screens/profile.dart';
import 'package:prosappco/src/screens/profile_web.dart'; import 'package:prosappco/src/screens/profile_web.dart';
import 'package:prosappco/src/screens/reputation.dart'; import 'package:prosappco/src/screens/reputation.dart';
import 'package:prosappco/src/screens/support.dart'; import 'package:prosappco/src/screens/support.dart';
import 'package:prosappco/src/screens/web_view.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
@@ -46,7 +47,7 @@ class _DrawerMenuState extends State<DrawerMenu> {
Future<void> _irSugerencias() async { Future<void> _irSugerencias() async {
const url = const url =
'https://admin.prosapp.co/sugerencias '; // Aquí debes poner la URL a la que quieres dirigirte 'https://admin.prosapp.co/sugerencias'; // Aquí debes poner la URL a la que quieres dirigirte
if (await canLaunch(url)) { if (await canLaunch(url)) {
await launch(url); await launch(url);
} else { } else {
@@ -224,7 +225,22 @@ class _DrawerMenuState extends State<DrawerMenu> {
), ),
), ),
ListTile( ListTile(
onTap: _irSugerencias, onTap: () {
if (kIsWeb) {
_irSugerencias();
} else {
Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext context) {
return WebViewScreen(
label: 'Sugerencias',
link: 'https://admin.prosapp.co/sugerencias');
},
),
);
}
},
leading: const Icon( leading: const Icon(
Icons.campaign_outlined, Icons.campaign_outlined,
color: Colors.black, color: Colors.black,
@@ -390,14 +406,14 @@ class _DrawerMenuState extends State<DrawerMenu> {
user?.phoneNumber == null) { user?.phoneNumber == null) {
Get.snackbar( Get.snackbar(
'Completa tu perfil', 'Completa tu perfil',
'Para ser un profesional registrado, completa tu perfil. No olvides guardar tus cambios para que sean efectivos.', 'Para ser un profesional registrado, asegúrate de llenar todos los campos necesarios y no olvides guardar tus cambios para que surtan efecto.',
snackPosition: SnackPosition.BOTTOM, snackPosition: SnackPosition.BOTTOM,
); );
} else { } else {
if (currentUser?.phoneNumber != user?.phoneNumber) { if (currentUser?.phoneNumber != user?.phoneNumber) {
Get.snackbar( Get.snackbar(
'Número de teléfono sin cambios', 'Tu número de teléfono sigue sin cambios.',
'Tu número de teléfono no se ha actualizado. Para guardar los cambios, ve al apartado de perfil y presiona en "Guardar".', 'Para guardar esta información, dirígete a tu perfil y selecciona la opción Guardar',
snackPosition: SnackPosition.BOTTOM, snackPosition: SnackPosition.BOTTOM,
); );
} else { } else {
+17 -1
View File
@@ -14,6 +14,7 @@ import 'package:prosappco/src/screens/profile.dart';
import 'package:prosappco/src/screens/profile_pro.dart'; import 'package:prosappco/src/screens/profile_pro.dart';
import 'package:prosappco/src/screens/profile_pro_web.dart'; import 'package:prosappco/src/screens/profile_pro_web.dart';
import 'package:prosappco/src/screens/reputacion_pro.dart'; import 'package:prosappco/src/screens/reputacion_pro.dart';
import 'package:prosappco/src/screens/web_view.dart';
import '../models/scores_model.dart'; import '../models/scores_model.dart';
import '../screens/configuracion.dart'; import '../screens/configuracion.dart';
import '../screens/support.dart'; import '../screens/support.dart';
@@ -211,7 +212,22 @@ class _DrawerProfessionalState extends State<DrawerProfessional> {
), ),
), ),
ListTile( ListTile(
onTap: _irSugerencias, onTap: () {
if (kIsWeb) {
_irSugerencias();
} else {
Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext context) {
return WebViewScreen(
label: 'Sugerencias',
link: 'https://admin.prosapp.co/sugerencias');
},
),
);
}
},
leading: const Icon( leading: const Icon(
Icons.campaign_outlined, Icons.campaign_outlined,
color: Colors.black, color: Colors.black,
+21 -7
View File
@@ -3,26 +3,40 @@ import 'package:flutter/material.dart';
class PrimaryButtom extends StatelessWidget { class PrimaryButtom extends StatelessWidget {
final VoidCallback onPressed; final VoidCallback onPressed;
final String label; final String label;
final bool
isEnabled; // Nuevo parámetro para indicar si el botón está habilitado
const PrimaryButtom( const PrimaryButtom({
{super.key, required this.onPressed, required this.label}); Key? key,
required this.onPressed,
required this.label,
this.isEnabled = true, // Valor predeterminado: habilitado
}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ElevatedButton( return ElevatedButton(
onPressed: onPressed, onPressed: isEnabled
? onPressed
: null, // Habilita/deshabilita el botón según isEnabled
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF2BA4EC), backgroundColor: isEnabled
? const Color(0xFF2BA4EC)
: Colors.grey, // Cambia el color de fondo
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50), borderRadius: BorderRadius.circular(50),
), ),
elevation: 0, elevation: isEnabled
? 0
: 0, // Cambia la elevación para dar una sensación de clickeabilidad
minimumSize: const Size(230, 60), minimumSize: const Size(230, 60),
), ),
child: Text( child: Text(
label, label,
style: const TextStyle( style: TextStyle(
color: Colors.white, color: isEnabled
? Colors.white
: Colors.black, // Cambia el color del texto
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 18, fontSize: 18,
), ),
+2 -2
View File
@@ -170,7 +170,7 @@ class _CalendarScreenState extends State<CalendarScreen> {
content: StatefulBuilder( content: StatefulBuilder(
builder: (BuildContext context, StateSetter setStateDialog) { builder: (BuildContext context, StateSetter setStateDialog) {
return SizedBox( return SizedBox(
height: 350, height: 800,
child: Column( child: Column(
children: [ children: [
Padding( Padding(
@@ -352,7 +352,7 @@ class _CalendarScreenState extends State<CalendarScreen> {
future: getByProId(DateFormat("yyyy-MM-dd 00:00:00.000").format(today)), future: getByProId(DateFormat("yyyy-MM-dd 00:00:00.000").format(today)),
builder: (BuildContext context, AsyncSnapshot<List<Event>> snapshot) { builder: (BuildContext context, AsyncSnapshot<List<Event>> snapshot) {
if (!snapshot.hasData) { if (!snapshot.hasData) {
return const Text('No tiene citas'); return const Text('No tienes citas');
} }
List<Event> eventos = []; List<Event> eventos = [];
+285 -272
View File
@@ -71,7 +71,8 @@ class _CitaScreenState extends State<CitaScreen> {
'data': <String, dynamic>{ 'data': <String, dynamic>{
'click_action': 'FLUTTER_NOTIFICATION_CLICK', 'click_action': 'FLUTTER_NOTIFICATION_CLICK',
'id': '1', 'id': '1',
'status': 'done' 'status': 'done',
'screen': 'misservicios',
}, },
'to': user 'to': user
}, },
@@ -233,45 +234,47 @@ class _CitaScreenState extends State<CitaScreen> {
], ],
), ),
), ),
Container( widget.evento.userId == widget.evento.professionalId
margin: const EdgeInsets.only( ? const SizedBox()
left: 40, right: 40, top: 20, bottom: 20), : Container(
padding: margin: const EdgeInsets.only(
const EdgeInsets.symmetric(horizontal: 20, vertical: 15), left: 40, right: 40, top: 20, bottom: 20),
decoration: BoxDecoration( padding: const EdgeInsets.symmetric(
color: const Color(0xFFD6F4FF), horizontal: 20, vertical: 15),
borderRadius: BorderRadius.circular(20), decoration: BoxDecoration(
boxShadow: [ color: const Color(0xFFD6F4FF),
BoxShadow( borderRadius: BorderRadius.circular(20),
color: Colors.grey.withOpacity(0.5), boxShadow: [
spreadRadius: 1, BoxShadow(
blurRadius: 5, color: Colors.grey.withOpacity(0.5),
offset: const Offset(1, 3), spreadRadius: 1,
), blurRadius: 5,
], offset: const Offset(1, 3),
),
child: Row(
children: [
const Icon(
Icons.error_outline,
size: 27,
color: Colors.black54,
),
const SizedBox(width: 15),
widget.evento.ubicacion != 'sitio'
? const Text(
'Servicio a domicilio.',
style:
TextStyle(color: Colors.black, fontSize: 14),
)
: const Text(
'Servicio en su sitio / consultorio',
style:
TextStyle(color: Colors.black, fontSize: 14),
), ),
], ],
), ),
), child: Row(
children: [
const Icon(
Icons.error_outline,
size: 27,
color: Colors.black54,
),
const SizedBox(width: 15),
widget.evento.ubicacion != 'sitio'
? const Text(
'Servicio a domicilio.',
style: TextStyle(
color: Colors.black, fontSize: 14),
)
: const Text(
'Servicio en su sitio / consultorio',
style: TextStyle(
color: Colors.black, fontSize: 14),
),
],
),
),
settings?.tarifas == true && widget.evento.tarifa != 0 settings?.tarifas == true && widget.evento.tarifa != 0
? Column( ? Column(
children: [ children: [
@@ -292,249 +295,259 @@ class _CitaScreenState extends State<CitaScreen> {
style: const TextStyle( style: const TextStyle(
color: Colors.grey, fontStyle: FontStyle.italic), color: Colors.grey, fontStyle: FontStyle.italic),
), ),
widget.evento.status == 'terminado' widget.evento.userId == widget.evento.professionalId
? const SizedBox(height: 10) ? const SizedBox()
: const Padding( : widget.evento.status == 'terminado'
padding: EdgeInsets.symmetric(vertical: 20), ? const SizedBox(height: 10)
child: Text( : const Padding(
'Medios de comunicación con el usuario.', padding: EdgeInsets.symmetric(vertical: 20),
style: TextStyle(color: Color(0xFF2BA4EC)), child: Text(
), 'Medios de comunicación con el usuario.',
), style: TextStyle(color: Color(0xFF2BA4EC)),
widget.evento.status == 'terminado'
? pro == true
? widget.evento.professionalScored == true
? const SizedBox()
: Column(
children: [
const SizedBox(height: 120),
ElevatedButton(
onPressed: () {
Navigator.pushReplacement(
context,
CupertinoPageRoute(
builder: (BuildContext context) {
return ScoreScreen(
evento: widget.evento,
pro: pro!,
);
},
),
);
},
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF2BA4EC),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50),
),
elevation: 0,
minimumSize: const Size(230, 60),
),
child: const Text(
'Puntuar servicio',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
),
],
)
: widget.evento.userScored == true
? const SizedBox()
: Column(
children: [
const SizedBox(height: 120),
ElevatedButton(
onPressed: () {
Navigator.pushReplacement(
context,
CupertinoPageRoute(
builder: (BuildContext context) {
return ScoreScreen(
evento: widget.evento,
pro: pro!,
);
},
),
);
},
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF2BA4EC),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50),
),
elevation: 0,
minimumSize: const Size(230, 60),
),
child: const Text(
'Puntuar servicio',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
),
],
)
: Row(
children: [
const Expanded(child: SizedBox()),
ElevatedButton(
onPressed: () => launch("tel:$numberPhone"),
style: ElevatedButton.styleFrom(
foregroundColor: const Color(0xFF2BA4EC),
backgroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50),
side: const BorderSide(
color: Color(0xFF2BA4EC),
width: 2,
),
),
),
child: const Padding(
padding: EdgeInsets.symmetric(
vertical: 18, horizontal: 0),
child: Icon(
Icons.phone_android,
size: 30,
color: Color(0xFF2BA4EC),
),
), ),
), ),
const SizedBox(width: 20), widget.evento.userId == widget.evento.professionalId
ElevatedButton( ? const SizedBox()
onPressed: () async { : widget.evento.status == 'terminado'
if (widget.evento.status != 'pendiente') { ? pro == true
final chatDoc = FirebaseFirestore.instance ? widget.evento.professionalScored == true
.collection('chats') ? const SizedBox()
.doc(widget.evento.id); : Column(
final chatSnapshot = await chatDoc.get(); children: [
const SizedBox(height: 120),
if (!chatSnapshot.exists || ElevatedButton(
chatSnapshot.data()!['message'] == null) { onPressed: () {
await chatDoc.set( Navigator.pushReplacement(
{ context,
'professional_id': CupertinoPageRoute(
widget.evento.professionalId, builder: (BuildContext context) {
'user_id': widget.evento.userId, return ScoreScreen(
'message': [], evento: widget.evento,
}, pro: pro!,
SetOptions(merge: true), );
).catchError((error) => print( },
'Error al crear el documento: $error')); ),
} );
},
Navigator.push( style: ElevatedButton.styleFrom(
context, backgroundColor:
CupertinoPageRoute( const Color(0xFF2BA4EC),
builder: (BuildContext context) { shape: RoundedRectangleBorder(
return ChatScreen( borderRadius:
eventoId: widget.evento.id); BorderRadius.circular(50),
}, ),
), elevation: 0,
); minimumSize: const Size(230, 60),
} ),
child: const Text(
// if (widget.evento.status != 'pendiente') { 'Puntuar servicio',
// await FirebaseFirestore.instance style: TextStyle(
// .collection('chats') color: Colors.white,
// .doc(widget.evento.id) fontWeight: FontWeight.bold,
// .set( fontSize: 18,
// { ),
// 'professional_id': ),
// widget.evento.professionalId, ),
// 'user_id': widget.evento.userId, ],
// 'message': [], )
// }, : widget.evento.userScored == true
// SetOptions( ? const SizedBox()
// merge: : Column(
// true)).catchError((error) => print( children: [
// 'Error al crear el documento: $error')); const SizedBox(height: 120),
ElevatedButton(
// Navigator.push( onPressed: () {
// context, Navigator.pushReplacement(
// CupertinoPageRoute( context,
// builder: (BuildContext context) { CupertinoPageRoute(
// return ChatScreen( builder: (BuildContext context) {
// eventoId: widget.evento.id); return ScoreScreen(
// }, evento: widget.evento,
// ), pro: pro!,
// ); );
// } },
else { ),
final snackBar = SnackBar( );
backgroundColor: Colors.blue, },
content: const Text( style: ElevatedButton.styleFrom(
'Primero acepta la solicitud', backgroundColor:
style: TextStyle( const Color(0xFF2BA4EC),
color: Colors.white, shape: RoundedRectangleBorder(
fontWeight: FontWeight.bold, borderRadius:
), BorderRadius.circular(50),
), ),
elevation: 8.0, elevation: 0,
minimumSize: const Size(230, 60),
),
child: const Text(
'Puntuar servicio',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
),
],
)
: Row(
children: [
const Expanded(child: SizedBox()),
ElevatedButton(
onPressed: () => launch("tel:$numberPhone"),
style: ElevatedButton.styleFrom(
foregroundColor: const Color(0xFF2BA4EC),
backgroundColor: Colors.white,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0), borderRadius: BorderRadius.circular(50),
side: const BorderSide(
color: Color(0xFF2BA4EC),
width: 2,
),
), ),
); ),
child: const Padding(
padding: EdgeInsets.symmetric(
vertical: 18, horizontal: 0),
child: Icon(
Icons.phone_android,
size: 30,
color: Color(0xFF2BA4EC),
),
),
),
const SizedBox(width: 20),
ElevatedButton(
onPressed: () async {
if (widget.evento.status != 'pendiente') {
final chatDoc = FirebaseFirestore.instance
.collection('chats')
.doc(widget.evento.id);
final chatSnapshot = await chatDoc.get();
ScaffoldMessenger.of(context) if (!chatSnapshot.exists ||
.showSnackBar(snackBar); chatSnapshot.data()!['message'] ==
} null) {
}, await chatDoc.set(
style: ElevatedButton.styleFrom( {
foregroundColor: const Color(0xFF2BA4EC), 'professional_id':
backgroundColor: Colors.white, widget.evento.professionalId,
shape: RoundedRectangleBorder( 'user_id': widget.evento.userId,
borderRadius: BorderRadius.circular(50), 'message': [],
side: const BorderSide( },
color: Color(0xFF2BA4EC), SetOptions(merge: true),
width: 2, ).catchError((error) => print(
'Error al crear el documento: $error'));
}
Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext context) {
return ChatScreen(
eventoId: widget.evento.id);
},
),
);
}
// if (widget.evento.status != 'pendiente') {
// await FirebaseFirestore.instance
// .collection('chats')
// .doc(widget.evento.id)
// .set(
// {
// 'professional_id':
// widget.evento.professionalId,
// 'user_id': widget.evento.userId,
// 'message': [],
// },
// SetOptions(
// merge:
// true)).catchError((error) => print(
// 'Error al crear el documento: $error'));
// Navigator.push(
// context,
// CupertinoPageRoute(
// builder: (BuildContext context) {
// return ChatScreen(
// eventoId: widget.evento.id);
// },
// ),
// );
// }
else {
final snackBar = SnackBar(
backgroundColor: Colors.blue,
content: const Text(
'Primero acepta la solicitud',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
elevation: 8.0,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(10.0),
),
);
ScaffoldMessenger.of(context)
.showSnackBar(snackBar);
}
},
style: ElevatedButton.styleFrom(
foregroundColor: const Color(0xFF2BA4EC),
backgroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50),
side: const BorderSide(
color: Color(0xFF2BA4EC),
width: 2,
),
),
),
child: const Padding(
padding: EdgeInsets.symmetric(
vertical: 18, horizontal: 0),
child: Icon(
Icons.message,
size: 30,
color: Color(0xFF2BA4EC),
),
), ),
), ),
), const SizedBox(width: 20),
child: const Padding( ElevatedButton(
padding: EdgeInsets.symmetric( onPressed: () {
vertical: 18, horizontal: 0), _sendWhatsapp(numberPhone);
child: Icon( },
Icons.message, style: ElevatedButton.styleFrom(
size: 30, foregroundColor: const Color(0xFF2BA4EC),
color: Color(0xFF2BA4EC), backgroundColor: Colors.white,
), shape: RoundedRectangleBorder(
), borderRadius: BorderRadius.circular(50),
), side: const BorderSide(
const SizedBox(width: 20), color: Color(0xFF2BA4EC),
ElevatedButton( width: 2,
onPressed: () { ),
_sendWhatsapp(numberPhone); ),
}, ),
style: ElevatedButton.styleFrom( child: const Padding(
foregroundColor: const Color(0xFF2BA4EC), padding: EdgeInsets.symmetric(
backgroundColor: Colors.white, vertical: 18, horizontal: 0),
shape: RoundedRectangleBorder( child: Icon(
borderRadius: BorderRadius.circular(50), CommunityMaterialIcons.whatsapp,
side: const BorderSide( size: 30,
color: Color(0xFF2BA4EC), color: Color(0xFF2BA4EC),
width: 2, ),
), ),
), ),
), const Expanded(child: SizedBox()),
child: const Padding( ],
padding: EdgeInsets.symmetric(
vertical: 18, horizontal: 0),
child: Icon(
CommunityMaterialIcons.whatsapp,
size: 30,
color: Color(0xFF2BA4EC),
),
),
), ),
const Expanded(child: SizedBox()),
],
),
widget.evento.ubicacion == 'sitio' widget.evento.ubicacion == 'sitio'
? const SizedBox() ? const SizedBox()
: Padding( : Padding(
+2 -2
View File
@@ -152,7 +152,7 @@ class _CityScreenState extends State<CityScreen> {
onPressed: () { onPressed: () {
Navigator.pop(context); Navigator.pop(context);
}, },
label: 'Seleccione su ciudad'), label: 'Selecciona tu ciudad'),
body: Column( body: Column(
children: [ children: [
Padding( Padding(
@@ -160,7 +160,7 @@ class _CityScreenState extends State<CityScreen> {
child: TextField( child: TextField(
controller: searchController, controller: searchController,
decoration: const InputDecoration( decoration: const InputDecoration(
hintText: 'Buscar ciudad', hintText: 'Busca una ciudad',
prefixIcon: Icon(Icons.near_me), prefixIcon: Icon(Icons.near_me),
), ),
), ),
+3 -3
View File
@@ -40,7 +40,7 @@ class CodeValidationScreen extends StatelessWidget {
}, },
), ),
const Text( const Text(
'Validar código', 'Valida el código',
style: TextStyle( style: TextStyle(
color: Color(0xFF262626), color: Color(0xFF262626),
fontSize: 38.0, fontSize: 38.0,
@@ -121,7 +121,7 @@ class CodeValidationScreen extends StatelessWidget {
onPressed: () { onPressed: () {
OTPController.instance.verifyOTP(otp); OTPController.instance.verifyOTP(otp);
}, },
label: 'Validar código', label: 'Valida el código',
), ),
const SizedBox(height: 30), const SizedBox(height: 30),
], ],
@@ -257,7 +257,7 @@ class CodeValidationScreen extends StatelessWidget {
onPressed: () { onPressed: () {
OTPController.instance.verifyOTP(otp); OTPController.instance.verifyOTP(otp);
}, },
label: 'Validar código', label: 'Valida el código',
), ),
const SizedBox(height: 30), const SizedBox(height: 30),
], ],
+121 -6
View File
@@ -1,3 +1,5 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
@@ -5,8 +7,11 @@ import 'package:intl_phone_field/intl_phone_field.dart';
import 'package:prosappco/src/components/bottom_sheet.dart'; import 'package:prosappco/src/components/bottom_sheet.dart';
import 'package:prosappco/src/components/primary_btn.dart'; import 'package:prosappco/src/components/primary_btn.dart';
import 'package:prosappco/src/controllers/phone_auth_controller.dart'; import 'package:prosappco/src/controllers/phone_auth_controller.dart';
import 'package:prosappco/src/models/setting_model.dart';
import 'package:prosappco/src/screens/code_validation.dart'; import 'package:prosappco/src/screens/code_validation.dart';
import 'package:prosappco/src/screens/web_view.dart';
import 'package:responsive_builder/responsive_builder.dart'; import 'package:responsive_builder/responsive_builder.dart';
import 'package:url_launcher/url_launcher.dart';
class LoginScreen extends StatefulWidget { class LoginScreen extends StatefulWidget {
const LoginScreen({super.key}); const LoginScreen({super.key});
@@ -19,6 +24,28 @@ class _LoginScreenState extends State<LoginScreen> {
final controller = Get.put(PhoneAuthController()); final controller = Get.put(PhoneAuthController());
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
String completePhoneNumber = ''; String completePhoneNumber = '';
bool _isChecked = false;
SettingModel? settings;
void _launchURL(String url) async {
if (await canLaunch(url)) {
await launch(url, forceSafariVC: false, forceWebView: false);
} else {
throw 'No se pudo abrir el enlace $url';
}
}
@override
void initState() {
super.initState();
if (settings == null) {
SettingModel.getSettings().then(
(SettingModel value) => setState(() {
settings = value;
}),
);
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -98,7 +125,49 @@ class _LoginScreenState extends State<LoginScreen> {
color: Color(0xFF65676B), color: Color(0xFF65676B),
), ),
), ),
const SizedBox(height: 20), Padding(
padding: const EdgeInsets.symmetric(vertical: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Checkbox(
value: _isChecked,
onChanged: (value) {
setState(() {
_isChecked = value!;
});
},
),
GestureDetector(
onTap: () {
if (kIsWeb) {
_launchURL(settings?.terminosCondiciones ?? '');
} else {
Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext context) {
return WebViewScreen(
label: 'Términos y condiciones',
link: settings?.terminosCondiciones ?? '',
);
},
),
);
}
},
child: const Text(
'Acepto los términos y condiciones.',
style: TextStyle(
fontSize: 13.0,
color: Color(0xFF65676B),
decoration: TextDecoration.underline,
),
),
),
],
),
),
PrimaryButtom( PrimaryButtom(
onPressed: () { onPressed: () {
if (_formKey.currentState!.validate()) { if (_formKey.currentState!.validate()) {
@@ -112,6 +181,7 @@ class _LoginScreenState extends State<LoginScreen> {
); );
} }
}, },
isEnabled: _isChecked,
label: 'Enviar código', label: 'Enviar código',
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
@@ -216,14 +286,58 @@ class _LoginScreenState extends State<LoginScreen> {
), ),
), ),
const Text( const Text(
'Un código será enviado a este numero de celular.', 'Se enviará un código a este número de celular.',
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
fontSize: 13.0, fontSize: 13.0,
color: Color(0xFF65676B), color: Color(0xFF65676B),
), ),
), ),
const SizedBox(height: 20), Padding(
padding: const EdgeInsets.symmetric(vertical: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Checkbox(
value: _isChecked,
onChanged: (value) {
setState(() {
_isChecked = value!;
});
},
),
GestureDetector(
onTap: () {
if (kIsWeb) {
_launchURL(settings?.terminosCondiciones ?? '');
} else {
Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext context) {
return WebViewScreen(
label: 'Términos y condiciones',
link:
settings?.terminosCondiciones ?? '',
);
},
),
);
}
},
child: const Text(
'Acepto los términos y condiciones.',
style: TextStyle(
fontSize: 13.0,
color: Color(0xFF65676B),
decoration: TextDecoration
.underline, // Add underline style
),
),
),
],
),
),
PrimaryButtom( PrimaryButtom(
onPressed: () { onPressed: () {
if (_formKey.currentState!.validate()) { if (_formKey.currentState!.validate()) {
@@ -237,6 +351,7 @@ class _LoginScreenState extends State<LoginScreen> {
); );
} }
}, },
isEnabled: _isChecked,
label: 'Enviar código', label: 'Enviar código',
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
@@ -266,7 +381,7 @@ class GestureBottom extends StatelessWidget {
Navigator.pushNamed(context, '/login'); Navigator.pushNamed(context, '/login');
}, },
child: const Text( child: const Text(
'Entrar con correo electronico', 'Inicia sesión con tu correo electrónico',
style: TextStyle( style: TextStyle(
fontSize: 15.0, color: Color(0xFF65676B), fontSize: 15.0, color: Color(0xFF65676B),
decoration: TextDecoration.underline, // Subrayado decoration: TextDecoration.underline, // Subrayado
@@ -291,14 +406,14 @@ class RichTxTBottom extends StatelessWidget {
fontFamily: 'Poppins', fontFamily: 'Poppins',
), ),
children: [ children: [
const TextSpan(text: 'No estas registrado? '), const TextSpan(text: '¿No estás registrado? '),
WidgetSpan( WidgetSpan(
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {
Navigator.pushNamed(context, '/register'); Navigator.pushNamed(context, '/register');
}, },
child: const Text( child: const Text(
'Registrarse', 'Regístrate',
style: TextStyle( style: TextStyle(
fontSize: 16.0, fontSize: 16.0,
color: Color(0xFF2BA4EC), color: Color(0xFF2BA4EC),
+6 -6
View File
@@ -114,7 +114,7 @@ class _LoginEmailScreenState extends State<LoginEmailScreen> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Text( Text(
'Entrar con Google ', 'Entra con Google ',
style: TextStyle( style: TextStyle(
color: Colors.white, color: Colors.white,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@@ -179,7 +179,7 @@ class _LoginEmailScreenState extends State<LoginEmailScreen> {
obscureText: _obscureText, obscureText: _obscureText,
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Por favor ingrese una contraseña'; return 'Por favor, ingresa una contraseña';
} }
return null; return null;
}, },
@@ -383,7 +383,7 @@ class _LoginEmailScreenState extends State<LoginEmailScreen> {
obscureText: _obscureText, obscureText: _obscureText,
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Por favor ingrese una contraseña'; return 'Por favor, ingresa una contraseña';
} }
return null; return null;
}, },
@@ -466,12 +466,12 @@ class FormEmail extends StatelessWidget {
controller: controller.email, controller: controller.email,
validator: (String? value) { validator: (String? value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Por favor ingrese un email'; return 'Por favor, ingresa un Email';
} }
final RegExp emailRegExp = final RegExp emailRegExp =
RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$'); RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
if (!emailRegExp.hasMatch(value)) { if (!emailRegExp.hasMatch(value)) {
return 'Por favor ingrese un email válido'; return 'Por favor, ingresa un Email válido';
} }
return null; return null;
}, },
@@ -551,7 +551,7 @@ class RichTxtBottom extends StatelessWidget {
fontFamily: 'Poppins', fontFamily: 'Poppins',
), ),
children: [ children: [
const TextSpan(text: 'No estas registrado? '), const TextSpan(text: '¿No estás registrado? '),
WidgetSpan( WidgetSpan(
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {
+1 -1
View File
@@ -44,7 +44,7 @@ class _MessagesScreenState extends State<MessagesScreen> {
child: TextField( child: TextField(
// controller: searchController, // controller: searchController,
decoration: InputDecoration( decoration: InputDecoration(
hintText: 'Escriba un nombre', hintText: 'Escribe un nombre',
prefixIcon: Icon(CommunityMaterialIcons.stethoscope), prefixIcon: Icon(CommunityMaterialIcons.stethoscope),
), ),
), ),
+1 -1
View File
@@ -45,7 +45,7 @@ class _MessagesUserScreenState extends State<MessagesUserScreen> {
child: TextField( child: TextField(
// controller: searchController, // controller: searchController,
decoration: InputDecoration( decoration: InputDecoration(
hintText: 'Escriba un nombre', hintText: 'Escribe un nombre',
prefixIcon: Icon(CommunityMaterialIcons.stethoscope), prefixIcon: Icon(CommunityMaterialIcons.stethoscope),
), ),
), ),
+120 -90
View File
@@ -87,6 +87,7 @@ class _MyServicesScreenState extends State<MyServicesScreen> {
try { try {
eventos.addAll(snapshot.data!); eventos.addAll(snapshot.data!);
eventos.sort((a, b) => a.range1Hour1.compareTo(b.range1Hour1));
} catch (e) { } catch (e) {
print("Error" + e.toString()); print("Error" + e.toString());
} }
@@ -100,108 +101,137 @@ class _MyServicesScreenState extends State<MyServicesScreen> {
return Column( return Column(
children: [ children: [
...eventos.map( ...eventos
(event) => ListTile( .where((event) => event.professionalId != event.userId)
tileColor: event.status == 'denegado' .map(
? Colors.red[100] (event) => FutureBuilder<DocumentSnapshot>(
: Colors.blue[100], future: FirebaseFirestore.instance
onTap: () { .collection('users')
Navigator.push( .doc(event.professionalId)
context, .get(),
CupertinoPageRoute( builder: (BuildContext context,
builder: (BuildContext context) { AsyncSnapshot<DocumentSnapshot> profSnapshot) {
return CitaScreen(evento: event); if (profSnapshot.connectionState ==
}, ConnectionState.waiting) {
), return const CircularProgressIndicator();
); }
},
leading: event.status == 'aprobado' if (profSnapshot.hasError) {
? const Icon( return const Text(
Icons.check, 'Error al obtener los datos del profesional',
color: Colors.blue, // Aquí puedes agregar un estilo de texto apropiado
size: 40, );
) }
: event.status == 'iniciado'
? const Icon( final professionalData = profSnapshot.data;
Icons.access_time, final professionalName =
color: Colors.blue, professionalData?['name'] ?? 'N/D';
size: 40,
) return ListTile(
: event.status == 'pendiente' tileColor: event.status == 'denegado'
? Colors.red[100]
: Colors.blue[100],
onTap: () {
Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext context) {
return CitaScreen(evento: event);
},
),
);
},
leading: event.status == 'aprobado'
? const Icon( ? const Icon(
Icons.access_time_outlined, Icons.check,
color: Colors.blue, color: Colors.blue,
size: 40, size: 40,
) )
: event.status == 'terminado' : event.status == 'iniciado'
? const Icon( ? const Icon(
Icons.rocket_launch, Icons.access_time,
color: Colors.blue, color: Colors.blue,
size: 40, size: 40,
) )
: const Icon( : event.status == 'pendiente'
Icons.close, ? const Icon(
color: Colors.red, Icons.access_time_outlined,
size: 40, color: Colors.blue,
size: 40,
)
: event.status == 'terminado'
? const Icon(
Icons.rocket_launch,
color: Colors.blue,
size: 40,
)
: const Icon(
Icons.close,
color: Colors.red,
size: 40,
),
title: RichText(
text: TextSpan(
children: [
TextSpan(
text: '${professionalName}, ',
style: const TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
TextSpan(
text:
'${DateFormat('dd MMM', 'es').format(DateTime.parse(event.day))} - ${TimeOfDay.fromDateTime(DateTime.parse(event.range1Hour1)).format(context)}',
style: TextStyle(
color: Colors.grey[600],
fontSize: 16,
),
),
],
),
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
RatingBar.builder(
initialRating:
event.scoresModel?.average ?? 0,
minRating: 1,
direction: Axis.horizontal,
allowHalfRating: true,
itemCount: 5,
itemSize: 25,
maxRating: 5,
itemPadding:
const EdgeInsets.symmetric(horizontal: 0),
itemBuilder: (context, _) => const Icon(
Icons.star,
color: Color(0xFF2BA4EC),
), ),
title: RichText( onRatingUpdate: (rating) {},
text: TextSpan( ignoreGestures: true,
children: [ ),
TextSpan( const SizedBox(width: 5),
text: '${event.title}, ', Text(
style: const TextStyle( '(${event.scoresModel?.total.toString()}) ${event.scoresModel?.average.toStringAsFixed(1)}'),
color: Colors.black, ],
fontWeight: FontWeight.bold, ),
fontSize: 16, Text(
'" ${event.description}"',
style:
const TextStyle(fontStyle: FontStyle.italic),
),
],
), ),
), trailing: const Icon(Icons.keyboard_arrow_right),
TextSpan( );
text: },
'${DateFormat('dd MMM', 'es').format(DateTime.parse(event.day))} - ${TimeOfDay.fromDateTime(DateTime.parse(event.range1Hour1)).format(context)}',
style: TextStyle(
color: Colors.grey[600],
fontSize: 16,
),
),
],
), ),
), ),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
RatingBar.builder(
initialRating: event.scoresModel?.average ?? 0,
minRating: 1,
direction: Axis.horizontal,
allowHalfRating: true,
itemCount: 5,
itemSize: 25,
maxRating: 5,
itemPadding:
const EdgeInsets.symmetric(horizontal: 0),
itemBuilder: (context, _) => const Icon(
Icons.star,
color: Color(0xFF2BA4EC),
),
onRatingUpdate: (rating) {},
ignoreGestures: true,
),
const SizedBox(width: 5),
Text(
'(${event.scoresModel?.total.toString()}) ${event.scoresModel?.average.toStringAsFixed(1)}'),
],
),
Text(
'" ${event.description}"',
style: const TextStyle(fontStyle: FontStyle.italic),
),
],
),
trailing: const Icon(Icons.keyboard_arrow_right),
),
),
], ],
); );
}, },
+94 -94
View File
@@ -31,10 +31,11 @@ class _MyServicesProScreenState extends State<MyServicesProScreen> {
return SafeArea( return SafeArea(
child: Scaffold( child: Scaffold(
appBar: PopAppbar( appBar: PopAppbar(
onPressed: () { onPressed: () {
Navigator.pop(context); Navigator.pop(context);
}, },
label: 'Mis servicios'), label: 'Mis servicios',
),
drawer: DrawerProfessional(), drawer: DrawerProfessional(),
body: SingleChildScrollView( body: SingleChildScrollView(
child: Column( child: Column(
@@ -82,6 +83,7 @@ class _MyServicesProScreenState extends State<MyServicesProScreen> {
try { try {
eventos.addAll(snapshot.data!); eventos.addAll(snapshot.data!);
eventos.sort((a, b) => a.range1Hour1.compareTo(b.range1Hour1));
} catch (e) { } catch (e) {
print("Error" + e.toString()); print("Error" + e.toString());
} }
@@ -96,102 +98,100 @@ class _MyServicesProScreenState extends State<MyServicesProScreen> {
return Column( return Column(
children: [ children: [
...eventos.map( ...eventos.map(
(event) => event.userId == event.professionalId (event) => ListTile(
? const SizedBox() tileColor: event.status == 'denegado'
: ListTile( ? Colors.red[100]
tileColor: event.status == 'denegado' : Colors.blue[100],
? Colors.red[100] onTap: () {
: Colors.blue[100], Navigator.push(
onTap: () { context,
Navigator.push( CupertinoPageRoute(
context, builder: (BuildContext context) {
CupertinoPageRoute( return CitaScreen(evento: event);
builder: (BuildContext context) {
return CitaScreen(evento: event);
},
),
);
}, },
leading: event.status == 'aprobado' ),
? const Icon( );
Icons.check, },
color: Colors.blue, leading: event.status == 'aprobado'
size: 40, ? const Icon(
) Icons.check,
: event.status == 'iniciado' color: Colors.blue,
? const Icon( size: 40,
Icons.access_time, )
color: Colors.blue, : event.status == 'iniciado'
size: 40, ? const Icon(
) Icons.access_time,
: event.status == 'terminado' color: Colors.blue,
? const Icon( size: 40,
Icons.rocket_launch, )
color: Colors.blue, : event.status == 'terminado'
size: 40, ? const Icon(
) Icons.rocket_launch,
: const Icon( color: Colors.blue,
Icons.close, size: 40,
color: Colors.red, )
size: 40, : const Icon(
), Icons.close,
title: RichText( color: Colors.red,
text: TextSpan( size: 40,
children: [
TextSpan(
text: '${event.title}, ',
style: const TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 16,
), ),
), title: RichText(
TextSpan( text: TextSpan(
text: children: [
'${DateFormat('dd MMM', 'es').format(DateTime.parse(event.day))} - ${TimeOfDay.fromDateTime(DateTime.parse(event.range1Hour1)).format(context)}', TextSpan(
style: TextStyle( text: '${event.title}, ',
color: Colors.grey[600], style: const TextStyle(
fontSize: 16, color: Colors.black,
), fontWeight: FontWeight.bold,
), fontSize: 16,
],
), ),
), ),
subtitle: Column( TextSpan(
crossAxisAlignment: CrossAxisAlignment.start, text:
children: [ '${DateFormat('dd MMM', 'es').format(DateTime.parse(event.day))} - ${TimeOfDay.fromDateTime(DateTime.parse(event.range1Hour1)).format(context)}',
Row( style: TextStyle(
children: [ color: Colors.grey[600],
RatingBar.builder( fontSize: 16,
initialRating: event.scoresModel?.average ?? 0, ),
minRating: 1,
direction: Axis.horizontal,
allowHalfRating: true,
itemCount: 5,
itemSize: 25,
maxRating: 5,
itemPadding:
const EdgeInsets.symmetric(horizontal: 0),
itemBuilder: (context, _) => const Icon(
Icons.star,
color: Color(0xFF2BA4EC),
),
onRatingUpdate: (rating) {},
ignoreGestures: true,
),
const SizedBox(width: 5),
Text(
'(${event.scoresModel?.total.toString()}) ${event.scoresModel?.average.toStringAsFixed(1)}'),
],
),
Text(
'" ${event.description}"',
style: const TextStyle(fontStyle: FontStyle.italic),
),
],
), ),
trailing: const Icon(Icons.keyboard_arrow_right), ],
),
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
RatingBar.builder(
initialRating: event.scoresModel?.average ?? 0,
minRating: 1,
direction: Axis.horizontal,
allowHalfRating: true,
itemCount: 5,
itemSize: 25,
maxRating: 5,
itemPadding:
const EdgeInsets.symmetric(horizontal: 0),
itemBuilder: (context, _) => const Icon(
Icons.star,
color: Color(0xFF2BA4EC),
),
onRatingUpdate: (rating) {},
ignoreGestures: true,
),
const SizedBox(width: 5),
Text(
'(${event.scoresModel?.total.toString()}) ${event.scoresModel?.average.toStringAsFixed(1)}'),
],
), ),
Text(
'" ${event.description}"',
style: const TextStyle(fontStyle: FontStyle.italic),
),
],
),
trailing: const Icon(Icons.keyboard_arrow_right),
),
), ),
], ],
); );
+2 -2
View File
@@ -102,7 +102,7 @@ class _NewNumberScreenState extends State<NewNumberScreen> {
const Padding( const Padding(
padding: EdgeInsets.only(bottom: 30), padding: EdgeInsets.only(bottom: 30),
child: Text( child: Text(
'Un código será enviado a este numero de celular.', 'Se enviará un código a este número de celular',
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
fontSize: 13.0, color: Color(0xFF65676B))), fontSize: 13.0, color: Color(0xFF65676B))),
@@ -215,7 +215,7 @@ class _NewNumberScreenState extends State<NewNumberScreen> {
const Padding( const Padding(
padding: EdgeInsets.only(bottom: 30), padding: EdgeInsets.only(bottom: 30),
child: Text( child: Text(
'Un código será enviado a este numero de celular.', 'Se enviará un código a este número de celular',
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
fontSize: 13.0, color: Color(0xFF65676B))), fontSize: 13.0, color: Color(0xFF65676B))),
+3 -3
View File
@@ -49,7 +49,7 @@ class _NewNumberValidationScreenState extends State<NewNumberValidationScreen> {
}, },
), ),
const Text( const Text(
'Validar código', 'Valida el código',
style: TextStyle( style: TextStyle(
color: Color(0xFF262626), color: Color(0xFF262626),
fontSize: 38.0, fontSize: 38.0,
@@ -98,7 +98,7 @@ class _NewNumberValidationScreenState extends State<NewNumberValidationScreen> {
alignment: Alignment.topLeft, alignment: Alignment.topLeft,
child: Padding( child: Padding(
padding: EdgeInsets.only(bottom: 5), padding: EdgeInsets.only(bottom: 5),
child: Text('Codigo', child: Text('Código',
textAlign: TextAlign.left, textAlign: TextAlign.left,
style: style:
TextStyle(fontSize: 18.0, color: Color(0xFF65676B))), TextStyle(fontSize: 18.0, color: Color(0xFF65676B))),
@@ -135,7 +135,7 @@ class _NewNumberValidationScreenState extends State<NewNumberValidationScreen> {
minimumSize: const Size(230, 60), // Tamaño mínimo del botón minimumSize: const Size(230, 60), // Tamaño mínimo del botón
), ),
child: const Text( child: const Text(
'Validar código', 'Valida el código',
style: TextStyle( style: TextStyle(
color: Colors.white, color: Colors.white,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
+4 -4
View File
@@ -32,7 +32,7 @@ class _NewPasswordScreenState extends State<NewPasswordScreen> {
if (newPassword == currentPassword) { if (newPassword == currentPassword) {
Get.snackbar( Get.snackbar(
'Misma contraseña', 'Misma contraseña',
'La nueva contraseña debe ser diferente a la contraseña actual.', 'La nueva contraseña debe ser distinta a la contraseña actual.',
snackPosition: SnackPosition.BOTTOM, snackPosition: SnackPosition.BOTTOM,
); );
return; return;
@@ -50,7 +50,7 @@ class _NewPasswordScreenState extends State<NewPasswordScreen> {
// Muestra un mensaje de éxito // Muestra un mensaje de éxito
Get.snackbar( Get.snackbar(
'Contraseña actualizada', 'Contraseña actualizada',
'La contraseña ha sido actualizada correctamente.', 'Tu contraseña ha sido cambiada con éxito.',
snackPosition: SnackPosition.BOTTOM, snackPosition: SnackPosition.BOTTOM,
); );
} catch (e) { } catch (e) {
@@ -60,7 +60,7 @@ class _NewPasswordScreenState extends State<NewPasswordScreen> {
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
'Contraseña incorrecta', 'Contraseña incorrecta',
'Error al actualizar la contraseña asegurese de ingresar bien la contraseña actual.', 'Ha ocurrido un error al actualizar la contraseña. Asegúrate de ingresar correctamente la contraseña actual.',
snackPosition: SnackPosition.BOTTOM, snackPosition: SnackPosition.BOTTOM,
); );
return; return;
@@ -80,7 +80,7 @@ class _NewPasswordScreenState extends State<NewPasswordScreen> {
onPressed: () { onPressed: () {
Navigator.pop(context); Navigator.pop(context);
}, },
label: 'Cambie su contraseña', label: ' Cambia tu contraseña',
), ),
body: Center( body: Center(
child: SizedBox( child: SizedBox(
+1 -1
View File
@@ -138,7 +138,7 @@ class _ProfessionScreenState extends State<ProfessionScreen> {
child: TextField( child: TextField(
controller: searchController, controller: searchController,
decoration: const InputDecoration( decoration: const InputDecoration(
hintText: 'Buscar su profesión', hintText: 'Busca tu profesión',
prefixIcon: Icon(Icons.assignment_ind_rounded), prefixIcon: Icon(Icons.assignment_ind_rounded),
), ),
), ),
+1 -1
View File
@@ -206,7 +206,7 @@ class _ProfessionalDireccionScreenState
setState(() {}); setState(() {});
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
'ubicación desactivada', 'Ubicación desactivada',
'Por favor activa la ubicacion de tu telefono.', 'Por favor activa la ubicacion de tu telefono.',
snackPosition: SnackPosition.TOP, snackPosition: SnackPosition.TOP,
); );
+4 -3
View File
@@ -422,7 +422,8 @@ class ProfessionalProfileScreenState extends State<ProfessionalProfileScreen> {
especializacion.split(',').map((e) => e.trim()).toList(); especializacion.split(',').map((e) => e.trim()).toList();
if (cedula.isEmpty) { if (cedula.isEmpty) {
_showCustomSnackBar(context, 'Por favor, ingrese el número de cédula.'); _showCustomSnackBar(
context, 'Por favor, adjunta el documento PDF de tu cédula.');
return; return;
} }
@@ -434,7 +435,7 @@ class ProfessionalProfileScreenState extends State<ProfessionalProfileScreen> {
if (image_certificado == null) { if (image_certificado == null) {
_showCustomSnackBar(context, _showCustomSnackBar(context,
'Por favor, adjunte el documento PDF de su certificado. ¡Gracias por su colaboración!'); 'Por favor, adjunta el documento PDF de tu certificado. ¡Gracias por tu colaboración!');
return; return;
} }
@@ -770,7 +771,7 @@ class ProfessionalProfileScreenState extends State<ProfessionalProfileScreen> {
SizedBox(width: 15), SizedBox(width: 15),
Expanded( Expanded(
child: Text( child: Text(
'¡Importante! Solo aceptamos archivos en formato PDF. Si desea agregar más de una especialidad, envíe archivos adicionales separados por comas (,). ¡Gracias!', 'Si tienes más de una especialidad, por favor, adjunta un archivo con el diploma de respaldo para cada una de ellas y sepáralos por comas. ¡Gracias!',
style: TextStyle(color: Colors.black, fontSize: 14), style: TextStyle(color: Colors.black, fontSize: 14),
), ),
) )
@@ -645,7 +645,7 @@ class _ProfessionalProfileWebScreenState
SizedBox(width: 15), SizedBox(width: 15),
Expanded( Expanded(
child: Text( child: Text(
'Para añadir mas de una especialidad, envie mas fotos y separe por comas (,).', 'Si tienes más de una especialidad, por favor, adjunta un archivo con el diploma de respaldo para cada una de ellas y sepáralos por comas. ¡Gracias!',
style: TextStyle( style: TextStyle(
color: Colors.black, fontSize: 14), color: Colors.black, fontSize: 14),
), ),
+1 -1
View File
@@ -71,7 +71,7 @@ class _ProfessionalRevisionScreenState
children: [ children: [
Expanded( Expanded(
child: Text( child: Text(
'Gracias por proporcionar su información. Actualmente, estamos revisando sus datos y una vez aprobados, podrá acceder al perfil profesional sin problemas. Le notificaremos tan pronto como su cuenta esté lista. ¡Gracias por su paciencia!.', 'Gracias por proporcionar tu información. Actualmente, estamos revisando tus datos y una vez aprobados, podrás acceder al perfil profesional sin problemas. Te notificaremos tan pronto como tu cuenta esté lista. ¡Gracias por tu paciencia!',
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
), ),
+4 -5
View File
@@ -86,7 +86,6 @@ class _ProfileScreenState extends State<ProfileScreen> {
.collection('users') .collection('users')
.doc(uid) .doc(uid)
.update({'photo': image}); .update({'photo': image});
} catch (e) { } catch (e) {
try { try {
await FirebaseFirestore.instance await FirebaseFirestore.instance
@@ -222,7 +221,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
// Si el nuevo nombre está vacío, no lo actualizamos y mostramos un mensaje al usuario // Si el nuevo nombre está vacío, no lo actualizamos y mostramos un mensaje al usuario
Get.snackbar( Get.snackbar(
'Nombre Invalido', 'Nombre Invalido',
'Ingrese un nombre válido.', 'Ingresa un nombre válido.',
snackPosition: SnackPosition.BOTTOM, snackPosition: SnackPosition.BOTTOM,
); );
return; return;
@@ -232,7 +231,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
// Si el nuevo email está vacío, no lo actualizamos y mostramos un mensaje al usuario // Si el nuevo email está vacío, no lo actualizamos y mostramos un mensaje al usuario
Get.snackbar( Get.snackbar(
'Correo Invalido', 'Correo Invalido',
'Ingrese un email válido.', 'Ingresa un email válido.',
snackPosition: SnackPosition.BOTTOM, snackPosition: SnackPosition.BOTTOM,
); );
return; return;
@@ -259,7 +258,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
} else { } else {
Get.snackbar( Get.snackbar(
'Contraseña Invalida', 'Contraseña Invalida',
'Porfavor ingrese una contraseña.', 'Porfavor ingresa una contraseña.',
snackPosition: SnackPosition.BOTTOM, snackPosition: SnackPosition.BOTTOM,
); );
} }
@@ -305,7 +304,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
'Agregar correo', 'Agregar correo',
'Inicie sesión para asegurarnos de que seas tú .', 'Inicia sesión para asegurarnos de que seas tú.',
snackPosition: SnackPosition.BOTTOM, snackPosition: SnackPosition.BOTTOM,
); );
AuthenticationRepository.instance.logout(uid!); AuthenticationRepository.instance.logout(uid!);
+1 -1
View File
@@ -276,7 +276,7 @@ class _ProfileProScreenState extends State<ProfileProScreen> {
Get.snackbar( Get.snackbar(
'Información actualizada', 'Información actualizada',
'Su información a sido actualizada con exito.', 'Tu información ha sido actualizada con éxito.',
snackPosition: SnackPosition.TOP, snackPosition: SnackPosition.TOP,
); );
+1 -1
View File
@@ -178,7 +178,7 @@ class _ProfileProWebScreenState extends State<ProfileProWebScreen> {
Get.snackbar( Get.snackbar(
'Información actualizada', 'Información actualizada',
'Su información a sido actualizada con exito.', 'Tu información a sido actualizada con exito.',
snackPosition: SnackPosition.TOP, snackPosition: SnackPosition.TOP,
); );
+4 -4
View File
@@ -142,7 +142,7 @@ class _ProfileWebScreenState extends State<ProfileWebScreen> {
// Si el nuevo nombre está vacío, no lo actualizamos y mostramos un mensaje al usuario // Si el nuevo nombre está vacío, no lo actualizamos y mostramos un mensaje al usuario
Get.snackbar( Get.snackbar(
'Nombre Invalido', 'Nombre Invalido',
'Ingrese un nombre válido.', 'Ingresa un nombre válido.',
snackPosition: SnackPosition.BOTTOM, snackPosition: SnackPosition.BOTTOM,
); );
return; return;
@@ -161,7 +161,7 @@ class _ProfileWebScreenState extends State<ProfileWebScreen> {
// Si el nuevo nombre está vacío, no lo actualizamos y mostramos un mensaje al usuario // Si el nuevo nombre está vacío, no lo actualizamos y mostramos un mensaje al usuario
Get.snackbar( Get.snackbar(
'Correo Invalido', 'Correo Invalido',
'Ingrese un email válido.', 'Ingresa un email válido.',
snackPosition: SnackPosition.BOTTOM, snackPosition: SnackPosition.BOTTOM,
); );
return; return;
@@ -186,7 +186,7 @@ class _ProfileWebScreenState extends State<ProfileWebScreen> {
} else { } else {
Get.snackbar( Get.snackbar(
'Contraseña Invalida', 'Contraseña Invalida',
'Porfavor ingrese una contraseña.', 'Por favor, ingresa una contraseña.',
snackPosition: SnackPosition.BOTTOM, snackPosition: SnackPosition.BOTTOM,
); );
} }
@@ -262,7 +262,7 @@ class _ProfileWebScreenState extends State<ProfileWebScreen> {
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
'Agregar correo', 'Agregar correo',
'Inicie sesión para asegurarnos de que seas tú .', 'Inicia sesión para asegurarnos de que seas tú.',
snackPosition: SnackPosition.BOTTOM, snackPosition: SnackPosition.BOTTOM,
); );
AuthenticationRepository.instance.logout(uid!); AuthenticationRepository.instance.logout(uid!);
+364 -298
View File
@@ -1,4 +1,5 @@
import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
@@ -7,8 +8,11 @@ import 'package:prosappco/main.dart';
import 'package:prosappco/src/authentication/authentication_repository.dart'; import 'package:prosappco/src/authentication/authentication_repository.dart';
import 'package:prosappco/src/components/primary_btn.dart'; import 'package:prosappco/src/components/primary_btn.dart';
import 'package:prosappco/src/controllers/register_controller.dart'; import 'package:prosappco/src/controllers/register_controller.dart';
import 'package:prosappco/src/models/setting_model.dart';
import 'package:prosappco/src/screens/login.dart'; import 'package:prosappco/src/screens/login.dart';
import 'package:prosappco/src/screens/web_view.dart';
import 'package:responsive_builder/responsive_builder.dart'; import 'package:responsive_builder/responsive_builder.dart';
import 'package:url_launcher/url_launcher.dart';
class RegisterScreen extends StatefulWidget { class RegisterScreen extends StatefulWidget {
const RegisterScreen({super.key}); const RegisterScreen({super.key});
@@ -21,6 +25,28 @@ class _RegisterScreenState extends State<RegisterScreen> {
bool _obscureText = true; bool _obscureText = true;
final controller = Get.put(RegisterController()); final controller = Get.put(RegisterController());
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
bool _isChecked = false;
SettingModel? settings;
void _launchURL(String url) async {
if (await canLaunch(url)) {
await launch(url, forceSafariVC: false, forceWebView: false);
} else {
throw 'No se pudo abrir el enlace $url';
}
}
@override
void initState() {
super.initState();
if (settings == null) {
SettingModel.getSettings().then(
(SettingModel value) => setState(() {
settings = value;
}),
);
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -157,138 +183,184 @@ class _RegisterScreenState extends State<RegisterScreen> {
) )
: const SizedBox(), : const SizedBox(),
Form( Form(
key: _formKey, key: _formKey,
child: Column( child: Column(
children: [ children: [
const Padding( const Padding(
padding: EdgeInsets.only(bottom: 5), padding: EdgeInsets.only(bottom: 5),
child: Align( child: Align(
alignment: Alignment.topLeft, alignment: Alignment.topLeft,
child: Text('Email', child: Text('Email',
style: TextStyle( style: TextStyle(
fontSize: 18.0, fontSize: 18.0,
color: Color(0xFF65676B))), color: Color(0xFF65676B))),
)), )),
Padding( Padding(
padding: const EdgeInsets.only(bottom: 18), padding: const EdgeInsets.only(bottom: 18),
child: TextFormField( child: TextFormField(
controller: controller.email, controller: controller.email,
validator: (String? value) { validator: (String? value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Por favor ingrese un email'; return 'Por favor ingresa un email';
} }
final RegExp emailRegExp = RegExp( final RegExp emailRegExp = RegExp(
r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$'); r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
if (!emailRegExp.hasMatch(value)) { if (!emailRegExp.hasMatch(value)) {
return 'Por favor ingrese un email válido'; return 'Por favor ingresa un email válido';
} }
return null; return null;
}, },
decoration: const InputDecoration( decoration: const InputDecoration(
border: OutlineInputBorder( border: OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
color: Color(0xFFECECEC)), color: Color(0xFFECECEC)),
borderRadius: BorderRadius.all( borderRadius: BorderRadius.all(
Radius.circular(50), Radius.circular(50),
)), )),
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
color: Color(0xFFECECEC)), color: Color(0xFFECECEC)),
borderRadius: BorderRadius.all( borderRadius: BorderRadius.all(
Radius.circular(50), Radius.circular(50),
)), )),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
color: Color(0xFFECECEC)), color: Color(0xFFECECEC)),
borderRadius: BorderRadius.all( borderRadius: BorderRadius.all(
Radius.circular(50), Radius.circular(50),
)), )),
errorBorder: OutlineInputBorder( errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Color.fromARGB(
255, 184, 0, 0)),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
hintText: 'Hello@gmail.com',
fillColor:
Color.fromARGB(255, 239, 239, 239),
filled: true,
prefixIcon: Icon(Icons.email_outlined)),
),
),
const Padding(
padding: EdgeInsets.only(bottom: 5),
child: Align(
alignment: Alignment.topLeft,
child: Text('Password',
style: TextStyle(
fontSize: 18.0,
color: Color(0xFF65676B))),
)),
Padding(
padding: const EdgeInsets.only(bottom: 25),
child: TextFormField(
controller: controller.password,
obscureText: _obscureText,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Por favor ingrese una contraseña';
}
if (value.length <= 6) {
return 'Contraseña muy corta';
}
return null;
},
decoration: InputDecoration(
errorBorder: const OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
color: color:
Color.fromARGB(255, 184, 0, 0)), Color.fromARGB(255, 184, 0, 0)),
borderRadius: BorderRadius.all( borderRadius: BorderRadius.all(
Radius.circular(50), Radius.circular(50),
)), )),
enabledBorder: const OutlineInputBorder( hintText: 'Hello@gmail.com',
borderSide: BorderSide( fillColor:
color: Color(0xFFECECEC)), Color.fromARGB(255, 239, 239, 239),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
border: const OutlineInputBorder(
borderSide: BorderSide(
color: Color(0xFFECECEC)),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(
color: Color(0xFFECECEC)),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
hintText: 'Contraseña',
fillColor: const Color.fromARGB(
255, 239, 239, 239),
filled: true, filled: true,
prefixIcon: const Icon(Icons.lock_outline), prefixIcon: Icon(Icons.email_outlined)),
suffixIcon: IconButton( ),
icon: Icon( ),
_obscureText const Padding(
? Icons.visibility padding: EdgeInsets.only(bottom: 5),
: Icons.visibility_off, child: Align(
color: Colors.grey, alignment: Alignment.topLeft,
), child: Text('Password',
onPressed: () { style: TextStyle(
setState(() { fontSize: 18.0,
_obscureText = !_obscureText; color: Color(0xFF65676B))),
}); )),
}, Padding(
padding: const EdgeInsets.only(bottom: 25),
child: TextFormField(
controller: controller.password,
obscureText: _obscureText,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Por favor ingresa una contraseña';
}
if (value.length <= 6) {
return 'Contraseña muy corta';
}
return null;
},
decoration: InputDecoration(
errorBorder: const OutlineInputBorder(
borderSide: BorderSide(
color:
Color.fromARGB(255, 184, 0, 0)),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
enabledBorder: const OutlineInputBorder(
borderSide:
BorderSide(color: Color(0xFFECECEC)),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
border: const OutlineInputBorder(
borderSide:
BorderSide(color: Color(0xFFECECEC)),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
focusedBorder: const OutlineInputBorder(
borderSide:
BorderSide(color: Color(0xFFECECEC)),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
hintText: 'Contraseña',
fillColor:
const Color.fromARGB(255, 239, 239, 239),
filled: true,
prefixIcon: const Icon(Icons.lock_outline),
suffixIcon: IconButton(
icon: Icon(
_obscureText
? Icons.visibility
: Icons.visibility_off,
color: Colors.grey,
), ),
onPressed: () {
setState(() {
_obscureText = !_obscureText;
});
},
), ),
), ),
), ),
], ),
)), ],
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment
.center, // Centra horizontalmente
children: <Widget>[
Checkbox(
value: _isChecked,
onChanged: (value) {
setState(() {
_isChecked = value!;
});
},
),
GestureDetector(
onTap: () {
if (kIsWeb) {
_launchURL(
settings?.terminosCondiciones ?? '');
} else {
Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext context) {
return WebViewScreen(
label: 'Políticas de privacidad',
link: settings?.terminosCondiciones ??
'',
);
},
),
);
}
},
child: const Text(
'Acepto los términos y condiciones.',
style: TextStyle(
color: Color(0xFF65676B),
decoration: TextDecoration.underline,
),
),
),
],
),
),
Padding( Padding(
padding: const EdgeInsets.only(bottom: 25), padding: const EdgeInsets.only(bottom: 25),
child: Center( child: Center(
@@ -302,6 +374,7 @@ class _RegisterScreenState extends State<RegisterScreen> {
} }
}, },
label: 'Registrarme', label: 'Registrarme',
isEnabled: _isChecked,
), ),
), ),
), ),
@@ -407,195 +480,187 @@ class _RegisterScreenState extends State<RegisterScreen> {
horizontal: 0, vertical: 20), horizontal: 0, vertical: 20),
child: Column( child: Column(
children: [ children: [
// Padding(
// padding: const EdgeInsets.only(bottom: 20),
// child: ElevatedButton(
// onPressed: () async {
// await AuthenticationRepository.instance
// .signInWithGoogle();
// },
// style: ElevatedButton.styleFrom(
// backgroundColor: const Color(0xFF2BA4EC),
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(50),
// ),
// elevation: 0,
// minimumSize: const Size(230, 60),
// ),
// child: const Row(
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// Text(
// 'Entrar con Google ',
// style: TextStyle(
// color: Colors.white,
// fontWeight: FontWeight.bold,
// fontSize: 18,
// ),
// ),
// SizedBox(width: 5),
// FaIcon(FontAwesomeIcons.google),
// ],
// )),
// ),
// const Padding(
// padding: EdgeInsets.symmetric(vertical: 0),
// child: Row(
// children: <Widget>[
// Expanded(
// child: Divider(
// color: Colors.black38,
// thickness: 1,
// ),
// ),
// Padding(
// padding: EdgeInsets.symmetric(horizontal: 10),
// child: Text("ó"),
// ),
// Expanded(
// child: Divider(
// color: Colors.black38,
// thickness: 1,
// ),
// ),
// ],
// ),
// ),
Form( Form(
key: _formKey, key: _formKey,
child: Column( child: Column(
children: [ children: [
const Padding( const Padding(
padding: EdgeInsets.only(bottom: 5), padding: EdgeInsets.only(bottom: 5),
child: Align( child: Align(
alignment: Alignment.topLeft, alignment: Alignment.topLeft,
child: Text('Email', child: Text('Email',
style: TextStyle( style: TextStyle(
fontSize: 18.0, fontSize: 18.0,
color: Color(0xFF65676B))), color: Color(0xFF65676B))),
)), )),
Padding( Padding(
padding: const EdgeInsets.only(bottom: 18), padding: const EdgeInsets.only(bottom: 18),
child: TextFormField( child: TextFormField(
controller: controller.email, controller: controller.email,
validator: (String? value) { validator: (String? value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Por favor ingrese un email'; return 'Por favor ingresa un email';
} }
final RegExp emailRegExp = RegExp( final RegExp emailRegExp = RegExp(
r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$'); r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
if (!emailRegExp.hasMatch(value)) { if (!emailRegExp.hasMatch(value)) {
return 'Por favor ingrese un email válido'; return 'Por favor ingresa un email válido';
} }
return null; return null;
}, },
decoration: const InputDecoration( decoration: const InputDecoration(
border: OutlineInputBorder( border: OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
color: Color(0xFFECECEC)), color: Color(0xFFECECEC)),
borderRadius: BorderRadius.all( borderRadius: BorderRadius.all(
Radius.circular(50), Radius.circular(50),
)), )),
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
color: Color(0xFFECECEC)), color: Color(0xFFECECEC)),
borderRadius: BorderRadius.all( borderRadius: BorderRadius.all(
Radius.circular(50), Radius.circular(50),
)), )),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
color: Color(0xFFECECEC)), color: Color(0xFFECECEC)),
borderRadius: BorderRadius.all( borderRadius: BorderRadius.all(
Radius.circular(50), Radius.circular(50),
)), )),
errorBorder: OutlineInputBorder( errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Color.fromARGB(
255, 184, 0, 0)),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
hintText: 'Hello@gmail.com',
fillColor: Color.fromARGB(
255, 239, 239, 239),
filled: true,
prefixIcon:
Icon(Icons.email_outlined)),
),
),
const Padding(
padding: EdgeInsets.only(bottom: 5),
child: Align(
alignment: Alignment.topLeft,
child: Text('Password',
style: TextStyle(
fontSize: 18.0,
color: Color(0xFF65676B))),
)),
Padding(
padding: const EdgeInsets.only(bottom: 25),
child: TextFormField(
controller: controller.password,
obscureText: _obscureText,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Por favor ingrese una contraseña';
}
if (value.length <= 6) {
return 'Contraseña muy corta';
}
return null;
},
decoration: InputDecoration(
errorBorder: const OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
color: Color.fromARGB( color: Color.fromARGB(
255, 184, 0, 0)), 255, 184, 0, 0)),
borderRadius: BorderRadius.all( borderRadius: BorderRadius.all(
Radius.circular(50), Radius.circular(50),
)), )),
enabledBorder: const OutlineInputBorder( hintText: 'Hello@gmail.com',
borderSide: BorderSide( fillColor:
color: Color(0xFFECECEC)), Color.fromARGB(255, 239, 239, 239),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
border: const OutlineInputBorder(
borderSide: BorderSide(
color: Color(0xFFECECEC)),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(
color: Color(0xFFECECEC)),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
hintText: 'Contraseña',
fillColor: const Color.fromARGB(
255, 239, 239, 239),
filled: true, filled: true,
prefixIcon: prefixIcon: Icon(Icons.email_outlined)),
const Icon(Icons.lock_outline), ),
suffixIcon: IconButton( ),
icon: Icon( const Padding(
_obscureText padding: EdgeInsets.only(bottom: 5),
? Icons.visibility child: Align(
: Icons.visibility_off, alignment: Alignment.topLeft,
color: Colors.grey, child: Text('Password',
), style: TextStyle(
onPressed: () { fontSize: 18.0,
setState(() { color: Color(0xFF65676B))),
_obscureText = !_obscureText; )),
}); Padding(
}, padding: const EdgeInsets.only(bottom: 25),
child: TextFormField(
controller: controller.password,
obscureText: _obscureText,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Por favor ingresa una contraseña';
}
if (value.length <= 6) {
return 'Contraseña muy corta';
}
return null;
},
decoration: InputDecoration(
errorBorder: const OutlineInputBorder(
borderSide: BorderSide(
color: Color.fromARGB(
255, 184, 0, 0)),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(
color: Color(0xFFECECEC)),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
border: const OutlineInputBorder(
borderSide: BorderSide(
color: Color(0xFFECECEC)),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(
color: Color(0xFFECECEC)),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
hintText: 'Contraseña',
fillColor: const Color.fromARGB(
255, 239, 239, 239),
filled: true,
prefixIcon:
const Icon(Icons.lock_outline),
suffixIcon: IconButton(
icon: Icon(
_obscureText
? Icons.visibility
: Icons.visibility_off,
color: Colors.grey,
), ),
onPressed: () {
setState(() {
_obscureText = !_obscureText;
});
},
), ),
), ),
), ),
], ),
)), ],
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment
.center, // Centra horizontalmente
children: <Widget>[
Checkbox(
value: _isChecked,
onChanged: (value) {
setState(() {
_isChecked = value!;
});
},
),
GestureDetector(
onTap: () {
if (kIsWeb) {
_launchURL(
settings?.terminosCondiciones ?? '');
} else {
Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext context) {
return WebViewScreen(
label: 'Políticas de privacidad',
link: settings
?.terminosCondiciones ??
'',
);
},
),
);
}
},
child: const Text(
'Acepto los términos y condiciones.',
style: TextStyle(
color: Color(0xFF65676B),
decoration: TextDecoration.underline,
),
),
),
],
),
),
Padding( Padding(
padding: const EdgeInsets.only(bottom: 25), padding: const EdgeInsets.only(bottom: 25),
child: Center( child: Center(
@@ -608,6 +673,7 @@ class _RegisterScreenState extends State<RegisterScreen> {
); );
} }
}, },
isEnabled: _isChecked,
label: 'Registrarme', label: 'Registrarme',
), ),
), ),
File diff suppressed because it is too large Load Diff
+1
View File
@@ -75,6 +75,7 @@ class SolicitudScreen extends StatelessWidget {
try { try {
eventos.addAll(snapshot.data!); eventos.addAll(snapshot.data!);
eventos.sort((a, b) => a.range1Hour1.compareTo(b.range1Hour1));
} catch (e) { } catch (e) {
print("Error" + e.toString()); print("Error" + e.toString());
} }
+3 -9
View File
@@ -19,9 +19,7 @@ class SsupportStateScreen extends State<SupportScreen> {
final String body = ''; final String body = '';
Future<void> _sendWhatsapp(String? number) async { Future<void> _sendWhatsapp(String? number) async {
final _whatsappUrl = final _whatsappUrl = 'https://api.whatsapp.com/send?phone=$number&text=Hola%21+soy+usuario+de+Prosapp+y+quisiera+conocer+mas+sobre+esta+app+%F0%9F%98%81';
'https://wa.me/$number?text=${Uri.parse('Hola! soy usuario de Prosapp y quisiera conocer mas sobre esta app')}';
if (!await launch(_whatsappUrl)) { if (!await launch(_whatsappUrl)) {
throw Exception('Could not launch $_whatsappUrl'); throw Exception('Could not launch $_whatsappUrl');
} }
@@ -39,14 +37,10 @@ class SsupportStateScreen extends State<SupportScreen> {
} }
void _sendEmailWeb(String recipients) async { void _sendEmailWeb(String recipients) async {
final email = final email = 'mailto:$recipients?subject=${Uri.encodeComponent(recipients)}&body=${Uri.encodeComponent(body)}';
'mailto:$recipients?subject=${Uri.encodeComponent(recipients)}&body=${Uri.encodeComponent(body)}';
if (await canLaunch(email)) { if (await canLaunch(email)) {
await launch(email); await launch(email);
} else { } else {}
// No se pudo abrir el cliente de correo electrónico
// Puedes mostrar un diálogo o realizar otra acción en este caso
}
} }
@override @override
+17 -4
View File
@@ -1,4 +1,6 @@
import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:get/get.dart';
class FirebaseMessagingService { class FirebaseMessagingService {
FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance; FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;
@@ -18,11 +20,22 @@ class FirebaseMessagingService {
String? token = await _firebaseMessaging.getToken(); String? token = await _firebaseMessaging.getToken();
print('Token FCM: $token'); print('Token FCM: $token');
// Escuchar los mensajes entrantes en la aplicación
FirebaseMessaging.onMessage.listen((RemoteMessage message) { FirebaseMessaging.onMessage.listen((RemoteMessage message) {
print('Mensaje FCM recibido: ${message.notification?.title} - ${message.notification?.body}'); print('Mensaje FCM recibido: ${message.notification?.title} - ${message.notification?.body}');
// Aquí puedes mostrar la notificación o procesar los datos recibidos según tus necesidades
}); // Obtener el valor de la clave "screen" de los datos de la notificación
String? notificationScreen = message.data['screen'];
// Navegar a la pantalla correspondiente según el valor de la clave "screen"
if (notificationScreen == "misservicios") {
// Navegar a MyServicesScreen
Get.offNamed('/misservicios');
} else if (notificationScreen == "solicitud") {
// Navegar a SolicitudScreen
Get.offNamed('/solicitud');
}
});
// Manejar la notificación cuando se toca y la aplicación está en primer plano (opcional) // Manejar la notificación cuando se toca y la aplicación está en primer plano (opcional)
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) { FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
@@ -16,6 +16,7 @@ import firebase_storage
import flutter_local_notifications import flutter_local_notifications
import geolocator_apple import geolocator_apple
import path_provider_foundation import path_provider_foundation
import shared_preferences_foundation
import url_launcher_macos import url_launcher_macos
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
@@ -30,5 +31,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin")) GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
} }
+5 -1
View File
@@ -26,6 +26,7 @@
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
DFAE116AA0A5B93B39BF14BF /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = AE1007FC9B2143762CB9DF6D /* GoogleService-Info.plist */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@@ -54,7 +55,7 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
33CC10ED2044A3C60003C045 /* prosappco.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "prosappco.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10ED2044A3C60003C045 /* prosappco.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = prosappco.app; sourceTree = BUILT_PRODUCTS_DIR; };
33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
@@ -68,6 +69,7 @@
33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
AE1007FC9B2143762CB9DF6D /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@@ -99,6 +101,7 @@
33CEB47122A05771004F2AC0 /* Flutter */, 33CEB47122A05771004F2AC0 /* Flutter */,
33CC10EE2044A3C60003C045 /* Products */, 33CC10EE2044A3C60003C045 /* Products */,
D73912EC22F37F3D000D13A0 /* Frameworks */, D73912EC22F37F3D000D13A0 /* Frameworks */,
AE1007FC9B2143762CB9DF6D /* GoogleService-Info.plist */,
); );
sourceTree = "<group>"; sourceTree = "<group>";
}; };
@@ -227,6 +230,7 @@
files = ( files = (
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */,
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */,
DFAE116AA0A5B93B39BF14BF /* GoogleService-Info.plist in Resources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"file_generated_by": "FlutterFire CLI", "file_generated_by": "FlutterFire CLI",
"purpose": "FirebaseAppID & ProjectID for this Firebase app in this directory", "purpose": "FirebaseAppID & ProjectID for this Firebase app in this directory",
"GOOGLE_APP_ID": "1:245204384533:ios:aeb233e55c5ddf7a9f871c", "GOOGLE_APP_ID": "1:245204384533:ios:1d58f5624d0df4859f871c",
"FIREBASE_PROJECT_ID": "prosapp-5747a", "FIREBASE_PROJECT_ID": "prosapp-5747a",
"GCM_SENDER_ID": "245204384533" "GCM_SENDER_ID": "245204384533"
} }
+56
View File
@@ -960,6 +960,62 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.0" version: "2.0.0"
shared_preferences:
dependency: "direct main"
description:
name: shared_preferences
sha256: "0344316c947ffeb3a529eac929e1978fcd37c26be4e8468628bac399365a3ca1"
url: "https://pub.dev"
source: hosted
version: "2.2.0"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
sha256: fe8401ec5b6dcd739a0fe9588802069e608c3fdbfd3c3c93e546cf2f90438076
url: "https://pub.dev"
source: hosted
version: "2.2.0"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: d29753996d8eb8f7619a1f13df6ce65e34bc107bef6330739ed76f18b22310ef
url: "https://pub.dev"
source: hosted
version: "2.3.3"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
sha256: "71d6806d1449b0a9d4e85e0c7a917771e672a3d5dc61149cc9fac871115018e1"
url: "https://pub.dev"
source: hosted
version: "2.3.0"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
sha256: "23b052f17a25b90ff2b61aad4cc962154da76fb62848a9ce088efe30d7c50ab1"
url: "https://pub.dev"
source: hosted
version: "2.3.0"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
sha256: "7347b194fb0bbeb4058e6a4e87ee70350b6b2b90f8ac5f8bd5b3a01548f6d33a"
url: "https://pub.dev"
source: hosted
version: "2.2.0"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
sha256: f95e6a43162bce43c9c3405f3eb6f39e5b5d11f65fab19196cf8225e2777624d
url: "https://pub.dev"
source: hosted
version: "2.3.0"
simple_gesture_detector: simple_gesture_detector:
dependency: transitive dependency: transitive
description: description:
+3 -2
View File
@@ -1,5 +1,5 @@
name: prosappco name: prosappco
description: A new Flutter project. description: Encuentra personal médico certificado.
# The following line prevents the package from being accidentally published to # The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages. # pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev publish_to: 'none' # Remove this line if you wish to publish to pub.dev
@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 1.0.0+1 version: 1.1.0+1
environment: environment:
sdk: '>=2.19.3 <3.0.0' sdk: '>=2.19.3 <3.0.0'
@@ -30,6 +30,7 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
shared_preferences: ^2.0.10
# The following adds the Cupertino Icons font to your application. # The following adds the Cupertino Icons font to your application.
+3 -1
View File
@@ -23,7 +23,9 @@
<!-- iOS meta tags & icons --> <!-- iOS meta tags & icons -->
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black"> <meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="prosappco"> <meta name="apple-mobile-web-app-title" content="prosapp">
<meta name="package" content="prosapp"> <!-- Debe coincidir con el nuevo ID de paquete en Firebase -->
<link rel="apple-touch-icon" href="icons/Icon-192.png"> <link rel="apple-touch-icon" href="icons/Icon-192.png">
<!-- Favicon --> <!-- Favicon -->