label
This commit is contained in:
@@ -0,0 +1,43 @@
|
|||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:user_repository/user_repository.dart';
|
||||||
|
|
||||||
|
part 'auth_event.dart';
|
||||||
|
part 'auth_state.dart';
|
||||||
|
|
||||||
|
class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||||
|
final UserRepository _userRepository;
|
||||||
|
|
||||||
|
AuthBloc({required UserRepository userRepository})
|
||||||
|
: _userRepository = userRepository,
|
||||||
|
super(AuthStateInitial()) {
|
||||||
|
on<AuthEventLoginOAuth>(_onAuthEventLoginOAuth);
|
||||||
|
on<AuthEventVerifyOAuth>(_onAuthEventVerifyOAuth);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onAuthEventLoginOAuth(
|
||||||
|
AuthEventLoginOAuth event, Emitter<AuthState> emit) async {
|
||||||
|
emit(AuthStateProcess());
|
||||||
|
try {
|
||||||
|
await _userRepository.signInWithPhoneNumber(event.phone);
|
||||||
|
|
||||||
|
emit(const AuthStateVerifyOAuth(false));
|
||||||
|
} catch (e) {
|
||||||
|
emit(const AuthStateFailure());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onAuthEventVerifyOAuth(
|
||||||
|
AuthEventVerifyOAuth event, Emitter<AuthState> emit) async {
|
||||||
|
emit(AuthStateProcess());
|
||||||
|
try {
|
||||||
|
final bool isVerified = await _userRepository.verifyOTP(event.code);
|
||||||
|
|
||||||
|
(isVerified)
|
||||||
|
? emit(AuthStateSuccess())
|
||||||
|
: emit(const AuthStateVerifyOAuth(true));
|
||||||
|
} catch (e) {
|
||||||
|
emit(const AuthStateFailure());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
part of 'auth_bloc.dart';
|
||||||
|
|
||||||
|
abstract class AuthEvent extends Equatable {
|
||||||
|
const AuthEvent();
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
class AuthEventLoginOAuth extends AuthEvent {
|
||||||
|
final String phone;
|
||||||
|
|
||||||
|
const AuthEventLoginOAuth({required this.phone});
|
||||||
|
}
|
||||||
|
|
||||||
|
class AuthEventVerifyOAuth extends AuthEvent {
|
||||||
|
final String code;
|
||||||
|
|
||||||
|
const AuthEventVerifyOAuth({required this.code});
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
part of 'auth_bloc.dart';
|
||||||
|
|
||||||
|
abstract class AuthState extends Equatable {
|
||||||
|
const AuthState();
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
class AuthStateInitial extends AuthState {}
|
||||||
|
|
||||||
|
class AuthStateProcess extends AuthState {}
|
||||||
|
|
||||||
|
class AuthStateVerifyOAuth extends AuthState {
|
||||||
|
final bool isWrongCode;
|
||||||
|
|
||||||
|
const AuthStateVerifyOAuth(this.isWrongCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
class AuthStateSuccess extends AuthState {}
|
||||||
|
|
||||||
|
class AuthStateFailure extends AuthState {
|
||||||
|
final String? message;
|
||||||
|
|
||||||
|
const AuthStateFailure({this.message});
|
||||||
|
}
|
||||||
@@ -18,7 +18,7 @@ class SignUpBloc extends Bloc<SignUpEvent, SignUpState> {
|
|||||||
SignUpRequired event, Emitter<SignUpState> emit) async {
|
SignUpRequired event, Emitter<SignUpState> emit) async {
|
||||||
emit(SignUpProcess());
|
emit(SignUpProcess());
|
||||||
try {
|
try {
|
||||||
MyUser user = await _userRepository.signUp(event.user, event.password);
|
MyUser user = await _userRepository.signUp(event.email, event.password);
|
||||||
await _userRepository.setUserData(user);
|
await _userRepository.setUserData(user);
|
||||||
emit(SignUpSuccess());
|
emit(SignUpSuccess());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -8,8 +8,9 @@ abstract class SignUpEvent extends Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class SignUpRequired extends SignUpEvent {
|
class SignUpRequired extends SignUpEvent {
|
||||||
final MyUser user;
|
final String email;
|
||||||
final String password;
|
final String password;
|
||||||
|
|
||||||
const SignUpRequired(this.user, this.password);
|
const SignUpRequired({required this.email, required this.password});
|
||||||
|
// const SignUpRequired(this.email, this.password);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,11 +22,11 @@ class GeneralDrawerHeader extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
title: Text(
|
title: Text(
|
||||||
context.read<MyUserBloc>().state.user!.name,
|
context.read<MyUserBloc>().state.user!.name ?? '',
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
context.read<MyUserBloc>().state.user!.email,
|
context.read<MyUserBloc>().state.user!.email ?? '',
|
||||||
style: const TextStyle(fontSize: 12),
|
style: const TextStyle(fontSize: 12),
|
||||||
),
|
),
|
||||||
leading: context.read<MyUserBloc>().state.user!.picture == ""
|
leading: context.read<MyUserBloc>().state.user!.picture == ""
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class GeneralInputDecoration {
|
||||||
|
static InputDecoration getCustomDecoration({
|
||||||
|
required BuildContext context,
|
||||||
|
required String hintText,
|
||||||
|
String? labelText,
|
||||||
|
Widget? suffixIcon,
|
||||||
|
Widget? prefixIcon,
|
||||||
|
String? errorMsg,
|
||||||
|
}) {
|
||||||
|
Color? borderColor = errorMsg != null ? Colors.red : Colors.grey;
|
||||||
|
return InputDecoration(
|
||||||
|
labelText: labelText,
|
||||||
|
suffixIcon: suffixIcon,
|
||||||
|
prefixIcon: prefixIcon,
|
||||||
|
enabledBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
borderSide: BorderSide(color: borderColor),
|
||||||
|
),
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
borderSide: BorderSide(color: Theme.of(context).colorScheme.primary),
|
||||||
|
),
|
||||||
|
errorBorder: OutlineInputBorder(
|
||||||
|
// Border when there's an error
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
borderSide: BorderSide(color: Theme.of(context).colorScheme.error),
|
||||||
|
),
|
||||||
|
focusedErrorBorder: OutlineInputBorder(
|
||||||
|
// Border when focused with error
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
borderSide: BorderSide(color: Theme.of(context).colorScheme.error),
|
||||||
|
),
|
||||||
|
fillColor: Colors.grey.shade200,
|
||||||
|
filled: true,
|
||||||
|
hintText: hintText,
|
||||||
|
hintStyle: TextStyle(color: Colors.grey[500]),
|
||||||
|
errorText: errorMsg,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:prosappco/components/general_input_decoration.dart';
|
||||||
|
|
||||||
class MyTextField extends StatelessWidget {
|
class MyTextField extends StatelessWidget {
|
||||||
final TextEditingController controller;
|
final TextEditingController controller;
|
||||||
|
final String? labelText;
|
||||||
final String hintText;
|
final String hintText;
|
||||||
final bool obscureText;
|
final bool obscureText;
|
||||||
final TextInputType keyboardType;
|
final TextInputType keyboardType;
|
||||||
@@ -15,6 +17,7 @@ class MyTextField extends StatelessWidget {
|
|||||||
|
|
||||||
const MyTextField(
|
const MyTextField(
|
||||||
{super.key,
|
{super.key,
|
||||||
|
this.labelText,
|
||||||
required this.controller,
|
required this.controller,
|
||||||
required this.hintText,
|
required this.hintText,
|
||||||
required this.obscureText,
|
required this.obscureText,
|
||||||
@@ -38,23 +41,13 @@ class MyTextField extends StatelessWidget {
|
|||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
onChanged: onChanged,
|
onChanged: onChanged,
|
||||||
decoration: InputDecoration(
|
decoration: GeneralInputDecoration.getCustomDecoration(
|
||||||
suffixIcon: suffixIcon,
|
labelText: labelText,
|
||||||
prefixIcon: prefixIcon,
|
context: context,
|
||||||
enabledBorder: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
borderSide: const BorderSide(color: Colors.transparent),
|
|
||||||
),
|
|
||||||
focusedBorder: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(20),
|
|
||||||
borderSide:
|
|
||||||
BorderSide(color: Theme.of(context).colorScheme.secondary),
|
|
||||||
),
|
|
||||||
fillColor: Colors.grey.shade200,
|
|
||||||
filled: true,
|
|
||||||
hintText: hintText,
|
hintText: hintText,
|
||||||
hintStyle: TextStyle(color: Colors.grey[500]),
|
prefixIcon: prefixIcon,
|
||||||
errorText: errorMsg,
|
errorMsg: errorMsg,
|
||||||
|
suffixIcon: suffixIcon,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:firebase_auth/firebase_auth.dart';
|
import 'package:firebase_auth/firebase_auth.dart';
|
||||||
import 'package:injector/injector.dart';
|
import 'package:injector/injector.dart';
|
||||||
|
import 'package:prosappco/blocs/auth_bloc/auth_bloc.dart';
|
||||||
import 'package:prosappco/blocs/authentication_bloc/authentication_bloc.dart';
|
import 'package:prosappco/blocs/authentication_bloc/authentication_bloc.dart';
|
||||||
import 'package:prosappco/blocs/my_user_bloc/my_user_bloc.dart';
|
import 'package:prosappco/blocs/my_user_bloc/my_user_bloc.dart';
|
||||||
import 'package:prosappco/blocs/profile_bloc/profile_bloc.dart';
|
import 'package:prosappco/blocs/profile_bloc/profile_bloc.dart';
|
||||||
@@ -32,5 +33,8 @@ class UserDI {
|
|||||||
|
|
||||||
injector.registerDependency<SettingBloc>(
|
injector.registerDependency<SettingBloc>(
|
||||||
(() => SettingBloc(userRepository: injector.get<UserRepository>())));
|
(() => SettingBloc(userRepository: injector.get<UserRepository>())));
|
||||||
|
|
||||||
|
injector.registerDependency<AuthBloc>(
|
||||||
|
(() => AuthBloc(userRepository: injector.get<UserRepository>())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,102 @@
|
|||||||
|
import 'dart:developer';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:flutter_otp_text_field/flutter_otp_text_field.dart';
|
||||||
|
import 'package:injector/injector.dart';
|
||||||
|
import 'package:prosappco/blocs/auth_bloc/auth_bloc.dart';
|
||||||
|
|
||||||
|
class OtpAuthScreen extends StatefulWidget {
|
||||||
|
final String phoneNumber;
|
||||||
|
|
||||||
|
const OtpAuthScreen({super.key, required this.phoneNumber});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<OtpAuthScreen> createState() => _OtpAuthScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _OtpAuthScreenState extends State<OtpAuthScreen> {
|
||||||
|
bool _isRequestSent = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final authBloc = Injector.appInstance.get<AuthBloc>();
|
||||||
|
|
||||||
|
if (!_isRequestSent) {
|
||||||
|
authBloc.add(AuthEventLoginOAuth(phone: widget.phoneNumber));
|
||||||
|
_isRequestSent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BlocProvider<AuthBloc>(
|
||||||
|
create: (context) => authBloc,
|
||||||
|
child: BlocConsumer<AuthBloc, AuthState>(
|
||||||
|
listener: (context, state) {
|
||||||
|
if (state is AuthStateSuccess) {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
|
if (state is AuthStateVerifyOAuth) {
|
||||||
|
if (state.isWrongCode) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
||||||
|
content: Text('El Código es incorrecto'),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
builder: (context, state) {
|
||||||
|
return Scaffold(
|
||||||
|
body: Column(children: [
|
||||||
|
getContent(state, authBloc: authBloc),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget getContent(AuthState state, {required AuthBloc authBloc}) {
|
||||||
|
if (state is AuthStateInitial) {
|
||||||
|
return const Text('Inicio');
|
||||||
|
} else if (state is AuthStateProcess) {
|
||||||
|
return Center(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Text('${widget.phoneNumber} - $_isRequestSent'),
|
||||||
|
OtpTextField(
|
||||||
|
numberOfFields: 6,
|
||||||
|
borderColor: const Color(0xFF512DA8),
|
||||||
|
showFieldAsBox: true,
|
||||||
|
onCodeChanged: (String code) {},
|
||||||
|
onSubmit: (String verificationCode) {
|
||||||
|
authBloc.add(AuthEventVerifyOAuth(code: verificationCode));
|
||||||
|
}, // end onSubmit
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else if (state is AuthStateVerifyOAuth) {
|
||||||
|
return Center(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Text('${widget.phoneNumber} - $_isRequestSent'),
|
||||||
|
state.isWrongCode ? const Text('❌') : const Text(''),
|
||||||
|
OtpTextField(
|
||||||
|
numberOfFields: 6,
|
||||||
|
borderColor: const Color(0xFF512DA8),
|
||||||
|
showFieldAsBox: true,
|
||||||
|
onCodeChanged: (String code) {},
|
||||||
|
onSubmit: (String verificationCode) {
|
||||||
|
authBloc.add(AuthEventVerifyOAuth(code: verificationCode));
|
||||||
|
}, // end onSubmit
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else if (state is AuthStateSuccess) {
|
||||||
|
return const CircularProgressIndicator();
|
||||||
|
} else if (state is AuthStateFailure) {
|
||||||
|
return const Text('❌');
|
||||||
|
} else {
|
||||||
|
return const CircularProgressIndicator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -53,7 +53,10 @@ class _SignInScreenState extends State<SignInScreen> {
|
|||||||
hintText: 'Email',
|
hintText: 'Email',
|
||||||
obscureText: false,
|
obscureText: false,
|
||||||
keyboardType: TextInputType.emailAddress,
|
keyboardType: TextInputType.emailAddress,
|
||||||
prefixIcon: const Icon(CupertinoIcons.mail_solid),
|
prefixIcon: Icon(
|
||||||
|
CupertinoIcons.mail_solid,
|
||||||
|
color: Colors.grey[600],
|
||||||
|
),
|
||||||
errorMsg: _errorMsg,
|
errorMsg: _errorMsg,
|
||||||
validator: (val) {
|
validator: (val) {
|
||||||
if (val!.isEmpty) {
|
if (val!.isEmpty) {
|
||||||
@@ -72,7 +75,8 @@ class _SignInScreenState extends State<SignInScreen> {
|
|||||||
hintText: 'Password',
|
hintText: 'Password',
|
||||||
obscureText: obscurePassword,
|
obscureText: obscurePassword,
|
||||||
keyboardType: TextInputType.visiblePassword,
|
keyboardType: TextInputType.visiblePassword,
|
||||||
prefixIcon: const Icon(CupertinoIcons.lock_fill),
|
prefixIcon:
|
||||||
|
Icon(CupertinoIcons.lock_fill, color: Colors.grey[600]),
|
||||||
errorMsg: _errorMsg,
|
errorMsg: _errorMsg,
|
||||||
validator: (val) {
|
validator: (val) {
|
||||||
if (val!.isEmpty) {
|
if (val!.isEmpty) {
|
||||||
@@ -93,7 +97,7 @@ class _SignInScreenState extends State<SignInScreen> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
icon: Icon(iconPassword),
|
icon: Icon(iconPassword, color: Colors.grey[600]),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -58,32 +58,32 @@ class _SignScreenState extends State<SignScreen> with TickerProviderStateMixin {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
TabBar(
|
// TabBar(
|
||||||
controller: tabController,
|
// controller: tabController,
|
||||||
unselectedLabelColor:
|
// unselectedLabelColor:
|
||||||
Theme.of(context).colorScheme.onBackground,
|
// Theme.of(context).colorScheme.onBackground,
|
||||||
labelColor: Theme.of(context).colorScheme.onBackground,
|
// labelColor: Theme.of(context).colorScheme.onBackground,
|
||||||
tabs: const [
|
// tabs: const [
|
||||||
Padding(
|
// Padding(
|
||||||
padding: EdgeInsets.all(12.0),
|
// padding: EdgeInsets.all(12.0),
|
||||||
child: Text(
|
// child: Text(
|
||||||
'Inicia sesión',
|
// 'Inicia sesión',
|
||||||
style: TextStyle(
|
// style: TextStyle(
|
||||||
fontSize: 18,
|
// fontSize: 18,
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
Padding(
|
// Padding(
|
||||||
padding: EdgeInsets.all(12.0),
|
// padding: EdgeInsets.all(12.0),
|
||||||
child: Text(
|
// child: Text(
|
||||||
'Registrate',
|
// 'Registrate',
|
||||||
style: TextStyle(
|
// style: TextStyle(
|
||||||
fontSize: 18,
|
// fontSize: 18,
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
],
|
// ],
|
||||||
),
|
// ),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -197,8 +197,9 @@ class _SignUpScreenState extends State<SignUpScreen> {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
width: MediaQuery.of(context).size.width * 0.9,
|
width: MediaQuery.of(context).size.width * 0.9,
|
||||||
child: MyTextField(
|
child: MyTextField(
|
||||||
|
labelText: 'Nombre',
|
||||||
controller: nameController,
|
controller: nameController,
|
||||||
hintText: 'Name',
|
hintText: 'Ingresa tu nombre',
|
||||||
obscureText: false,
|
obscureText: false,
|
||||||
keyboardType: TextInputType.name,
|
keyboardType: TextInputType.name,
|
||||||
prefixIcon: const Icon(CupertinoIcons.person_fill),
|
prefixIcon: const Icon(CupertinoIcons.person_fill),
|
||||||
@@ -226,7 +227,9 @@ class _SignUpScreenState extends State<SignUpScreen> {
|
|||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
context.read<SignUpBloc>().add(SignUpRequired(
|
context.read<SignUpBloc>().add(SignUpRequired(
|
||||||
myUser, passwordController.text));
|
email: emailController.text,
|
||||||
|
password: passwordController.text,
|
||||||
|
));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,14 +3,18 @@ import 'package:flutter/gestures.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:intl_phone_field/intl_phone_field.dart';
|
import 'package:intl_phone_field/intl_phone_field.dart';
|
||||||
|
import 'package:prosappco/components/general_input_decoration.dart';
|
||||||
|
import 'package:prosappco/screens/authentication/otp_auth_screen.dart';
|
||||||
import 'package:prosappco/screens/authentication/sign_screen.dart';
|
import 'package:prosappco/screens/authentication/sign_screen.dart';
|
||||||
|
|
||||||
class WelcomeScreen extends StatelessWidget {
|
class WelcomeScreen extends StatelessWidget {
|
||||||
const WelcomeScreen({Key? key});
|
const WelcomeScreen({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
double width = MediaQuery.of(context).size.width;
|
double width = MediaQuery.of(context).size.width;
|
||||||
|
String? _phoneNumber;
|
||||||
|
String? _errorMsg;
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Theme.of(context).colorScheme.tertiary,
|
backgroundColor: Theme.of(context).colorScheme.tertiary,
|
||||||
@@ -70,6 +74,22 @@ class WelcomeScreen extends StatelessWidget {
|
|||||||
inputFormatters: [
|
inputFormatters: [
|
||||||
FilteringTextInputFormatter.digitsOnly
|
FilteringTextInputFormatter.digitsOnly
|
||||||
],
|
],
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null) {
|
||||||
|
return 'Ingresa un numero';
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onChanged: (phone) {
|
||||||
|
_phoneNumber = phone.completeNumber;
|
||||||
|
},
|
||||||
|
decoration:
|
||||||
|
GeneralInputDecoration.getCustomDecoration(
|
||||||
|
context: context,
|
||||||
|
hintText: 'Ingresa tu numero',
|
||||||
|
errorMsg: _errorMsg,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
@@ -82,15 +102,19 @@ class WelcomeScreen extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.push(
|
final phoneNumber = _phoneNumber;
|
||||||
context,
|
|
||||||
CupertinoPageRoute(
|
if (phoneNumber != null && phoneNumber.isNotEmpty) {
|
||||||
builder: (context) =>
|
Navigator.push(
|
||||||
const SignScreen(initialIndex: 1),
|
context,
|
||||||
),
|
CupertinoPageRoute(
|
||||||
);
|
builder: (context) =>
|
||||||
|
OtpAuthScreen(phoneNumber: phoneNumber),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {}
|
||||||
},
|
},
|
||||||
child: const Text('Iniciar Sesión'),
|
child: const Text('Enviar código'),
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
@@ -148,170 +172,5 @@ class WelcomeScreen extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Scaffold(
|
|
||||||
// backgroundColor: Theme.of(context).colorScheme.surface,
|
|
||||||
// body: Column(
|
|
||||||
// children: [
|
|
||||||
// Container(
|
|
||||||
// color: Theme.of(context).colorScheme.tertiary,
|
|
||||||
// child: Column(
|
|
||||||
// children: [
|
|
||||||
// const SizedBox(height: 20),
|
|
||||||
// Center(
|
|
||||||
// child: Image(
|
|
||||||
// width: width * 0.7,
|
|
||||||
// image: const AssetImage('images/logo_prosapp.png'),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// const SizedBox(height: 20),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// SizedBox(
|
|
||||||
// width: double.infinity,
|
|
||||||
// child: Text(
|
|
||||||
// 'Iniciar sesión',
|
|
||||||
// style: TextStyle(
|
|
||||||
// // fontSize: 30,
|
|
||||||
// fontSize: width * 0.08,
|
|
||||||
// fontWeight: FontWeight.bold,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// Expanded(
|
|
||||||
// child: SingleChildScrollView(
|
|
||||||
// child: Column(
|
|
||||||
// children: [
|
|
||||||
// const SizedBox(height: 10),
|
|
||||||
// SizedBox(
|
|
||||||
// width: double.infinity,
|
|
||||||
// child: Text(
|
|
||||||
// 'Numero de celular',
|
|
||||||
// style: TextStyle(
|
|
||||||
// fontSize: width * 0.045,
|
|
||||||
// color: Theme.of(context).colorScheme.onBackground,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// Form(
|
|
||||||
// child: IntlPhoneField(
|
|
||||||
// initialCountryCode: 'CO',
|
|
||||||
// keyboardType: TextInputType.number,
|
|
||||||
// inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// Text(
|
|
||||||
// 'Un código será enviado a este numero de celular.',
|
|
||||||
// textAlign: TextAlign.center,
|
|
||||||
// style: TextStyle(
|
|
||||||
// fontSize: 13.0,
|
|
||||||
// color: Theme.of(context).colorScheme.onBackground,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// TextButton(
|
|
||||||
// onPressed: () {
|
|
||||||
// Navigator.push(
|
|
||||||
// context,
|
|
||||||
// CupertinoPageRoute(
|
|
||||||
// builder: (context) => SignScreen(initialIndex: 0),
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// },
|
|
||||||
// child: Text(
|
|
||||||
// 'Inicia sesión con tu correo electrónico',
|
|
||||||
// style: TextStyle(
|
|
||||||
// fontSize: width * 0.04,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// RichText(
|
|
||||||
// text: TextSpan(
|
|
||||||
// style: const TextStyle(
|
|
||||||
// fontSize: 16.0,
|
|
||||||
// color: Color(0xFF65676B),
|
|
||||||
// fontFamily: 'Poppins',
|
|
||||||
// ),
|
|
||||||
// children: [
|
|
||||||
// const TextSpan(text: '¿No estás registrado? '),
|
|
||||||
// TextSpan(
|
|
||||||
// text: 'Regístrate',
|
|
||||||
// style: TextStyle(
|
|
||||||
// fontSize: width * 0.04,
|
|
||||||
// color: Colors.blue,
|
|
||||||
// fontWeight: FontWeight.w600,
|
|
||||||
// ),
|
|
||||||
// recognizer: TapGestureRecognizer()
|
|
||||||
// ..onTap = () {
|
|
||||||
// Navigator.push(
|
|
||||||
// context,
|
|
||||||
// CupertinoPageRoute(
|
|
||||||
// builder: (context) =>
|
|
||||||
// SignScreen(initialIndex: 1),
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
|
|
||||||
// Scaffold(
|
|
||||||
// backgroundColor: Theme.of(context).colorScheme.surface,
|
|
||||||
// body: ListView(
|
|
||||||
// children: [
|
|
||||||
// Container(
|
|
||||||
// color: Theme.of(context).colorScheme.tertiary,
|
|
||||||
// padding: const EdgeInsets.symmetric(vertical: 20.0),
|
|
||||||
// child: Center(
|
|
||||||
// child: Image(
|
|
||||||
// width: width * 0.7,
|
|
||||||
// image: const AssetImage('images/logo_prosapp.png'),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// Container(
|
|
||||||
// decoration: const BoxDecoration(
|
|
||||||
// color: Colors.white,
|
|
||||||
// borderRadius: BorderRadius.only(
|
|
||||||
// topLeft: Radius.circular(60),
|
|
||||||
// topRight: Radius.circular(60),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// child: Padding(
|
|
||||||
// padding: const EdgeInsets.all(20.0),
|
|
||||||
// child: Column(
|
|
||||||
// mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
// children: [
|
|
||||||
// const TextField(
|
|
||||||
// decoration: InputDecoration(
|
|
||||||
// labelText: 'Usuario',
|
|
||||||
// border: OutlineInputBorder(),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// const SizedBox(height: 20.0),
|
|
||||||
// const TextField(
|
|
||||||
// decoration: InputDecoration(
|
|
||||||
// labelText: 'Contraseña',
|
|
||||||
// border: OutlineInputBorder(),
|
|
||||||
// ),
|
|
||||||
// obscureText: true,
|
|
||||||
// ),
|
|
||||||
// const SizedBox(height: 20.0),
|
|
||||||
//
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
|||||||
),
|
),
|
||||||
body: BlocBuilder<MyUserBloc, MyUserState>(builder: (context, state) {
|
body: BlocBuilder<MyUserBloc, MyUserState>(builder: (context, state) {
|
||||||
if (state.status == MyUserStatus.success) {
|
if (state.status == MyUserStatus.success) {
|
||||||
_nameController.text = state.user!.name;
|
_nameController.text = state.user!.name ?? '';
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.all(20.0),
|
padding: const EdgeInsets.all(20.0),
|
||||||
|
|||||||
@@ -58,6 +58,13 @@ class AuthenticationRepository extends GetxController {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<bool> verifyOTP(String otp) async {
|
||||||
|
var credentials = await _auth.signInWithCredential(
|
||||||
|
PhoneAuthProvider.credential(
|
||||||
|
verificationId: verificationId.value, smsCode: otp));
|
||||||
|
return credentials.user != null ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> updatePhoneNumber(String verificationId, String smsCode) async {
|
Future<void> updatePhoneNumber(String verificationId, String smsCode) async {
|
||||||
try {
|
try {
|
||||||
PhoneAuthCredential credential = PhoneAuthProvider.credential(
|
PhoneAuthCredential credential = PhoneAuthProvider.credential(
|
||||||
@@ -69,13 +76,6 @@ class AuthenticationRepository extends GetxController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> verifyOTP(String otp) async {
|
|
||||||
var credentials = await _auth.signInWithCredential(
|
|
||||||
PhoneAuthProvider.credential(
|
|
||||||
verificationId: verificationId.value, smsCode: otp));
|
|
||||||
return credentials.user != null ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> createUserWithEmailAndPassword(
|
Future<void> createUserWithEmailAndPassword(
|
||||||
String email, String password) async {
|
String email, String password) async {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ import 'package:equatable/equatable.dart';
|
|||||||
|
|
||||||
class MyUserEntity extends Equatable {
|
class MyUserEntity extends Equatable {
|
||||||
final String id;
|
final String id;
|
||||||
final String email;
|
final String? email;
|
||||||
final String name;
|
final String? name;
|
||||||
final String? picture;
|
final String? picture;
|
||||||
|
|
||||||
const MyUserEntity({
|
const MyUserEntity({
|
||||||
required this.id,
|
required this.id,
|
||||||
required this.email,
|
this.email,
|
||||||
required this.name,
|
this.name,
|
||||||
this.picture,
|
this.picture,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -25,8 +25,8 @@ class MyUserEntity extends Equatable {
|
|||||||
static MyUserEntity fromDocument(Map<String, dynamic> doc) {
|
static MyUserEntity fromDocument(Map<String, dynamic> doc) {
|
||||||
return MyUserEntity(
|
return MyUserEntity(
|
||||||
id: doc['id'] as String,
|
id: doc['id'] as String,
|
||||||
email: doc['email'] as String,
|
email: doc['email'] as String?,
|
||||||
name: doc['name'] as String,
|
name: doc['name'] as String?,
|
||||||
picture: doc['picture'] as String?,
|
picture: doc['picture'] as String?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ import '../entities/entities.dart';
|
|||||||
|
|
||||||
class MyUser extends Equatable {
|
class MyUser extends Equatable {
|
||||||
final String id;
|
final String id;
|
||||||
final String email;
|
final String? email;
|
||||||
final String name;
|
final String? name;
|
||||||
String? picture;
|
final String? picture;
|
||||||
|
|
||||||
MyUser({
|
MyUser({
|
||||||
required this.id,
|
required this.id,
|
||||||
required this.email,
|
this.email,
|
||||||
required this.name,
|
this.name,
|
||||||
this.picture,
|
this.picture,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ class FirebaseUserRepository implements UserRepository {
|
|||||||
final usersCollection = FirebaseFirestore.instance.collection('users');
|
final usersCollection = FirebaseFirestore.instance.collection('users');
|
||||||
final StreamController<MyUser?> _userStreamController =
|
final StreamController<MyUser?> _userStreamController =
|
||||||
StreamController<MyUser?>.broadcast();
|
StreamController<MyUser?>.broadcast();
|
||||||
|
String verificationId = '';
|
||||||
|
|
||||||
FirebaseUserRepository(this._firebaseAuth) {
|
FirebaseUserRepository(this._firebaseAuth) {
|
||||||
_firebaseAuth.userChanges().listen((user) async {
|
_firebaseAuth.userChanges().listen((user) async {
|
||||||
@@ -49,18 +50,14 @@ class FirebaseUserRepository implements UserRepository {
|
|||||||
|
|
||||||
// Sign up
|
// Sign up
|
||||||
@override
|
@override
|
||||||
Future<MyUser> signUp(MyUser myUser, String password) async {
|
Future<MyUser> signUp(String email, String password) async {
|
||||||
try {
|
try {
|
||||||
UserCredential user = await _firebaseAuth.createUserWithEmailAndPassword(
|
UserCredential user = await _firebaseAuth.createUserWithEmailAndPassword(
|
||||||
email: myUser.email,
|
email: email,
|
||||||
password: password,
|
password: password,
|
||||||
);
|
);
|
||||||
|
|
||||||
myUser = myUser.copyWith(
|
return await getMyUser(user.user!.uid);
|
||||||
id: user.user!.uid,
|
|
||||||
);
|
|
||||||
|
|
||||||
return myUser;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e.toString());
|
log(e.toString());
|
||||||
rethrow;
|
rethrow;
|
||||||
@@ -71,34 +68,21 @@ class FirebaseUserRepository implements UserRepository {
|
|||||||
@override
|
@override
|
||||||
Future<void> signInWithPhoneNumber(String phoneNumber) async {
|
Future<void> signInWithPhoneNumber(String phoneNumber) async {
|
||||||
try {
|
try {
|
||||||
await FirebaseAuth.instance.verifyPhoneNumber(
|
await _firebaseAuth.verifyPhoneNumber(
|
||||||
phoneNumber: phoneNumber,
|
phoneNumber: phoneNumber,
|
||||||
verificationCompleted: (PhoneAuthCredential credential) async {
|
verificationCompleted: (PhoneAuthCredential credential) async {
|
||||||
// Esta función se llama automáticamente cuando se completa la verificación del número de teléfono.
|
await _firebaseAuth.signInWithCredential(credential);
|
||||||
// Puedes usar 'credential' para iniciar sesión o vincular la cuenta.
|
|
||||||
// En la mayoría de los casos, no necesitas implementar esto, ya que Firebase manejará la autenticación automáticamente.
|
|
||||||
|
|
||||||
await FirebaseAuth.instance.signInWithCredential(credential);
|
|
||||||
},
|
|
||||||
verificationFailed: (FirebaseAuthException e) {
|
|
||||||
// Esta función se llama si la verificación del número de teléfono falla.
|
|
||||||
// Maneja los errores o muestra un mensaje al usuario.
|
|
||||||
if (e.code == 'invalid-phone-number') {
|
|
||||||
// Manejar el caso de número de teléfono no válido
|
|
||||||
} else if (e.code == 'network-request-failed') {
|
|
||||||
// Manejar problemas de conectividad
|
|
||||||
} else {
|
|
||||||
// Manejar otros errores
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
codeSent: (String verificationId, int? resendToken) {
|
codeSent: (String verificationId, int? resendToken) {
|
||||||
// Esta función se llama cuando se envía el código de verificación al número de teléfono del usuario.
|
this.verificationId = verificationId;
|
||||||
// Debes guardar 'verificationId' para usarlo posteriormente en la verificación.
|
|
||||||
// Puedes mostrar un diálogo para que el usuario ingrese el código o puedes verificarlo automáticamente.
|
|
||||||
},
|
},
|
||||||
codeAutoRetrievalTimeout: (String verificationId) {
|
codeAutoRetrievalTimeout: (String verificationId) {
|
||||||
// Esta función se llama cuando el tiempo de espera de recuperación automática del código ha expirado.
|
this.verificationId = verificationId;
|
||||||
// Puedes manejar esto como prefieras, por ejemplo, mostrando un mensaje al usuario o reenviando el código.
|
},
|
||||||
|
verificationFailed: (FirebaseAuthException e) {
|
||||||
|
if (e.code == 'invalid-phone-number') {
|
||||||
|
} else if (e.code == 'network-request-failed') {
|
||||||
|
} else {}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -107,6 +91,26 @@ class FirebaseUserRepository implements UserRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> verifyOTP(String code) async {
|
||||||
|
try {
|
||||||
|
var credentials = await _firebaseAuth.signInWithCredential(
|
||||||
|
PhoneAuthProvider.credential(
|
||||||
|
verificationId: verificationId, smsCode: code));
|
||||||
|
return credentials.user != null ? true : false;
|
||||||
|
} catch (e) {
|
||||||
|
if (e is FirebaseAuthException) {
|
||||||
|
if (e.code == 'invalid-verification-code') {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Sign in
|
// Sign in
|
||||||
@override
|
@override
|
||||||
Future<void> signIn(String email, String password) async {
|
Future<void> signIn(String email, String password) async {
|
||||||
@@ -158,8 +162,12 @@ class FirebaseUserRepository implements UserRepository {
|
|||||||
@override
|
@override
|
||||||
Future<MyUser> getMyUser(String myUserId) async {
|
Future<MyUser> getMyUser(String myUserId) async {
|
||||||
try {
|
try {
|
||||||
return usersCollection.doc(myUserId).get().then((value) =>
|
return usersCollection.doc(myUserId).get().then((value) {
|
||||||
MyUser.fromEntity(MyUserEntity.fromDocument(value.data()!)));
|
log('xd -- ${value.data().toString()}'); // Imprime el valor de value
|
||||||
|
return MyUser.fromEntity(
|
||||||
|
MyUserEntity.fromDocument(value.data()!),
|
||||||
|
);
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e.toString());
|
log(e.toString());
|
||||||
rethrow;
|
rethrow;
|
||||||
|
|||||||
@@ -9,10 +9,12 @@ abstract class UserRepository {
|
|||||||
|
|
||||||
Future<void> logOut();
|
Future<void> logOut();
|
||||||
|
|
||||||
Future<MyUser> signUp(MyUser myUser, String password);
|
Future<MyUser> signUp(String email, String password);
|
||||||
|
|
||||||
Future<void> signInWithPhoneNumber(String phoneNumber);
|
Future<void> signInWithPhoneNumber(String phoneNumber);
|
||||||
|
|
||||||
|
Future<bool> verifyOTP(String code);
|
||||||
|
|
||||||
Future<void> resetPassword(String email);
|
Future<void> resetPassword(String email);
|
||||||
|
|
||||||
Future<void> setUserData(MyUser user);
|
Future<void> setUserData(MyUser user);
|
||||||
|
|||||||
+2
-2
@@ -11,7 +11,7 @@ environment:
|
|||||||
dependencies:
|
dependencies:
|
||||||
animate_do: ^3.0.2
|
animate_do: ^3.0.2
|
||||||
animated_splash_screen: ^1.3.0
|
animated_splash_screen: ^1.3.0
|
||||||
cloud_firestore: null
|
cloud_firestore: ^4.15.4
|
||||||
community_material_icon: ^5.9.55
|
community_material_icon: ^5.9.55
|
||||||
cupertino_icons: ^1.0.2
|
cupertino_icons: ^1.0.2
|
||||||
diacritic: null
|
diacritic: null
|
||||||
@@ -29,8 +29,8 @@ dependencies:
|
|||||||
flutter_localizations:
|
flutter_localizations:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_polyline_points: ^2.0.0
|
flutter_polyline_points: ^2.0.0
|
||||||
flutter_otp_text_field: ^1.1.1
|
|
||||||
flutter_rating_bar: ^4.0.1
|
flutter_rating_bar: ^4.0.1
|
||||||
|
flutter_otp_text_field: ^1.1.1
|
||||||
otp_timer_button: ^1.1.0
|
otp_timer_button: ^1.1.0
|
||||||
font_awesome_flutter: ^10.4.0
|
font_awesome_flutter: ^10.4.0
|
||||||
geocoding: ^2.1.0
|
geocoding: ^2.1.0
|
||||||
|
|||||||
Reference in New Issue
Block a user