before
This commit is contained in:
+7
-7
@@ -25,16 +25,16 @@ class MainApp extends StatelessWidget {
|
|||||||
BlocProvider<UpdateUserInfoBloc>(
|
BlocProvider<UpdateUserInfoBloc>(
|
||||||
create: (context) => Injector.appInstance.get<UpdateUserInfoBloc>(),
|
create: (context) => Injector.appInstance.get<UpdateUserInfoBloc>(),
|
||||||
),
|
),
|
||||||
BlocProvider<SignInBloc>(
|
// BlocProvider<SignInBloc>(
|
||||||
create: (context) => Injector.appInstance.get<SignInBloc>(),
|
// create: (context) => Injector.appInstance.get<SignInBloc>(),
|
||||||
),
|
// ),
|
||||||
BlocProvider<SignUpBloc>(
|
// BlocProvider<SignUpBloc>(
|
||||||
create: (context) => Injector.appInstance.get<SignUpBloc>(),
|
// create: (context) => Injector.appInstance.get<SignUpBloc>(),
|
||||||
)
|
// ),
|
||||||
],
|
],
|
||||||
child: BlocBuilder<MyUserBloc, MyUserState>(
|
child: BlocBuilder<MyUserBloc, MyUserState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
return const MyAppView();
|
return const SafeArea(child: MyAppView());
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
+24
-19
@@ -16,29 +16,34 @@ class MyAppView extends StatelessWidget {
|
|||||||
title: 'Prosappco',
|
title: 'Prosappco',
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
colorScheme: const ColorScheme.light(
|
colorScheme: const ColorScheme.light(
|
||||||
background: Colors.white,
|
background: Colors.white,
|
||||||
onBackground: Colors.black,
|
onBackground: Colors.black,
|
||||||
primary: Color.fromRGBO(66, 164, 239, 1),
|
primary: Color.fromRGBO(66, 164, 239, 1),
|
||||||
onPrimary: Colors.black,
|
onPrimary: Colors.black,
|
||||||
secondary: Color.fromRGBO(35, 108, 244, 1),
|
secondary: Color.fromRGBO(35, 108, 244, 1),
|
||||||
onSecondary: Colors.white,
|
onSecondary: Colors.white,
|
||||||
tertiary: Color.fromRGBO(255, 204, 128, 1),
|
tertiary: Color.fromRGBO(214, 244, 255, 1),
|
||||||
error: Colors.red,
|
error: Colors.red,
|
||||||
outline: Color(0xFF424242)),
|
outline: Color(0xFF424242),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
home: BlocBuilder<AuthenticationBloc, AuthenticationState>(
|
home: BlocBuilder<AuthenticationBloc, AuthenticationState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
switch (state.status) {
|
return getScreen(state);
|
||||||
case AuthenticationStatus.authenticated:
|
|
||||||
return const HomeScreen();
|
|
||||||
|
|
||||||
case AuthenticationStatus.unauthenticated:
|
|
||||||
return const WelcomeScreen();
|
|
||||||
|
|
||||||
case AuthenticationStatus.unknown:
|
|
||||||
return const SplashScreen();
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getScreen(AuthenticationState state) {
|
||||||
|
switch (state.status) {
|
||||||
|
case AuthenticationStatus.authenticated:
|
||||||
|
return const HomeScreen();
|
||||||
|
|
||||||
|
case AuthenticationStatus.unauthenticated:
|
||||||
|
return WelcomeScreen();
|
||||||
|
|
||||||
|
case AuthenticationStatus.unknown:
|
||||||
|
return const SplashScreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,13 +19,23 @@ class AuthenticationBloc
|
|||||||
_userSubscription = userRepository.streamUser().listen((authUser) {
|
_userSubscription = userRepository.streamUser().listen((authUser) {
|
||||||
add(AuthenticationUserChanged(authUser));
|
add(AuthenticationUserChanged(authUser));
|
||||||
});
|
});
|
||||||
on<AuthenticationUserChanged>((event, emit) {
|
on<AuthenticationUserChanged>(_onAuthenticationUserChanged);
|
||||||
if (event.user != null) {
|
on<AuthenticationLogoutRequested>(_onAuthenticationLogoutRequested);
|
||||||
emit(AuthenticationState.authenticated(event.user!));
|
}
|
||||||
} else {
|
|
||||||
emit(const AuthenticationState.unauthenticated());
|
void _onAuthenticationUserChanged(
|
||||||
}
|
AuthenticationUserChanged event, Emitter<AuthenticationState> emit) {
|
||||||
});
|
emit(
|
||||||
|
event.user != null
|
||||||
|
? AuthenticationState.authenticated(event.user!)
|
||||||
|
: const AuthenticationState.unauthenticated(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onAuthenticationLogoutRequested(AuthenticationLogoutRequested event,
|
||||||
|
Emitter<AuthenticationState> emit) async {
|
||||||
|
await userRepository.logOut();
|
||||||
|
emit(const AuthenticationState.unauthenticated());
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -11,15 +11,18 @@ class SignUpBloc extends Bloc<SignUpEvent, SignUpState> {
|
|||||||
SignUpBloc({required UserRepository userRepository})
|
SignUpBloc({required UserRepository userRepository})
|
||||||
: _userRepository = userRepository,
|
: _userRepository = userRepository,
|
||||||
super(SignUpInitial()) {
|
super(SignUpInitial()) {
|
||||||
on<SignUpRequired>((event, emit) async {
|
on<SignUpRequired>(_onSignUpRequired);
|
||||||
emit(SignUpProcess());
|
}
|
||||||
try {
|
|
||||||
MyUser user = await _userRepository.signUp(event.user, event.password);
|
void _onSignUpRequired(
|
||||||
await _userRepository.setUserData(user);
|
SignUpRequired event, Emitter<SignUpState> emit) async {
|
||||||
emit(SignUpSuccess());
|
emit(SignUpProcess());
|
||||||
} catch (e) {
|
try {
|
||||||
emit(SignUpFailure());
|
MyUser user = await _userRepository.signUp(event.user, event.password);
|
||||||
}
|
await _userRepository.setUserData(user);
|
||||||
});
|
emit(SignUpSuccess());
|
||||||
|
} catch (e) {
|
||||||
|
emit(SignUpFailure());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,18 +14,35 @@ class SignInBloc extends Bloc<SignInEvent, SignInState> {
|
|||||||
SignInBloc({required UserRepository userRepository})
|
SignInBloc({required UserRepository userRepository})
|
||||||
: _userRepository = userRepository,
|
: _userRepository = userRepository,
|
||||||
super(SignInInitial()) {
|
super(SignInInitial()) {
|
||||||
on<SignInRequired>((event, emit) async {
|
userRepository.streamUser().listen((authUser) {
|
||||||
emit(SignInProcess());
|
|
||||||
try {
|
try {
|
||||||
await _userRepository.signIn(event.email, event.password);
|
if (authUser == null) {
|
||||||
emit(SignInSuccess());
|
emit(SignInFailure());
|
||||||
|
} else {
|
||||||
|
emit(SignInSuccess());
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e.toString());
|
log(e.toString());
|
||||||
emit(const SignInFailure());
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
on<SignOutRequired>((event, emit) async {
|
on<SignInRequired>(_onSignInRequired);
|
||||||
await _userRepository.logOut();
|
on<SignOutRequired>(_onSignOutRequired);
|
||||||
});
|
}
|
||||||
|
|
||||||
|
void _onSignInRequired(
|
||||||
|
SignInRequired event, Emitter<SignInState> emit) async {
|
||||||
|
emit(SignInProcess());
|
||||||
|
try {
|
||||||
|
await _userRepository.signIn(event.email, event.password);
|
||||||
|
emit(SignInSuccess());
|
||||||
|
} catch (e) {
|
||||||
|
log(e.toString());
|
||||||
|
emit(const SignInFailure());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onSignOutRequired(
|
||||||
|
SignOutRequired event, Emitter<SignInState> emit) async {
|
||||||
|
await _userRepository.logOut();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,96 +1,91 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:prosappco/blocs/my_user_bloc/my_user_bloc.dart';
|
|
||||||
import 'package:prosappco/blocs/update_user_info_bloc/update_user_info_bloc.dart';
|
|
||||||
import 'package:prosappco/components/general_drawer_header.dart';
|
import 'package:prosappco/components/general_drawer_header.dart';
|
||||||
import 'package:prosappco/components/general_drawer_item.dart';
|
import 'package:prosappco/components/general_drawer_item.dart';
|
||||||
|
import 'package:prosappco/screens/configuration/configuration_screen.dart';
|
||||||
|
|
||||||
class GeneralDrawer extends StatefulWidget {
|
class GeneralDrawer extends StatelessWidget {
|
||||||
const GeneralDrawer({super.key});
|
const GeneralDrawer({super.key});
|
||||||
|
|
||||||
@override
|
|
||||||
State<GeneralDrawer> createState() => _GeneralDrawerState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _GeneralDrawerState extends State<GeneralDrawer> {
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocListener<UpdateUserInfoBloc, UpdateUserInfoState>(
|
return Drawer(
|
||||||
listener: (context, state) {
|
backgroundColor: Theme.of(context).colorScheme.background,
|
||||||
if (state is UploadPictureSuccess) {
|
child: Column(
|
||||||
setState(() {
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
context.read<MyUserBloc>().state.user!.picture = state.userImage;
|
children: [
|
||||||
});
|
const GeneralDrawerHeader(),
|
||||||
}
|
Divider(
|
||||||
},
|
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.1),
|
||||||
child: Drawer(
|
thickness: 0.5,
|
||||||
backgroundColor: Theme.of(context).colorScheme.background,
|
height: 1,
|
||||||
child: Column(
|
),
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
Expanded(
|
||||||
children: [
|
child: SingleChildScrollView(
|
||||||
const GeneralDrawerHeader(),
|
child: Column(
|
||||||
Divider(
|
children: [
|
||||||
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.1),
|
GeneralDrawerItem(
|
||||||
thickness: 0.5,
|
leading: Icons.history,
|
||||||
height: 1,
|
label: 'Mis servicios',
|
||||||
),
|
onTap: () {
|
||||||
Expanded(
|
Navigator.pop(context);
|
||||||
child: SingleChildScrollView(
|
},
|
||||||
child: Column(
|
),
|
||||||
children: [
|
GeneralDrawerItem(
|
||||||
GeneralDrawerItem(
|
leading: Icons.settings_outlined,
|
||||||
icon: Icons.person_outline,
|
label: 'Configuración',
|
||||||
label: 'Mi Perfil',
|
onTap: () {
|
||||||
onTap: () {
|
Navigator.pop(context);
|
||||||
Navigator.pop(context);
|
Navigator.push(
|
||||||
},
|
context,
|
||||||
),
|
CupertinoPageRoute(
|
||||||
],
|
builder: (context) => const ConfigurationScreen(),
|
||||||
),
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
GeneralDrawerItem(
|
||||||
|
leading: Icons.help_outline,
|
||||||
|
label: 'Soporte',
|
||||||
|
onTap: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
GeneralDrawerItem(
|
||||||
|
leading: Icons.campaign_outlined,
|
||||||
|
label: 'Sugerencias',
|
||||||
|
onTap: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Divider(
|
),
|
||||||
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.1),
|
Divider(
|
||||||
thickness: 0.5,
|
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.1),
|
||||||
height: 1,
|
thickness: 0.5,
|
||||||
),
|
height: 1,
|
||||||
const SizedBox(height: 15),
|
),
|
||||||
Padding(
|
const SizedBox(height: 15),
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
Padding(
|
||||||
child: ElevatedButton(
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
onPressed: () {},
|
child: ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(
|
onPressed: () {},
|
||||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
style: ElevatedButton.styleFrom(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 15),
|
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||||
shape: RoundedRectangleBorder(
|
padding: const EdgeInsets.symmetric(vertical: 15),
|
||||||
borderRadius: BorderRadius.circular(10),
|
shape: RoundedRectangleBorder(
|
||||||
)),
|
borderRadius: BorderRadius.circular(10),
|
||||||
child: const Text(
|
)),
|
||||||
'Modo Profesional',
|
child: const Text(
|
||||||
style: TextStyle(color: Colors.white, fontSize: 18),
|
'Modo Profesional',
|
||||||
),
|
style: TextStyle(color: Colors.white, fontSize: 18),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 15),
|
),
|
||||||
// Container(
|
const SizedBox(height: 15),
|
||||||
// height: MediaQuery.of(context).size.height,
|
],
|
||||||
// color: Theme.of(context).colorScheme.background,
|
|
||||||
// child: ListView(
|
|
||||||
// children: [
|
|
||||||
// ListTile(
|
|
||||||
// onTap: () {
|
|
||||||
// context.read<SignInBloc>().add(const SignOutRequired());
|
|
||||||
// },
|
|
||||||
// title: const Text(
|
|
||||||
// 'Cerrar Sesión',
|
|
||||||
// ),
|
|
||||||
// )
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// )
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,78 +2,63 @@ import 'package:flutter/cupertino.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_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/update_user_info_bloc/update_user_info_bloc.dart';
|
|
||||||
import 'package:prosappco/screens/profile/profile_screen.dart';
|
import 'package:prosappco/screens/profile/profile_screen.dart';
|
||||||
|
|
||||||
class GeneralDrawerHeader extends StatefulWidget {
|
class GeneralDrawerHeader extends StatelessWidget {
|
||||||
const GeneralDrawerHeader({super.key});
|
const GeneralDrawerHeader({super.key});
|
||||||
|
|
||||||
@override
|
|
||||||
State<GeneralDrawerHeader> createState() => _GeneralDrawerHeaderState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _GeneralDrawerHeaderState extends State<GeneralDrawerHeader> {
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocListener<UpdateUserInfoBloc, UpdateUserInfoState>(
|
return ListTile(
|
||||||
listener: (context, state) {
|
onTap: () {
|
||||||
if (state is UploadPictureSuccess) {
|
Navigator.pop(context);
|
||||||
setState(() {
|
Navigator.push(
|
||||||
context.read<MyUserBloc>().state.user!.picture = state.userImage;
|
context,
|
||||||
});
|
CupertinoPageRoute(
|
||||||
}
|
builder: (BuildContext context) {
|
||||||
|
return const ProfileScreen();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
child: ListTile(
|
title: Text(
|
||||||
onTap: () {
|
context.read<MyUserBloc>().state.user!.name,
|
||||||
Navigator.push(
|
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||||
context,
|
),
|
||||||
CupertinoPageRoute(
|
subtitle: Text(
|
||||||
builder: (BuildContext context) {
|
context.read<MyUserBloc>().state.user!.email,
|
||||||
return const ProfileScreen();
|
style: const TextStyle(fontSize: 12),
|
||||||
},
|
),
|
||||||
),
|
leading: context.read<MyUserBloc>().state.user!.picture == ""
|
||||||
);
|
? Container(
|
||||||
},
|
width: 80,
|
||||||
title: Text(
|
height: 80,
|
||||||
context.read<MyUserBloc>().state.user!.name,
|
decoration: BoxDecoration(
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
color: Colors.grey.shade300,
|
||||||
),
|
shape: BoxShape.circle,
|
||||||
subtitle: Text(
|
),
|
||||||
context.read<MyUserBloc>().state.user!.email,
|
child: Icon(
|
||||||
style: const TextStyle(fontSize: 12),
|
CupertinoIcons.person,
|
||||||
),
|
color: Colors.grey.shade400,
|
||||||
leading: context.read<MyUserBloc>().state.user!.picture == ""
|
size: 35,
|
||||||
? Container(
|
),
|
||||||
width: 80,
|
)
|
||||||
height: 80,
|
: Container(
|
||||||
decoration: BoxDecoration(
|
width: 60,
|
||||||
color: Colors.grey.shade300,
|
height: 60,
|
||||||
shape: BoxShape.circle,
|
decoration: BoxDecoration(
|
||||||
),
|
color: Colors.grey,
|
||||||
child: Icon(
|
shape: BoxShape.circle,
|
||||||
CupertinoIcons.person,
|
image: DecorationImage(
|
||||||
color: Colors.grey.shade400,
|
image: NetworkImage(
|
||||||
size: 35,
|
context.read<MyUserBloc>().state.user!.picture!,
|
||||||
),
|
|
||||||
)
|
|
||||||
: Container(
|
|
||||||
width: 60,
|
|
||||||
height: 60,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.grey,
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
image: DecorationImage(
|
|
||||||
image: NetworkImage(
|
|
||||||
context.read<MyUserBloc>().state.user!.picture!,
|
|
||||||
),
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
),
|
),
|
||||||
|
fit: BoxFit.cover,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
trailing: const Icon(Icons.keyboard_arrow_right, color: Colors.black),
|
),
|
||||||
contentPadding:
|
trailing: const Icon(Icons.keyboard_arrow_right, color: Colors.black),
|
||||||
const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
|
contentPadding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,17 @@ import 'package:flutter/material.dart';
|
|||||||
|
|
||||||
class GeneralDrawerItem extends StatelessWidget {
|
class GeneralDrawerItem extends StatelessWidget {
|
||||||
final String label;
|
final String label;
|
||||||
final IconData icon;
|
final IconData? leading;
|
||||||
|
final bool trailing;
|
||||||
|
final Color? color;
|
||||||
final VoidCallback onTap;
|
final VoidCallback onTap;
|
||||||
|
|
||||||
const GeneralDrawerItem({
|
const GeneralDrawerItem({
|
||||||
super.key,
|
super.key,
|
||||||
required this.label,
|
required this.label,
|
||||||
required this.icon,
|
this.leading,
|
||||||
|
this.trailing = false,
|
||||||
|
this.color,
|
||||||
required this.onTap,
|
required this.onTap,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -16,13 +20,21 @@ class GeneralDrawerItem extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
leading: Icon(
|
leading: leading == null
|
||||||
icon,
|
? null
|
||||||
color: Colors.black,
|
: Icon(
|
||||||
),
|
leading,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
trailing: trailing
|
||||||
|
? const Icon(
|
||||||
|
Icons.keyboard_arrow_right,
|
||||||
|
color: Colors.black,
|
||||||
|
)
|
||||||
|
: null,
|
||||||
title: Text(
|
title: Text(
|
||||||
label,
|
label,
|
||||||
style: const TextStyle(fontSize: 15),
|
style: TextStyle(fontSize: 15, color: color),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class GeneralPrimaryButton extends StatelessWidget {
|
||||||
|
const GeneralPrimaryButton({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,10 +23,10 @@ class UserDI {
|
|||||||
injector.registerSingleton<UpdateUserInfoBloc>((() =>
|
injector.registerSingleton<UpdateUserInfoBloc>((() =>
|
||||||
UpdateUserInfoBloc(userRepository: injector.get<UserRepository>())));
|
UpdateUserInfoBloc(userRepository: injector.get<UserRepository>())));
|
||||||
|
|
||||||
injector.registerSingleton<SignInBloc>(
|
injector.registerDependency<SignInBloc>(
|
||||||
(() => SignInBloc(userRepository: injector.get<UserRepository>())));
|
(() => SignInBloc(userRepository: injector.get<UserRepository>())));
|
||||||
|
|
||||||
injector.registerSingleton<SignUpBloc>(
|
injector.registerDependency<SignUpBloc>(
|
||||||
(() => SignUpBloc(userRepository: injector.get<UserRepository>())));
|
(() => SignUpBloc(userRepository: injector.get<UserRepository>())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,32 +103,33 @@ class _SignInScreenState extends State<SignInScreen> {
|
|||||||
width: MediaQuery.of(context).size.width * 0.9,
|
width: MediaQuery.of(context).size.width * 0.9,
|
||||||
height: 50,
|
height: 50,
|
||||||
child: TextButton(
|
child: TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (_formKey.currentState!.validate()) {
|
if (_formKey.currentState!.validate()) {
|
||||||
context.read<SignInBloc>().add(SignInRequired(
|
context.read<SignInBloc>().add(SignInRequired(
|
||||||
emailController.text,
|
emailController.text, passwordController.text));
|
||||||
passwordController.text));
|
}
|
||||||
}
|
},
|
||||||
},
|
style: TextButton.styleFrom(
|
||||||
style: TextButton.styleFrom(
|
elevation: 3.0,
|
||||||
elevation: 3.0,
|
backgroundColor:
|
||||||
backgroundColor:
|
Theme.of(context).colorScheme.primary,
|
||||||
Theme.of(context).colorScheme.primary,
|
foregroundColor: Colors.white,
|
||||||
foregroundColor: Colors.white,
|
shape: RoundedRectangleBorder(
|
||||||
shape: RoundedRectangleBorder(
|
borderRadius: BorderRadius.circular(60))),
|
||||||
borderRadius: BorderRadius.circular(60))),
|
child: const Padding(
|
||||||
child: const Padding(
|
padding:
|
||||||
padding: EdgeInsets.symmetric(
|
EdgeInsets.symmetric(horizontal: 25, vertical: 5),
|
||||||
horizontal: 25, vertical: 5),
|
child: Text(
|
||||||
child: Text(
|
'Iniciar Sesión',
|
||||||
'Sign In',
|
textAlign: TextAlign.center,
|
||||||
textAlign: TextAlign.center,
|
style: TextStyle(
|
||||||
style: TextStyle(
|
color: Colors.white,
|
||||||
color: Colors.white,
|
fontSize: 16,
|
||||||
fontSize: 16,
|
fontWeight: FontWeight.w600,
|
||||||
fontWeight: FontWeight.w600),
|
|
||||||
),
|
),
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
: const CircularProgressIndicator()
|
: const CircularProgressIndicator()
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -0,0 +1,131 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:injector/injector.dart';
|
||||||
|
import 'package:prosappco/blocs/authentication_bloc/authentication_bloc.dart';
|
||||||
|
import 'package:prosappco/blocs/sign_up_bloc/sign_up_bloc.dart';
|
||||||
|
import 'package:prosappco/blocs/sing_in_bloc/sign_in_bloc.dart';
|
||||||
|
import 'package:prosappco/screens/authentication/sign_in_screen.dart';
|
||||||
|
import 'package:prosappco/screens/authentication/sign_up_screen.dart';
|
||||||
|
|
||||||
|
class SignScreen extends StatefulWidget {
|
||||||
|
final int initialIndex;
|
||||||
|
|
||||||
|
SignScreen({super.key, required this.initialIndex});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SignScreen> createState() => _SignScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SignScreenState extends State<SignScreen> with TickerProviderStateMixin {
|
||||||
|
late TabController tabController;
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
tabController = TabController(
|
||||||
|
initialIndex: widget.initialIndex,
|
||||||
|
length: 2,
|
||||||
|
vsync: this,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
double width = MediaQuery.of(context).size.width;
|
||||||
|
return BlocListener<AuthenticationBloc, AuthenticationState>(
|
||||||
|
listener: (context, state) {
|
||||||
|
if (state.status == AuthenticationStatus.authenticated) {
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: Theme.of(context).colorScheme.tertiary,
|
||||||
|
),
|
||||||
|
body: Column(
|
||||||
|
children: [
|
||||||
|
// Text('${context.read<SignInBloc>().state}'),
|
||||||
|
Container(
|
||||||
|
color: Theme.of(context).colorScheme.tertiary,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Center(
|
||||||
|
child: Image(
|
||||||
|
width: width * 0.7,
|
||||||
|
image: AssetImage('images/logo_prosapp.png'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 20),
|
||||||
|
TabBar(
|
||||||
|
controller: tabController,
|
||||||
|
unselectedLabelColor:
|
||||||
|
Theme.of(context).colorScheme.onBackground,
|
||||||
|
labelColor: Theme.of(context).colorScheme.onBackground,
|
||||||
|
tabs: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.all(12.0),
|
||||||
|
child: Text(
|
||||||
|
'Inicia sesión',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.all(12.0),
|
||||||
|
child: Text(
|
||||||
|
'Registrate',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: SizedBox(
|
||||||
|
height: MediaQuery.of(context).size.height,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: TabBarView(controller: tabController, children: [
|
||||||
|
BlocProvider<SignInBloc>(
|
||||||
|
create: (context) =>
|
||||||
|
Injector.appInstance.get<SignInBloc>(),
|
||||||
|
child: SignInScreen(),
|
||||||
|
),
|
||||||
|
BlocProvider<SignUpBloc>(
|
||||||
|
create: (context) =>
|
||||||
|
Injector.appInstance.get<SignUpBloc>(),
|
||||||
|
child: SignUpScreen(),
|
||||||
|
),
|
||||||
|
// BlocProvider<SignInBloc>(
|
||||||
|
// create: (context) => SignInBloc(
|
||||||
|
// userRepository: context
|
||||||
|
// .read<AuthenticationBloc>()
|
||||||
|
// .userRepository),
|
||||||
|
// child: SignInScreen(),
|
||||||
|
// ),
|
||||||
|
// BlocProvider<SignUpBloc>(
|
||||||
|
// create: (context) => SignUpBloc(
|
||||||
|
// userRepository: context
|
||||||
|
// .read<AuthenticationBloc>()
|
||||||
|
// .userRepository),
|
||||||
|
// child: SignUpScreen(),
|
||||||
|
// ),
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -45,212 +45,214 @@ class _SignUpScreenState extends State<SignUpScreen> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Form(
|
child: Scaffold(
|
||||||
key: _formKey,
|
body: Form(
|
||||||
child: Center(
|
key: _formKey,
|
||||||
child: Column(
|
child: Center(
|
||||||
children: [
|
child: Column(
|
||||||
const SizedBox(height: 20),
|
children: [
|
||||||
SizedBox(
|
const SizedBox(height: 20),
|
||||||
width: MediaQuery.of(context).size.width * 0.9,
|
SizedBox(
|
||||||
child: MyTextField(
|
width: MediaQuery.of(context).size.width * 0.9,
|
||||||
controller: emailController,
|
child: MyTextField(
|
||||||
hintText: 'Email',
|
controller: emailController,
|
||||||
obscureText: false,
|
hintText: 'Email',
|
||||||
keyboardType: TextInputType.emailAddress,
|
obscureText: false,
|
||||||
prefixIcon: const Icon(CupertinoIcons.mail_solid),
|
keyboardType: TextInputType.emailAddress,
|
||||||
validator: (val) {
|
prefixIcon: const Icon(CupertinoIcons.mail_solid),
|
||||||
if (val!.isEmpty) {
|
validator: (val) {
|
||||||
return 'Please fill in this field';
|
if (val!.isEmpty) {
|
||||||
} else if (!emailRexExp.hasMatch(val)) {
|
return 'Please fill in this field';
|
||||||
return 'Please enter a valid email';
|
} else if (!emailRexExp.hasMatch(val)) {
|
||||||
}
|
return 'Please enter a valid email';
|
||||||
return null;
|
}
|
||||||
}),
|
return null;
|
||||||
),
|
}),
|
||||||
const SizedBox(height: 10),
|
),
|
||||||
SizedBox(
|
const SizedBox(height: 10),
|
||||||
width: MediaQuery.of(context).size.width * 0.9,
|
SizedBox(
|
||||||
child: MyTextField(
|
width: MediaQuery.of(context).size.width * 0.9,
|
||||||
controller: passwordController,
|
child: MyTextField(
|
||||||
hintText: 'Password',
|
controller: passwordController,
|
||||||
obscureText: obscurePassword,
|
hintText: 'Password',
|
||||||
keyboardType: TextInputType.visiblePassword,
|
obscureText: obscurePassword,
|
||||||
prefixIcon: const Icon(CupertinoIcons.lock_fill),
|
keyboardType: TextInputType.visiblePassword,
|
||||||
onChanged: (val) {
|
prefixIcon: const Icon(CupertinoIcons.lock_fill),
|
||||||
if (val!.contains(RegExp(r'[A-Z]'))) {
|
onChanged: (val) {
|
||||||
setState(() {
|
if (val!.contains(RegExp(r'[A-Z]'))) {
|
||||||
containsUpperCase = true;
|
setState(() {
|
||||||
});
|
containsUpperCase = true;
|
||||||
} else {
|
});
|
||||||
setState(() {
|
} else {
|
||||||
containsUpperCase = false;
|
setState(() {
|
||||||
});
|
containsUpperCase = false;
|
||||||
}
|
});
|
||||||
if (val.contains(RegExp(r'[a-z]'))) {
|
}
|
||||||
setState(() {
|
if (val.contains(RegExp(r'[a-z]'))) {
|
||||||
containsLowerCase = true;
|
setState(() {
|
||||||
});
|
containsLowerCase = true;
|
||||||
} else {
|
});
|
||||||
setState(() {
|
} else {
|
||||||
containsLowerCase = false;
|
setState(() {
|
||||||
});
|
containsLowerCase = false;
|
||||||
}
|
});
|
||||||
if (val.contains(RegExp(r'[0-9]'))) {
|
}
|
||||||
setState(() {
|
if (val.contains(RegExp(r'[0-9]'))) {
|
||||||
containsNumber = true;
|
setState(() {
|
||||||
});
|
containsNumber = true;
|
||||||
} else {
|
});
|
||||||
setState(() {
|
} else {
|
||||||
containsNumber = false;
|
setState(() {
|
||||||
});
|
containsNumber = false;
|
||||||
}
|
});
|
||||||
if (val.contains(specialCharRexExp)) {
|
}
|
||||||
setState(() {
|
if (val.contains(specialCharRexExp)) {
|
||||||
containsSpecialChar = true;
|
setState(() {
|
||||||
});
|
containsSpecialChar = true;
|
||||||
} else {
|
});
|
||||||
setState(() {
|
} else {
|
||||||
containsSpecialChar = false;
|
setState(() {
|
||||||
});
|
containsSpecialChar = false;
|
||||||
}
|
});
|
||||||
if (val.length >= 8) {
|
}
|
||||||
setState(() {
|
if (val.length >= 8) {
|
||||||
contains8Length = true;
|
setState(() {
|
||||||
});
|
contains8Length = true;
|
||||||
} else {
|
});
|
||||||
setState(() {
|
} else {
|
||||||
contains8Length = false;
|
setState(() {
|
||||||
});
|
contains8Length = false;
|
||||||
}
|
});
|
||||||
return null;
|
}
|
||||||
},
|
return null;
|
||||||
suffixIcon: IconButton(
|
|
||||||
onPressed: () {
|
|
||||||
setState(() {
|
|
||||||
obscurePassword = !obscurePassword;
|
|
||||||
if (obscurePassword) {
|
|
||||||
iconPassword = CupertinoIcons.eye_fill;
|
|
||||||
} else {
|
|
||||||
iconPassword = CupertinoIcons.eye_slash_fill;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
icon: Icon(iconPassword),
|
suffixIcon: IconButton(
|
||||||
),
|
onPressed: () {
|
||||||
validator: (val) {
|
setState(() {
|
||||||
if (val!.isEmpty) {
|
obscurePassword = !obscurePassword;
|
||||||
return 'Please fill in this field';
|
if (obscurePassword) {
|
||||||
} else if (!passwordRexExp.hasMatch(val)) {
|
iconPassword = CupertinoIcons.eye_fill;
|
||||||
return 'Please enter a valid password';
|
} else {
|
||||||
}
|
iconPassword = CupertinoIcons.eye_slash_fill;
|
||||||
return null;
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
"⚈ 1 uppercase",
|
|
||||||
style: TextStyle(
|
|
||||||
color: containsUpperCase
|
|
||||||
? Colors.green
|
|
||||||
: Theme.of(context).colorScheme.onBackground),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"⚈ 1 lowercase",
|
|
||||||
style: TextStyle(
|
|
||||||
color: containsLowerCase
|
|
||||||
? Colors.green
|
|
||||||
: Theme.of(context).colorScheme.onBackground),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
"⚈ 8 minimum character",
|
|
||||||
style: TextStyle(
|
|
||||||
color: contains8Length
|
|
||||||
? Colors.green
|
|
||||||
: Theme.of(context).colorScheme.onBackground),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"⚈ 1 number",
|
|
||||||
style: TextStyle(
|
|
||||||
color: containsNumber
|
|
||||||
? Colors.green
|
|
||||||
: Theme.of(context).colorScheme.onBackground),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
SizedBox(
|
|
||||||
width: MediaQuery.of(context).size.width * 0.9,
|
|
||||||
child: MyTextField(
|
|
||||||
controller: nameController,
|
|
||||||
hintText: 'Name',
|
|
||||||
obscureText: false,
|
|
||||||
keyboardType: TextInputType.name,
|
|
||||||
prefixIcon: const Icon(CupertinoIcons.person_fill),
|
|
||||||
validator: (val) {
|
|
||||||
if (val!.isEmpty) {
|
|
||||||
return 'Please fill in this field';
|
|
||||||
} else if (val.length > 30) {
|
|
||||||
return 'Name too long';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
SizedBox(height: MediaQuery.of(context).size.height * 0.02),
|
|
||||||
!signUpRequired
|
|
||||||
? SizedBox(
|
|
||||||
width: MediaQuery.of(context).size.width * 0.5,
|
|
||||||
child: TextButton(
|
|
||||||
onPressed: () {
|
|
||||||
if (_formKey.currentState!.validate()) {
|
|
||||||
MyUser myUser = MyUser.empty;
|
|
||||||
myUser = myUser.copyWith(
|
|
||||||
email: emailController.text,
|
|
||||||
name: nameController.text,
|
|
||||||
);
|
|
||||||
|
|
||||||
setState(() {
|
|
||||||
context.read<SignUpBloc>().add(SignUpRequired(
|
|
||||||
myUser, passwordController.text));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
});
|
||||||
style: TextButton.styleFrom(
|
},
|
||||||
elevation: 3.0,
|
icon: Icon(iconPassword),
|
||||||
backgroundColor:
|
),
|
||||||
Theme.of(context).colorScheme.primary,
|
validator: (val) {
|
||||||
foregroundColor: Colors.white,
|
if (val!.isEmpty) {
|
||||||
shape: RoundedRectangleBorder(
|
return 'Please fill in this field';
|
||||||
borderRadius: BorderRadius.circular(60))),
|
} else if (!passwordRexExp.hasMatch(val)) {
|
||||||
child: const Padding(
|
return 'Please enter a valid password';
|
||||||
padding: EdgeInsets.symmetric(
|
}
|
||||||
horizontal: 25, vertical: 5),
|
return null;
|
||||||
child: Text(
|
}),
|
||||||
'Sign Up',
|
),
|
||||||
textAlign: TextAlign.center,
|
const SizedBox(height: 10),
|
||||||
style: TextStyle(
|
Row(
|
||||||
color: Colors.white,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
fontSize: 16,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
fontWeight: FontWeight.w600),
|
children: [
|
||||||
),
|
Column(
|
||||||
)),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
)
|
children: [
|
||||||
: const CircularProgressIndicator()
|
Text(
|
||||||
],
|
"⚈ 1 uppercase",
|
||||||
|
style: TextStyle(
|
||||||
|
color: containsUpperCase
|
||||||
|
? Colors.green
|
||||||
|
: Theme.of(context).colorScheme.onBackground),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"⚈ 1 lowercase",
|
||||||
|
style: TextStyle(
|
||||||
|
color: containsLowerCase
|
||||||
|
? Colors.green
|
||||||
|
: Theme.of(context).colorScheme.onBackground),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"⚈ 8 minimum character",
|
||||||
|
style: TextStyle(
|
||||||
|
color: contains8Length
|
||||||
|
? Colors.green
|
||||||
|
: Theme.of(context).colorScheme.onBackground),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"⚈ 1 number",
|
||||||
|
style: TextStyle(
|
||||||
|
color: containsNumber
|
||||||
|
? Colors.green
|
||||||
|
: Theme.of(context).colorScheme.onBackground),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
SizedBox(
|
||||||
|
width: MediaQuery.of(context).size.width * 0.9,
|
||||||
|
child: MyTextField(
|
||||||
|
controller: nameController,
|
||||||
|
hintText: 'Name',
|
||||||
|
obscureText: false,
|
||||||
|
keyboardType: TextInputType.name,
|
||||||
|
prefixIcon: const Icon(CupertinoIcons.person_fill),
|
||||||
|
validator: (val) {
|
||||||
|
if (val!.isEmpty) {
|
||||||
|
return 'Please fill in this field';
|
||||||
|
} else if (val.length > 30) {
|
||||||
|
return 'Name too long';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
SizedBox(height: MediaQuery.of(context).size.height * 0.02),
|
||||||
|
!signUpRequired
|
||||||
|
? SizedBox(
|
||||||
|
width: MediaQuery.of(context).size.width * 0.5,
|
||||||
|
child: TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
if (_formKey.currentState!.validate()) {
|
||||||
|
MyUser myUser = MyUser.empty;
|
||||||
|
myUser = myUser.copyWith(
|
||||||
|
email: emailController.text,
|
||||||
|
name: nameController.text,
|
||||||
|
);
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
context.read<SignUpBloc>().add(SignUpRequired(
|
||||||
|
myUser, passwordController.text));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
elevation: 3.0,
|
||||||
|
backgroundColor:
|
||||||
|
Theme.of(context).colorScheme.primary,
|
||||||
|
foregroundColor: Colors.white,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(60))),
|
||||||
|
child: const Padding(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 25, vertical: 5),
|
||||||
|
child: Text(
|
||||||
|
'Sign Up',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w600),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
: const CircularProgressIndicator(),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,102 +1,128 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:prosappco/blocs/sing_in_bloc/sign_in_bloc.dart';
|
import 'package:intl_phone_field/intl_phone_field.dart';
|
||||||
import 'package:prosappco/screens/authentication/sign_in_screen.dart';
|
import 'package:prosappco/screens/authentication/sign_screen.dart';
|
||||||
import 'package:prosappco/screens/authentication/sign_up_screen.dart';
|
|
||||||
|
|
||||||
import '../../blocs/authentication_bloc/authentication_bloc.dart';
|
class WelcomeScreen extends StatelessWidget {
|
||||||
import '../../blocs/sign_up_bloc/sign_up_bloc.dart';
|
|
||||||
|
|
||||||
class WelcomeScreen extends StatefulWidget {
|
|
||||||
const WelcomeScreen({super.key});
|
const WelcomeScreen({super.key});
|
||||||
|
|
||||||
@override
|
|
||||||
State<WelcomeScreen> createState() => _WelcomeScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _WelcomeScreenState extends State<WelcomeScreen>
|
|
||||||
with TickerProviderStateMixin {
|
|
||||||
late TabController tabController;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
tabController = TabController(
|
|
||||||
initialIndex: 0,
|
|
||||||
length: 2,
|
|
||||||
vsync: this,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
double width = MediaQuery.of(context).size.width;
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Theme.of(context).colorScheme.background,
|
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||||
appBar: AppBar(
|
body: Column(
|
||||||
elevation: 0,
|
children: [
|
||||||
backgroundColor: Colors.transparent,
|
Container(
|
||||||
),
|
color: Theme.of(context).colorScheme.tertiary,
|
||||||
body: SingleChildScrollView(
|
|
||||||
child: SizedBox(
|
|
||||||
height: MediaQuery.of(context).size.height,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
const Text(
|
const SizedBox(height: 20),
|
||||||
'Welcome Back !',
|
Center(
|
||||||
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
|
child: Image(
|
||||||
|
width: width * 0.7,
|
||||||
|
image: const AssetImage('images/logo_prosapp.png'),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: kToolbarHeight),
|
const SizedBox(height: 20),
|
||||||
TabBar(
|
|
||||||
controller: tabController,
|
|
||||||
unselectedLabelColor: Theme.of(context)
|
|
||||||
.colorScheme
|
|
||||||
.onBackground
|
|
||||||
.withOpacity(0.5),
|
|
||||||
labelColor: Theme.of(context).colorScheme.onBackground,
|
|
||||||
tabs: const [
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.all(12.0),
|
|
||||||
child: Text(
|
|
||||||
'Sign In',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 18,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.all(12.0),
|
|
||||||
child: Text(
|
|
||||||
'Sign Up',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 18,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
Expanded(
|
|
||||||
child: TabBarView(controller: tabController, children: [
|
|
||||||
BlocProvider<SignInBloc>(
|
|
||||||
create: (context) => SignInBloc(
|
|
||||||
userRepository: context
|
|
||||||
.read<AuthenticationBloc>()
|
|
||||||
.userRepository),
|
|
||||||
child: const SignInScreen(),
|
|
||||||
),
|
|
||||||
BlocProvider<SignUpBloc>(
|
|
||||||
create: (context) => SignUpBloc(
|
|
||||||
userRepository: context
|
|
||||||
.read<AuthenticationBloc>()
|
|
||||||
.userRepository),
|
|
||||||
child: const SignUpScreen(),
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
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),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,171 @@
|
|||||||
|
// import 'package:cloud_firestore/cloud_firestore.dart';
|
||||||
|
// import 'package:firebase_auth/firebase_auth.dart';
|
||||||
|
// import 'package:flutter/cupertino.dart';
|
||||||
|
// import 'package:flutter/material.dart';
|
||||||
|
// import 'package:get/get.dart';
|
||||||
|
// import 'package:prosappco/src/components/pop_appbar.dart';
|
||||||
|
// import 'package:prosappco/src/presentation/screens/about.dart';
|
||||||
|
|
||||||
|
// class ConfigurationScreen extends StatefulWidget {
|
||||||
|
// const ConfigurationScreen({super.key});
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// State<ConfigurationScreen> createState() => _ConfigurationScreenState();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// class _ConfigurationScreenState extends State<ConfigurationScreen> {
|
||||||
|
// late final FirebaseAuth _auth;
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// void initState() {
|
||||||
|
// super.initState();
|
||||||
|
// _auth = FirebaseAuth.instance;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Future<void> deleteAccount() async {
|
||||||
|
// try {
|
||||||
|
// final currentUser = _auth.currentUser;
|
||||||
|
|
||||||
|
// if (currentUser != null) {
|
||||||
|
// final uid = currentUser.uid;
|
||||||
|
|
||||||
|
// await FirebaseFirestore.instance.collection('users').doc(uid).delete();
|
||||||
|
|
||||||
|
// await currentUser.delete();
|
||||||
|
|
||||||
|
// await _auth.signOut();
|
||||||
|
|
||||||
|
// Get.snackbar(
|
||||||
|
// 'Cuenta Eliminada',
|
||||||
|
// 'Tu cuenta ha sido eliminada con éxito.',
|
||||||
|
// snackPosition: SnackPosition.BOTTOM,
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// } catch (e) {
|
||||||
|
// Get.snackbar(
|
||||||
|
// 'Error al Eliminar Cuenta',
|
||||||
|
// 'Hubo un error al eliminar tu cuenta. Por favor, inténtalo de nuevo más tarde.',
|
||||||
|
// snackPosition: SnackPosition.BOTTOM,
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Future<void> _showDeleteAccountConfirmationDialog(
|
||||||
|
// BuildContext context) async {
|
||||||
|
// return showDialog(
|
||||||
|
// context: context,
|
||||||
|
// builder: (BuildContext context) {
|
||||||
|
// return AlertDialog(
|
||||||
|
// title: const Text('Eliminar Cuenta'),
|
||||||
|
// content: const Text(
|
||||||
|
// '¿Estás seguro de que deseas eliminar tu cuenta? Esta acción no se puede deshacer.'),
|
||||||
|
// actions: [
|
||||||
|
// TextButton(
|
||||||
|
// onPressed: () {
|
||||||
|
// Navigator.of(context).pop();
|
||||||
|
// },
|
||||||
|
// child: const Text('Cancelar'),
|
||||||
|
// ),
|
||||||
|
// TextButton(
|
||||||
|
// onPressed: () {
|
||||||
|
// deleteAccount();
|
||||||
|
// Navigator.of(context).pop();
|
||||||
|
// },
|
||||||
|
// child: const Text(
|
||||||
|
// 'Eliminar',
|
||||||
|
// style:
|
||||||
|
// TextStyle(color: Colors.red, fontWeight: FontWeight.w600),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// Widget build(BuildContext context) {
|
||||||
|
// return Scaffold(
|
||||||
|
// appBar: PopAppbar(
|
||||||
|
// onPressed: () {
|
||||||
|
// Navigator.pop(context);
|
||||||
|
// },
|
||||||
|
// label: 'Configuración'),
|
||||||
|
// body: ListView(
|
||||||
|
// children: [
|
||||||
|
// ListTile(
|
||||||
|
// onTap: () {
|
||||||
|
// Navigator.push(
|
||||||
|
// context,
|
||||||
|
// CupertinoPageRoute(
|
||||||
|
// builder: (BuildContext context) {
|
||||||
|
// return const AboutScreen();
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
// title: const Text('Acerca de la aplicación'),
|
||||||
|
// trailing: const Icon(
|
||||||
|
// Icons.keyboard_arrow_right,
|
||||||
|
// color: Colors.black,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ListTile(
|
||||||
|
// onTap: () {
|
||||||
|
// _showDeleteAccountConfirmationDialog(context);
|
||||||
|
// },
|
||||||
|
// title: const Text(
|
||||||
|
// 'Eliminar cuenta',
|
||||||
|
// style: TextStyle(color: Colors.red),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:prosappco/blocs/authentication_bloc/authentication_bloc.dart';
|
||||||
|
import 'package:prosappco/components/general_drawer_item.dart';
|
||||||
|
|
||||||
|
class ConfigurationScreen extends StatelessWidget {
|
||||||
|
const ConfigurationScreen({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocListener<AuthenticationBloc, AuthenticationState>(
|
||||||
|
listener: (context, state) {
|
||||||
|
if (state.status == AuthenticationStatus.unauthenticated) {
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('Configuración'),
|
||||||
|
),
|
||||||
|
body: ListView(children: [
|
||||||
|
GeneralDrawerItem(
|
||||||
|
label: 'Acerca de la aplicación',
|
||||||
|
onTap: () {},
|
||||||
|
trailing: true,
|
||||||
|
),
|
||||||
|
GeneralDrawerItem(
|
||||||
|
label: 'Cerrar sesión',
|
||||||
|
onTap: () {
|
||||||
|
context
|
||||||
|
.read<AuthenticationBloc>()
|
||||||
|
.add(AuthenticationLogoutRequested());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
GeneralDrawerItem(
|
||||||
|
label: 'Eliminar cuenta',
|
||||||
|
onTap: () {},
|
||||||
|
color: Theme.of(context).colorScheme.error,
|
||||||
|
)
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,36 +1,18 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:prosappco/blocs/my_user_bloc/my_user_bloc.dart';
|
|
||||||
import 'package:prosappco/blocs/update_user_info_bloc/update_user_info_bloc.dart';
|
|
||||||
import 'package:prosappco/components/general_drawer.dart';
|
import 'package:prosappco/components/general_drawer.dart';
|
||||||
|
|
||||||
class HomeScreen extends StatefulWidget {
|
class HomeScreen extends StatelessWidget {
|
||||||
const HomeScreen({super.key});
|
const HomeScreen({super.key});
|
||||||
|
|
||||||
@override
|
|
||||||
State<HomeScreen> createState() => _HomeScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _HomeScreenState extends State<HomeScreen> {
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocListener<UpdateUserInfoBloc, UpdateUserInfoState>(
|
return SafeArea(
|
||||||
listener: (context, state) {
|
child: Scaffold(
|
||||||
if (state is UploadPictureSuccess) {
|
backgroundColor: Theme.of(context).colorScheme.background,
|
||||||
setState(() {
|
drawer: GeneralDrawer(),
|
||||||
context.read<MyUserBloc>().state.user!.picture = state.userImage;
|
appBar: AppBar(),
|
||||||
});
|
body: const Center(
|
||||||
}
|
child: Text('Bienvenido'),
|
||||||
},
|
|
||||||
child: SafeArea(
|
|
||||||
child: Scaffold(
|
|
||||||
backgroundColor: Theme.of(context).colorScheme.background,
|
|
||||||
drawer: const GeneralDrawer(),
|
|
||||||
appBar: AppBar(),
|
|
||||||
body: const Center(
|
|
||||||
child: Text('Bienvenido'),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -27,9 +27,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
|||||||
return BlocListener<UpdateUserInfoBloc, UpdateUserInfoState>(
|
return BlocListener<UpdateUserInfoBloc, UpdateUserInfoState>(
|
||||||
listener: (context, state) {
|
listener: (context, state) {
|
||||||
if (state is UploadPictureSuccess) {
|
if (state is UploadPictureSuccess) {
|
||||||
setState(() {
|
setState(() {});
|
||||||
context.read<MyUserBloc>().state.user!.picture = state.userImage;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
|
|||||||
@@ -69,6 +69,30 @@ class _LoginScreenState extends State<LoginScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _mobileView(BuildContext context) {
|
Widget _mobileView(BuildContext context) {
|
||||||
|
const inputDecoration = 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,
|
||||||
|
);
|
||||||
return BottomSheetExpanded(
|
return BottomSheetExpanded(
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
@@ -103,30 +127,7 @@ class _LoginScreenState extends State<LoginScreen> {
|
|||||||
onChanged: (phoneNo) {
|
onChanged: (phoneNo) {
|
||||||
completePhoneNumber = phoneNo.completeNumber;
|
completePhoneNumber = phoneNo.completeNumber;
|
||||||
},
|
},
|
||||||
decoration: const InputDecoration(
|
decoration: 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 Text(
|
const Text(
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
|
||||||
|
class CityEntity extends Equatable {
|
||||||
|
final String name;
|
||||||
|
final String coords;
|
||||||
|
|
||||||
|
const CityEntity({
|
||||||
|
required this.name,
|
||||||
|
required this.coords,
|
||||||
|
});
|
||||||
|
|
||||||
|
Map<String, Object?> toDocument() {
|
||||||
|
return {
|
||||||
|
'name': name,
|
||||||
|
'coords': coords,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static CityEntity fromDocument(Map<String, dynamic> doc) {
|
||||||
|
return CityEntity(
|
||||||
|
name: doc['name'] as String,
|
||||||
|
coords: doc['coords'] as String,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [name, coords];
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return '''CityEntity {
|
||||||
|
name: $name
|
||||||
|
coords: $coords
|
||||||
|
}''';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:user_repository/user_repository.dart';
|
||||||
|
|
||||||
|
class CountryEntity extends Equatable {
|
||||||
|
final String name;
|
||||||
|
final List<RegionEntity> regions;
|
||||||
|
|
||||||
|
const CountryEntity({
|
||||||
|
required this.name,
|
||||||
|
required this.regions,
|
||||||
|
});
|
||||||
|
|
||||||
|
Map<String, Object?> toDocument() {
|
||||||
|
return {
|
||||||
|
'name': name,
|
||||||
|
'regions': regions,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static CountryEntity fromDocument(Map<String, dynamic> doc) {
|
||||||
|
return CountryEntity(
|
||||||
|
name: doc['name'] as String,
|
||||||
|
regions: (doc['regions'] as List)
|
||||||
|
.map((region) => RegionEntity.fromDocument(region))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [name, regions];
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return '''CountryEntity {
|
||||||
|
name: $name
|
||||||
|
regions: $regions
|
||||||
|
}''';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1 +1,4 @@
|
|||||||
export 'my_user_entity.dart';
|
export 'my_user_entity.dart';
|
||||||
|
export 'country_entity.dart';
|
||||||
|
export 'region_entity.dart';
|
||||||
|
export 'city_entity.dart';
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:user_repository/user_repository.dart';
|
||||||
|
|
||||||
|
class RegionEntity extends Equatable {
|
||||||
|
final String name;
|
||||||
|
final List<CityEntity> cities;
|
||||||
|
|
||||||
|
const RegionEntity({
|
||||||
|
required this.name,
|
||||||
|
required this.cities,
|
||||||
|
});
|
||||||
|
|
||||||
|
Map<String, Object?> toDocument() {
|
||||||
|
return {
|
||||||
|
'name': name,
|
||||||
|
'cities': cities,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static RegionEntity fromDocument(Map<String, dynamic> doc) {
|
||||||
|
return RegionEntity(
|
||||||
|
name: doc['name'] as String,
|
||||||
|
cities: (doc['cities'] as List)
|
||||||
|
.map((city) => CityEntity.fromDocument(city))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [name, cities];
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return '''RegionEntity {
|
||||||
|
name: $name
|
||||||
|
cities: $cities
|
||||||
|
}''';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
|
||||||
|
import '../entities/entities.dart';
|
||||||
|
|
||||||
|
class City extends Equatable {
|
||||||
|
final String name;
|
||||||
|
final String coords;
|
||||||
|
|
||||||
|
const City({
|
||||||
|
required this.name,
|
||||||
|
required this.coords,
|
||||||
|
});
|
||||||
|
|
||||||
|
static const empty = City(name: '', coords: '');
|
||||||
|
|
||||||
|
City copyWith({
|
||||||
|
String? name,
|
||||||
|
String? coords,
|
||||||
|
}) {
|
||||||
|
return City(
|
||||||
|
name: name ?? this.name,
|
||||||
|
coords: coords ?? this.coords,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get isEmpty => this == City.empty;
|
||||||
|
|
||||||
|
bool get isNotEmpty => this != City.empty;
|
||||||
|
|
||||||
|
City toEntity() {
|
||||||
|
return City(
|
||||||
|
name: name,
|
||||||
|
coords: coords,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static City fromEntity(CityEntity entity) {
|
||||||
|
return City(
|
||||||
|
name: entity.name,
|
||||||
|
coords: entity.coords,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [name, coords];
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:user_repository/user_repository.dart';
|
||||||
|
|
||||||
|
class Country extends Equatable {
|
||||||
|
final String name;
|
||||||
|
final List<Region> regions;
|
||||||
|
|
||||||
|
const Country({
|
||||||
|
required this.name,
|
||||||
|
required this.regions,
|
||||||
|
});
|
||||||
|
|
||||||
|
static const empty = Country(name: '', regions: []);
|
||||||
|
Country copyWith({
|
||||||
|
String? name,
|
||||||
|
List<Region>? regions,
|
||||||
|
}) {
|
||||||
|
return Country(
|
||||||
|
name: name ?? this.name,
|
||||||
|
regions: regions ?? this.regions,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get isEmpty => this == Country.empty;
|
||||||
|
|
||||||
|
bool get isNotEmpty => this != Country.empty;
|
||||||
|
|
||||||
|
Country toEntity() {
|
||||||
|
return Country(name: name, regions: regions);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Country fromEntity(CountryEntity entity) {
|
||||||
|
return Country(
|
||||||
|
name: entity.name,
|
||||||
|
regions:
|
||||||
|
entity.regions.map((region) => Region.fromEntity(region)).toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [name, regions];
|
||||||
|
}
|
||||||
@@ -1 +1,4 @@
|
|||||||
export 'my_user.dart';
|
export 'my_user.dart';
|
||||||
|
export 'country.dart';
|
||||||
|
export 'region.dart';
|
||||||
|
export 'city.dart';
|
||||||
|
|||||||
@@ -60,11 +60,3 @@ class MyUser extends Equatable {
|
|||||||
@override
|
@override
|
||||||
List<Object?> get props => [id, email, name, picture];
|
List<Object?> get props => [id, email, name, picture];
|
||||||
}
|
}
|
||||||
// final String name;
|
|
||||||
// final String city;
|
|
||||||
// final String? profession;
|
|
||||||
// final String? state;
|
|
||||||
// final Reference? photo;
|
|
||||||
// final int? tarifa;
|
|
||||||
// final String? phoneNumber;
|
|
||||||
// final String? token;
|
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:user_repository/user_repository.dart';
|
||||||
|
|
||||||
|
class Region extends Equatable {
|
||||||
|
final String name;
|
||||||
|
final List<City> cities;
|
||||||
|
|
||||||
|
const Region({
|
||||||
|
required this.name,
|
||||||
|
required this.cities,
|
||||||
|
});
|
||||||
|
|
||||||
|
static const empty = Region(name: '', cities: []);
|
||||||
|
Region copyWith({
|
||||||
|
String? name,
|
||||||
|
List<City>? cities,
|
||||||
|
}) {
|
||||||
|
return Region(
|
||||||
|
name: name ?? this.name,
|
||||||
|
cities: cities ?? this.cities,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get isEmpty => this == Region.empty;
|
||||||
|
|
||||||
|
bool get isNotEmpty => this != Region.empty;
|
||||||
|
|
||||||
|
Region toEntity() {
|
||||||
|
return Region(name: name, cities: cities);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Region fromEntity(RegionEntity entity) {
|
||||||
|
return Region(
|
||||||
|
name: entity.name,
|
||||||
|
cities: entity.cities.map((city) => City.fromEntity(city)).toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [name, cities];
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
abstract class CityRepository {}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||||
|
|
||||||
|
import 'city_repo.dart';
|
||||||
|
|
||||||
|
class FirebaseCityRepository implements CityRepository {
|
||||||
|
final usersCollection = FirebaseFirestore.instance.collection('users');
|
||||||
|
}
|
||||||
+41
-9
@@ -6,7 +6,7 @@ import 'package:cloud_firestore/cloud_firestore.dart';
|
|||||||
import 'package:firebase_auth/firebase_auth.dart';
|
import 'package:firebase_auth/firebase_auth.dart';
|
||||||
import 'package:firebase_storage/firebase_storage.dart';
|
import 'package:firebase_storage/firebase_storage.dart';
|
||||||
import 'package:user_repository/src/models/my_user.dart';
|
import 'package:user_repository/src/models/my_user.dart';
|
||||||
import 'entities/entities.dart';
|
import '../entities/entities.dart';
|
||||||
import 'user_repo.dart';
|
import 'user_repo.dart';
|
||||||
|
|
||||||
class FirebaseUserRepository implements UserRepository {
|
class FirebaseUserRepository implements UserRepository {
|
||||||
@@ -42,14 +42,6 @@ class FirebaseUserRepository implements UserRepository {
|
|||||||
return _userStreamController.stream;
|
return _userStreamController.stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @override
|
|
||||||
// Stream<User?> get user {
|
|
||||||
// return _firebaseAuth.authStateChanges().map((firebaseUser) {
|
|
||||||
// final user = firebaseUser;
|
|
||||||
// return user;
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Sign up
|
// Sign up
|
||||||
@override
|
@override
|
||||||
Future<MyUser> signUp(MyUser myUser, String password) async {
|
Future<MyUser> signUp(MyUser myUser, String password) async {
|
||||||
@@ -70,6 +62,46 @@ class FirebaseUserRepository implements UserRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sign in with phone number
|
||||||
|
@override
|
||||||
|
Future<void> signInWithPhoneNumber(String phoneNumber) async {
|
||||||
|
try {
|
||||||
|
await FirebaseAuth.instance.verifyPhoneNumber(
|
||||||
|
phoneNumber: phoneNumber,
|
||||||
|
verificationCompleted: (PhoneAuthCredential credential) async {
|
||||||
|
// Esta función se llama automáticamente cuando se completa la verificación del número de teléfono.
|
||||||
|
// 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) {
|
||||||
|
// Esta función se llama cuando se envía el código de verificación al número de teléfono del usuario.
|
||||||
|
// 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) {
|
||||||
|
// Esta función se llama cuando el tiempo de espera de recuperación automática del código ha expirado.
|
||||||
|
// Puedes manejar esto como prefieras, por ejemplo, mostrando un mensaje al usuario o reenviando el código.
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
log(e.toString());
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Sign in
|
// Sign in
|
||||||
@override
|
@override
|
||||||
Future<void> signIn(String email, String password) async {
|
Future<void> signIn(String email, String password) async {
|
||||||
+3
-1
@@ -1,4 +1,4 @@
|
|||||||
import '../user_repository.dart';
|
import '../../user_repository.dart';
|
||||||
|
|
||||||
abstract class UserRepository {
|
abstract class UserRepository {
|
||||||
// Stream<User?> get user;
|
// Stream<User?> get user;
|
||||||
@@ -10,6 +10,8 @@ abstract class UserRepository {
|
|||||||
|
|
||||||
Future<MyUser> signUp(MyUser myUser, String password);
|
Future<MyUser> signUp(MyUser myUser, String password);
|
||||||
|
|
||||||
|
Future<void> signInWithPhoneNumber(String phoneNumber);
|
||||||
|
|
||||||
Future<void> resetPassword(String email);
|
Future<void> resetPassword(String email);
|
||||||
|
|
||||||
Future<void> setUserData(MyUser user);
|
Future<void> setUserData(MyUser user);
|
||||||
@@ -2,5 +2,5 @@ library user_repository;
|
|||||||
|
|
||||||
export 'src/models/models.dart';
|
export 'src/models/models.dart';
|
||||||
export 'src/entities/entities.dart';
|
export 'src/entities/entities.dart';
|
||||||
export 'src/user_repo.dart';
|
export 'src/repositories/user_repo.dart';
|
||||||
export 'src/firebase_user_repository.dart';
|
export 'src/repositories/firebase_user_repository.dart';
|
||||||
|
|||||||
@@ -853,6 +853,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
|
otp_timer_button:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: otp_timer_button
|
||||||
|
sha256: e6516573bc31b99ae3b67f4f8f8bbe721672f6f4d04c96e493b08b5ff1afa06e
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
package_config:
|
package_config:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
+5
-4
@@ -28,9 +28,10 @@ dependencies:
|
|||||||
flutter_local_notifications: ^14.1.1
|
flutter_local_notifications: ^14.1.1
|
||||||
flutter_localizations:
|
flutter_localizations:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_otp_text_field: null
|
|
||||||
flutter_polyline_points: ^2.0.0
|
flutter_polyline_points: ^2.0.0
|
||||||
flutter_rating_bar: null
|
flutter_otp_text_field: ^1.1.1
|
||||||
|
flutter_rating_bar: ^4.0.1
|
||||||
|
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
|
||||||
geolocator: ^9.0.2
|
geolocator: ^9.0.2
|
||||||
@@ -40,8 +41,8 @@ dependencies:
|
|||||||
http: ^1.1.0
|
http: ^1.1.0
|
||||||
image_picker: ^1.0.7
|
image_picker: ^1.0.7
|
||||||
injector: ^3.0.0
|
injector: ^3.0.0
|
||||||
intl: any
|
intl_phone_field: ^3.2.0
|
||||||
intl_phone_field: null
|
intl: ^0.18.1
|
||||||
location: ^5.0.3
|
location: ^5.0.3
|
||||||
package_info_plus: ^4.2.0
|
package_info_plus: ^4.2.0
|
||||||
provider: ^6.0.5
|
provider: ^6.0.5
|
||||||
|
|||||||
Reference in New Issue
Block a user