This commit is contained in:
Felipe
2023-11-10 15:34:13 -05:00
parent b3d1740649
commit f732d461d0
14 changed files with 613 additions and 235 deletions
@@ -187,6 +187,34 @@ class AuthenticationRepository extends GetxController {
return city; return city;
} }
Future<String> getGender(String uid) async {
String gender = '';
try {
final snapshot =
await FirebaseFirestore.instance.collection('users').doc(uid).get();
final Map<String, dynamic>? data = snapshot.data();
gender = data?['gender'] ?? '';
} catch (e) {
print('Error getting gender: $e');
}
return gender;
}
Future<String> getBirthday(String uid) async {
String birthDate = '';
try {
final snapshot =
await FirebaseFirestore.instance.collection('users').doc(uid).get();
final Map<String, dynamic>? data = snapshot.data();
birthDate = data?['birth_date'] ?? '';
print('nada $birthDate');
} catch (e) {
print('Error getting birthDate: $e');
}
return birthDate;
}
Future<String> getCoordsOfCity(String uid) async { Future<String> getCoordsOfCity(String uid) async {
String coords = ''; String coords = '';
try { try {
@@ -30,10 +30,12 @@ class _LoginScreenState extends State<LoginScreen> {
SettingModel? settings; SettingModel? settings;
void _clearPhoneNumber() { void _clearPhoneNumber() {
if (mounted) {
setState(() { setState(() {
controller.phoneNo.text = ''; controller.phoneNo.text = '';
}); });
} }
}
void _launchURL(String url) async { void _launchURL(String url) async {
if (await canLaunch(url)) { if (await canLaunch(url)) {
@@ -47,11 +49,13 @@ class _LoginScreenState extends State<LoginScreen> {
void initState() { void initState() {
super.initState(); super.initState();
if (settings == null) { if (settings == null) {
SettingModel.getSettings().then( SettingModel.getSettings().then((SettingModel value) {
(SettingModel value) => setState(() { if (mounted) {
setState(() {
settings = value; settings = value;
}), });
); }
});
} }
} }
@@ -182,12 +186,12 @@ class _LoginScreenState extends State<LoginScreen> {
PhoneAuthController.instance.phoneAuthentication( PhoneAuthController.instance.phoneAuthentication(
completePhoneNumber.trim(), completePhoneNumber.trim(),
); );
_clearPhoneNumber();
await Get.to( await Get.to(
() => CodeValidationScreen( () => CodeValidationScreen(
phoneNumber: completePhoneNumber.trim(), phoneNumber: completePhoneNumber.trim(),
), ),
); );
_clearPhoneNumber();
Provider.of<UserProvider>(context, listen: false) Provider.of<UserProvider>(context, listen: false)
.initUserProvider(); .initUserProvider();
} }
+30 -1
View File
@@ -9,6 +9,7 @@ import 'package:prosappco/src/components/pop_appbar.dart';
import 'package:prosappco/src/models/event_model.dart'; import 'package:prosappco/src/models/event_model.dart';
import 'package:prosappco/src/models/scores_model.dart'; import 'package:prosappco/src/models/scores_model.dart';
import 'package:prosappco/src/presentation/screens/cita.dart'; import 'package:prosappco/src/presentation/screens/cita.dart';
import 'package:prosappco/src/presentation/screens/score.dart';
class MyServicesScreen extends StatelessWidget { class MyServicesScreen extends StatelessWidget {
MyServicesScreen({super.key}); MyServicesScreen({super.key});
@@ -54,6 +55,7 @@ class MyServicesScreen extends StatelessWidget {
.asyncMap((snapshot) async { .asyncMap((snapshot) async {
try { try {
List<Event> eventos = []; List<Event> eventos = [];
for (var element in snapshot.docs) { for (var element in snapshot.docs) {
final event = Event.fromJson(element.data()); final event = Event.fromJson(element.data());
event.scoresModel = event.scoresModel =
@@ -79,8 +81,10 @@ class MyServicesScreen extends StatelessWidget {
try { try {
eventos.addAll(snapshot.data!); eventos.addAll(snapshot.data!);
eventos.sort((a, b) => a.timeStamp!.compareTo(b.timeStamp!)); eventos.sort((a, b) => a.timeStamp!.compareTo(b.timeStamp!));
print('snapshot mi b ${eventos}');
} catch (e) { } catch (e) {
print("Error" + e.toString()); print("Error snapshot" + e.toString());
} }
if (eventos.isEmpty) { if (eventos.isEmpty) {
@@ -122,6 +126,9 @@ class MyServicesScreen extends StatelessWidget {
? Colors.red[100] ? Colors.red[100]
: Colors.blue[100], : Colors.blue[100],
onTap: () { onTap: () {
if (event.status == 'terminado') {
if (event.userId == uid) {
if (event.userScored) {
Navigator.push( Navigator.push(
context, context,
CupertinoPageRoute( CupertinoPageRoute(
@@ -130,6 +137,28 @@ class MyServicesScreen extends StatelessWidget {
}, },
), ),
); );
} else {
Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext context) {
return ScoreScreen(
evento: event, pro: false);
},
),
);
}
}
} else {
Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext context) {
return CitaScreen(evento: event);
},
),
);
}
}, },
leading: event.status == 'aprobado' leading: event.status == 'aprobado'
? const Column( ? const Column(
@@ -9,6 +9,7 @@ import 'package:prosappco/src/components/pop_appbar.dart';
import 'package:prosappco/src/models/event_model.dart'; import 'package:prosappco/src/models/event_model.dart';
import 'package:prosappco/src/models/scores_model.dart'; import 'package:prosappco/src/models/scores_model.dart';
import 'package:prosappco/src/presentation/screens/cita.dart'; import 'package:prosappco/src/presentation/screens/cita.dart';
import 'package:prosappco/src/presentation/screens/score.dart';
class MyServicesProScreen extends StatelessWidget { class MyServicesProScreen extends StatelessWidget {
MyServicesProScreen({super.key}); MyServicesProScreen({super.key});
@@ -98,6 +99,9 @@ class MyServicesProScreen extends StatelessWidget {
? Colors.red[100] ? Colors.red[100]
: Colors.blue[100], : Colors.blue[100],
onTap: () { onTap: () {
if (event.status == 'terminado') {
if (event.professionalId == uid) {
if (event.professionalScored) {
Navigator.push( Navigator.push(
context, context,
CupertinoPageRoute( CupertinoPageRoute(
@@ -106,6 +110,27 @@ class MyServicesProScreen extends StatelessWidget {
}, },
), ),
); );
} else {
Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext context) {
return ScoreScreen(evento: event, pro: true);
},
),
);
}
}
} else {
Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext context) {
return CitaScreen(evento: event);
},
),
);
}
}, },
leading: event.status == 'aprobado' leading: event.status == 'aprobado'
? const Column( ? const Column(
@@ -4,7 +4,6 @@ import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:prosappco/src/authentication/authentication_repository.dart'; import 'package:prosappco/src/authentication/authentication_repository.dart';
import 'package:prosappco/src/components/pop_appbar.dart'; import 'package:prosappco/src/components/pop_appbar.dart';
import 'package:prosappco/src/presentation/screens/support.dart';
final CollectionReference professionsCollection = final CollectionReference professionsCollection =
FirebaseFirestore.instance.collection('professions'); FirebaseFirestore.instance.collection('professions');
@@ -1,3 +1,4 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_rating_bar/flutter_rating_bar.dart'; import 'package:flutter_rating_bar/flutter_rating_bar.dart';
@@ -38,6 +39,33 @@ class _ProfessionalInfoScreenState extends State<ProfessionalInfoScreen> {
}), }),
); );
} }
loadPaymentMethods();
}
Map<String, bool> paymentMethods = {};
String _formatPaymentMethods(Map<String, bool> paymentMethods) {
List<String> enabledMethods = paymentMethods.entries
.where((entry) => entry.value)
.map((entry) => entry.key)
.toList();
return enabledMethods.join(', ');
}
void loadPaymentMethods() {
FirebaseFirestore.instance
.collection('users')
.doc(widget.professional.id)
.get()
.then((doc) {
if (doc.exists) {
setState(() {
paymentMethods = Map<String, bool>.from(doc['paymentMethods'] ?? {});
});
}
});
} }
@override @override
@@ -156,7 +184,38 @@ class _ProfessionalInfoScreenState extends State<ProfessionalInfoScreen> {
), ),
) )
: const SizedBox(), : const SizedBox(),
const SizedBox(height: 10), const SizedBox(height: 5),
paymentMethods.containsValue(true)
? Container(
width: MediaQuery.of(context).size.width * 0.8,
padding: const EdgeInsets.symmetric(
horizontal: 16, vertical: 8),
decoration: BoxDecoration(
color: Colors.blue.withOpacity(0.1),
borderRadius: BorderRadius.circular(10),
),
child: RichText(
text: TextSpan(
style: const TextStyle(
fontSize: 12,
color: Colors.blue,
),
children: [
const TextSpan(
text: 'Métodos de pago recibidos: ',
style:
TextStyle(fontWeight: FontWeight.normal),
),
TextSpan(
text: _formatPaymentMethods(paymentMethods),
style: const TextStyle(
fontWeight: FontWeight.bold),
),
],
),
))
: const SizedBox(),
const SizedBox(height: 5),
const Text( const Text(
'Se unió el 02 de abril del 2023', 'Se unió el 02 de abril del 2023',
style: TextStyle(fontSize: 12), style: TextStyle(fontSize: 12),
@@ -1,6 +1,5 @@
import 'dart:io'; import 'dart:io';
import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_storage/firebase_storage.dart'; import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
@@ -25,7 +24,6 @@ class ProfessionalProfileScreenState extends State<ProfessionalProfileScreen> {
File? image_cedula; File? image_cedula;
File? image_certificado; File? image_certificado;
late final FirebaseAuth _auth;
final FirebaseStorage storage = FirebaseStorage.instance; final FirebaseStorage storage = FirebaseStorage.instance;
final uid = AuthenticationRepository.instance.getCurrentUserUid(); final uid = AuthenticationRepository.instance.getCurrentUserUid();
@@ -44,7 +42,6 @@ class ProfessionalProfileScreenState extends State<ProfessionalProfileScreen> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_auth = FirebaseAuth.instance;
if (_photo == '...') { if (_photo == '...') {
AuthenticationRepository.instance AuthenticationRepository.instance
.getPhoto(uid.toString()) .getPhoto(uid.toString())
@@ -43,13 +43,14 @@ class _ProfileScreenState extends State<ProfileScreen> {
var _photo = '...'; var _photo = '...';
String? _email = ''; String? _email = '';
String gender = ''; String gender = '';
String genderDb = '';
DateTime? birthDate; DateTime? birthDate;
String birthDateDb = '';
@override @override
void initState() { void initState() {
super.initState(); super.initState();
final uid = AuthenticationRepository.instance.getCurrentUserUid();
_auth = FirebaseAuth.instance; _auth = FirebaseAuth.instance;
final currentUser = _auth.currentUser; final currentUser = _auth.currentUser;
@@ -65,22 +66,40 @@ class _ProfileScreenState extends State<ProfileScreen> {
_emailController.text = currentUser.email!; _emailController.text = currentUser.email!;
} }
if (gender.isEmpty) {
AuthenticationRepository.instance.getGender(uid.toString()).then(
(String s) => setState(() {
genderDb = s;
}),
);
}
if (birthDate == null) {
AuthenticationRepository.instance.getBirthday(uid.toString()).then(
(String s) => setState(() {
if (s.isNotEmpty) {
birthDateDb = s;
}
}),
);
}
_email = currentUser?.email; _email = currentUser?.email;
if (_ciudad == '...') { if (_ciudad == '...') {
AuthenticationRepository.instance AuthenticationRepository.instance.getCity(uid.toString()).then(
.getCity(uid.toString()) (String s) => setState(() {
.then((String s) => setState(() {
_ciudad = s; _ciudad = s;
})); }),
);
} }
if (_photo == '...') { if (_photo == '...') {
AuthenticationRepository.instance AuthenticationRepository.instance.getPhoto(uid.toString()).then(
.getPhoto(uid.toString()) (String s) => setState(() {
.then((String s) => setState(() {
_photo = s; _photo = s;
})); }),
);
} }
} }
@@ -221,6 +240,32 @@ class _ProfileScreenState extends State<ProfileScreen> {
String newEmail = _emailController.text.trim(); String newEmail = _emailController.text.trim();
String newPassword = _passwordController.text.trim(); String newPassword = _passwordController.text.trim();
if (gender.isNotEmpty) {
try {
await FirebaseFirestore.instance.collection('users').doc(uid).set({
'gender': gender,
}, SetOptions(merge: true));
genderDb = gender;
} catch (e) {
print('Error al actualizar el genero: $e');
}
}
if (birthDate != null) {
try {
await FirebaseFirestore.instance.collection('users').doc(uid).set({
'birth_date': birthDate.toString(),
}, SetOptions(merge: true));
birthDateDb = birthDate.toString();
} catch (e) {
print('Error al actualizar la fecha de nacimiento: $e');
}
}
setState(() {});
if (newName.isEmpty) { if (newName.isEmpty) {
Get.snackbar( Get.snackbar(
'Nombre Invalido', 'Nombre Invalido',
@@ -281,7 +326,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
.doc(uid) .doc(uid)
.update({'email': newEmail}); .update({'email': newEmail});
} catch (e) { } catch (e) {
print('e'); print('Error al actualizar la imagen de perfil $e');
} }
try { try {
@@ -296,7 +341,11 @@ class _ProfileScreenState extends State<ProfileScreen> {
print('Error al actualizar la imagen de perfil $e'); print('Error al actualizar la imagen de perfil $e');
} }
// notifyListeners(); Get.snackbar(
'Informacion actualizada',
'Tu informacion ha sido actualizada con exito.',
snackPosition: SnackPosition.BOTTOM,
);
} }
Future<void> _updateEmailAndPassword( Future<void> _updateEmailAndPassword(
@@ -435,7 +484,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
'Inicia 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!);
} }
} }
} }
@@ -644,15 +693,20 @@ class _ProfileScreenState extends State<ProfileScreen> {
), ),
), ),
const SizedBox(height: 20.0), const SizedBox(height: 20.0),
GenderDropdown( genderDb == ''
? GenderDropdown(
onChanged: (selectedGender) { onChanged: (selectedGender) {
setState(() { setState(() {
gender = selectedGender; gender = selectedGender;
}); });
}, },
), )
const SizedBox(height: 20.0), : const SizedBox(),
BirthDatePicker( genderDb == ''
? const SizedBox(height: 20.0)
: const SizedBox(),
birthDateDb == ''
? BirthDatePicker(
onDateSelected: (birthDay) { onDateSelected: (birthDay) {
setState(() { setState(() {
birthDate = birthDay; birthDate = birthDay;
@@ -663,7 +717,8 @@ class _ProfileScreenState extends State<ProfileScreen> {
? '' ? ''
: formatter.format(birthDate!), : formatter.format(birthDate!),
), ),
), )
: const SizedBox(),
], ],
), ),
), ),
@@ -9,12 +9,13 @@ import 'package:get/get.dart';
import 'package:prosappco/src/authentication/authentication_repository.dart'; import 'package:prosappco/src/authentication/authentication_repository.dart';
import 'package:prosappco/src/components/banner_photo.dart'; import 'package:prosappco/src/components/banner_photo.dart';
import 'package:prosappco/src/components/pop_appbar.dart'; import 'package:prosappco/src/components/pop_appbar.dart';
import 'package:prosappco/src/components/primary_btn.dart';
import 'package:prosappco/src/components/schedule_picker.dart'; import 'package:prosappco/src/components/schedule_picker.dart';
import 'package:prosappco/src/models/setting_model.dart'; import 'package:prosappco/src/models/setting_model.dart';
import 'package:prosappco/src/presentation/screens/horario.dart'; import 'package:prosappco/src/presentation/screens/horario.dart';
import 'package:prosappco/src/presentation/screens/professional.dart'; import 'package:prosappco/src/presentation/screens/professional.dart';
import 'package:prosappco/src/presentation/screens/professional_direccion.dart'; import 'package:prosappco/src/presentation/screens/professional_direccion.dart';
import 'package:prosappco/src/presentation/widgets/shared/primary_button.dart';
import 'package:prosappco/src/presentation/widgets/shared/primary_checkbox.dart';
import 'package:prosappco/src/services/select_image_profile.dart'; import 'package:prosappco/src/services/select_image_profile.dart';
class ProfileProScreen extends StatefulWidget { class ProfileProScreen extends StatefulWidget {
@@ -47,8 +48,18 @@ class _ProfileProScreenState extends State<ProfileProScreen> {
int _tarifa = 0; int _tarifa = 0;
SettingModel? settings; SettingModel? settings;
bool nequiValue = false;
bool banktransferValue = false;
bool datafoneValue = false;
Map<String, Schedule>? _horarios; Map<String, Schedule>? _horarios;
Map<String, bool> paymentMethods = {
'Nequi': false,
'Transferencia Bancaria': false,
'Datafono': false,
};
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@@ -131,6 +142,8 @@ class _ProfileProScreenState extends State<ProfileProScreen> {
), ),
); );
} }
loadPaymentMethods();
} }
void createSchedules() async { void createSchedules() async {
@@ -276,6 +289,8 @@ class _ProfileProScreenState extends State<ProfileProScreen> {
print('Error al actualizar la imagen de perfil $e'); print('Error al actualizar la imagen de perfil $e');
} }
updatePaymentMethods();
Get.snackbar( Get.snackbar(
'Información actualizada', 'Información actualizada',
'Tu información ha sido actualizada con éxito.', 'Tu información ha sido actualizada con éxito.',
@@ -405,6 +420,22 @@ class _ProfileProScreenState extends State<ProfileProScreen> {
}); });
} }
void updatePaymentMethods() {
FirebaseFirestore.instance.collection('users').doc(uid).update({
'paymentMethods': paymentMethods,
});
}
void loadPaymentMethods() {
FirebaseFirestore.instance.collection('users').doc(uid).get().then((doc) {
if (doc.exists) {
setState(() {
paymentMethods = Map<String, bool>.from(doc['paymentMethods'] ?? {});
});
}
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
String address = _direccion.toString(); String address = _direccion.toString();
@@ -522,6 +553,33 @@ class _ProfileProScreenState extends State<ProfileProScreen> {
) )
: const SizedBox(), : const SizedBox(),
const Divider(), const Divider(),
Padding(
padding: const EdgeInsets.only(left: 30, right: 30, bottom: 30),
child: SizedBox(
width: double.infinity,
child: Column(
children: [
const Text(
'Metodos de pago',
style: TextStyle(
color: Colors.black,
fontSize: 17,
),
),
for (var entry in paymentMethods.entries)
PrimaryCheckbox(
text: entry.key,
initialValue: entry.value,
onChanged: (value) {
setState(() {
paymentMethods[entry.key] = value;
});
},
),
],
),
),
),
const Padding( const Padding(
padding: EdgeInsets.symmetric(horizontal: 30), padding: EdgeInsets.symmetric(horizontal: 30),
child: SizedBox( child: SizedBox(
@@ -530,7 +588,7 @@ class _ProfileProScreenState extends State<ProfileProScreen> {
'Horario estandar', 'Horario estandar',
style: TextStyle( style: TextStyle(
color: Colors.black, color: Colors.black,
fontSize: 15, fontSize: 17,
), ),
), ),
), ),
@@ -666,15 +724,14 @@ class _ProfileProScreenState extends State<ProfileProScreen> {
), ),
), ),
), ),
PrimaryButtom( const SizedBox(height: 10),
PrimaryButton(
onPressed: () { onPressed: () {
updateInfo(); updateInfo();
// name();
}, },
label: 'Guardar'), text: 'Guardar',
const SizedBox( ),
height: 20, const SizedBox(height: 20),
)
], ],
), ),
), ),
+72 -28
View File
@@ -26,6 +26,8 @@ import 'package:prosappco/src/presentation/screens/ubicacion.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:prosappco/src/components/network_utility.dart'; import 'package:prosappco/src/components/network_utility.dart';
import 'package:package_info_plus/package_info_plus.dart'; import 'package:package_info_plus/package_info_plus.dart';
import 'package:prosappco/src/presentation/widgets/shared/primary_button.dart';
import 'package:prosappco/src/presentation/widgets/shared/warning_snackbar.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
class ServiceScreen extends StatefulWidget { class ServiceScreen extends StatefulWidget {
@@ -178,11 +180,13 @@ class _ServiceScreenState extends State<ServiceScreen> {
); );
if (picked != null && picked != _selectedDate) { if (picked != null && picked != _selectedDate) {
if (mounted) {
setState(() { setState(() {
_selectedDate = picked; _selectedDate = picked;
}); });
} }
} }
}
Future<void> _selectTime(BuildContext context) async { Future<void> _selectTime(BuildContext context) async {
final TimeOfDay? pickedTime = await showTimePicker( final TimeOfDay? pickedTime = await showTimePicker(
@@ -191,11 +195,13 @@ class _ServiceScreenState extends State<ServiceScreen> {
); );
if (pickedTime != null) { if (pickedTime != null) {
if (mounted) {
setState(() { setState(() {
_selectedTime = pickedTime; _selectedTime = pickedTime;
}); });
} }
} }
}
Future<List<DocumentSnapshot<Map<String, dynamic>>>> getUsersWithActiveStatus( Future<List<DocumentSnapshot<Map<String, dynamic>>>> getUsersWithActiveStatus(
String _serviceType) async { String _serviceType) async {
@@ -252,13 +258,25 @@ class _ServiceScreenState extends State<ServiceScreen> {
), ),
), ),
); );
if (mounted) {
setState(() {}); setState(() {});
}
} catch (e) { } catch (e) {
print('Error: $e'); print('Error: $e');
} }
} }
@override
void dispose() {
_locationController.dispose();
_ubicationController.dispose();
_profesionalController.dispose();
_serviceTypeController.dispose();
_observacionController.dispose();
super.dispose();
}
void updateMarkersForServiceType(String serviceType) { void updateMarkersForServiceType(String serviceType) {
getUsersWithActiveStatus(serviceType).then((value) { getUsersWithActiveStatus(serviceType).then((value) {
markers.clear(); markers.clear();
@@ -287,9 +305,11 @@ class _ServiceScreenState extends State<ServiceScreen> {
PackageInfo packageInfo = await PackageInfo.fromPlatform(); PackageInfo packageInfo = await PackageInfo.fromPlatform();
String version = packageInfo.version; String version = packageInfo.version;
if (mounted) {
setState(() { setState(() {
appVersion = version; appVersion = version;
}); });
}
if (settings != null) { if (settings != null) {
_checkForUpdate(settings); _checkForUpdate(settings);
@@ -348,12 +368,14 @@ class _ServiceScreenState extends State<ServiceScreen> {
} }
if (settings == null) { if (settings == null) {
SettingModel.getSettings().then( SettingModel.getSettings().then((SettingModel value) => (value) {
(SettingModel value) => setState(() { if (mounted) {
setState(() {
settings = value.version; settings = value.version;
_getAppVersion(); _getAppVersion();
}), });
); }
});
} }
if (_ciudad == '...') { if (_ciudad == '...') {
@@ -364,15 +386,19 @@ class _ServiceScreenState extends State<ServiceScreen> {
FirebaseFirestore.instance.collection('users').doc(uid).set({ FirebaseFirestore.instance.collection('users').doc(uid).set({
'city': 'Cúcuta', 'city': 'Cúcuta',
}).then((_) { }).then((_) {
if (mounted) {
setState(() { setState(() {
_ciudad = 'Cúcuta'; _ciudad = 'Cúcuta';
}); });
}
}); });
} else { } else {
if (mounted) {
setState(() { setState(() {
_ciudad = s; _ciudad = s;
}); });
} }
}
}); });
} }
@@ -380,27 +406,33 @@ class _ServiceScreenState extends State<ServiceScreen> {
AuthenticationRepository.instance AuthenticationRepository.instance
.getCoordsOfCity(uid.toString()) .getCoordsOfCity(uid.toString())
.then((String s) { .then((String s) {
if (mounted) {
setState(() { setState(() {
_coordsOfCity = s; _coordsOfCity = s;
_setInitialCameraPosition(_coordsOfCity); _setInitialCameraPosition(_coordsOfCity);
}); });
}
}); });
} }
_saveToken(); _saveToken();
if (user == null) { if (user == null) {
UserModel.getUser(uid.toString()).then( UserModel.getUser(uid.toString()).then((UserModel s) => (value) {
(UserModel s) => setState(() => user = s), if (mounted) {
); setState(() => user = s);
}
});
} }
BitmapDescriptor.fromAssetImage( BitmapDescriptor.fromAssetImage(
const ImageConfiguration(size: Size(6, 6)), 'images/pro_marke.png') const ImageConfiguration(size: Size(6, 6)), 'images/pro_marke.png')
.then((icon) { .then((icon) {
if (mounted) {
setState(() { setState(() {
_markerIcon = icon; _markerIcon = icon;
}); });
}
}); });
updateMarkersForServiceType(_serviceType); updateMarkersForServiceType(_serviceType);
@@ -456,11 +488,13 @@ class _ServiceScreenState extends State<ServiceScreen> {
String? response = await NetworkUtility.fetchUrl(uri); String? response = await NetworkUtility.fetchUrl(uri);
if (response != null) { if (response != null) {
if (mounted) {
setState(() { setState(() {
_placesList = jsonDecode(response.toString())['results']; _placesList = jsonDecode(response.toString())['results'];
}); });
} }
} }
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -511,6 +545,7 @@ class _ServiceScreenState extends State<ServiceScreen> {
ubicacion = datos[1]; ubicacion = datos[1];
if (profesional != null) { if (profesional != null) {
if (mounted) {
setState(() { setState(() {
_profesionalController.text = _profesionalController.text =
profesional.name.toString(); profesional.name.toString();
@@ -533,6 +568,7 @@ class _ServiceScreenState extends State<ServiceScreen> {
}); });
} }
} }
}
}, },
decoration: const InputDecoration( decoration: const InputDecoration(
prefixIcon: Icon(Icons.assignment_ind_rounded), prefixIcon: Icon(Icons.assignment_ind_rounded),
@@ -558,12 +594,14 @@ class _ServiceScreenState extends State<ServiceScreen> {
final lat = datos[1]; final lat = datos[1];
final lng = datos[2]; final lng = datos[2];
if (mounted) {
setState(() { setState(() {
_ubicationController.text = formattedAddress; _ubicationController.text = formattedAddress;
latUser = lat; latUser = lat;
lngUser = lng; lngUser = lng;
}); });
} }
}
}, },
decoration: const InputDecoration( decoration: const InputDecoration(
hintText: 'Escribe tu ubicación', hintText: 'Escribe tu ubicación',
@@ -826,17 +864,21 @@ class _ServiceScreenState extends State<ServiceScreen> {
getLocationName( getLocationName(
coordinates.latitude, coordinates.longitude) coordinates.latitude, coordinates.longitude)
.then((locationName) { .then((locationName) {
if (mounted) {
setState(() { setState(() {
_locationController.text = locationName; _locationController.text = locationName;
}); });
}
}); });
} }
} }
}, },
onCameraMove: (position) { onCameraMove: (position) {
if (mounted) {
setState(() { setState(() {
coordinates = position.target; coordinates = position.target;
}); });
}
}, },
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{ gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{
Factory<OneSequenceGestureRecognizer>( Factory<OneSequenceGestureRecognizer>(
@@ -874,7 +916,9 @@ class _ServiceScreenState extends State<ServiceScreen> {
zoom: 17), zoom: 17),
), ),
); );
if (mounted) {
setState(() {}); setState(() {});
}
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
'ubicación desactivada', 'ubicación desactivada',
@@ -945,14 +989,17 @@ class _ServiceScreenState extends State<ServiceScreen> {
) as String?; ) as String?;
if (serviceType != null) { if (serviceType != null) {
if (mounted) {
setState(() { setState(() {
_serviceType = serviceType; _serviceType = serviceType;
_serviceTypeController.text = _serviceTypeController.text =
_serviceType; _serviceType;
updateMarkersForServiceType(_serviceType); updateMarkersForServiceType(
_serviceType);
}); });
} }
}
}, },
decoration: const InputDecoration( decoration: const InputDecoration(
prefixIcon: prefixIcon:
@@ -984,6 +1031,7 @@ class _ServiceScreenState extends State<ServiceScreen> {
ubicacion = datos[1]; ubicacion = datos[1];
if (profesional != null) { if (profesional != null) {
if (mounted) {
setState(() { setState(() {
_profesionalController.text = _profesionalController.text =
profesional.name.toString(); profesional.name.toString();
@@ -1018,7 +1066,8 @@ class _ServiceScreenState extends State<ServiceScreen> {
professionalLatitude != 0 && professionalLatitude != 0 &&
professionalLongitude != professionalLongitude !=
null && null &&
professionalLongitude != 0) { professionalLongitude !=
0) {
googleMapController googleMapController
?.animateCamera( ?.animateCamera(
CameraUpdate CameraUpdate
@@ -1036,6 +1085,7 @@ class _ServiceScreenState extends State<ServiceScreen> {
}); });
} }
} }
}
}, },
decoration: const InputDecoration( decoration: const InputDecoration(
prefixIcon: prefixIcon:
@@ -1090,9 +1140,11 @@ class _ServiceScreenState extends State<ServiceScreen> {
newCoordinates), newCoordinates),
); );
if (mounted) {
setState(() { setState(() {
_placesList = []; _placesList = [];
}); });
}
}, },
title: Text(_placesList[index] title: Text(_placesList[index]
['formatted_address']), ['formatted_address']),
@@ -1170,12 +1222,18 @@ class _ServiceScreenState extends State<ServiceScreen> {
hintText: 'Observaciones'), hintText: 'Observaciones'),
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
ElevatedButton( PrimaryButton(
onPressed: () { onPressed: () {
if (user?.name == null || if (user?.name == null ||
user?.name == '' || user?.name == '' ||
user?.phoneNumber == null || user?.phoneNumber == null ||
user?.phoneNumber == '') { user?.phoneNumber == '') {
WarningSnackbar.show(
title: 'Completa tu perfil',
message:
'Diligencia la información de tu perfil antes de solicitar un servicio.',
);
Navigator.push( Navigator.push(
context, context,
CupertinoPageRoute( CupertinoPageRoute(
@@ -1247,23 +1305,9 @@ class _ServiceScreenState extends State<ServiceScreen> {
} }
} }
}, },
style: ElevatedButton.styleFrom( text: 'Solicitar servicio',
backgroundColor: const Color(0xFF2BA4EC), minWidth: 230,
shape: RoundedRectangleBorder( )
borderRadius: BorderRadius.circular(50),
),
elevation: 0,
minimumSize: const Size(230, 50),
),
child: const Text(
'Solicitar servicio',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
),
], ],
), ),
), ),
@@ -0,0 +1,28 @@
import 'package:flutter/material.dart';
class PrimaryCheckbox extends StatelessWidget {
final String text;
final bool initialValue;
final Function(bool) onChanged;
const PrimaryCheckbox({
Key? key,
required this.text,
required this.initialValue,
required this.onChanged,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return CheckboxListTile(
title: Text(
text,
style: const TextStyle(fontSize: 15),
),
value: initialValue,
onChanged: (value) {
onChanged(value!);
},
);
}
}
@@ -0,0 +1,51 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class WarningSnackbar {
static void show({
required String title,
required String message,
SnackPosition position = SnackPosition.TOP,
Duration duration = const Duration(seconds: 4),
Color backgroundColor = Colors.red,
Color textColor = Colors.white,
double borderRadius = 10.0,
EdgeInsets margin = const EdgeInsets.all(10.0),
SnackStyle snackStyle = SnackStyle.FLOATING,
Duration animationDuration = const Duration(milliseconds: 800),
bool isDismissible = true,
DismissDirection dismissDirection = DismissDirection.horizontal,
Curve forwardAnimationCurve = Curves.easeOutBack,
Curve reverseAnimationCurve = Curves.easeInBack,
Icon icon = const Icon(Icons.warning, color: Colors.white),
bool shouldIconPulse = true,
}) {
Get.snackbar(
title,
message,
snackPosition: position,
duration: duration,
backgroundColor: backgroundColor,
colorText: textColor,
borderRadius: borderRadius,
margin: margin,
snackStyle: snackStyle,
animationDuration: animationDuration,
isDismissible: isDismissible,
dismissDirection: dismissDirection,
forwardAnimationCurve: forwardAnimationCurve,
reverseAnimationCurve: reverseAnimationCurve,
icon: icon,
shouldIconPulse: shouldIconPulse,
titleText: Text(
title,
style: const TextStyle(
fontSize: 18.0, fontWeight: FontWeight.bold, color: Colors.white),
),
messageText: Text(
message,
style: const TextStyle(fontSize: 16.0, color: Colors.white),
),
);
}
}
+9 -7
View File
@@ -1,7 +1,6 @@
import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
class FirebaseMessagingService { class FirebaseMessagingService {
FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance; FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;
@@ -21,7 +20,8 @@ class FirebaseMessagingService {
print('Token FCM: $token'); print('Token FCM: $token');
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}');
// Obtener el valor de la clave "screen" de los datos de la notificación // Obtener el valor de la clave "screen" de los datos de la notificación
String? notificationScreen = message.data['screen']; String? notificationScreen = message.data['screen'];
@@ -34,19 +34,21 @@ class FirebaseMessagingService {
// Navegar a SolicitudScreen // Navegar a SolicitudScreen
Get.offNamed('/solicitud'); 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) {
print('Mensaje FCM abierto desde la aplicación en primer plano: ${message.notification?.title} - ${message.notification?.body}'); print(
'Mensaje FCM abierto desde la aplicación en primer plano: ${message.notification?.title} - ${message.notification?.body}');
// Aquí puedes redirigir al usuario a una pantalla específica o realizar acciones según los datos recibidos // Aquí puedes redirigir al usuario a una pantalla específica o realizar acciones según los datos recibidos
}); });
// Manejar la notificación cuando se toca y la aplicación está cerrada (opcional) // Manejar la notificación cuando se toca y la aplicación está cerrada (opcional)
RemoteMessage? initialMessage = await FirebaseMessaging.instance.getInitialMessage(); RemoteMessage? initialMessage =
await FirebaseMessaging.instance.getInitialMessage();
if (initialMessage != null) { if (initialMessage != null) {
print('Mensaje FCM abierto desde la aplicación cerrada: ${initialMessage.notification?.title} - ${initialMessage.notification?.body}'); print(
'Mensaje FCM abierto desde la aplicación cerrada: ${initialMessage.notification?.title} - ${initialMessage.notification?.body}');
// Aquí puedes redirigir al usuario a una pantalla específica o realizar acciones según los datos recibidos // Aquí puedes redirigir al usuario a una pantalla específica o realizar acciones según los datos recibidos
} }
} }
+1 -1
View File
@@ -51,7 +51,7 @@ dependencies:
flutter_animate: flutter_animate:
flutter_rating_bar: flutter_rating_bar:
table_calendar: table_calendar:
google_maps_flutter: ^2.2.5 google_maps_flutter: ^2.5.0
flutter_polyline_points: ^2.0.0 flutter_polyline_points: ^2.0.0
http: ^1.1.0 http: ^1.1.0
geolocator: ^9.0.2 geolocator: ^9.0.2