diff --git a/lib/main.dart b/lib/main.dart index 79a00b5..491b83c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -8,11 +8,14 @@ import 'package:prosappco/src/screens/login_email.dart'; import 'package:prosappco/src/screens/new_number.dart'; import 'package:prosappco/src/screens/new_password.dart'; import 'package:prosappco/src/screens/profession.dart'; +import 'package:prosappco/src/screens/professional.dart'; +import 'package:prosappco/src/screens/professional_info.dart'; import 'package:prosappco/src/screens/professional_profile.dart'; import 'package:prosappco/src/screens/professional_revision.dart'; import 'package:prosappco/src/screens/profile.dart'; import 'package:prosappco/src/screens/register.dart'; import 'package:prosappco/src/screens/request_sent.dart'; +import 'package:prosappco/src/screens/service.dart'; import 'package:prosappco/src/screens/welcome.dart'; import 'firebase_options.dart'; @@ -35,18 +38,20 @@ class MyApp extends StatelessWidget { title: 'ProsApp', initialRoute: '/', routes: { - '/': (context) => LoginScreen(), - '/login': (context) => LoginEmailScreen(), - '/welcome': (context) => WelcomeScreen(), + '/': (context) => const LoginScreen(), + '/login': (context) => const LoginEmailScreen(), + '/welcome': (context) => const WelcomeScreen(), '/profile': (context) => ProfileScreen(), - '/register': (context) => RegisterScreen(), - '/city': (context) => CityScreen(), - '/profession': (context) => ProfessionScreen(), - '/newNumber': (context) => NewNumberScreen(), - '/profesionalRevision': (context) => ProfessionalRevisionScreen(), - '/profesionalProfile': (context) => ProfessionalProfileScreen(), - '/solicitudEnviada': (context) => RequestSentScreen(), - '/nuevaPassword': (context) => NewPasswordScreen() + '/register': (context) => const RegisterScreen(), + '/city': (context) => const CityScreen(), + '/profession': (context) => const ProfessionScreen(), + '/newNumber': (context) => const NewNumberScreen(), + '/profesionalRevision': (context) => const ProfessionalRevisionScreen(), + '/profesionalProfile': (context) => const ProfessionalProfileScreen(), + '/solicitudEnviada': (context) => const RequestSentScreen(), + '/nuevaPassword': (context) => NewPasswordScreen(), + '/servicio': (context) => const ServiceScreen(), + '/profesional': (context) => const ProfessionalScreen(), }, onGenerateRoute: (settings) { throw Exception('Ruta desconocida: ${settings.name}'); diff --git a/lib/src/components/bottom_sheet.dart b/lib/src/components/bottom_sheet.dart new file mode 100644 index 0000000..9428348 --- /dev/null +++ b/lib/src/components/bottom_sheet.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; + +class BottomSheetExpanded extends StatelessWidget { + final List children; + final double horizontalPadding; + + const BottomSheetExpanded({ + super.key, + required this.children, + this.horizontalPadding = 35, + }); + + @override + Widget build(BuildContext context) { + return SafeArea( + child: Scaffold( + backgroundColor: const Color(0xFFD6F4FF), + body: Column( + children: [ + const Expanded( + child: Padding( + padding: EdgeInsets.all(15.0), + child: Image( + image: AssetImage('images/logo_prosapp.png'), + ), + ), + ), + Container( + width: double.infinity, + decoration: const BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(30), + topRight: Radius.circular(30), + ), + ), + child: Padding( + padding: EdgeInsets.symmetric( + horizontal: horizontalPadding, + vertical: 15, + ), + child: Column(children: children), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/src/components/column_padding.dart b/lib/src/components/column_padding.dart new file mode 100644 index 0000000..d0e7337 --- /dev/null +++ b/lib/src/components/column_padding.dart @@ -0,0 +1,17 @@ +import 'package:flutter/material.dart'; + +class ColumnPadding extends StatelessWidget { + final List children; + final EdgeInsetsGeometry padding; + + const ColumnPadding({ + super.key, + required this.children, + required this.padding, + }); + + @override + Widget build(BuildContext context) { + return Padding(padding: padding, child: Column(children: children)); + } +} diff --git a/lib/src/components/photo_view.dart b/lib/src/components/photo_view.dart index a9f010a..936aee5 100644 --- a/lib/src/components/photo_view.dart +++ b/lib/src/components/photo_view.dart @@ -2,18 +2,23 @@ import 'dart:io'; import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_animate/flutter_animate.dart'; const double photoSize = 100; +const double iconSize = 55; class ReferencePhoto extends StatelessWidget { Reference? ref; double size; + double sizeIcon; double sizeCircle; - ReferencePhoto( - {super.key, - required this.ref, - this.size = photoSize, - this.sizeCircle = photoSize}); + ReferencePhoto({ + super.key, + required this.ref, + this.sizeIcon = iconSize, + this.size = photoSize, + this.sizeCircle = photoSize, + }); Future downloadImage() async { try { @@ -33,7 +38,10 @@ class ReferencePhoto extends StatelessWidget { // ignore: empty_catches } catch (e) {} - return DefaultPhoto(sizeDefault: sizeCircle); + return DefaultPhoto( + sizeDefault: sizeCircle, + iconDefault: sizeIcon, + ); } @override @@ -43,12 +51,13 @@ class ReferencePhoto extends StatelessWidget { builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { // mientras la llamada asíncrona está en proceso, muestra un mensaje de carga - return const SizedBox( - width: photoSize, - height: photoSize, - child: Center( - child: CircularProgressIndicator(), - )); + return SizedBox( + width: size, + height: size, + child: const Center( + child: CircularProgressIndicator(), + ), + ); } else if (snapshot.connectionState == ConnectionState.done && snapshot.hasData) { return snapshot.data!; @@ -61,7 +70,12 @@ class ReferencePhoto extends StatelessWidget { class DefaultPhoto extends StatelessWidget { double sizeDefault; - DefaultPhoto({super.key, this.sizeDefault = photoSize}); + double iconDefault; + DefaultPhoto({ + super.key, + this.sizeDefault = photoSize, + this.iconDefault = iconSize, + }); @override Widget build(BuildContext context) { @@ -72,12 +86,12 @@ class DefaultPhoto extends StatelessWidget { color: const Color(0xFF2BA4EC), borderRadius: BorderRadius.circular(50), ), - child: const Icon( + child: Icon( Icons.person, - color: Color.fromARGB(255, 255, 255, 255), - size: 55, + color: const Color.fromARGB(255, 255, 255, 255), + size: iconDefault, ), - ); + ).animate().shake(); } } diff --git a/lib/src/screens/city.dart b/lib/src/screens/city.dart index 9aef3b1..28cd129 100644 --- a/lib/src/screens/city.dart +++ b/lib/src/screens/city.dart @@ -4,7 +4,6 @@ import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:prosappco/src/authentication/authentication_repository.dart'; import 'package:prosappco/src/components/pop_appbar.dart'; -import 'package:prosappco/src/components/primary_btn.dart'; class CityScreen extends StatefulWidget { const CityScreen({super.key}); @@ -136,16 +135,16 @@ class _CityScreenState extends State { child: Scaffold( appBar: PopAppbar( onPressed: () { - Navigator.pushReplacementNamed(context, '/profile'); + Navigator.pop(context); }, label: 'Seleccione su ciudad'), body: Column( children: [ Padding( - padding: EdgeInsets.only(left: 10, right: 10, top: 10), + padding: const EdgeInsets.only(left: 10, right: 10, top: 10), child: TextField( controller: searchController, - decoration: InputDecoration( + decoration: const InputDecoration( hintText: 'Buscar ciudad', prefixIcon: Icon(Icons.near_me), ), @@ -162,7 +161,7 @@ class _CityScreenState extends State { fontSize: 18.0, color: Colors.black, ), - children: [ + children: [ TextSpan( text: '${citys[index].cityName ?? ""}, ', style: const TextStyle(fontWeight: FontWeight.bold), diff --git a/lib/src/screens/code_validation.dart b/lib/src/screens/code_validation.dart index af0ddb5..9fdd70c 100644 --- a/lib/src/screens/code_validation.dart +++ b/lib/src/screens/code_validation.dart @@ -1,6 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_otp_text_field/flutter_otp_text_field.dart'; import 'package:get/get.dart'; +import 'package:prosappco/src/components/bottom_sheet.dart'; +import 'package:prosappco/src/components/column_padding.dart'; +import 'package:prosappco/src/components/primary_btn.dart'; import 'package:prosappco/src/controllers/otp_controller.dart'; import 'package:prosappco/src/controllers/phone_auth_controller.dart'; @@ -14,160 +17,107 @@ class CodeValidationScreen extends StatelessWidget { Widget build(BuildContext context) { var otp; - return SafeArea( - child: Scaffold( - backgroundColor: const Color(0xFFD6F4FF), - body: SingleChildScrollView( - reverse: true, - child: Stack( - children: [ - Container( - margin: const EdgeInsets.only(top: 280), - width: double.infinity, - height: MediaQuery.of(context).size.height / 1.5, - decoration: const BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - topRight: Radius.circular(50), - topLeft: Radius.circular(50))), + return BottomSheetExpanded( + horizontalPadding: 10, + children: [ + Row( + children: [ + IconButton( + icon: const Icon( + Icons.arrow_back, + size: 30, ), - Container( - margin: const EdgeInsets.only(top: 120, left: 70, right: 70), - child: - const Image(image: AssetImage('images/logo_prosapp.png')), + onPressed: () { + Navigator.pop(context); + }, + ), + const Text( + 'Validar código', + style: TextStyle( + color: Color(0xFF262626), + fontSize: 38.0, + fontWeight: FontWeight.bold, ), - Container( - padding: - const EdgeInsets.symmetric(horizontal: 0, vertical: 20), - margin: const EdgeInsets.only(top: 280, left: 25), - child: Row( - children: [ - IconButton( - icon: Icon( - Icons.arrow_back, - size: 30, - ), - onPressed: () { - Navigator.pop(context); - }, - ), - Text( - 'Validar código', - style: TextStyle( - color: Color(0xFF262626), - fontSize: 38.0, - fontWeight: FontWeight.bold, - ), - textAlign: TextAlign.right, - ), - ], - ), - ), - Container( - padding: - const EdgeInsets.symmetric(horizontal: 0, vertical: 20), - margin: const EdgeInsets.only(top: 350, 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))), - )), - Padding( - padding: EdgeInsets.only(bottom: 20), - child: Row( - children: [ - Expanded( - child: TextField( - onChanged: (value) { - phoneNumber = value; - }, - controller: TextEditingController( - text: phoneNumber ?? ''), - decoration: InputDecoration( - border: InputBorder.none, - hintText: '', - suffixIcon: Icon(Icons.edit), - ), - ), - ), - TextButton( - child: Text('Reenviar código'), - onPressed: () { - if (phoneNumber!.isNotEmpty) { - PhoneAuthController.instance - .phoneAuthentication( - phoneNumber!, - ); - } - }, - ), - ], - ), - ), - Align( - alignment: Alignment.topLeft, - child: Padding( - padding: const EdgeInsets.only(bottom: 5), - child: Text('Codigo', - textAlign: TextAlign.left, - style: TextStyle( - fontSize: 18.0, color: Color(0xFF65676B))), - ), - ), - Padding( - padding: EdgeInsets.only(bottom: 20), - child: OtpTextField( - numberOfFields: 6, - focusedBorderColor: Colors.blue, - fillColor: Colors.black.withOpacity(0.1), - filled: true, - keyboardType: TextInputType.number, - onSubmit: (code) { - otp = code; - OTPController.instance.verifyOTP(otp); - }, - ), - ), - Padding( - padding: EdgeInsets.only(bottom: 40), - child: Center( - child: ElevatedButton( - onPressed: () { - OTPController.instance.verifyOTP(otp); - }, - child: Text( - 'Validar código', - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - fontSize: 18, - ), - ), - style: ElevatedButton.styleFrom( - primary: Color(0xFF2BA4EC), // Color del botón - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular( - 50), // Bordes redondeados - ), - elevation: 0, - minimumSize: - Size(230, 60), // Tamaño mínimo del botón - ), - ), - ), - ), - ], - ), - ), - ], - ), + ), + ], ), - ), + ColumnPadding( + padding: const EdgeInsets.symmetric(horizontal: 25), + children: [ + const SizedBox(height: 10), + const SizedBox( + width: double.infinity, + child: Text( + 'Numero de celular', + style: TextStyle( + fontSize: 18.0, + color: Color(0xFF65676B), + ), + ), + ), + const SizedBox(height: 10), + Row( + children: [ + Expanded( + child: TextField( + onChanged: (value) { + phoneNumber = value; + }, + controller: TextEditingController(text: phoneNumber ?? ''), + decoration: const InputDecoration( + border: InputBorder.none, + hintText: '', + suffixIcon: Icon(Icons.edit), + ), + ), + ), + TextButton( + child: const Text('Reenviar código'), + onPressed: () { + if (phoneNumber!.isNotEmpty) { + PhoneAuthController.instance.phoneAuthentication( + phoneNumber!, + ); + } + }, + ), + ], + ), + const SizedBox(height: 10), + const SizedBox( + width: double.infinity, + child: Text( + 'Codigo', + textAlign: TextAlign.left, + style: TextStyle( + fontSize: 18.0, + color: Color(0xFF65676B), + ), + ), + ), + const SizedBox(height: 10), + OtpTextField( + numberOfFields: 6, + focusedBorderColor: Colors.blue, + fillColor: Colors.black.withOpacity(0.1), + filled: true, + keyboardType: TextInputType.number, + onSubmit: (code) { + otp = code; + OTPController.instance.verifyOTP(otp); + }, + ), + const SizedBox(height: 40), + PrimaryButtom( + onPressed: () { + OTPController.instance.verifyOTP(otp); + }, + label: 'Validar código', + ), + const SizedBox(height: 30), + ], + ), + ], ); } } diff --git a/lib/src/screens/login.dart b/lib/src/screens/login.dart index 82afe8f..bb5a5cc 100644 --- a/lib/src/screens/login.dart +++ b/lib/src/screens/login.dart @@ -1,12 +1,11 @@ import 'package:flutter/material.dart'; +import 'package:flutter_animate/flutter_animate.dart'; import 'package:get/get.dart'; import 'package:intl_phone_field/intl_phone_field.dart'; -import 'package:prosappco/src/authentication/authentication_repository.dart'; +import 'package:prosappco/src/components/bottom_sheet.dart'; import 'package:prosappco/src/components/primary_btn.dart'; import 'package:prosappco/src/controllers/phone_auth_controller.dart'; import 'package:prosappco/src/screens/code_validation.dart'; -import 'package:prosappco/src/screens/login_email.dart'; -import 'package:prosappco/src/screens/register.dart'; class LoginScreen extends StatefulWidget { const LoginScreen({super.key}); @@ -22,166 +21,121 @@ class _LoginScreenState extends State { @override Widget build(BuildContext context) { - return SafeArea( - child: Scaffold( - backgroundColor: const Color(0xFFD6F4FF), - body: SingleChildScrollView( - reverse: true, - child: Stack( + return BottomSheetExpanded( + children: [ + const SizedBox( + width: double.infinity, + child: Text( + 'Iniciar sesión', + style: TextStyle( + color: Color(0xFF262626), + fontSize: 38.0, + fontWeight: FontWeight.bold, + ), + ), + ), + const SizedBox(height: 10), + const SizedBox( + width: double.infinity, + child: Text( + 'Numero de celular', + style: TextStyle( + fontSize: 18.0, + color: Color(0xFF65676B), + ), + ), + ), + Form( + key: _formKey, + child: IntlPhoneField( + controller: controller.phoneNo, + initialCountryCode: 'CO', + onChanged: (phoneNo) { + completePhoneNumber = phoneNo.completeNumber; + }, + decoration: const InputDecoration( + 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 Text( + 'Un código será enviado a este numero de celular.', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 13.0, + color: Color(0xFF65676B), + ), + ), + const SizedBox(height: 20), + PrimaryButtom( + onPressed: () { + if (_formKey.currentState!.validate()) { + PhoneAuthController.instance.phoneAuthentication( + completePhoneNumber.trim(), + ); + Get.to( + () => CodeValidationScreen( + phoneNumber: completePhoneNumber.trim(), + ), + ); + } + }, + label: 'Enviar código', + ), + const SizedBox(height: 20), + GestureDetector( + onTap: () { + Navigator.pushNamed(context, '/login'); + }, + child: const Text( + 'Entrar con correo electronico', + style: TextStyle( + fontSize: 15.0, color: Color(0xFF65676B), + decoration: TextDecoration.underline, // Subrayado + ), + ), + ), + const SizedBox(height: 20), + RichText( + text: TextSpan( + style: const TextStyle( + fontSize: 16.0, + color: Color(0xFF65676B), + fontFamily: 'Poppins', + ), children: [ - Container( - margin: const EdgeInsets.only(top: 280), - width: double.infinity, - height: MediaQuery.of(context).size.height / 1.5, - decoration: const BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - topRight: Radius.circular(50), - topLeft: Radius.circular(50))), - ), - Container( - margin: const EdgeInsets.only(top: 120, left: 70, right: 70), - child: - const Image(image: AssetImage('images/logo_prosapp.png')), - ), - Container( - padding: - const EdgeInsets.symmetric(horizontal: 0, vertical: 20), - margin: const EdgeInsets.only(top: 280, left: 30, right: 50), - child: Column(children: const [ - Align( - alignment: Alignment.topLeft, - child: Text( - 'Iniciar sesión', - style: TextStyle( - color: Color(0xFF262626), - fontSize: 38.0, - fontWeight: FontWeight.bold, - ), + const TextSpan(text: 'No estas registrado? '), + WidgetSpan( + child: GestureDetector( + onTap: () { + Navigator.pushNamed(context, '/register'); + }, + child: const Text( + 'Registrarse', + style: TextStyle( + fontSize: 16.0, + color: Color(0xFF2BA4EC), + fontWeight: FontWeight.w600, ), ), - ]), - ), - Container( - padding: - const EdgeInsets.symmetric(horizontal: 0, vertical: 20), - margin: const EdgeInsets.only(top: 350, 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: EdgeInsets.only(bottom: 5), - child: IntlPhoneField( - controller: controller.phoneNo, - initialCountryCode: 'CO', - onChanged: (phoneNo) { - completePhoneNumber = phoneNo.completeNumber; - }, - decoration: InputDecoration( - 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: () { - if (_formKey.currentState!.validate()) { - PhoneAuthController.instance.phoneAuthentication( - completePhoneNumber.trim(), - ); - Get.to( - () => CodeValidationScreen( - phoneNumber: completePhoneNumber.trim(), - ), - ); - } - }, - label: 'Enviar código', - ), - ), - ), - Padding( - padding: EdgeInsets.only(bottom: 27), - child: GestureDetector( - onTap: () { - Navigator.pushNamed(context, '/login'); - }, - child: Text( - 'Entrar con correo electronico', - style: TextStyle( - fontSize: 15.0, color: Color(0xFF65676B), - decoration: TextDecoration.underline, // Subrayado - ), - ), - ), - ), - RichText( - text: TextSpan( - style: TextStyle( - fontSize: 16.0, - color: Color(0xFF65676B), - fontFamily: 'Poppins', - ), - children: [ - TextSpan(text: 'No estas registrado? '), - WidgetSpan( - child: GestureDetector( - onTap: () { - Navigator.pushNamed(context, '/register'); - }, - child: Text( - 'Registrarse', - style: TextStyle( - fontSize: 16.0, - color: Color(0xFF2BA4EC), - fontWeight: FontWeight.w600, - ), - ), - ), - ), - ], - ), - ) - ], ), ), ], ), ), - ), + const SizedBox(height: 20), + ], ); } } diff --git a/lib/src/screens/login_email.dart b/lib/src/screens/login_email.dart index d44d4c9..e564b20 100644 --- a/lib/src/screens/login_email.dart +++ b/lib/src/screens/login_email.dart @@ -1,18 +1,9 @@ import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:get/get.dart'; -import 'package:prosappco/main.dart'; import 'package:prosappco/src/authentication/authentication_repository.dart'; import 'package:prosappco/src/components/primary_btn.dart'; import 'package:prosappco/src/controllers/login_email_controller.dart'; -import 'package:prosappco/src/controllers/register_controller.dart'; -import 'package:prosappco/src/screens/login.dart'; -import 'package:prosappco/src/screens/welcome.dart'; -import 'package:provider/provider.dart'; - -import 'package:firebase_auth/firebase_auth.dart'; -import 'package:google_sign_in/google_sign_in.dart'; -import 'package:prosappco/src/screens/register.dart'; class LoginEmailScreen extends StatefulWidget { const LoginEmailScreen({super.key}); @@ -30,7 +21,7 @@ class _LoginEmailScreenState extends State { Widget build(BuildContext context) { return SafeArea( child: Scaffold( - backgroundColor: Color(0xFFD6F4FF), + backgroundColor: const Color(0xFFD6F4FF), body: SingleChildScrollView( reverse: true, child: Stack( @@ -62,7 +53,7 @@ class _LoginEmailScreenState extends State { child: Row( children: [ IconButton( - icon: Icon( + icon: const Icon( Icons.arrow_back, size: 30, ), @@ -70,7 +61,7 @@ class _LoginEmailScreenState extends State { Navigator.pop(context); }, ), - Text( + const Text( 'Iniciar sesión', style: TextStyle( color: Color(0xFF262626), @@ -90,23 +81,23 @@ class _LoginEmailScreenState extends State { margin: const EdgeInsets.only(top: 210, left: 50, right: 50), child: Column(children: [ Padding( - padding: EdgeInsets.only(bottom: 20), + padding: const EdgeInsets.only(bottom: 20), child: ElevatedButton( onPressed: () async { await AuthenticationRepository.instance .signInWithGoogle(); }, style: ElevatedButton.styleFrom( - primary: Color(0xFF2BA4EC), + backgroundColor: const Color(0xFF2BA4EC), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(50), ), elevation: 0, - minimumSize: Size(230, 60), + minimumSize: const Size(230, 60), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ + children: const [ Text( 'Entrar con Google ', style: TextStyle( @@ -121,9 +112,9 @@ class _LoginEmailScreenState extends State { )), ), Padding( - padding: EdgeInsets.symmetric(vertical: 5), + padding: const EdgeInsets.symmetric(vertical: 5), child: Row( - children: [ + children: const [ Expanded( child: Divider( color: Colors.black38, @@ -152,10 +143,10 @@ class _LoginEmailScreenState extends State { fontSize: 18.0, color: Color(0xFF65676B))), )), Padding( - padding: EdgeInsets.only(bottom: 20), + padding: const EdgeInsets.only(bottom: 20), child: TextFormField( controller: controller.email, - decoration: InputDecoration( + decoration: const InputDecoration( enabledBorder: OutlineInputBorder( borderSide: BorderSide(color: Color(0xFFECECEC)), borderRadius: BorderRadius.all( @@ -173,7 +164,7 @@ class _LoginEmailScreenState extends State { ), ), ), - Padding( + const Padding( padding: EdgeInsets.only(bottom: 5), child: Align( alignment: Alignment.topLeft, @@ -182,25 +173,25 @@ class _LoginEmailScreenState extends State { fontSize: 18.0, color: Color(0xFF65676B))), )), Padding( - padding: EdgeInsets.only(bottom: 50), + padding: const EdgeInsets.only(bottom: 50), child: TextFormField( controller: controller.password, obscureText: _obscureText, decoration: InputDecoration( - enabledBorder: OutlineInputBorder( + enabledBorder: const OutlineInputBorder( borderSide: BorderSide(color: Color(0xFFECECEC)), borderRadius: BorderRadius.all( Radius.circular(50), )), - focusedBorder: OutlineInputBorder( + focusedBorder: const OutlineInputBorder( borderSide: BorderSide(color: Color(0xFFECECEC)), borderRadius: BorderRadius.all( Radius.circular(50), )), hintText: 'Contraseña', - fillColor: Color.fromARGB(255, 239, 239, 239), + fillColor: const Color.fromARGB(255, 239, 239, 239), filled: true, - prefixIcon: Icon(Icons.lock_outline), + prefixIcon: const Icon(Icons.lock_outline), suffixIcon: IconButton( icon: Icon( _obscureText @@ -234,20 +225,20 @@ class _LoginEmailScreenState extends State { ), RichText( text: TextSpan( - style: TextStyle( + style: const TextStyle( fontSize: 16.0, color: Color(0xFF65676B), fontFamily: 'Poppins', ), children: [ - TextSpan(text: 'No estas registrado? '), + const TextSpan(text: 'No estas registrado? '), WidgetSpan( child: GestureDetector( onTap: () { Navigator.pushReplacementNamed( context, '/register'); }, - child: Text( + child: const Text( 'Registrarse', style: TextStyle( fontSize: 16.0, diff --git a/lib/src/screens/professional.dart b/lib/src/screens/professional.dart new file mode 100644 index 0000000..be8405f --- /dev/null +++ b/lib/src/screens/professional.dart @@ -0,0 +1,229 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:diacritic/diacritic.dart'; +import 'package:firebase_storage/firebase_storage.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:prosappco/src/authentication/authentication_repository.dart'; +import 'package:prosappco/src/components/photo_view.dart'; +import 'package:prosappco/src/components/pop_appbar.dart'; +import 'package:prosappco/src/screens/professional_info.dart'; + +class ProfessionalScreen extends StatefulWidget { + const ProfessionalScreen({super.key}); + + @override + State createState() => _ProfessionalScreenState(); +} + +final FirebaseStorage storage = FirebaseStorage.instance; + +final CollectionReference usersCollection = + FirebaseFirestore.instance.collection('users'); +var _photo = '...'; + +class Professional { + final Reference professionalRef; + final String name; + final String professionName; + final String cityName; + final String ubicacion; + final List professionalEspecializado; + + Professional({ + required this.professionalRef, + required this.name, + required this.professionName, + required this.cityName, + required this.ubicacion, + required this.professionalEspecializado, + }); + + String getEspecializaciones() { + return professionalEspecializado.join(',\n'); + } + + @override + String toString() { + return 'Professional {\n' + ' professionalRef: $professionalRef,\n' + ' name: $name,\n' + ' professionName: $professionName,\n' + ' cityName: $cityName,\n' + ' ubicacion: $ubicacion,\n' + ' professionalEspecializado: ${getEspecializaciones()}\n' + '}'; + } +} + +Future> getProfessionals() async { + List professionals = []; + + try { + QuerySnapshot users = await usersCollection.get(); + for (DocumentSnapshot user in users.docs) { + // Acceder a los datos de cada usuario + Map data = user.data() as Map; + + // Crear un objeto Professional a partir de los datos del usuario + _photo = await AuthenticationRepository.instance.getPhoto(user.id); + + if (data['estado'] == 'activo') { + List especializaciones; + + especializaciones = (data['especializaciones'] as List) + .map((e) => e.toString()) + .toList(); + + Professional professional = Professional( + name: data['name'], + professionName: data['profesion'], + cityName: data['city'], + professionalRef: storage.ref().child(_photo), + professionalEspecializado: especializaciones, + ubicacion: data['ubicacion'], + ); + professionals.add(professional); + } + } + } catch (e) { + print('Error al obtener profesionales: $e'); + } + + return professionals; +} + +class _ProfessionalScreenState extends State { + List? filteredProfessionals; + + TextEditingController searchController = TextEditingController(); + + final uid = AuthenticationRepository.instance.getCurrentUserUid(); + List? _professionals; + + @override + void initState() { + super.initState(); + searchController.addListener(() { + setState(() { + if (_professionals != null) { + if (searchController.text.isEmpty) { + filteredProfessionals = _professionals!; + } else { + filteredProfessionals = _professionals! + .where((professional) => removeDiacritics(professional.name) + .toLowerCase() + .contains( + removeDiacritics(searchController.text.toLowerCase()))) + .toList(); + } + } + }); + }); + + if (_professionals == null) { + getProfessionals().then((List element) => setState(() { + _professionals = element; + filteredProfessionals = element; + })); + } + } + + @override + Widget build(BuildContext context) { + if (filteredProfessionals == null) { + return const Center( + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(Color(0xFF2BA4EC)), + ), + ); + } + var professionals = filteredProfessionals!; + + return SafeArea( + child: Scaffold( + appBar: PopAppbar( + onPressed: () { + Navigator.pop(context); + }, + label: 'Seleccione un profesional'), + body: Column( + children: [ + Padding( + padding: const EdgeInsets.all(10), + child: TextField( + controller: searchController, + decoration: const InputDecoration( + hintText: 'Escriba un nombre', + prefixIcon: Icon(Icons.assignment_ind_rounded), + ), + ), + ), + Expanded( + child: ListView.builder( + itemCount: professionals.length, + itemBuilder: (BuildContext context, int index) { + return ListTile( + leading: GestureDetector( + onTap: () { + Navigator.of(context).push( + CupertinoPageRoute( + builder: (BuildContext context) { + return ProfessionalInfoScreen( + professional: professionals[index], + ); + }, + ), + ); + }, + child: ReferencePhoto( + ref: professionals[index].professionalRef, + sizeCircle: 50, + size: 50, + sizeIcon: 35, + ), + ), + trailing: GestureDetector( + child: const Icon(Icons.keyboard_arrow_right), + onTap: () { + Navigator.of(context).push( + CupertinoPageRoute( + builder: (BuildContext context) { + return ProfessionalInfoScreen( + professional: professionals[index], + ); + }, + ), + ); + }, + ), + title: RichText( + text: TextSpan( + style: const TextStyle( + fontSize: 15.0, + color: Colors.black, + ), + children: [ + TextSpan( + text: '${professionals[index].name}, ', + style: const TextStyle(fontWeight: FontWeight.bold), + ), + TextSpan( + text: + "${professionals[index].professionName}, ${professionals[index].cityName}", + style: TextStyle(color: Colors.grey[600]), + ), + ], + ), + ), + onTap: () { + // Navigator.pop(context, professionals[index]); + }, + ); + }, + ), + ), + ], + ), + )); + } +} diff --git a/lib/src/screens/professional_info.dart b/lib/src/screens/professional_info.dart new file mode 100644 index 0000000..f3f165c --- /dev/null +++ b/lib/src/screens/professional_info.dart @@ -0,0 +1,229 @@ +import 'package:flutter/material.dart'; +import 'package:prosappco/src/components/photo_view.dart'; +import 'package:prosappco/src/components/pop_appbar.dart'; +import 'package:prosappco/src/screens/professional.dart'; + +class ProfessionalInfoScreen extends StatelessWidget { + Professional professional; + + ProfessionalInfoScreen({super.key, required this.professional}); + + @override + Widget build(BuildContext context) { + return SafeArea( + child: Scaffold( + appBar: PopAppbar( + onPressed: () { + Navigator.pop(context); + }, + label: professional.name), + body: SingleChildScrollView( + child: Stack( + children: [ + Column( + children: [ + Container( + width: double.infinity, + height: 140, + decoration: BoxDecoration( + color: const Color(0xFFD6F4FF), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.5), + spreadRadius: 1, + blurRadius: 7, + offset: const Offset(0, 2), + ), + ], + ), + ), + Padding( + padding: const EdgeInsets.only(left: 50), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox( + height: 5, + ), + Text( + professional.name, + style: const TextStyle(fontWeight: FontWeight.w500), + ), + Text( + professional.professionName, + style: const TextStyle(color: Color(0xFF1688C9)), + ), + professional.getEspecializaciones().isEmpty + ? const SizedBox() + : Text( + 'Especializado/a en ${professional.getEspecializaciones()}', + style: const TextStyle(color: Colors.black54), + ), + Text( + professional.cityName, + ), + ], + ), + ), + professional.ubicacion == 'domicilio' + ? Container( + margin: const EdgeInsets.only( + left: 40, right: 40, top: 20, bottom: 20), + 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: Row( + children: const [ + Icon( + Icons.error_outline, + size: 27, + color: Colors.black54, + ), + SizedBox(width: 15), + Text( + 'Este profesional solo atiende en\nsu dirección de trabajo.', + style: TextStyle( + color: Colors.black, fontSize: 13), + ), + ], + ), + ) + : const SizedBox(), + const SizedBox(height: 10), + const Text( + 'Se unió el 02 de abril del 2023', + style: TextStyle(fontSize: 12), + ), + const SizedBox(height: 15), + Container( + decoration: BoxDecoration( + color: const Color(0xFFD6F4FF), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.2), + spreadRadius: 3, + blurRadius: 5, + offset: const Offset(0, 3), + ), + ], + ), + child: ListTile( + onTap: () {}, + trailing: const Icon(Icons.keyboard_arrow_right, + color: Colors.black), + title: const Text( + 'Reputación', + style: TextStyle(color: Colors.black), + ), + subtitle: Row( + children: const [ + Icon(Icons.star), + Icon(Icons.star), + Icon(Icons.star), + Icon(Icons.star), + Icon(Icons.star_half), + ], + ), + ), + ), + ListTile( + onTap: () {}, + leading: ReferencePhoto( + ref: professional.professionalRef, + size: 50, + sizeCircle: 50, + sizeIcon: 35, + ), + title: Row( + children: const [ + Icon(Icons.star), + Icon(Icons.star), + Icon(Icons.star), + Icon(Icons.star), + Icon(Icons.star_half), + ], + ), + subtitle: const Text( + 'Mi perfil', + style: TextStyle(fontSize: 15), + ), + ), + ListTile( + onTap: () {}, + leading: ReferencePhoto( + ref: professional.professionalRef, + size: 50, + sizeCircle: 50, + sizeIcon: 35, + ), + title: Row( + children: const [ + Icon(Icons.star), + Icon(Icons.star), + Icon(Icons.star), + Icon(Icons.star), + Icon(Icons.star), + ], + ), + subtitle: const Text( + 'Mi perfil', + style: TextStyle(fontSize: 15), + ), + ), + ListTile( + onTap: () {}, + leading: ReferencePhoto( + ref: professional.professionalRef, + sizeCircle: 50, + sizeIcon: 35, + size: 50, + ), + title: Row( + children: const [ + Icon(Icons.star), + Icon(Icons.star), + Icon(Icons.star), + Icon(Icons.star), + Icon(Icons.star_border), + ], + ), + subtitle: const Text( + 'Mi perfil', + style: TextStyle(fontSize: 15), + ), + ), + const SizedBox( + height: 10, + ), + ], + ), + Container( + padding: const EdgeInsets.only( + top: 110, + left: 10, + ), + child: ReferencePhoto( + ref: professional.professionalRef, + size: 100, + sizeCircle: 100, + sizeIcon: 50, + ), + ) + ], + ), + ), + ), + ); + } +} diff --git a/lib/src/screens/professional_revision.dart b/lib/src/screens/professional_revision.dart index 79fb8bf..8bc2c6d 100644 --- a/lib/src/screens/professional_revision.dart +++ b/lib/src/screens/professional_revision.dart @@ -29,7 +29,7 @@ class _ProfessionalRevisionScreenState children: [ Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ + children: const [ Icon( Icons.access_time, color: Color(0xFF2BA4EC), @@ -47,25 +47,26 @@ class _ProfessionalRevisionScreenState width: 300, ), Container( - margin: EdgeInsets.symmetric(horizontal: 40), + margin: const EdgeInsets.symmetric(horizontal: 40), decoration: BoxDecoration( - color: Color(0xFFD6F4FF), + color: const Color(0xFFD6F4FF), borderRadius: BorderRadius.circular(30), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.5), spreadRadius: 2, blurRadius: 5, - offset: Offset(0, 3), // changes position of shadow + offset: const Offset(0, 3), // changes position of shadow ), ], ), - padding: EdgeInsets.symmetric(vertical: 15, horizontal: 25), + padding: + const EdgeInsets.symmetric(vertical: 15, horizontal: 25), child: Wrap( alignment: WrapAlignment.start, // Centra el contenido children: [ Row( - children: [ + children: const [ Icon( Icons.info_outline, size: 20, @@ -79,13 +80,13 @@ class _ProfessionalRevisionScreenState ), ], ), - Text( + const Text( 'una vez aprobada podrá acceder, ', style: TextStyle( fontSize: 14, ), ), - Text( + const Text( 'al perfil profesional.', style: TextStyle( fontSize: 14, diff --git a/lib/src/screens/profile.dart b/lib/src/screens/profile.dart index a4021a1..36b004d 100644 --- a/lib/src/screens/profile.dart +++ b/lib/src/screens/profile.dart @@ -1,12 +1,17 @@ import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_storage/firebase_storage.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_animate/flutter_animate.dart'; import 'package:get/get.dart'; import 'dart:io'; import 'package:prosappco/src/authentication/authentication_repository.dart'; import 'package:prosappco/src/components/drawer_menu.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/services/select_image_profile.dart'; import '../components/photo_view.dart'; @@ -176,14 +181,14 @@ class _ProfileScreenState extends State { _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, @@ -199,14 +204,14 @@ class _ProfileScreenState extends State { _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, @@ -406,8 +411,11 @@ class _ProfileScreenState extends State { _email != null ? TextFormField( onTap: () { - Navigator.pushNamed( - context, '/nuevaPassword'); + Navigator.push(context, CupertinoPageRoute( + builder: (BuildContext context) { + return NewPasswordScreen(); + }, + )); }, readOnly: true, controller: _emailController, @@ -451,32 +459,43 @@ class _ProfileScreenState extends State { TextFormField( readOnly: true, onTap: () async { - final String? ciudad = - (await Navigator.pushNamed(context, '/city')) - as String?; + final String? ciudad = await Navigator.push( + context, + CupertinoPageRoute( + builder: (BuildContext context) { + return const CityScreen(); + }, + ), + ) as String?; if (ciudad != null) { setState(() { - _ciudad = ciudad as String; + _ciudad = ciudad; }); } }, decoration: InputDecoration( - prefixIcon: Icon(Icons.near_me), - suffixIcon: Icon(Icons.arrow_drop_down), + prefixIcon: const Icon(Icons.near_me), + suffixIcon: const Icon(Icons.arrow_drop_down), hintStyle: city == '' - ? TextStyle() - : TextStyle(color: Colors.black87), - hintText: city == '' ? 'Ciudad' : '$city'), + ? const TextStyle() + : const TextStyle(color: Colors.black87), + hintText: city == '' ? 'Ciudad' : city), ), const SizedBox(height: 20.0), TextFormField( controller: _phoneNumberController, readOnly: true, onTap: () { - Navigator.pushNamed(context, '/newNumber'); + Navigator.of(context).push( + CupertinoPageRoute( + builder: (BuildContext context) { + return const NewNumberScreen(); + }, + ), + ); }, - decoration: InputDecoration( + decoration: const InputDecoration( prefixIcon: Icon(Icons.phone_android), suffixIcon: Icon(Icons.edit_outlined), hintText: '+57'), @@ -486,12 +505,21 @@ class _ProfileScreenState extends State { ), Container( alignment: Alignment.bottomCenter, - margin: EdgeInsets.only(top: 100), + margin: const EdgeInsets.only(top: 100), + padding: const EdgeInsets.only(bottom: 30), child: ElevatedButton( onPressed: () async { await updateInfo(); }, - child: Text( + 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, @@ -499,16 +527,7 @@ class _ProfileScreenState extends State { fontSize: 17, ), ), - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF2BA4EC), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(50), - ), - elevation: 0, - minimumSize: Size(200, 50), - ), ), - padding: EdgeInsets.only(bottom: 30), ), ], ), diff --git a/lib/src/screens/service.dart b/lib/src/screens/service.dart new file mode 100644 index 0000000..57e2df5 --- /dev/null +++ b/lib/src/screens/service.dart @@ -0,0 +1,255 @@ +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:firebase_storage/firebase_storage.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:prosappco/src/authentication/authentication_repository.dart'; +import 'package:prosappco/src/components/drawer_menu.dart'; +import 'package:prosappco/src/components/primary_btn.dart'; +import 'package:prosappco/src/screens/professional.dart'; + +class ServiceScreen extends StatefulWidget { + const ServiceScreen({super.key}); + + @override + State createState() => _ServiceScreenState(); +} + +class _ServiceScreenState extends State { + final FirebaseStorage storage = FirebaseStorage.instance; + final uid = AuthenticationRepository.instance.getCurrentUserUid(); + var _ciudad = ''; + var _photo = '...'; + var _estado = '...'; + + @override + void initState() { + super.initState(); + + if (_estado == '...') { + AuthenticationRepository.instance + .getState(uid.toString()) + .then((String s) => setState(() { + _estado = s; + })); + } + + 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; + })); + } + } + + @override + Widget build(BuildContext context) { + final User? user = FirebaseAuth.instance.currentUser; + + List opc = ["Servicio", "Opción 1", "Opción 2", "Opción 3"]; + String defaultValue = opc[0]; + + String city = _ciudad.toString(); + String state = _estado.toString(); + + return SafeArea( + child: Scaffold( + backgroundColor: Color(0xFFD6F4FF), + drawer: DrawerMenu( + ref: storage.ref().child(_photo), + userName: user?.displayName ?? '', + userPhoneNumber: user?.phoneNumber ?? '', + userCity: city, + userState: state), + body: SingleChildScrollView( + reverse: true, + child: Stack( + children: [ + Padding( + padding: const EdgeInsets.all(20.0), + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + shape: const CircleBorder(), + elevation: 3, + minimumSize: const Size(50, 50), + ), + child: const Icon( + Icons.menu, + color: Colors.black, + size: 30, + ), + onPressed: () { + Scaffold.of(context).openDrawer(); + }, + ); + }, + ), + ), + Padding( + padding: const EdgeInsets.only(top: 23, left: 100, right: 25), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(50), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.4), + spreadRadius: 1, + blurRadius: 2, + offset: + const Offset(1, 2), // changes position of shadow + ), + ], + ), + child: DropdownButtonFormField( + value: defaultValue, + elevation: 0, + decoration: InputDecoration( + filled: true, + fillColor: Colors.white, + contentPadding: const EdgeInsets.symmetric( + horizontal: 16, vertical: 8), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(50), + borderSide: BorderSide.none, + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(50), + borderSide: BorderSide.none, + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(50), + borderSide: BorderSide.none, + ), + ), + items: opc.map((e) { + return DropdownMenuItem( + value: e, + child: Text( + e, + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ); + }).toList(), + onChanged: (value) { + print(value); + }, + ), + ), + ), + ], + ), + ), + bottomNavigationBar: Container( + decoration: const BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topRight: Radius.circular(50), topLeft: Radius.circular(50))), + height: MediaQuery.of(context).size.height / 2.3, + child: Column( + children: [ + const SizedBox(height: 15), + SizedBox( + width: 300, + child: Form( + child: Column( + children: [ + TextFormField( + // controller: _cedulaController, + decoration: const InputDecoration( + prefixIcon: Icon(Icons.near_me), + hintText: 'Dirección'), + ), + const SizedBox(height: 15), + TextFormField( + // controller: _cedulaController, + readOnly: true, + onTap: () async { + final String? profesional = await Navigator.push( + context, + CupertinoPageRoute( + builder: (BuildContext context) { + return const ProfessionalScreen(); + }, + ), + ) as String?; + + if (profesional != null) { + setState(() { + // _profession = profesional; + }); + } + }, + decoration: const InputDecoration( + prefixIcon: Icon(Icons.assignment_ind_rounded), + suffixIcon: Icon(Icons.arrow_drop_down), + hintText: 'Seleccionar profesional'), + ), + const SizedBox(height: 15), + Row( + children: [ + SizedBox( + width: 150, + child: TextFormField( + decoration: const InputDecoration( + suffixIcon: Icon(Icons.arrow_drop_down), + prefixIcon: Icon(Icons.calendar_month), + hintText: 'Fecha'), + )), + SizedBox( + width: 150, + child: TextFormField( + decoration: const InputDecoration( + suffixIcon: Icon(Icons.arrow_drop_down), + hintText: 'Hora'), + )), + ], + ), + const SizedBox(height: 15), + TextFormField( + // controller: _cedulaController, + decoration: const InputDecoration( + prefixIcon: Icon(Icons.message_outlined), + hintText: 'Observaciones'), + ), + const SizedBox(height: 30), + ElevatedButton( + onPressed: () {}, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF2BA4EC), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(50), + ), + elevation: 0, + minimumSize: const Size(230, 50), + ), + child: const Text( + 'Solicitar servicio', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + ), + ], + ), + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/src/screens/welcome.dart b/lib/src/screens/welcome.dart index 327837f..ca44cc6 100644 --- a/lib/src/screens/welcome.dart +++ b/lib/src/screens/welcome.dart @@ -146,7 +146,10 @@ class _WelcomeScreenState extends State { padding: const EdgeInsets.only(bottom: 40), child: Center( child: PrimaryButtom( - onPressed: () {}, label: 'Solicitar un servicio'), + onPressed: () { + Navigator.pushNamed(context, '/servicio'); + }, + label: 'Solicitar un servicio'), ), ), ]), diff --git a/pubspec.lock b/pubspec.lock index 2453e6f..8c66f77 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -182,6 +182,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_animate: + dependency: "direct main" + description: + name: flutter_animate + sha256: f611a67082d4c5ff9b8b7737ec7e675a22af70a94c8c3c22109f14b078d4d2bf + url: "https://pub.dev" + source: hosted + version: "4.1.1+1" flutter_lints: dependency: "direct dev" description: diff --git a/pubspec.yaml b/pubspec.yaml index ce59801..2450de5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -49,6 +49,7 @@ dependencies: diacritic: ^0.1.3 firebase_storage: ^11.1.0 image_picker: ^0.8.7+1 + flutter_animate: ^4.1.1+1 dev_dependencies: flutter_test: