update
This commit is contained in:
@@ -3,6 +3,7 @@ import 'package:flutter/services.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:intl/date_symbol_data_local.dart';
|
import 'package:intl/date_symbol_data_local.dart';
|
||||||
import 'package:prosappco/src/authentication/authentication_repository.dart';
|
import 'package:prosappco/src/authentication/authentication_repository.dart';
|
||||||
|
import 'package:prosappco/src/presentation/screens/service_web.dart';
|
||||||
import 'package:prosappco/src/providers/user_provider.dart';
|
import 'package:prosappco/src/providers/user_provider.dart';
|
||||||
import 'package:prosappco/src/presentation/screens/calendar.dart';
|
import 'package:prosappco/src/presentation/screens/calendar.dart';
|
||||||
import 'package:prosappco/src/presentation/screens/city.dart';
|
import 'package:prosappco/src/presentation/screens/city.dart';
|
||||||
@@ -117,6 +118,7 @@ class MyApp extends StatelessWidget {
|
|||||||
'/solicitudEnviada': (context) => const RequestSentScreen(),
|
'/solicitudEnviada': (context) => const RequestSentScreen(),
|
||||||
'/nuevaPassword': (context) => NewPasswordScreen(),
|
'/nuevaPassword': (context) => NewPasswordScreen(),
|
||||||
'/servicio': (context) => const ServiceScreen(),
|
'/servicio': (context) => const ServiceScreen(),
|
||||||
|
'/servicioWeb': (context) => const ServiceWebScreen(),
|
||||||
'/profilePro': (context) => const ProfileProScreen(),
|
'/profilePro': (context) => const ProfileProScreen(),
|
||||||
'/calendar': (context) => const CalendarScreen(),
|
'/calendar': (context) => const CalendarScreen(),
|
||||||
'/solicitud': (context) => SolicitudScreen(),
|
'/solicitud': (context) => SolicitudScreen(),
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||||
import 'package:firebase_auth/firebase_auth.dart';
|
import 'package:firebase_auth/firebase_auth.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:google_sign_in/google_sign_in.dart';
|
import 'package:google_sign_in/google_sign_in.dart';
|
||||||
import 'package:prosappco/src/authentication/exceptions/register_failed.dart';
|
import 'package:prosappco/src/authentication/exceptions/register_failed.dart';
|
||||||
import 'package:prosappco/src/presentation/screens/login/login.dart';
|
import 'package:prosappco/src/presentation/screens/login/login.dart';
|
||||||
// import 'package:prosappco/src/presentation/screens/service.dart';
|
// import 'package:prosappco/src/presentation/screens/service.dart';
|
||||||
import 'package:prosappco/src/presentation/screens/map/service.dart';
|
import 'package:prosappco/src/presentation/screens/map/service.dart';
|
||||||
|
import 'package:prosappco/src/presentation/screens/service_web.dart';
|
||||||
|
|
||||||
class AuthenticationRepository extends GetxController {
|
class AuthenticationRepository extends GetxController {
|
||||||
static AuthenticationRepository get instance => Get.find();
|
static AuthenticationRepository get instance => Get.find();
|
||||||
@@ -29,7 +31,9 @@ class AuthenticationRepository extends GetxController {
|
|||||||
_setInitialScreen(User? user) {
|
_setInitialScreen(User? user) {
|
||||||
user == null
|
user == null
|
||||||
? Get.offAll(const LoginScreen())
|
? Get.offAll(const LoginScreen())
|
||||||
: Get.offAll(const ServiceScreen());
|
: kIsWeb
|
||||||
|
? Get.offAll(const ServiceWebScreen())
|
||||||
|
: Get.offAll(const ServiceScreen());
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> phoneAuthentication(String phoneNo) async {
|
Future<void> phoneAuthentication(String phoneNo) async {
|
||||||
@@ -79,7 +83,9 @@ class AuthenticationRepository extends GetxController {
|
|||||||
email: email, password: password);
|
email: email, password: password);
|
||||||
|
|
||||||
firebaseUser.value != null
|
firebaseUser.value != null
|
||||||
? Get.offAll(const ServiceScreen())
|
? kIsWeb
|
||||||
|
? Get.offAll(const ServiceWebScreen())
|
||||||
|
: Get.to(const ServiceScreen())
|
||||||
: Get.to(const LoginScreen());
|
: Get.to(const LoginScreen());
|
||||||
} on FirebaseAuthException catch (e) {
|
} on FirebaseAuthException catch (e) {
|
||||||
final ex = SignUpWithEmailAndPasswordFailure.code(e.code);
|
final ex = SignUpWithEmailAndPasswordFailure.code(e.code);
|
||||||
@@ -140,7 +146,9 @@ class AuthenticationRepository extends GetxController {
|
|||||||
// Continúa con el flujo de la aplicación después del inicio de sesión exitoso
|
// Continúa con el flujo de la aplicación después del inicio de sesión exitoso
|
||||||
// Por ejemplo, redirecciona a la siguiente pantalla
|
// Por ejemplo, redirecciona a la siguiente pantalla
|
||||||
firebaseUser.value != null
|
firebaseUser.value != null
|
||||||
? Get.offAll(const ServiceScreen())
|
? kIsWeb
|
||||||
|
? Get.offAll(const ServiceWebScreen())
|
||||||
|
: Get.to(const ServiceScreen())
|
||||||
: Get.to(const LoginScreen());
|
: Get.to(const LoginScreen());
|
||||||
} else {
|
} else {
|
||||||
// El usuario canceló el inicio de sesión con Google
|
// El usuario canceló el inicio de sesión con Google
|
||||||
@@ -208,8 +216,6 @@ class AuthenticationRepository extends GetxController {
|
|||||||
await FirebaseFirestore.instance.collection('users').doc(uid).get();
|
await FirebaseFirestore.instance.collection('users').doc(uid).get();
|
||||||
final Map<String, dynamic>? data = snapshot.data();
|
final Map<String, dynamic>? data = snapshot.data();
|
||||||
birthDate = data?['birth_date'] ?? '';
|
birthDate = data?['birth_date'] ?? '';
|
||||||
|
|
||||||
print('nada $birthDate');
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error getting birthDate: $e');
|
print('Error getting birthDate: $e');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,19 @@
|
|||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:get/get.dart';
|
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/presentation/screens/service.dart';
|
// import 'package:prosappco/src/presentation/screens/service.dart';
|
||||||
import 'package:prosappco/src/presentation/screens/map/service.dart';
|
import 'package:prosappco/src/presentation/screens/map/service.dart';
|
||||||
|
import 'package:prosappco/src/presentation/screens/service_web.dart';
|
||||||
|
|
||||||
class OTPController extends GetxController {
|
class OTPController extends GetxController {
|
||||||
static OTPController get instance => Get.find();
|
static OTPController get instance => Get.find();
|
||||||
|
|
||||||
Future<void> verifyOTP(String otp) async {
|
Future<void> verifyOTP(String otp) async {
|
||||||
var isVerified = AuthenticationRepository.instance.verifyOTP(otp);
|
var isVerified = AuthenticationRepository.instance.verifyOTP(otp);
|
||||||
await isVerified ? Get.offAll(const ServiceScreen()) : Get.back();
|
await isVerified
|
||||||
|
? kIsWeb
|
||||||
|
? Get.offAll(const ServiceWebScreen())
|
||||||
|
: Get.to(const ServiceScreen())
|
||||||
|
: Get.back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
@@ -40,6 +41,8 @@ class _ServiceScreenState extends State<ServiceScreen> {
|
|||||||
late String appVersion;
|
late String appVersion;
|
||||||
final Uri _url = Uri.parse(
|
final Uri _url = Uri.parse(
|
||||||
'https://play.google.com/store/apps/details?id=com.prosapp.prosapp');
|
'https://play.google.com/store/apps/details?id=com.prosapp.prosapp');
|
||||||
|
final Uri _urlIos =
|
||||||
|
Uri.parse('https://apps.apple.com/co/app/prosapp/id6469028900');
|
||||||
|
|
||||||
final Location _locationController = Location();
|
final Location _locationController = Location();
|
||||||
|
|
||||||
@@ -958,7 +961,11 @@ class _ServiceScreenState extends State<ServiceScreen> {
|
|||||||
TextStyle(fontWeight: FontWeight.w600, fontSize: 20),
|
TextStyle(fontWeight: FontWeight.w600, fontSize: 20),
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
launchUrl(_url);
|
if (Platform.isAndroid) {
|
||||||
|
launchUrl(_url);
|
||||||
|
} else {
|
||||||
|
launchUrl(_urlIos);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:cloud_firestore/cloud_firestore.dart';
|
|||||||
import 'package:firebase_auth/firebase_auth.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/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
@@ -21,6 +22,7 @@ import 'package:prosappco/src/presentation/widgets/profile/gender_dropdown.dart'
|
|||||||
import 'package:prosappco/src/presentation/widgets/shared/primary_button.dart';
|
import 'package:prosappco/src/presentation/widgets/shared/primary_button.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import '../../../components/photo_view.dart';
|
import '../../../components/photo_view.dart';
|
||||||
|
import 'package:universal_html/html.dart' as html;
|
||||||
|
|
||||||
class ProfileScreen extends StatefulWidget {
|
class ProfileScreen extends StatefulWidget {
|
||||||
const ProfileScreen({Key? key}) : super(key: key);
|
const ProfileScreen({Key? key}) : super(key: key);
|
||||||
@@ -302,6 +304,18 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String? selectedCity = _ciudad;
|
||||||
|
|
||||||
|
if (kIsWeb) {
|
||||||
|
try {
|
||||||
|
await FirebaseFirestore.instance.collection('users').doc(uid).update({
|
||||||
|
'city': selectedCity,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
print('Error al actualizar la ciudad: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (enableLoginWithEmail) {
|
if (enableLoginWithEmail) {
|
||||||
if (currentUser?.email != newEmail) {
|
if (currentUser?.email != newEmail) {
|
||||||
if (newPassword.isNotEmpty) {
|
if (newPassword.isNotEmpty) {
|
||||||
@@ -342,7 +356,6 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
|||||||
} else {
|
} else {
|
||||||
final uploaded = await uploadImage(imagen_to_upload!);
|
final uploaded = await uploadImage(imagen_to_upload!);
|
||||||
updateImage(photoTemp);
|
updateImage(photoTemp);
|
||||||
//image
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error al actualizar la imagen de perfil $e');
|
print('Error al actualizar la imagen de perfil $e');
|
||||||
@@ -428,8 +441,6 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
|||||||
message:
|
message:
|
||||||
'Verifica tu contraseña actual y asegúrate de que el nuevo correo electrónico no se haya utilizado previamente.',
|
'Verifica tu contraseña actual y asegúrate de que el nuevo correo electrónico no se haya utilizado previamente.',
|
||||||
);
|
);
|
||||||
|
|
||||||
print('Error al actualizar el correo electrónico: $e');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -497,9 +508,10 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
|||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
WarningSnackbar.show(
|
WarningSnackbar.show(
|
||||||
title: 'Inicia sesión de nuevo',
|
title: 'Inicia sesión de nuevo',
|
||||||
message:
|
message: 'Inicia la sesión de nuevo para guardar los cambios.',
|
||||||
'Para agregar un correo debes haber iniciado sesión recientemente.');
|
);
|
||||||
|
AuthenticationRepository.instance.logout(uid!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -507,6 +519,42 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
|||||||
|
|
||||||
bool enableLoginWithEmail = false;
|
bool enableLoginWithEmail = false;
|
||||||
|
|
||||||
|
Future<List<City>> _getCities() async {
|
||||||
|
List<City> citys = [];
|
||||||
|
if (kIsWeb) {
|
||||||
|
try {
|
||||||
|
QuerySnapshot countries = await countriesCollection.get();
|
||||||
|
for (DocumentSnapshot country in countries.docs) {
|
||||||
|
String countryName = country.id;
|
||||||
|
Map<String, dynamic> data = country.data() as Map<String, dynamic>;
|
||||||
|
Map<String, Map<String, String>> states = {};
|
||||||
|
|
||||||
|
for (var entry in data.entries) {
|
||||||
|
String key = entry.key;
|
||||||
|
Map<String, String> cityData =
|
||||||
|
Map<String, String>.from(entry.value);
|
||||||
|
states[key] = cityData;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var state in states.entries) {
|
||||||
|
var citysState = state.value.entries.map((city) => City(
|
||||||
|
cityName: city.key,
|
||||||
|
coordsOfCity: city.value,
|
||||||
|
stateOfCity: state.key,
|
||||||
|
countryOfCity: countryName,
|
||||||
|
));
|
||||||
|
|
||||||
|
citys.addAll(citysState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print('Error obteniendo las ciudades: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return citys;
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _showChoiceDialog(BuildContext context) async {
|
Future<void> _showChoiceDialog(BuildContext context) async {
|
||||||
return showDialog(
|
return showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
@@ -560,10 +608,11 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
|||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: PopAppbar(
|
appBar: PopAppbar(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
},
|
},
|
||||||
label: 'Perfil'),
|
label: 'Perfil',
|
||||||
|
),
|
||||||
body: SingleChildScrollView(
|
body: SingleChildScrollView(
|
||||||
reverse: true,
|
reverse: true,
|
||||||
child: Center(
|
child: Center(
|
||||||
@@ -599,37 +648,76 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
|||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
prefixIcon: Icon(Icons.person_outline),
|
prefixIcon: Icon(Icons.person_outline),
|
||||||
hintText: 'Nombre (Obligatorio)'),
|
hintText: 'Nombre (Obligatorio)',
|
||||||
),
|
|
||||||
const SizedBox(),
|
|
||||||
TextFormField(
|
|
||||||
readOnly: true,
|
|
||||||
onTap: () async {
|
|
||||||
final String? ciudad = await Navigator.push(
|
|
||||||
context,
|
|
||||||
CupertinoPageRoute(
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
return const CityScreen();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
) as String?;
|
|
||||||
|
|
||||||
if (ciudad != null) {
|
|
||||||
setState(() {
|
|
||||||
_ciudad = ciudad;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
decoration: InputDecoration(
|
|
||||||
prefixIcon: const Icon(Icons.near_me),
|
|
||||||
suffixIcon: const Icon(Icons.arrow_drop_down),
|
|
||||||
hintStyle: city == ''
|
|
||||||
? const TextStyle()
|
|
||||||
: const TextStyle(color: Colors.black87),
|
|
||||||
hintText: city == '' ? 'Ciudad' : city,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
const SizedBox(),
|
||||||
|
kIsWeb
|
||||||
|
? FutureBuilder<List<City>>(
|
||||||
|
future: _getCities(),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.connectionState ==
|
||||||
|
ConnectionState.waiting) {
|
||||||
|
return const Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
);
|
||||||
|
} else if (snapshot.hasError) {
|
||||||
|
return const Center(
|
||||||
|
child:
|
||||||
|
Text('Error al obtener las ciudades'),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
List<City> filteredCities = snapshot.data!;
|
||||||
|
|
||||||
|
return DropdownButtonFormField<String>(
|
||||||
|
value: _ciudad,
|
||||||
|
onChanged: (String? newValue) {
|
||||||
|
setState(() {
|
||||||
|
_ciudad = newValue!;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
items: filteredCities.map((City city) {
|
||||||
|
return DropdownMenuItem<String>(
|
||||||
|
value: city.cityName,
|
||||||
|
child: Text(city.cityName ?? ''),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
prefixIcon: const Icon(Icons.near_me),
|
||||||
|
hintText: _ciudad,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
: TextFormField(
|
||||||
|
readOnly: true,
|
||||||
|
onTap: () async {
|
||||||
|
final String? ciudad = await Navigator.push(
|
||||||
|
context,
|
||||||
|
CupertinoPageRoute(
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return const CityScreen();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
) as String?;
|
||||||
|
|
||||||
|
if (ciudad != null) {
|
||||||
|
setState(() {
|
||||||
|
_ciudad = ciudad;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
decoration: InputDecoration(
|
||||||
|
prefixIcon: const Icon(Icons.near_me),
|
||||||
|
suffixIcon: const Icon(Icons.arrow_drop_down),
|
||||||
|
hintStyle: city == ''
|
||||||
|
? const TextStyle()
|
||||||
|
: const TextStyle(color: Colors.black87),
|
||||||
|
hintText: city == '' ? 'Ciudad' : city,
|
||||||
|
),
|
||||||
|
),
|
||||||
const SizedBox(height: 20.0),
|
const SizedBox(height: 20.0),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: _phoneNumberController,
|
controller: _phoneNumberController,
|
||||||
@@ -732,8 +820,9 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
prefixIcon: Icon(Icons.email_outlined),
|
prefixIcon: Icon(Icons.email_outlined),
|
||||||
hintText: 'Email'),
|
hintText: 'Email',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20.0),
|
const SizedBox(height: 20.0),
|
||||||
_email != null
|
_email != null
|
||||||
@@ -777,6 +866,47 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
|||||||
_email != null
|
_email != null
|
||||||
? const SizedBox.shrink()
|
? const SizedBox.shrink()
|
||||||
: const SizedBox(height: 20),
|
: const SizedBox(height: 20),
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.only(
|
||||||
|
left: 5,
|
||||||
|
right: 5,
|
||||||
|
top: 5,
|
||||||
|
bottom: 5,
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 10, vertical: 8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xFFD6F4FF),
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.grey.withOpacity(0.5),
|
||||||
|
spreadRadius: 1,
|
||||||
|
blurRadius: 5,
|
||||||
|
offset: const Offset(1, 3),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: const Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.error_outline,
|
||||||
|
size: 20,
|
||||||
|
color: Colors.black54,
|
||||||
|
),
|
||||||
|
SizedBox(width: 10),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
'Al habilitar el inicio de sesión con correo, se cerrara la sesión actual.',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.black54,
|
||||||
|
fontSize: 13,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -808,11 +938,17 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
|||||||
minHeight: 45,
|
minHeight: 45,
|
||||||
)
|
)
|
||||||
: const SizedBox(height: 20),
|
: const SizedBox(height: 20),
|
||||||
const SizedBox(height: 60),
|
const SizedBox(height: 40),
|
||||||
PrimaryButton(
|
PrimaryButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
if (_formKey.currentState!.validate()) {
|
if (_formKey.currentState!.validate()) {
|
||||||
await updateInfo();
|
if (kIsWeb) {
|
||||||
|
await updateInfo().whenComplete(() {
|
||||||
|
html.window.location.reload();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await updateInfo();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await userProvider.updateUserDataAndScores();
|
await userProvider.updateUserDataAndScores();
|
||||||
|
|||||||
@@ -1,628 +0,0 @@
|
|||||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
|
||||||
import 'package:firebase_auth/firebase_auth.dart';
|
|
||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:get/get.dart';
|
|
||||||
import 'package:intl/intl.dart';
|
|
||||||
import 'package:firebase_storage/firebase_storage.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:file_picker/file_picker.dart';
|
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:image_picker/image_picker.dart';
|
|
||||||
import 'package:prosappco/src/authentication/authentication_repository.dart';
|
|
||||||
import 'package:prosappco/src/components/photo_view_web.dart';
|
|
||||||
import 'package:prosappco/src/components/pop_appbar.dart';
|
|
||||||
import 'package:prosappco/src/presentation/screens/city.dart';
|
|
||||||
import 'package:prosappco/src/presentation/screens/new_number.dart';
|
|
||||||
import 'package:prosappco/src/presentation/screens/new_password.dart';
|
|
||||||
import 'package:universal_html/html.dart' as html;
|
|
||||||
|
|
||||||
class ProfileWebScreen extends StatefulWidget {
|
|
||||||
const ProfileWebScreen({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<ProfileWebScreen> createState() => _ProfileWebScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ProfileWebScreenState extends State<ProfileWebScreen> {
|
|
||||||
final uid = AuthenticationRepository.instance.getCurrentUserUid();
|
|
||||||
final FirebaseStorage storage = FirebaseStorage.instance;
|
|
||||||
late final FirebaseAuth _auth;
|
|
||||||
List<City>? filteredCities;
|
|
||||||
|
|
||||||
// variables imagen
|
|
||||||
String selectedImage = '';
|
|
||||||
XFile? file;
|
|
||||||
Uint8List? selectedImagInBytes;
|
|
||||||
String photoTemp = '';
|
|
||||||
|
|
||||||
// controladores
|
|
||||||
final _formKey = GlobalKey<FormState>();
|
|
||||||
final TextEditingController _nameController = TextEditingController();
|
|
||||||
final TextEditingController _emailController = TextEditingController();
|
|
||||||
final TextEditingController _phoneNumberController = TextEditingController();
|
|
||||||
final TextEditingController _passwordController = TextEditingController();
|
|
||||||
bool _obscureText = true;
|
|
||||||
|
|
||||||
// variables
|
|
||||||
String _ciudad = '...';
|
|
||||||
String _photo = '...';
|
|
||||||
String? _email = '';
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
|
|
||||||
final uid = AuthenticationRepository.instance.getCurrentUserUid();
|
|
||||||
_auth = FirebaseAuth.instance;
|
|
||||||
|
|
||||||
final currentUser = _auth.currentUser;
|
|
||||||
|
|
||||||
if (currentUser != null && currentUser.phoneNumber != null) {
|
|
||||||
_phoneNumberController.text = currentUser.phoneNumber!;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentUser != null && currentUser.displayName != null) {
|
|
||||||
_nameController.text = currentUser.displayName!;
|
|
||||||
}
|
|
||||||
if (currentUser != null && currentUser.email != null) {
|
|
||||||
_emailController.text = currentUser.email!;
|
|
||||||
}
|
|
||||||
|
|
||||||
_email = currentUser?.email;
|
|
||||||
|
|
||||||
if (_ciudad == '...') {
|
|
||||||
AuthenticationRepository.instance
|
|
||||||
.getCity(uid.toString())
|
|
||||||
.then((String s) => setState(() {
|
|
||||||
_ciudad = s;
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_photo == '...') {
|
|
||||||
AuthenticationRepository.instance
|
|
||||||
.getPhoto(uid.toString())
|
|
||||||
.then((String s) => setState(() {
|
|
||||||
_photo = s;
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_selectFile(bool imageFrom) async {
|
|
||||||
FilePickerResult? fileResult = await FilePicker.platform.pickFiles();
|
|
||||||
|
|
||||||
if (fileResult != null) {
|
|
||||||
setState(() {
|
|
||||||
selectedImage = fileResult.files.first.name;
|
|
||||||
selectedImagInBytes = fileResult.files.first.bytes;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_uploadFile() async {
|
|
||||||
try {
|
|
||||||
final now = DateTime.now();
|
|
||||||
final formattedDate = DateFormat('HHmmssddMMyyyy').format(now);
|
|
||||||
final milliseconds = (now.microsecondsSinceEpoch / 1000).round();
|
|
||||||
final random = '$formattedDate$milliseconds';
|
|
||||||
|
|
||||||
final Reference ref = FirebaseStorage.instance
|
|
||||||
.ref()
|
|
||||||
.child('users')
|
|
||||||
.child(uid!)
|
|
||||||
.child('profile')
|
|
||||||
.child(random);
|
|
||||||
|
|
||||||
final metaData = SettableMetadata(contentType: 'image/jpeg');
|
|
||||||
|
|
||||||
final UploadTask uploadTask = ref.putData(selectedImagInBytes!, metaData);
|
|
||||||
|
|
||||||
final TaskSnapshot snapshot = await uploadTask.whenComplete(() => true);
|
|
||||||
|
|
||||||
photoTemp = ref.fullPath;
|
|
||||||
|
|
||||||
if (snapshot.state == TaskState.success) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
print('web image error - $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> updateInfo() async {
|
|
||||||
final currentUser = _auth.currentUser;
|
|
||||||
final currentPhoneNumber = _auth.currentUser!.phoneNumber;
|
|
||||||
|
|
||||||
String newName = _nameController.text.trim();
|
|
||||||
String newEmail = _emailController.text.trim();
|
|
||||||
String newPassword = _passwordController.text.trim();
|
|
||||||
|
|
||||||
if (newName.isEmpty) {
|
|
||||||
// Si el nuevo nombre está vacío, no lo actualizamos y mostramos un mensaje al usuario
|
|
||||||
Get.snackbar(
|
|
||||||
'Nombre Invalido',
|
|
||||||
'Ingresa un nombre válido.',
|
|
||||||
snackPosition: SnackPosition.BOTTOM,
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
await FirebaseAuth.instance.currentUser!.updateDisplayName(newName);
|
|
||||||
await FirebaseFirestore.instance.collection('users').doc(uid).update({
|
|
||||||
'name': newName,
|
|
||||||
'lowerName': newName.toLowerCase(),
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
print('Error al actualizar el nombre: $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (newEmail.isEmpty) {
|
|
||||||
// Si el nuevo nombre está vacío, no lo actualizamos y mostramos un mensaje al usuario
|
|
||||||
Get.snackbar(
|
|
||||||
'Correo Invalido',
|
|
||||||
'Ingresa un email válido.',
|
|
||||||
snackPosition: SnackPosition.BOTTOM,
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await FirebaseAuth.instance.currentUser!.updateDisplayName(newName);
|
|
||||||
await FirebaseFirestore.instance.collection('users').doc(uid).update({
|
|
||||||
'name': newName,
|
|
||||||
'lowerName': newName.toLowerCase(),
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
print('Error al actualizar el nombre: $e');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentUser?.email != newEmail) {
|
|
||||||
if (newPassword.isNotEmpty) {
|
|
||||||
await FirebaseFirestore.instance.collection('users').doc(uid).update({
|
|
||||||
'email': newEmail,
|
|
||||||
});
|
|
||||||
updateEmailAndPassword(newEmail, newPassword);
|
|
||||||
} else {
|
|
||||||
Get.snackbar(
|
|
||||||
'Contraseña Invalida',
|
|
||||||
'Por favor, ingresa una contraseña.',
|
|
||||||
snackPosition: SnackPosition.BOTTOM,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String? selectedCity = _ciudad;
|
|
||||||
|
|
||||||
// Guardar la ciudad seleccionada en el documento del usuario
|
|
||||||
try {
|
|
||||||
await FirebaseFirestore.instance.collection('users').doc(uid).update({
|
|
||||||
'city': selectedCity,
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
print('Error al actualizar la ciudad: $e');
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await FirebaseFirestore.instance
|
|
||||||
.collection('users')
|
|
||||||
.doc(uid)
|
|
||||||
.update({'phoneNumber': currentPhoneNumber});
|
|
||||||
} catch (e) {
|
|
||||||
print('e');
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await FirebaseFirestore.instance
|
|
||||||
.collection('users')
|
|
||||||
.doc(uid)
|
|
||||||
.update({'email': newEmail});
|
|
||||||
} catch (e) {
|
|
||||||
print('e');
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (selectedImagInBytes == null) {
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
await _uploadFile();
|
|
||||||
updateImage(photoTemp);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
print('Error al actualizar la imagen de perfil $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> updateImage(image) async {
|
|
||||||
try {
|
|
||||||
await FirebaseFirestore.instance
|
|
||||||
.collection('users')
|
|
||||||
.doc(uid)
|
|
||||||
.update({'photo': image});
|
|
||||||
} catch (e) {
|
|
||||||
try {
|
|
||||||
await FirebaseFirestore.instance
|
|
||||||
.collection('users')
|
|
||||||
.doc(uid)
|
|
||||||
.set({'photo': image});
|
|
||||||
} catch (e) {
|
|
||||||
print('Error al agregar la imagen de perfil: $e');
|
|
||||||
}
|
|
||||||
|
|
||||||
print('Error al actualizar la imagen de perfil: $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> updateEmailAndPassword(String email, String password) async {
|
|
||||||
final User? user = FirebaseAuth.instance.currentUser;
|
|
||||||
if (user != null) {
|
|
||||||
try {
|
|
||||||
await user.updateEmail(email);
|
|
||||||
await user.updatePassword(password);
|
|
||||||
} catch (e) {
|
|
||||||
Get.snackbar(
|
|
||||||
'Agregar correo',
|
|
||||||
'Inicia sesión para asegurarnos de que seas tú.',
|
|
||||||
snackPosition: SnackPosition.BOTTOM,
|
|
||||||
);
|
|
||||||
AuthenticationRepository.instance.logout(uid!);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<List<City>> _getCities() async {
|
|
||||||
List<City> citys = [];
|
|
||||||
try {
|
|
||||||
QuerySnapshot countries = await countriesCollection.get();
|
|
||||||
for (DocumentSnapshot country in countries.docs) {
|
|
||||||
String countryName = country.id;
|
|
||||||
Map<String, dynamic> data = country.data() as Map<String, dynamic>;
|
|
||||||
Map<String, Map<String, String>> states = {};
|
|
||||||
|
|
||||||
for (var entry in data.entries) {
|
|
||||||
String key = entry.key;
|
|
||||||
Map<String, String> cityData = Map<String, String>.from(entry.value);
|
|
||||||
states[key] = cityData;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var state in states.entries) {
|
|
||||||
var citysState = state.value.entries.map((city) => City(
|
|
||||||
cityName: city.key,
|
|
||||||
coordsOfCity: city.value,
|
|
||||||
stateOfCity: state.key,
|
|
||||||
countryOfCity: countryName,
|
|
||||||
));
|
|
||||||
|
|
||||||
citys.addAll(citysState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
print('Error obteniendo las ciudades: $e');
|
|
||||||
}
|
|
||||||
return citys;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _showEmailUpdateDialog(BuildContext context) async {
|
|
||||||
TextEditingController emailController = TextEditingController();
|
|
||||||
String currentEmail = FirebaseAuth.instance.currentUser?.email ?? '';
|
|
||||||
|
|
||||||
await showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
return AlertDialog(
|
|
||||||
title: const Text('Actualizar Correo Electrónico'),
|
|
||||||
content: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
TextFormField(
|
|
||||||
controller: emailController,
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
labelText: 'Nuevo Correo Electrónico',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
actions: <Widget>[
|
|
||||||
TextButton(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
child: const Text('Cancelar'),
|
|
||||||
),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () async {
|
|
||||||
String newEmail = emailController.text.trim();
|
|
||||||
if (newEmail.isNotEmpty && newEmail != currentEmail) {
|
|
||||||
// Actualiza el correo electrónico aquí
|
|
||||||
try {
|
|
||||||
await FirebaseAuth.instance.currentUser
|
|
||||||
?.updateEmail(newEmail);
|
|
||||||
await FirebaseFirestore.instance
|
|
||||||
.collection('users')
|
|
||||||
.doc(FirebaseAuth.instance.currentUser?.uid)
|
|
||||||
.update({'email': newEmail});
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(
|
|
||||||
content:
|
|
||||||
Text('Correo Electrónico actualizado con éxito'),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(
|
|
||||||
content:
|
|
||||||
Text('Error al actualizar el correo electrónico'),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(
|
|
||||||
content:
|
|
||||||
Text('Ingresa un nuevo correo electrónico válido'),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
backgroundColor: Colors.blue,
|
|
||||||
),
|
|
||||||
child: const Text('Guardar'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
backgroundColor: const Color(0xFFD6F4FF),
|
|
||||||
appBar: PopAppbar(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.pop(context);
|
|
||||||
},
|
|
||||||
label: 'Perfil'),
|
|
||||||
body: Center(
|
|
||||||
child: SizedBox(
|
|
||||||
width: 300,
|
|
||||||
height: 680,
|
|
||||||
child: Card(
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
),
|
|
||||||
color: Colors.white,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20.0),
|
|
||||||
child: Form(
|
|
||||||
key: _formKey,
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
padding: const EdgeInsets.only(top: 20, bottom: 20),
|
|
||||||
child: (selectedImagInBytes != null)
|
|
||||||
? LocalPhotoWeb(file: selectedImagInBytes)
|
|
||||||
: ReferencePhotoWeb(ref: storage.ref().child(_photo)),
|
|
||||||
),
|
|
||||||
TextFormField(
|
|
||||||
controller: _nameController,
|
|
||||||
maxLength: 50,
|
|
||||||
validator: (value) {
|
|
||||||
if (value == null || value.isEmpty) {
|
|
||||||
return 'Porfavor ingrese un nombre.';
|
|
||||||
}
|
|
||||||
if (value.length < 5) {
|
|
||||||
return 'Debe tener al menos 5 caracteres.';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
prefixIcon: Icon(Icons.person_outline),
|
|
||||||
hintText: 'Nombre (Obligatorio)',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
_email != null
|
|
||||||
? TextFormField(
|
|
||||||
onTap: () {
|
|
||||||
_showEmailUpdateDialog(context);
|
|
||||||
},
|
|
||||||
readOnly: true,
|
|
||||||
controller: _emailController,
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
prefixIcon: Icon(Icons.email_outlined),
|
|
||||||
hintText: 'Email (Obligatorio)',
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: TextFormField(
|
|
||||||
controller: _emailController,
|
|
||||||
validator: (String? value) {
|
|
||||||
if (value == null || value.isEmpty) {
|
|
||||||
return 'Por favor ingrese un email';
|
|
||||||
}
|
|
||||||
final RegExp emailRegExp =
|
|
||||||
RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
|
|
||||||
if (!emailRegExp.hasMatch(value)) {
|
|
||||||
return 'Por favor ingrese un email válido';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
prefixIcon: Icon(Icons.email_outlined),
|
|
||||||
hintText: 'Email (Obligatorio)',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20.0),
|
|
||||||
_email != null
|
|
||||||
? const SizedBox.shrink()
|
|
||||||
: TextFormField(
|
|
||||||
controller: _passwordController,
|
|
||||||
obscureText: _obscureText,
|
|
||||||
validator: (value) {
|
|
||||||
if (value == null || value.isEmpty) {
|
|
||||||
return 'Porfavor ingrese una contraseña.';
|
|
||||||
}
|
|
||||||
if (value.length < 5) {
|
|
||||||
return 'Debe tener al menos 5 caracteres.';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
decoration: InputDecoration(
|
|
||||||
prefixIcon: const Icon(Icons.lock_outline),
|
|
||||||
suffixIcon: IconButton(
|
|
||||||
icon: Icon(
|
|
||||||
_obscureText
|
|
||||||
? Icons.visibility
|
|
||||||
: Icons.visibility_off,
|
|
||||||
color: Colors.grey,
|
|
||||||
),
|
|
||||||
onPressed: () {
|
|
||||||
setState(() {
|
|
||||||
_obscureText = !_obscureText;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
hintText: 'Contraseña (Obligatorio)',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
_email != null
|
|
||||||
? const SizedBox.shrink()
|
|
||||||
: const SizedBox(height: 20.0),
|
|
||||||
FutureBuilder<List<City>>(
|
|
||||||
future: _getCities(),
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (snapshot.connectionState ==
|
|
||||||
ConnectionState.waiting) {
|
|
||||||
return const Center(
|
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
);
|
|
||||||
} else if (snapshot.hasError) {
|
|
||||||
return const Center(
|
|
||||||
child: Text('Error al obtener las ciudades'),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
List<City> filteredCities = snapshot.data!;
|
|
||||||
|
|
||||||
return DropdownButtonFormField<String>(
|
|
||||||
value: _ciudad,
|
|
||||||
onChanged: (String? newValue) {
|
|
||||||
setState(() {
|
|
||||||
_ciudad = newValue!;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
items: filteredCities.map((City city) {
|
|
||||||
return DropdownMenuItem<String>(
|
|
||||||
value: city.cityName,
|
|
||||||
child: Text(city.cityName ?? ''),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
decoration: InputDecoration(
|
|
||||||
prefixIcon: const Icon(Icons.near_me),
|
|
||||||
hintText: _ciudad,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20.0),
|
|
||||||
TextFormField(
|
|
||||||
controller: _phoneNumberController,
|
|
||||||
readOnly: true,
|
|
||||||
onTap: () {
|
|
||||||
Navigator.of(context).push(
|
|
||||||
CupertinoPageRoute(
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
return const NewNumberScreen();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
prefixIcon: Icon(Icons.phone_android),
|
|
||||||
suffixIcon: Icon(Icons.edit_outlined),
|
|
||||||
hintText: '+57'),
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
alignment: Alignment.bottomCenter,
|
|
||||||
margin: const EdgeInsets.only(top: 30),
|
|
||||||
padding: const EdgeInsets.only(bottom: 30),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
_email != null
|
|
||||||
? ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
CupertinoPageRoute(
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
return NewPasswordScreen();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
backgroundColor: const Color(0xFF2BA4EC),
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(50),
|
|
||||||
),
|
|
||||||
elevation: 0,
|
|
||||||
minimumSize: const Size(300, 45),
|
|
||||||
),
|
|
||||||
child: const Text(
|
|
||||||
'Cambiar Contraseña',
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontSize: 17,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: const SizedBox(height: 20),
|
|
||||||
const SizedBox(height: 60),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () async {
|
|
||||||
if (_formKey.currentState!.validate()) {
|
|
||||||
await updateInfo().whenComplete(() {
|
|
||||||
html.window.location.reload();
|
|
||||||
|
|
||||||
Get.snackbar(
|
|
||||||
'Perfil',
|
|
||||||
'Información actualizada correctamente.',
|
|
||||||
snackPosition: SnackPosition.TOP,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
backgroundColor: const Color(0xFF2BA4EC),
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(50),
|
|
||||||
),
|
|
||||||
elevation: 0,
|
|
||||||
minimumSize: const Size(200, 50),
|
|
||||||
),
|
|
||||||
child: const Text(
|
|
||||||
'Guardar',
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontSize: 17,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/foundation.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';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
@@ -9,6 +10,7 @@ import 'package:prosappco/src/models/scores_model.dart';
|
|||||||
import 'package:prosappco/src/models/setting_model.dart';
|
import 'package:prosappco/src/models/setting_model.dart';
|
||||||
import 'package:prosappco/src/models/user_model.dart';
|
import 'package:prosappco/src/models/user_model.dart';
|
||||||
import 'package:prosappco/src/presentation/screens/map/service.dart';
|
import 'package:prosappco/src/presentation/screens/map/service.dart';
|
||||||
|
import 'package:prosappco/src/presentation/screens/service_web.dart';
|
||||||
|
|
||||||
class ServiceAfterScreen extends StatefulWidget {
|
class ServiceAfterScreen extends StatefulWidget {
|
||||||
var eventoId;
|
var eventoId;
|
||||||
@@ -66,14 +68,23 @@ class _ServiceAfterScreenState extends State<ServiceAfterScreen> {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: PopAppbar(
|
appBar: PopAppbar(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.pushReplacement(
|
kIsWeb
|
||||||
context,
|
? Navigator.pushReplacement(
|
||||||
CupertinoPageRoute(
|
context,
|
||||||
builder: (BuildContext context) {
|
CupertinoPageRoute(
|
||||||
return const ServiceScreen();
|
builder: (BuildContext context) {
|
||||||
},
|
return const ServiceWebScreen();
|
||||||
),
|
},
|
||||||
);
|
),
|
||||||
|
)
|
||||||
|
: Navigator.pushReplacement(
|
||||||
|
context,
|
||||||
|
CupertinoPageRoute(
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return const ServiceScreen();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
label: 'Servicio'),
|
label: 'Servicio'),
|
||||||
body: Column(
|
body: Column(
|
||||||
|
|||||||
@@ -3,31 +3,24 @@ import 'package:cloud_firestore/cloud_firestore.dart';
|
|||||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||||
import 'package:firebase_storage/firebase_storage.dart';
|
import 'package:firebase_storage/firebase_storage.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:flutter/gestures.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:geocoding/geocoding.dart';
|
import 'package:geocoding/geocoding.dart';
|
||||||
import 'package:geolocator/geolocator.dart';
|
import 'package:geolocator/geolocator.dart';
|
||||||
import 'package:get/get.dart';
|
|
||||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||||
import 'package:prosappco/src/authentication/authentication_repository.dart';
|
import 'package:prosappco/src/authentication/authentication_repository.dart';
|
||||||
|
import 'package:prosappco/src/presentation/screens/profile/profile.dart';
|
||||||
import 'package:prosappco/src/presentation/widgets/shared/drawer_menu.dart';
|
import 'package:prosappco/src/presentation/widgets/shared/drawer_menu.dart';
|
||||||
import 'package:prosappco/src/models/event_model.dart';
|
import 'package:prosappco/src/models/event_model.dart';
|
||||||
import 'package:prosappco/src/models/setting_model.dart';
|
|
||||||
import 'package:prosappco/src/models/user_model.dart';
|
import 'package:prosappco/src/models/user_model.dart';
|
||||||
import 'package:prosappco/src/presentation/screens/professional.dart';
|
import 'package:prosappco/src/presentation/screens/professional.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:prosappco/src/presentation/screens/profile/profile.dart';
|
|
||||||
import 'package:prosappco/src/presentation/screens/profile/profile_web.dart';
|
|
||||||
import 'package:prosappco/src/presentation/screens/service_after.dart';
|
import 'package:prosappco/src/presentation/screens/service_after.dart';
|
||||||
import 'package:prosappco/src/presentation/screens/service_type.dart';
|
|
||||||
import 'package:prosappco/src/presentation/screens/ubicacion.dart';
|
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:prosappco/src/presentation/widgets/shared/primary_button.dart';
|
|
||||||
import 'package:prosappco/src/presentation/widgets/shared/warning_snackbar.dart';
|
import 'package:prosappco/src/presentation/widgets/shared/warning_snackbar.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:prosappco/src/providers/user_provider.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class ServiceWebScreen extends StatefulWidget {
|
class ServiceWebScreen extends StatefulWidget {
|
||||||
const ServiceWebScreen({super.key});
|
const ServiceWebScreen({super.key});
|
||||||
@@ -199,7 +192,6 @@ class _ServiceOldScreenState extends State<ServiceWebScreen> {
|
|||||||
|
|
||||||
final FirebaseStorage storage = FirebaseStorage.instance;
|
final FirebaseStorage storage = FirebaseStorage.instance;
|
||||||
final uid = AuthenticationRepository.instance.getCurrentUserUid();
|
final uid = AuthenticationRepository.instance.getCurrentUserUid();
|
||||||
UserModel? user;
|
|
||||||
final fcmToken = FirebaseMessaging.instance.getToken();
|
final fcmToken = FirebaseMessaging.instance.getToken();
|
||||||
|
|
||||||
BitmapDescriptor? _markerIcon;
|
BitmapDescriptor? _markerIcon;
|
||||||
@@ -320,14 +312,6 @@ class _ServiceOldScreenState extends State<ServiceWebScreen> {
|
|||||||
|
|
||||||
_saveToken();
|
_saveToken();
|
||||||
|
|
||||||
if (user == null) {
|
|
||||||
UserModel.getUser(uid.toString()).then((UserModel s) => (value) {
|
|
||||||
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) {
|
||||||
@@ -401,6 +385,9 @@ class _ServiceOldScreenState extends State<ServiceWebScreen> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final userProvider = Provider.of<UserProvider>(context);
|
||||||
|
UserModel? user = userProvider.user;
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: const Color(0xFFD6F4FF),
|
backgroundColor: const Color(0xFFD6F4FF),
|
||||||
drawer: DrawerMenu(),
|
drawer: DrawerMenu(),
|
||||||
@@ -516,10 +503,10 @@ class _ServiceOldScreenState extends State<ServiceWebScreen> {
|
|||||||
if (_profesionalController.text.isNotEmpty) {
|
if (_profesionalController.text.isNotEmpty) {
|
||||||
_selectDate(context);
|
_selectDate(context);
|
||||||
} else {
|
} else {
|
||||||
Get.snackbar(
|
WarningSnackbar.show(
|
||||||
'Selecciona un profesional',
|
title: 'Selecciona un profesional',
|
||||||
'Selecciona un profesional antes de elegir la fecha y la hora de la cita.',
|
message:
|
||||||
snackPosition: SnackPosition.BOTTOM,
|
'Selecciona un profesional antes de elegir la fecha y la hora de la cita.',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -542,10 +529,10 @@ class _ServiceOldScreenState extends State<ServiceWebScreen> {
|
|||||||
if (_profesionalController.text.isNotEmpty) {
|
if (_profesionalController.text.isNotEmpty) {
|
||||||
_selectTime(context);
|
_selectTime(context);
|
||||||
} else {
|
} else {
|
||||||
Get.snackbar(
|
WarningSnackbar.show(
|
||||||
'Selecciona un profesional',
|
title: 'Selecciona un profesional',
|
||||||
'Selecciona un profesional antes de elegir la fecha y la hora de la cita.',
|
message:
|
||||||
snackPosition: SnackPosition.BOTTOM,
|
'Selecciona un profesional antes de elegir la fecha y la hora de la cita.',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -578,7 +565,7 @@ class _ServiceOldScreenState extends State<ServiceWebScreen> {
|
|||||||
context,
|
context,
|
||||||
CupertinoPageRoute(
|
CupertinoPageRoute(
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return const ProfileWebScreen();
|
return const ProfileScreen();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -630,10 +617,9 @@ class _ServiceOldScreenState extends State<ServiceWebScreen> {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Get.snackbar(
|
WarningSnackbar.show(
|
||||||
'Llena todos los campos',
|
title: 'Llena todos los campos',
|
||||||
'Asegurate de llenar todos los campos.',
|
message: 'Asegurate de llenar todos los campos.',
|
||||||
snackPosition: SnackPosition.BOTTOM,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,10 +9,8 @@ import 'package:prosappco/src/models/user_model.dart';
|
|||||||
import 'package:prosappco/src/presentation/widgets/shared/warning_snackbar.dart';
|
import 'package:prosappco/src/presentation/widgets/shared/warning_snackbar.dart';
|
||||||
import 'package:prosappco/src/providers/user_provider.dart';
|
import 'package:prosappco/src/providers/user_provider.dart';
|
||||||
import 'package:prosappco/src/presentation/screens/configuracion.dart';
|
import 'package:prosappco/src/presentation/screens/configuracion.dart';
|
||||||
import 'package:prosappco/src/presentation/screens/messages_user.dart';
|
|
||||||
import 'package:prosappco/src/presentation/screens/professional_profile_web.dart';
|
import 'package:prosappco/src/presentation/screens/professional_profile_web.dart';
|
||||||
import 'package:prosappco/src/presentation/screens/profile/profile.dart';
|
import 'package:prosappco/src/presentation/screens/profile/profile.dart';
|
||||||
import 'package:prosappco/src/presentation/screens/profile/profile_web.dart';
|
|
||||||
import 'package:prosappco/src/presentation/screens/reputation.dart';
|
import 'package:prosappco/src/presentation/screens/reputation.dart';
|
||||||
import 'package:prosappco/src/presentation/screens/support.dart';
|
import 'package:prosappco/src/presentation/screens/support.dart';
|
||||||
import 'package:prosappco/src/presentation/screens/web_view.dart';
|
import 'package:prosappco/src/presentation/screens/web_view.dart';
|
||||||
@@ -91,25 +89,14 @@ class DrawerMenu extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (kIsWeb) {
|
Navigator.push(
|
||||||
Navigator.push(
|
context,
|
||||||
context,
|
CupertinoPageRoute(
|
||||||
CupertinoPageRoute(
|
builder: (BuildContext context) {
|
||||||
builder: (BuildContext context) {
|
return const ProfileScreen();
|
||||||
return const ProfileWebScreen();
|
},
|
||||||
},
|
),
|
||||||
),
|
);
|
||||||
);
|
|
||||||
} else {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
CupertinoPageRoute(
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
return const ProfileScreen();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
leading: const Icon(
|
leading: const Icon(
|
||||||
Icons.person_outline,
|
Icons.person_outline,
|
||||||
@@ -170,8 +157,9 @@ class DrawerMenu extends StatelessWidget {
|
|||||||
CupertinoPageRoute(
|
CupertinoPageRoute(
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return WebViewScreen(
|
return WebViewScreen(
|
||||||
label: 'Sugerencias',
|
label: 'Sugerencias',
|
||||||
link: 'https://admin.prosapp.co/sugerencias');
|
link: 'https://admin.prosapp.co/sugerencias',
|
||||||
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -186,26 +174,6 @@ class DrawerMenu extends StatelessWidget {
|
|||||||
style: TextStyle(fontSize: 15),
|
style: TextStyle(fontSize: 15),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// ListTile(
|
|
||||||
// onTap: () {
|
|
||||||
// Navigator.push(
|
|
||||||
// context,
|
|
||||||
// CupertinoPageRoute(
|
|
||||||
// builder: (BuildContext context) {
|
|
||||||
// return const MessagesUserScreen();
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// },
|
|
||||||
// leading: const Icon(
|
|
||||||
// Icons.messenger_outline,
|
|
||||||
// color: Colors.black,
|
|
||||||
// ),
|
|
||||||
// title: const Text(
|
|
||||||
// 'Mensajes',
|
|
||||||
// style: TextStyle(fontSize: 15),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
Builder(builder: (BuildContext context) {
|
Builder(builder: (BuildContext context) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
@@ -406,25 +374,14 @@ class DrawerMenu extends StatelessWidget {
|
|||||||
ListTile infoUser(BuildContext context, UserModel? user) {
|
ListTile infoUser(BuildContext context, UserModel? user) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (kIsWeb) {
|
Navigator.push(
|
||||||
Navigator.push(
|
context,
|
||||||
context,
|
CupertinoPageRoute(
|
||||||
CupertinoPageRoute(
|
builder: (BuildContext context) {
|
||||||
builder: (BuildContext context) {
|
return const ProfileScreen();
|
||||||
return const ProfileWebScreen();
|
},
|
||||||
},
|
),
|
||||||
),
|
);
|
||||||
);
|
|
||||||
} else {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
CupertinoPageRoute(
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
return const ProfileScreen();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
title: Text(user?.name ?? '',
|
title: Text(user?.name ?? '',
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold)),
|
style: const TextStyle(fontWeight: FontWeight.bold)),
|
||||||
|
|||||||
+3
-1
@@ -63,6 +63,8 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.flutterWebRenderer = "html";
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user