imagenes falta especializaciones

This commit is contained in:
Juan Felipe Duarte
2023-06-07 17:29:43 -05:00
parent ebcc95d06a
commit 583d99b3bb
11 changed files with 1630 additions and 305 deletions
+1 -1
View File
@@ -27,6 +27,6 @@ subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
tasks.register("clean", Delete) {
delete rootProject.buildDir
}
+51 -17
View File
@@ -1,5 +1,6 @@
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_rating_bar/flutter_rating_bar.dart';
import 'package:prosappco/src/authentication/authentication_repository.dart';
@@ -8,7 +9,9 @@ import 'package:prosappco/src/models/scores_model.dart';
import 'package:prosappco/src/models/user_model.dart';
import 'package:prosappco/src/screens/configuracion.dart';
import 'package:prosappco/src/screens/messages_user.dart';
import 'package:prosappco/src/screens/professional_profile_web.dart';
import 'package:prosappco/src/screens/profile.dart';
import 'package:prosappco/src/screens/profile_web.dart';
import 'package:prosappco/src/screens/reputation.dart';
import 'package:prosappco/src/screens/support.dart';
import 'package:get/get.dart';
@@ -53,14 +56,25 @@ class _DrawerMenuState extends State<DrawerMenu> {
children: [
ListTile(
onTap: () {
Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext context) {
return const ProfileScreen();
},
),
);
if (kIsWeb) {
Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext context) {
return const ProfileWebScreen();
},
),
);
} else {
Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext context) {
return const ProfileScreen();
},
),
);
}
},
title: Text(user?.name ?? '',
style: const TextStyle(fontWeight: FontWeight.bold)),
@@ -129,14 +143,25 @@ class _DrawerMenuState extends State<DrawerMenu> {
),
ListTile(
onTap: () {
Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext context) {
return const ProfileScreen();
},
),
);
if (kIsWeb) {
Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext context) {
return const ProfileWebScreen();
},
),
);
} else {
Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext context) {
return const ProfileScreen();
},
),
);
}
},
leading: const Icon(
Icons.person_outline,
@@ -347,7 +372,16 @@ class _DrawerMenuState extends State<DrawerMenu> {
);
} else {
if (user?.state == 'pendiente' || user?.state == null) {
Navigator.pushNamed(context, '/profesionalProfile');
if (kIsWeb) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const ProfessionalProfileWebScreen()),
);
} else {
Navigator.pushNamed(context, '/profesionalProfile');
}
} else if (user?.state == 'revision') {
Navigator.pushNamed(context, '/profesionalRevision');
} else if (user?.state == 'activo') {
+118
View File
@@ -0,0 +1,118 @@
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart';
const double photoSize = 100;
const double iconSize = 55;
class ReferencePhotoWeb extends StatelessWidget {
Reference? ref;
double size;
double sizeIcon;
double sizeCircle;
ReferencePhotoWeb({
super.key,
required this.ref,
this.sizeIcon = iconSize,
this.size = photoSize,
this.sizeCircle = photoSize,
});
Future<Widget> downloadImage() async {
try {
if (ref != null) {
final imageData = await ref!.getData();
if (imageData != null) {
return ClipOval(
child: Image.memory(
imageData,
width: size,
height: size,
fit: BoxFit.cover,
),
);
}
}
// ignore: empty_catches
} catch (e) {}
return DefaultPhotoWeb(
sizeDefault: sizeCircle,
iconDefault: sizeIcon,
);
}
@override
Widget build(BuildContext context) {
return FutureBuilder<Widget>(
future: downloadImage(),
builder: (BuildContext context, AsyncSnapshot<Widget> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
// mientras la llamada asíncrona está en proceso, muestra un mensaje de carga
return SizedBox(
width: size,
height: size,
child: const Center(
child: CircularProgressIndicator(),
),
);
} else if (snapshot.connectionState == ConnectionState.done &&
snapshot.hasData) {
return snapshot.data!;
} else {
return DefaultPhotoWeb();
}
});
}
}
class DefaultPhotoWeb extends StatelessWidget {
double sizeDefault;
double iconDefault;
DefaultPhotoWeb({
super.key,
this.sizeDefault = photoSize,
this.iconDefault = iconSize,
});
@override
Widget build(BuildContext context) {
return Container(
width: sizeDefault,
height: sizeDefault,
decoration: BoxDecoration(
color: const Color(0xFF2BA4EC),
borderRadius: BorderRadius.circular(50),
),
child: Icon(
Icons.person,
color: const Color.fromARGB(255, 255, 255, 255),
size: iconDefault,
),
).animate().shake();
}
}
class LocalPhotoWeb extends StatelessWidget {
Uint8List? file;
LocalPhotoWeb({super.key, required this.file});
@override
Widget build(BuildContext context) {
if (file == null) {
return DefaultPhotoWeb();
} else {
return ClipOval(
child: Image.memory(
file!,
width: photoSize,
height: photoSize,
fit: BoxFit.cover,
),
);
}
}
}
+170 -77
View File
@@ -1,4 +1,5 @@
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intl_phone_field/intl_phone_field.dart';
@@ -33,87 +34,179 @@ class _NewNumberScreenState extends State<NewNumberScreen> {
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
backgroundColor: Colors.white,
iconTheme: const IconThemeData(
color: Colors.black,
),
title: const Text(
'Añadir numero',
style: TextStyle(
child: Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
backgroundColor: Colors.white,
iconTheme: const IconThemeData(
color: Colors.black,
),
),
),
body: Container(
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 20),
margin: const EdgeInsets.only(top: 30, left: 50, right: 50),
child: Column(children: [
const Padding(
padding: EdgeInsets.only(bottom: 5),
child: Align(
alignment: Alignment.topLeft,
child: Text('Numero de celular',
style: TextStyle(fontSize: 18.0, color: Color(0xFF65676B))),
)),
Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.only(bottom: 5),
child: IntlPhoneField(
controller: controller.newPhoneNo,
initialCountryCode: 'CO',
onChanged: (newPhoneNo) {
completePhoneNumber = newPhoneNo.completeNumber;
},
decoration: const InputDecoration(
border: OutlineInputBorder(
borderSide: BorderSide(color: Color(0xFFECECEC)),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
errorBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Color.fromARGB(255, 184, 0, 0)),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Color(0xFFECECEC)),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Color(0xFFECECEC)),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
fillColor: Color.fromARGB(255, 239, 239, 239),
filled: true,
),
),
title: const Text(
'Añadir numero',
style: TextStyle(
color: Colors.black,
),
),
const Padding(
padding: EdgeInsets.only(bottom: 30),
child: Text('Un código será enviado a este numero de celular.',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 13.0, color: Color(0xFF65676B))),
),
Padding(
padding: const EdgeInsets.only(bottom: 30),
child: Center(
child: PrimaryButtom(
onPressed: () {
controller
.updatePhoneNumber(completePhoneNumber.toString());
},
label: 'Enviar código')),
),
]),
),
body: !kIsWeb
? Container(
padding:
const EdgeInsets.symmetric(horizontal: 0, vertical: 20),
margin: const EdgeInsets.only(top: 30, left: 50, right: 50),
child: Column(
children: [
const Padding(
padding: EdgeInsets.only(bottom: 5),
child: Align(
alignment: Alignment.topLeft,
child: Text('Numero de celular',
style: TextStyle(
fontSize: 18.0, color: Color(0xFF65676B))),
)),
Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.only(bottom: 5),
child: IntlPhoneField(
controller: controller.newPhoneNo,
initialCountryCode: 'CO',
onChanged: (newPhoneNo) {
completePhoneNumber = newPhoneNo.completeNumber;
},
decoration: const InputDecoration(
border: OutlineInputBorder(
borderSide:
BorderSide(color: Color(0xFFECECEC)),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Color.fromARGB(255, 184, 0, 0)),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
enabledBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Color(0xFFECECEC)),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
focusedBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Color(0xFFECECEC)),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
fillColor: Color.fromARGB(255, 239, 239, 239),
filled: true,
),
),
),
),
const Padding(
padding: EdgeInsets.only(bottom: 30),
child: Text(
'Un código será enviado a este numero de celular.',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 13.0, color: Color(0xFF65676B))),
),
Padding(
padding: const EdgeInsets.only(bottom: 30),
child: Center(
child: PrimaryButtom(
onPressed: () {
controller.updatePhoneNumber(
completePhoneNumber.toString());
},
label: 'Enviar código'),
),
),
],
),
)
: Center(
child: Container(
padding:
const EdgeInsets.symmetric(horizontal: 0, vertical: 20),
width: 400,
margin: const EdgeInsets.only(top: 30, left: 50, right: 50),
child: Column(
children: [
const Padding(
padding: EdgeInsets.only(bottom: 5),
child: Align(
alignment: Alignment.topLeft,
child: Text('Numero de celular',
style: TextStyle(
fontSize: 18.0, color: Color(0xFF65676B))),
)),
Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.only(bottom: 5),
child: IntlPhoneField(
controller: controller.newPhoneNo,
initialCountryCode: 'CO',
onChanged: (newPhoneNo) {
completePhoneNumber = newPhoneNo.completeNumber;
},
decoration: const InputDecoration(
border: OutlineInputBorder(
borderSide:
BorderSide(color: Color(0xFFECECEC)),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Color.fromARGB(255, 184, 0, 0)),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
enabledBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Color(0xFFECECEC)),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
focusedBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Color(0xFFECECEC)),
borderRadius: BorderRadius.all(
Radius.circular(50),
)),
fillColor: Color.fromARGB(255, 239, 239, 239),
filled: true,
),
),
),
),
const Padding(
padding: EdgeInsets.only(bottom: 30),
child: Text(
'Un código será enviado a este numero de celular.',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 13.0, color: Color(0xFF65676B))),
),
Padding(
padding: const EdgeInsets.only(bottom: 30),
child: Center(
child: PrimaryButtom(
onPressed: () {
controller.updatePhoneNumber(
completePhoneNumber.toString());
},
label: 'Enviar código'),
),
),
],
),
),
),
),
));
);
}
}
+173 -169
View File
@@ -3,6 +3,7 @@ import 'dart:io';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:prosappco/src/authentication/authentication_repository.dart';
@@ -160,7 +161,7 @@ class ProfessionalProfileScreenState extends State<ProfessionalProfileScreen> {
child: ListBody(
children: [
GestureDetector(
child: Text(
child: const Text(
textAlign: TextAlign.center,
"Tomar foto",
style: TextStyle(color: Color(0xFF2BA4EC)),
@@ -173,9 +174,9 @@ class ProfessionalProfileScreenState extends State<ProfessionalProfileScreen> {
Navigator.of(context).pop();
},
),
Divider(color: Colors.black54),
const Divider(color: Colors.black54),
GestureDetector(
child: Text(
child: const Text(
textAlign: TextAlign.center,
"Abrir Galería",
style: TextStyle(color: Color(0xFF2BA4EC)),
@@ -428,11 +429,11 @@ class ProfessionalProfileScreenState extends State<ProfessionalProfileScreen> {
_showChoiceDialog(context);
},
child: Container(
margin: EdgeInsets.symmetric(vertical: 50),
margin: const EdgeInsets.symmetric(vertical: 50),
width: 100,
height: 100,
decoration: BoxDecoration(
color: Color(0xFF2BA4EC),
color: const Color(0xFF2BA4EC),
borderRadius: BorderRadius.circular(50),
),
child: const Icon(
@@ -451,7 +452,7 @@ class ProfessionalProfileScreenState extends State<ProfessionalProfileScreen> {
_showChoiceDialog(context);
},
child: Container(
margin: EdgeInsets.symmetric(vertical: 50),
margin: const EdgeInsets.symmetric(vertical: 50),
child: ClipOval(
child: Image.memory(
imageData,
@@ -469,14 +470,14 @@ class ProfessionalProfileScreenState extends State<ProfessionalProfileScreen> {
_showChoiceDialog(context);
},
child: Container(
margin: EdgeInsets.symmetric(vertical: 50),
margin: const EdgeInsets.symmetric(vertical: 50),
width: 100,
height: 100,
decoration: BoxDecoration(
color: Color(0xFF2BA4EC),
color: const Color(0xFF2BA4EC),
borderRadius: BorderRadius.circular(50),
),
child: Icon(
child: const Icon(
Icons.person,
color: Colors.white,
size: 90,
@@ -492,14 +493,14 @@ class ProfessionalProfileScreenState extends State<ProfessionalProfileScreen> {
_showChoiceDialog(context);
},
child: Container(
margin: EdgeInsets.symmetric(vertical: 50),
margin: const EdgeInsets.symmetric(vertical: 50),
width: 100,
height: 100,
decoration: BoxDecoration(
color: Color(0xFF2BA4EC),
color: const Color(0xFF2BA4EC),
borderRadius: BorderRadius.circular(50),
),
child: Icon(
child: const Icon(
Icons.person,
color: Colors.white,
size: 90,
@@ -547,162 +548,162 @@ class ProfessionalProfileScreenState extends State<ProfessionalProfileScreen> {
width: 300,
padding: const EdgeInsets.only(top: 0),
child: Form(
key: _formKey,
child: Column(
children: [
TextFormField(
keyboardType: TextInputType.number,
controller: _cedulaController,
validator: (String? value) {
if (value == null || value.isEmpty) {
return 'Ingrese una cedula válida';
}
return null;
},
decoration: const InputDecoration(
prefixIcon: Icon(Icons.person_outline),
hintText: 'Cedula (Obligatorio)'),
key: _formKey,
child: Column(
children: [
TextFormField(
keyboardType: TextInputType.number,
controller: _cedulaController,
validator: (String? value) {
if (value == null || value.isEmpty) {
return 'Ingrese una cedula válida';
}
return null;
},
decoration: const InputDecoration(
prefixIcon: Icon(Icons.person_outline),
hintText: 'Cedula (Obligatorio)'),
),
SizedBox(height: _space),
ElevatedButton(
onPressed: () {
_showChoiceDialogCedula(context);
},
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFD6F4FF),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50),
),
elevation: 0,
minimumSize: const Size(250, 50),
),
SizedBox(height: _space),
ElevatedButton(
onPressed: () {
_showChoiceDialogCedula(context);
},
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFD6F4FF),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'Cedula',
style: TextStyle(
color: Color(0xFF2BA4EC),
fontSize: 17,
),
),
elevation: 0,
minimumSize: const Size(250, 50),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'Cedula',
style: TextStyle(
color: Color(0xFF2BA4EC),
fontSize: 17,
),
),
const SizedBox(width: 15),
Icon(
image_cedula != null
? Icons.check
: Icons.file_upload_outlined,
color: const Color(0xFF2BA4EC),
size: 30,
),
],
),
const SizedBox(width: 15),
Icon(
image_cedula != null
? Icons.check
: Icons.file_upload_outlined,
color: const Color(0xFF2BA4EC),
size: 30,
),
],
),
SizedBox(height: _space),
TextFormField(
readOnly: true,
onTap: () async {
final String? profesion =
(await Navigator.pushNamed(
context, '/profession')) as String?;
),
SizedBox(height: _space),
TextFormField(
readOnly: true,
onTap: () async {
final String? profesion = (await Navigator.pushNamed(
context, '/profession')) as String?;
if (profesion != null) {
setState(() {
_profession = profesion;
});
}
},
decoration: InputDecoration(
prefixIcon:
const Icon(Icons.assignment_ind_rounded),
suffixIcon: const Icon(Icons.arrow_drop_down),
hintStyle: profession == ''
? const TextStyle()
: const TextStyle(color: Colors.black87),
hintText: profession == ''
? 'Profesión (Obligatorio)'
: profession),
),
SizedBox(height: _space),
ElevatedButton(
onPressed: () {
_showChoiceDialogCertificado(context);
},
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFD6F4FF),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50),
),
elevation: 0,
minimumSize: const Size(250, 50),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'Certificado profesional',
style: TextStyle(
color: Color(0xFF2BA4EC),
fontSize: 17,
),
),
const SizedBox(width: 15),
Icon(
image_certificado != null
? Icons.check
: Icons.file_upload_outlined,
color: const Color(0xFF2BA4EC),
size: 30,
),
],
),
),
SizedBox(height: _space),
TextFormField(
controller: _especializacionController,
decoration: const InputDecoration(
prefixIcon: Icon(Icons.assignment_ind_rounded),
hintText: 'Especialización'),
),
SizedBox(height: _space),
ElevatedButton(
onPressed: () async {
final images = await getImage(3);
if (profesion != null) {
setState(() {
images_especializacion =
images.map((e) => File(e!.path)).toList();
_profession = profesion;
});
},
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFD6F4FF),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50),
),
elevation: 0,
minimumSize: const Size(250, 50),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'Especialización',
style: TextStyle(
color: Color(0xFF2BA4EC),
fontSize: 17,
),
),
const SizedBox(width: 15),
Icon(
images_especializacion.isEmpty
? Icons.file_upload_outlined
: Icons.check,
color: const Color(0xFF2BA4EC),
size: 30,
),
],
}
},
decoration: InputDecoration(
prefixIcon:
const Icon(Icons.assignment_ind_rounded),
suffixIcon: const Icon(Icons.arrow_drop_down),
hintStyle: profession == ''
? const TextStyle()
: const TextStyle(color: Colors.black87),
hintText: profession == ''
? 'Profesión (Obligatorio)'
: profession),
),
SizedBox(height: _space),
ElevatedButton(
onPressed: () {
_showChoiceDialogCertificado(context);
},
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFD6F4FF),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50),
),
elevation: 0,
minimumSize: const Size(250, 50),
),
],
)),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'Certificado profesional',
style: TextStyle(
color: Color(0xFF2BA4EC),
fontSize: 17,
),
),
const SizedBox(width: 15),
Icon(
image_certificado != null
? Icons.check
: Icons.file_upload_outlined,
color: const Color(0xFF2BA4EC),
size: 30,
),
],
),
),
SizedBox(height: _space),
TextFormField(
controller: _especializacionController,
decoration: const InputDecoration(
prefixIcon: Icon(Icons.assignment_ind_rounded),
hintText: 'Especialización'),
),
SizedBox(height: _space),
ElevatedButton(
onPressed: () async {
final images = await getImage(3);
setState(() {
images_especializacion =
images.map((e) => File(e!.path)).toList();
});
},
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFD6F4FF),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50),
),
elevation: 0,
minimumSize: const Size(250, 50),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'Especialización',
style: TextStyle(
color: Color(0xFF2BA4EC),
fontSize: 17,
),
),
const SizedBox(width: 15),
Icon(
images_especializacion.isEmpty
? Icons.file_upload_outlined
: Icons.check,
color: const Color(0xFF2BA4EC),
size: 30,
),
],
),
),
],
),
),
),
Container(
margin: const EdgeInsets.only(
@@ -721,25 +722,27 @@ class ProfessionalProfileScreenState extends State<ProfessionalProfileScreen> {
),
],
),
child: Row(
children: const [
child: const Row(
children: [
Icon(
Icons.error_outline,
size: 27,
color: Colors.black54,
),
SizedBox(width: 15),
Text(
'Para añadir mas de una especialidad, \nenvie mas fotos y separe por comas (,).',
style: TextStyle(color: Colors.black, fontSize: 14),
),
Expanded(
child: Text(
'Para añadir mas de una especialidad, envie mas fotos y separe por comas (,).',
style: TextStyle(color: Colors.black, fontSize: 14),
),
)
],
),
),
Container(
alignment: Alignment.bottomCenter,
margin: const EdgeInsets.only(
top: 80, right: 70, left: 70, bottom: 30),
top: 80, right: 20, left: 20, bottom: 30),
child: ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
@@ -753,10 +756,11 @@ class ProfessionalProfileScreenState extends State<ProfessionalProfileScreen> {
),
elevation: 0,
minimumSize: const Size(250, 50),
maximumSize: const Size(350, 50),
),
child: Row(
child: const Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
children: [
Text(
'Enviar información',
style: TextStyle(
@@ -0,0 +1,621 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:file_picker/file_picker.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.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:intl/intl.dart';
class ProfessionalProfileWebScreen extends StatefulWidget {
const ProfessionalProfileWebScreen({super.key});
@override
State<ProfessionalProfileWebScreen> createState() =>
_ProfessionalProfileWebScreenState();
}
class _ProfessionalProfileWebScreenState
extends State<ProfessionalProfileWebScreen> {
final uid = AuthenticationRepository.instance.getCurrentUserUid();
final FirebaseStorage storage = FirebaseStorage.instance;
late final FirebaseAuth _auth;
// variables imagen
String selectedImage = '';
String selectedCedulaImage = '';
String selectedCertificadoImage = '';
List selectedEspecializacionImages = [];
XFile? file;
Uint8List? selectedImagInBytes;
XFile? image_cedula;
Uint8List? imageCedulaBytes;
XFile? image_certificado;
Uint8List? imageCertificadoBytes;
XFile? image_especializaciones;
Uint8List? imageespEcializacionesBytes;
// controllers
final _formKey = GlobalKey<FormState>();
final TextEditingController _cedulaController = TextEditingController();
final TextEditingController _especializacionController =
TextEditingController();
// variables
bool _isLoading = false;
String _profession = '...';
String photoTemp = '';
String photoCedulaTemp = '';
String photoCertificadoTemp = '';
String _photo = '...';
@override
void initState() {
super.initState();
_auth = FirebaseAuth.instance;
if (_photo == '...') {
AuthenticationRepository.instance.getPhoto(uid.toString()).then(
(String s) => setState(() {
_photo = s;
}),
);
}
if (_profession == '...') {
AuthenticationRepository.instance.getProfession(uid.toString()).then(
(String s) => setState(() {
_profession = 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;
});
}
}
_selectFileCedula(bool imageFrom) async {
FilePickerResult? fileResult = await FilePicker.platform.pickFiles();
if (fileResult != null) {
setState(() {
selectedCedulaImage = fileResult.files.first.name;
imageCedulaBytes = fileResult.files.first.bytes;
});
}
}
_selectFileCertificado(bool imageFrom) async {
FilePickerResult? fileResult = await FilePicker.platform.pickFiles();
if (fileResult != null) {
setState(() {
selectedCertificadoImage = fileResult.files.first.name;
imageCertificadoBytes = fileResult.files.first.bytes;
});
}
}
_selectFilesEspecializaciones(bool imageFrom) async {
FilePickerResult? fileResult =
await FilePicker.platform.pickFiles(allowMultiple: true);
if (fileResult != null) {
setState(() {
fileResult.files.forEach((element) {
selectedEspecializacionImages.add(element.name);
});
print('array - $selectedEspecializacionImages');
});
}
}
Future<void> sendInfo() async {
setState(() {
_isLoading = true;
});
final String cedula = _cedulaController.text.trim();
if (cedula.isEmpty) {
showSnackBar('Cedula invalida', 'Ingrese una cedula válida');
return;
}
if (imageCedulaBytes == null) {
showSnackBar('Cedula', 'Ingrese una imagen de su cedula');
return;
}
if (imageCertificadoBytes == null) {
showSnackBar('Certificado', 'Ingrese una imagen de su certificado');
return;
}
// Actualiza los datos del usuario en Firestore
await FirebaseFirestore.instance.collection('users').doc(uid).update({
'cedula': cedula,
'estado': 'revision',
// 'especializaciones': especializaciones
});
// Sube las imágenes al storage de Firebase
await uploadCedula();
await uploadCertificado();
// uploadEspecializaciones(images_especializacion);
// Actualiza la imagen de perfil si hay cambios
if (selectedImagInBytes != null) {
await uploadFile();
await updateImage(photoTemp);
}
setState(() {
_isLoading = false;
});
// Navega a la siguiente pantalla
Navigator.pushReplacementNamed(context, '/solicitudEnviada');
}
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');
}
}
uploadCedula() async {
try {
final now = DateTime.now();
final formattedDate = DateFormat('HHmmssddMMyyyy').format(now);
final milliseconds = (now.microsecondsSinceEpoch / 1000).round();
final random = 'c$formattedDate$milliseconds';
final Reference ref = FirebaseStorage.instance
.ref()
.child('users')
.child(uid!)
.child('cedula')
.child(random);
final metaData = SettableMetadata(contentType: 'image/jpeg');
final UploadTask uploadTask = ref.putData(imageCedulaBytes!, metaData);
final TaskSnapshot snapshot = await uploadTask.whenComplete(() => true);
photoCedulaTemp = ref.fullPath;
if (snapshot.state == TaskState.success) {
updateImageCedula(photoCedulaTemp);
return true;
} else {
return false;
}
} catch (e) {
print('web image cedula error - $e');
}
}
uploadCertificado() async {
try {
final now = DateTime.now();
final formattedDate = DateFormat('HHmmssddMMyyyy').format(now);
final milliseconds = (now.microsecondsSinceEpoch / 1000).round();
final random = 'f$formattedDate$milliseconds';
final Reference ref = FirebaseStorage.instance
.ref()
.child('users')
.child(uid!)
.child('certificado_profesional')
.child(random);
final metaData = SettableMetadata(contentType: 'image/jpeg');
final UploadTask uploadTask =
ref.putData(imageCertificadoBytes!, metaData);
final TaskSnapshot snapshot = await uploadTask.whenComplete(() => true);
photoCertificadoTemp = ref.fullPath;
if (snapshot.state == TaskState.success) {
updateImageCertificado(photoCertificadoTemp);
return true;
} else {
return false;
}
} catch (e) {
print('web image certificado error - $e');
}
}
Future<void> updateImageCedula(image) async {
try {
final userRef = FirebaseFirestore.instance.collection('users').doc(uid);
final userSnapshot = await userRef.get();
if (userSnapshot.exists) {
await userRef.update({'imgCedula': image});
print('¡Imagen de cédula actualizada correctamente!');
} else {
await userRef.set({'imgCedula': image});
print('¡Imagen de cédula agregada correctamente!');
}
} catch (e) {
print('Error al agregar o actualizar la imagen de cédula: $e');
}
}
Future<void> updateImageCertificado(image) async {
try {
final userRef = FirebaseFirestore.instance.collection('users').doc(uid);
final userSnapshot = await userRef.get();
if (userSnapshot.exists) {
await userRef.update({'imgCertificado': image});
print('¡Imagen de certificado actualizada correctamente!');
} else {
await userRef.set({'imgCertificado': image});
print('¡Imagen de certificado agregada correctamente!');
}
} catch (e) {
print('Error al agregar o actualizar la imagen de certificado: $e');
}
}
Future<void> updateImage(image) async {
try {
await FirebaseFirestore.instance
.collection('users')
.doc(uid)
.update({'photo': image});
print('imagen actualizada correctamente');
} catch (e) {
try {
await FirebaseFirestore.instance
.collection('users')
.doc(uid)
.set({'photo': image});
} catch (e) {
print('Error al agregar la imagen de perfil: $e');
}
print('Error al actualizar la imagen de perfil: $e');
}
}
void showSnackBar(String title, String message) {
Get.snackbar(
title,
message,
snackPosition: SnackPosition.TOP,
);
}
@override
Widget build(BuildContext context) {
String profession = _profession.toString();
double _space = 10;
return Scaffold(
appBar: PopAppbar(
onPressed: () {
Navigator.pop(context);
},
label: 'Perfil profesional'),
body: SingleChildScrollView(
child: Center(
child: _isLoading
? const CircularProgressIndicator()
: Column(
children: [
Container(
padding: const EdgeInsets.only(top: 20),
child: (selectedImagInBytes != null)
? LocalPhotoWeb(file: selectedImagInBytes)
: ReferencePhotoWeb(ref: storage.ref().child(_photo)),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: ElevatedButton.icon(
onPressed: () {
_selectFile(true);
},
icon: const Icon(Icons.image),
label: const Text('Elige una imagen'),
),
),
Container(
width: 300,
child: Form(
key: _formKey,
child: Column(
children: [
TextFormField(
keyboardType: TextInputType.number,
controller: _cedulaController,
inputFormatters: [
FilteringTextInputFormatter
.digitsOnly // Solo permite caracteres numéricos
],
validator: (String? value) {
if (value == null || value.isEmpty) {
return 'Ingrese una cedula válida';
}
return null;
},
decoration: const InputDecoration(
prefixIcon: Icon(Icons.person_outline),
hintText: 'Cedula (Obligatorio)',
),
),
SizedBox(height: _space),
ElevatedButton(
onPressed: () {
_selectFileCedula(true);
},
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFD6F4FF),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50),
),
elevation: 0,
minimumSize: const Size(250, 50),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'Cedula',
style: TextStyle(
color: Color(0xFF2BA4EC),
fontSize: 17,
),
),
const SizedBox(width: 15),
Icon(
imageCedulaBytes != null
? Icons.check
: Icons.file_upload_outlined,
color: const Color(0xFF2BA4EC),
size: 30,
),
],
),
),
SizedBox(height: _space),
TextFormField(
readOnly: true,
onTap: () async {
final String? profesion =
(await Navigator.pushNamed(
context, '/profession')) as String?;
if (profesion != null) {
setState(() {
_profession = profesion;
});
}
},
decoration: InputDecoration(
prefixIcon:
const Icon(Icons.assignment_ind_rounded),
suffixIcon: const Icon(Icons.arrow_drop_down),
hintStyle: profession == ''
? const TextStyle()
: const TextStyle(color: Colors.black87),
hintText: profession == ''
? 'Profesión (Obligatorio)'
: profession),
),
SizedBox(height: _space),
ElevatedButton(
onPressed: () {
_selectFileCertificado(true);
},
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFD6F4FF),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50),
),
elevation: 0,
minimumSize: const Size(250, 50),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'Certificado profesional',
style: TextStyle(
color: Color(0xFF2BA4EC),
fontSize: 17,
),
),
const SizedBox(width: 15),
Icon(
imageCertificadoBytes != null
? Icons.check
: Icons.file_upload_outlined,
color: const Color(0xFF2BA4EC),
size: 30,
),
],
),
),
SizedBox(height: _space),
TextFormField(
controller: _especializacionController,
decoration: const InputDecoration(
prefixIcon:
Icon(Icons.assignment_ind_rounded),
hintText: 'Especialización'),
),
SizedBox(height: _space),
ElevatedButton(
onPressed: () async {
_selectFilesEspecializaciones(true);
// final images = await getImage(3);
// setState(() {
// images_especializacion =
// images.map((e) => File(e!.path)).toList();
// });
},
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFD6F4FF),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50),
),
elevation: 0,
minimumSize: const Size(250, 50),
),
child: const Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Especialización',
style: TextStyle(
color: Color(0xFF2BA4EC),
fontSize: 17,
),
),
SizedBox(width: 15),
// Icon(
// images_especializacion.isEmpty
// ? Icons.file_upload_outlined
// : Icons.check,
// color: const Color(0xFF2BA4EC),
// size: 30,
// ),
],
),
),
],
),
),
),
Container(
width: 450,
margin: const EdgeInsets.only(
left: 40, right: 40, top: 40, bottom: 0),
padding: const EdgeInsets.symmetric(
horizontal: 20, vertical: 15),
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: 27,
color: Colors.black54,
),
SizedBox(width: 15),
Expanded(
child: Text(
'Para añadir mas de una especialidad, envie mas fotos y separe por comas (,).',
style:
TextStyle(color: Colors.black, fontSize: 14),
),
),
],
),
),
Container(
alignment: Alignment.bottomCenter,
margin: const EdgeInsets.only(
top: 80, right: 20, left: 20, bottom: 30),
child: ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
sendInfo();
}
},
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF2BA4EC),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50),
),
elevation: 0,
minimumSize: const Size(250, 50),
maximumSize: const Size(350, 50),
),
child: const Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Enviar información',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 17,
),
),
SizedBox(width: 15),
Icon(
Icons.send,
color: Colors.white,
size: 20,
),
],
),
),
),
],
),
),
),
);
}
}
+10 -15
View File
@@ -5,13 +5,13 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'dart:io';
import 'package:intl/intl.dart';
import 'package:prosappco/src/authentication/authentication_repository.dart';
import 'package:prosappco/src/components/pop_appbar.dart';
import 'package:prosappco/src/controllers/add_name_email_city.dart';
import 'package:prosappco/src/screens/city.dart';
import 'package:prosappco/src/screens/new_number.dart';
import 'package:prosappco/src/screens/new_password.dart';
import 'package:prosappco/src/screens/service.dart';
import 'package:prosappco/src/services/select_image_profile.dart';
import '../components/photo_view.dart';
@@ -103,14 +103,13 @@ class _ProfileScreenState extends State<ProfileScreen> {
}
Future<bool> uploadImage(File image) async {
final String namefile = image.path.split('/').last;
final now = DateTime.now();
final formattedDate = DateFormat('HHmmssddMMyyyy').format(now);
final milliseconds = (now.microsecondsSinceEpoch / 1000).round();
final random = '$formattedDate$milliseconds';
Reference ref = storage
.ref()
.child('users')
.child(uid!)
.child('profile')
.child(namefile);
Reference ref =
storage.ref().child('users').child(uid!).child('profile').child(random);
final UploadTask uploadTask = ref.putFile(image);
@@ -231,7 +230,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
}
if (newEmail.isEmpty) {
// Si el nuevo nombre está vacío, no lo actualizamos y mostramos un mensaje al usuario
// Si el nuevo email está vacío, no lo actualizamos y mostramos un mensaje al usuario
Get.snackbar(
'Correo Invalido',
'Ingrese un email válido.',
@@ -374,12 +373,8 @@ class _ProfileScreenState extends State<ProfileScreen> {
child: Container(
margin: const EdgeInsets.symmetric(vertical: 50),
child: (imagen_to_upload != null)
? LocalPhoto(
file: imagen_to_upload!,
)
: ReferencePhoto(
ref: storage.ref().child(_photo),
)),
? LocalPhoto(file: imagen_to_upload!)
: ReferencePhoto(ref: storage.ref().child(_photo))),
),
Container(
width: 300,
+460
View File
@@ -0,0 +1,460 @@
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/screens/city.dart';
import 'package:prosappco/src/screens/new_number.dart';
import 'package:prosappco/src/screens/new_password.dart';
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;
// 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',
'Ingrese un nombre válido.',
snackPosition: SnackPosition.BOTTOM,
);
return;
}
if (newEmail.isEmpty) {
// Si el nuevo nombre está vacío, no lo actualizamos y mostramos un mensaje al usuario
Get.snackbar(
'Correo Invalido',
'Ingrese un email válido.',
snackPosition: SnackPosition.BOTTOM,
);
return;
}
if (currentUser?.displayName != newName) {
try {
await FirebaseAuth.instance.currentUser!.updateDisplayName(newName);
await FirebaseFirestore.instance.collection('users').doc(uid).update({
'name': newName,
'lowerName': newName.toLowerCase(),
});
print('Nombre actualizado correctamente');
} 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',
'Porfavor ingrese una contraseña.',
snackPosition: SnackPosition.BOTTOM,
);
}
}
try {
await FirebaseFirestore.instance
.collection('users')
.doc(uid)
.update({'phoneNumber': currentPhoneNumber});
} catch (e) {
print('e');
}
try {
if (selectedImagInBytes == null) {
return;
} else {
await _uploadFile();
updateImage(photoTemp);
//image
}
} 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});
print('imagen actualizada correctamente');
} catch (e) {
try {
await FirebaseFirestore.instance
.collection('users')
.doc(uid)
.set({'photo': image});
} catch (e) {
print('Error al agregar la imagen de perfil: $e');
}
print('Error al actualizar la imagen de perfil: $e');
}
}
Future<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',
'Inicie sesión para asegurarnos de que seas tú .',
snackPosition: SnackPosition.BOTTOM,
);
AuthenticationRepository.instance.logout();
}
}
}
@override
Widget build(BuildContext context) {
String city = _ciudad.toString();
return Scaffold(
appBar: PopAppbar(
onPressed: () {
Navigator.pop(context);
},
label: 'Perfil'),
body: SingleChildScrollView(
reverse: true,
child: Center(
child: Column(
children: [
Container(
padding: const EdgeInsets.only(top: 20),
child: (selectedImagInBytes != null)
? LocalPhotoWeb(file: selectedImagInBytes)
: ReferencePhotoWeb(ref: storage.ref().child(_photo)),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: ElevatedButton.icon(
onPressed: () {
_selectFile(true);
},
icon: const Icon(Icons.image),
label: const Text('Elige una imagen'),
),
),
Container(
width: 300,
child: Form(
key: _formKey,
child: Column(
children: [
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: () {
Navigator.push(context, CupertinoPageRoute(
builder: (BuildContext context) {
return NewPasswordScreen();
},
));
},
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),
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),
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: 50),
padding: const EdgeInsets.only(bottom: 30),
child: ElevatedButton(
onPressed: () async {
if (_formKey.currentState!.validate()) {
await updateInfo().whenComplete(() {
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,
),
),
),
),
],
),
),
),
],
),
),
),
);
}
}
+2 -2
View File
@@ -330,8 +330,8 @@ class _ServiceScreenState extends State<ServiceScreen> {
coordinates = position.target;
});
},
gestureRecognizers: <
Factory<OneSequenceGestureRecognizer>>{
gestureRecognizers: <Factory<
OneSequenceGestureRecognizer>>{
Factory<OneSequenceGestureRecognizer>(
() => EagerGestureRecognizer(),
),
+20 -20
View File
@@ -5,10 +5,10 @@ packages:
dependency: transitive
description:
name: _flutterfire_internals
sha256: "867b77e2367bc502dcd4d5a66302615409f04eb20ed82ba1c0ba073f9107e018"
sha256: "9ebe81588e666f7e2b21309f2b5653bd9642d7f27fd0a6894278d2ff40cb9481"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
version: "1.3.2"
args:
dependency: transitive
description:
@@ -157,50 +157,50 @@ packages:
dependency: "direct main"
description:
name: firebase_auth
sha256: "94c229e296a5b9ee5c8cda918e0b320e3a0cc4f6a349cd410c427da347f2a244"
sha256: "19508428ca37f611ae47067ee6ebb3ba5a27014941177cc224f71bf7d0720cdd"
url: "https://pub.dev"
source: hosted
version: "4.3.0"
version: "4.6.2"
firebase_auth_platform_interface:
dependency: transitive
description:
name: firebase_auth_platform_interface
sha256: "1217d8aa313b49d58b489aa8879544563abc8793d9612ff20d8df193f202aedc"
sha256: e46e136a6f6eec88b30f12445ff7f5b19b23b7ede694921ced4f8eba8eb634f6
url: "https://pub.dev"
source: hosted
version: "6.12.0"
version: "6.15.2"
firebase_auth_web:
dependency: transitive
description:
name: firebase_auth_web
sha256: bf7f1a87995a58b0f07dc617806dabd7ff25c64be7fa47b41ab1bb9a485b0062
sha256: "553bd576d793d05b920971a2c7ab02bd049d4971153702074ea2555877efd392"
url: "https://pub.dev"
source: hosted
version: "5.2.10"
version: "5.5.2"
firebase_core:
dependency: "direct main"
description:
name: firebase_core
sha256: dcf54c170c5371ad0e79229d0fb372c58262ae0968b7de222bf28e51dd236be0
sha256: e9b36b391690cf329c6fb1de220045e97c13784c303820cd33962319580a56c6
url: "https://pub.dev"
source: hosted
version: "2.11.0"
version: "2.13.1"
firebase_core_platform_interface:
dependency: transitive
description:
name: firebase_core_platform_interface
sha256: ae79f335f6c7f2dadb00c98c429da2ca905d265e0225fb5e7dfa62ac3accad48
sha256: b63e3be6c96ef5c33bdec1aab23c91eb00696f6452f0519401d640938c94cba2
url: "https://pub.dev"
source: hosted
version: "4.7.0"
version: "4.8.0"
firebase_core_web:
dependency: transitive
description:
name: firebase_core_web
sha256: e57ef862257a0d977c1308d02e2fbb9b68525e6d85711b08f3df8cec836fb444
sha256: "8c0f4c87d20e2d001a5915df238c1f9c88704231f591324205f5a5d2a7740a45"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
version: "2.5.0"
firebase_messaging:
dependency: "direct main"
description:
@@ -229,26 +229,26 @@ packages:
dependency: "direct main"
description:
name: firebase_storage
sha256: a27909491c25acef90acc932be4d87bafb9d33fb98678edd2f81eaec9568a109
sha256: ba695c4905da360a9daa5ecb12a8c272b2dfd681a12aaf109fa7666abc54f8a5
url: "https://pub.dev"
source: hosted
version: "11.1.0"
version: "11.2.2"
firebase_storage_platform_interface:
dependency: transitive
description:
name: firebase_storage_platform_interface
sha256: f254e064890df4ee588f10bea06d679e047018910451a4bc3c529b9791adb0a9
sha256: "81e8498e26c4ba0a88400666e4f6777ebecf0c49e89d54f9f0f989b249c29abb"
url: "https://pub.dev"
source: hosted
version: "4.2.0"
version: "4.4.2"
firebase_storage_web:
dependency: transitive
description:
name: firebase_storage_web
sha256: b6d3c104fecafdce5fe1795306d33856c9a11fa76f73fe7eb062430fc151d686
sha256: "4406f263c7a6a53502bde436e0c53ced8385142a2f8ef4005f0781749d87d286"
url: "https://pub.dev"
source: hosted
version: "3.4.0"
version: "3.6.2"
flutter:
dependency: "direct main"
description: flutter
+4 -4
View File
@@ -37,8 +37,9 @@ dependencies:
cupertino_icons: ^1.0.2
# Google Sign In
firebase_auth:
firebase_core:
firebase_auth: ^4.6.2
firebase_core: ^2.13.1
file_picker: ^5.3.2
google_sign_in:
provider:
get:
@@ -59,11 +60,10 @@ dependencies:
community_material_icon: ^5.9.55
flutter_email_sender: ^5.2.0
webview_flutter: ^4.2.0
firebase_storage:
firebase_storage: ^11.2.2
firebase_messaging: ^14.5.0
flutter_local_notifications: ^14.0.0+1
responsive_builder: ^0.7.0
file_picker: ^5.3.2
http: ^0.13.5
dev_dependencies: