This commit is contained in:
Felipe
2024-02-16 11:14:01 -05:00
parent 9ca2b62be3
commit d9d6b50d78
15 changed files with 452 additions and 294 deletions
+31 -6
View File
@@ -1,19 +1,44 @@
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/my_user_bloc/my_user_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/blocs/update_user_info_bloc/update_user_info_bloc.dart';
import 'package:prosappco/screens/home/home_screen.dart';
import 'package:user_repository/user_repository.dart';
import 'app_view.dart';
class MainApp extends StatelessWidget {
final UserRepository userRepository;
const MainApp(this.userRepository, {super.key});
const MainApp({super.key});
@override
Widget build(BuildContext context) {
return MultiRepositoryProvider(providers: [
RepositoryProvider<AuthenticationBloc>(
create: (_) => AuthenticationBloc(myUserRepository: userRepository))
], child: const MyAppView());
return MultiBlocProvider(
providers: [
BlocProvider<AuthenticationBloc>(
create: (context) => Injector.appInstance.get<AuthenticationBloc>(),
),
BlocProvider<MyUserBloc>(
create: (context) => Injector.appInstance.get<MyUserBloc>(),
),
BlocProvider<UpdateUserInfoBloc>(
create: (context) => Injector.appInstance.get<UpdateUserInfoBloc>(),
),
BlocProvider<SignInBloc>(
create: (context) => Injector.appInstance.get<SignInBloc>(),
),
BlocProvider<SignUpBloc>(
create: (context) => Injector.appInstance.get<SignUpBloc>(),
)
// RepositoryProvider<AuthenticationBloc>(
// create: (_) => AuthenticationBloc(myUserRepository: userRepository),
// ),
],
child: BlocBuilder<MyUserBloc, MyUserState>(builder: (context, state) {
return const MyAppView();
}));
}
}
+24 -23
View File
@@ -32,29 +32,30 @@ class MyAppView extends StatelessWidget {
home: BlocBuilder<AuthenticationBloc, AuthenticationState>(
builder: (context, state) {
if (state.status == AuthenticationStatus.authenticated) {
return MultiBlocProvider(
providers: [
BlocProvider(
create: (context) => SignInBloc(
userRepository:
context.read<AuthenticationBloc>().userRepository),
),
BlocProvider(
create: (context) => UpdateUserInfoBloc(
userRepository:
context.read<AuthenticationBloc>().userRepository),
),
BlocProvider(
create: (context) => MyUserBloc(
myUserRepository:
context.read<AuthenticationBloc>().userRepository)
..add(GetMyUser(
myUserId:
context.read<AuthenticationBloc>().state.user!.uid)),
),
],
child: const HomeScreen(),
);
// MultiBlocProvider(
// providers: [
// BlocProvider(
// create: (context) => SignInBloc(
// userRepository:
// context.read<AuthenticationBloc>().userRepository),
// ),
// BlocProvider(
// create: (context) => UpdateUserInfoBloc(
// userRepository:
// context.read<AuthenticationBloc>().userRepository),
// ),
// BlocProvider(
// create: (context) => MyUserBloc(
// myUserRepository:
// context.read<AuthenticationBloc>().userRepository)
// ..add(GetMyUser(
// myUserId:
// context.read<AuthenticationBloc>().state.user!.uid)),
// ),
// ],
// child: const HomeScreen(),
// );
return const HomeScreen();
} else {
return const WelcomeScreen();
}
@@ -12,12 +12,12 @@ part 'authentication_state.dart';
class AuthenticationBloc
extends Bloc<AuthenticationEvent, AuthenticationState> {
final UserRepository userRepository;
late final StreamSubscription<User?> _userSubscription;
late final StreamSubscription<MyUser?> _userSubscription;
AuthenticationBloc({required UserRepository myUserRepository})
: userRepository = myUserRepository,
super(const AuthenticationState.unknown()) {
_userSubscription = userRepository.user.listen((authUser) {
_userSubscription = userRepository.streamUser().listen((authUser) {
add(AuthenticationUserChanged(authUser));
});
on<AuthenticationUserChanged>((event, emit) {
@@ -11,7 +11,7 @@ abstract class AuthenticationEvent extends Equatable {
class AuthenticationUserChanged extends AuthenticationEvent {
const AuthenticationUserChanged(this.user);
final User? user;
final MyUser? user;
}
class AuthenticationLogoutRequested extends AuthenticationEvent {}
@@ -4,7 +4,7 @@ enum AuthenticationStatus { authenticated, unauthenticated, unknown }
class AuthenticationState extends Equatable {
final AuthenticationStatus status;
final User? user;
final MyUser? user;
const AuthenticationState._({
this.status = AuthenticationStatus.unknown,
@@ -13,7 +13,7 @@ class AuthenticationState extends Equatable {
const AuthenticationState.unknown() : this._();
const AuthenticationState.authenticated(User user)
const AuthenticationState.authenticated(MyUser user)
: this._(status: AuthenticationStatus.authenticated, user: user);
const AuthenticationState.unauthenticated()
+56 -7
View File
@@ -1,3 +1,6 @@
import 'dart:async';
import 'dart:developer';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:user_repository/user_repository.dart';
@@ -11,16 +14,62 @@ class MyUserBloc extends Bloc<MyUserEvent, MyUserState> {
MyUserBloc({required UserRepository myUserRepository})
: _userRepository = myUserRepository,
super(const MyUserState.loading()) {
on<GetMyUser>(_onGetMyUser);
_userRepository.streamUser().listen((event) {
log('xd ---: ${event}');
if (event == null) {
log('UserChanged: ${event}');
emit(const MyUserState.failure());
} else {
log('UserChanged: ${event}');
emit(MyUserState.success(event!));
}
});
// on<UserChanged>(_onUserChanged);
// _userRepository.user.first.then((user) {
// log('xd: ${user}');
// if (user != null) {
// add(UserChanged(user: user));
// _userSubscription = _userRepository.user.listen((user) {
// log('xd: ${user}');
// add(UserChanged(user: user));
// });
// }
// }).catchError((e) {
// log('xd: ${e}');
// add(UserChanged(user: null));
// });
// on<GetMyUser>(_onGetMyUser);
// _userRepository.user.listen((user) {
// if (user != null) {
// add(GetMyUser(myUserId: user.uid));
// }
// });
// emit(MyUserState.success(MyUser(
// name: 'John', id: '123', email: 'johndoe@gmail.com', picture: '')));
}
void _onGetMyUser(GetMyUser event, Emitter<MyUserState> emit) async {
emit(const MyUserState.loading());
try {
MyUser myUser = await _userRepository.getMyUser(event.myUserId);
emit(MyUserState.success(myUser));
} catch (e) {
void _onUserChanged(UserChanged event, Emitter<MyUserState> emit) {
log('UserChanged: ${event.user}');
if (event.user == null) {
log('UserChanged: ${event.user}');
emit(const MyUserState.failure());
} else {
log('UserChanged: ${event.user}');
emit(MyUserState.success(event.user!));
}
}
// void _onGetMyUser(GetMyUser event, Emitter<MyUserState> emit) async {
// log('GetMyUser: ${event.myUserId}');
// emit(const MyUserState.loading());
// try {
// MyUser myUser = await _userRepository.getMyUser(event.myUserId);
// log('GetMyUser: $myUser');
// emit(MyUserState.success(myUser));
// } catch (e) {
// log('GetMyUser: $e');
// emit(const MyUserState.failure());
// }
// }
}
+14 -5
View File
@@ -4,14 +4,23 @@ abstract class MyUserEvent extends Equatable {
const MyUserEvent();
@override
List<Object> get props => [];
List<Object?> get props => [];
}
class GetMyUser extends MyUserEvent {
final String myUserId;
// class GetMyUser extends MyUserEvent {
// final String myUserId;
const GetMyUser({required this.myUserId});
// const GetMyUser({required this.myUserId});
// @override
// List<Object> get props => [myUserId];
// }
class UserChanged extends MyUserEvent {
final MyUser? user;
const UserChanged({required this.user});
@override
List<Object> get props => [myUserId];
List<Object?> get props => [user];
}
+32
View File
@@ -0,0 +1,32 @@
import 'package:firebase_auth/firebase_auth.dart';
import 'package:injector/injector.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/sign_up_bloc/sign_up_bloc.dart';
import 'package:prosappco/blocs/sing_in_bloc/sign_in_bloc.dart';
import 'package:prosappco/blocs/update_user_info_bloc/update_user_info_bloc.dart';
import 'package:user_repository/user_repository.dart';
class UserDI {
void register() {
final injector = Injector.appInstance;
injector.registerSingleton<UserRepository>(
(() => FirebaseUserRepository(FirebaseAuth.instance)));
injector.registerSingleton<AuthenticationBloc>((() =>
AuthenticationBloc(myUserRepository: injector.get<UserRepository>())));
injector.registerSingleton<MyUserBloc>(
(() => MyUserBloc(myUserRepository: injector.get<UserRepository>())));
injector.registerSingleton<UpdateUserInfoBloc>((() =>
UpdateUserInfoBloc(userRepository: injector.get<UserRepository>())));
injector.registerSingleton<SignInBloc>(
(() => SignInBloc(userRepository: injector.get<UserRepository>())));
injector.registerSingleton<SignUpBloc>(
(() => SignUpBloc(userRepository: injector.get<UserRepository>())));
}
}
+3 -1
View File
@@ -173,6 +173,7 @@ import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:prosappco/dependency_user/user_di.dart';
import 'package:user_repository/user_repository.dart';
import 'app.dart';
import 'simple_bloc_observer.dart';
@@ -182,5 +183,6 @@ void main() async {
await Firebase.initializeApp();
Bloc.observer = SimpleBlocObserver();
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
runApp(MainApp(FirebaseUserRepository()));
UserDI().register();
runApp(const MainApp());
}
+101 -97
View File
@@ -1,7 +1,6 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:image_picker/image_picker.dart';
import 'package:prosappco/blocs/my_user_bloc/my_user_bloc.dart';
import 'package:prosappco/blocs/sing_in_bloc/sign_in_bloc.dart';
import 'package:prosappco/blocs/update_user_info_bloc/update_user_info_bloc.dart';
@@ -26,114 +25,119 @@ class _HomeScreenState extends State<HomeScreen> {
}
},
child: Scaffold(
backgroundColor: Theme.of(context).colorScheme.background,
drawer: BlocBuilder<MyUserBloc, MyUserState>(builder: (context, state) {
if (state.status == MyUserStatus.success) {
return Drawer(
backgroundColor: Theme.of(context).colorScheme.background,
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Material(
color: Theme.of(context).colorScheme.primary,
child: InkWell(
onTap: () {
Navigator.push(
context,
CupertinoPageRoute(
builder: (context) => const ProfileScreen(),
backgroundColor: Theme.of(context).colorScheme.background,
drawer:
BlocBuilder<MyUserBloc, MyUserState>(builder: (context, state) {
if (state.status == MyUserStatus.success) {
return Drawer(
backgroundColor: Theme.of(context).colorScheme.background,
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Material(
color: Theme.of(context).colorScheme.primary,
child: InkWell(
onTap: () {
Navigator.push(
context,
CupertinoPageRoute(
builder: (context) => const ProfileScreen(),
),
);
},
child: Container(
padding: EdgeInsets.only(
top: 20 + MediaQuery.of(context).padding.top,
bottom: 20,
),
);
},
child: Container(
padding: EdgeInsets.only(
top: 20 + MediaQuery.of(context).padding.top,
bottom: 20,
),
child: Column(
children: [
state.user!.picture == ""
? Container(
width: 80,
height: 80,
decoration: BoxDecoration(
color: Colors.grey.shade300,
shape: BoxShape.circle,
),
child: Icon(
CupertinoIcons.person,
color: Colors.grey.shade400,
size: 35,
),
)
: Container(
width: 80,
height: 80,
decoration: BoxDecoration(
color: Colors.grey,
shape: BoxShape.circle,
image: DecorationImage(
image: NetworkImage(
state.user!.picture!,
child: Column(
children: [
state.user!.picture == ""
? Container(
width: 80,
height: 80,
decoration: BoxDecoration(
color: Colors.grey.shade300,
shape: BoxShape.circle,
),
child: Icon(
CupertinoIcons.person,
color: Colors.grey.shade400,
size: 35,
),
)
: Container(
width: 80,
height: 80,
decoration: BoxDecoration(
color: Colors.grey,
shape: BoxShape.circle,
image: DecorationImage(
image: NetworkImage(
state.user!.picture!,
),
fit: BoxFit.cover,
),
fit: BoxFit.cover,
),
),
),
const SizedBox(height: 12),
Text(
context.read<MyUserBloc>().state.user!.name,
style: const TextStyle(
fontSize: 24,
color: Colors.white,
const SizedBox(height: 12),
Text(
state.user!.name,
style: const TextStyle(
fontSize: 24,
color: Colors.white,
),
),
),
Text(
state.user!.email,
style: const TextStyle(
fontSize: 15,
color: Colors.white,
),
)
],
Text(
state.user!.email,
style: const TextStyle(
fontSize: 15,
color: Colors.white,
),
)
],
),
),
),
),
),
Container(
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',
),
)
],
),
)
],
Container(
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',
),
)
],
),
)
],
),
),
),
);
} else {
return Drawer(
);
} else {
return Drawer(
backgroundColor: Theme.of(context).colorScheme.background,
child: const Center(
child: CircularProgressIndicator(),
));
}
}),
appBar: AppBar(),
body: const Placeholder(),
),
),
);
}
}),
appBar: AppBar(),
body: Center(
child: Text(
context.read<MyUserBloc>().state.user?.name ?? 'null',
),
)),
);
}
}
+140 -139
View File
@@ -17,153 +17,154 @@ class ProfileScreen extends StatefulWidget {
class _ProfileScreenState extends State<ProfileScreen> {
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider(
create: (context) => MyUserBloc(
myUserRepository:
context.read<AuthenticationBloc>().userRepository)
..add(GetMyUser(
myUserId: context.read<AuthenticationBloc>().state.user!.uid)),
),
BlocProvider(
create: (context) => UpdateUserInfoBloc(
userRepository: context.read<AuthenticationBloc>().userRepository,
),
)
],
child: BlocListener<UpdateUserInfoBloc, UpdateUserInfoState>(
listener: (context, state) {
if (state is UploadPictureSuccess) {
setState(() {
context.read<MyUserBloc>().state.user!.picture = state.userImage;
});
}
},
child: Scaffold(
appBar: PopAppbar(
onPressed: () {
Navigator.pop(context);
},
label: 'Perfil',
),
body:
BlocBuilder<MyUserBloc, MyUserState>(builder: (context, state) {
if (state.status == MyUserStatus.success) {
return Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
GestureDetector(
onTap: () async {
final ImagePicker picker = ImagePicker();
final XFile? image = await picker.pickImage(
source: ImageSource.gallery,
maxHeight: 500,
maxWidth: 500,
imageQuality: 40,
);
return
if (image != null) {
context.read<UpdateUserInfoBloc>().add(
UploadPicture(image.path, state.user!.id),
);
}
},
child: state.user!.picture == ""
? Container(
width: 120,
height: 120,
decoration: BoxDecoration(
color: Colors.grey.shade300,
shape: BoxShape.circle,
),
child: Icon(
CupertinoIcons.person,
color: Colors.grey.shade400,
size: 40,
),
)
: Container(
width: 120,
height: 120,
decoration: BoxDecoration(
color: Colors.grey,
shape: BoxShape.circle,
image: DecorationImage(
image: NetworkImage(
state.user!.picture!,
),
fit: BoxFit.cover,
// MultiBlocProvider(
// providers: [
// BlocProvider(
// create: (context) => MyUserBloc(
// myUserRepository:
// context.read<AuthenticationBloc>().userRepository)
// ..add(GetMyUser(
// myUserId: context.read<AuthenticationBloc>().state.user!.uid)),
// ),
// BlocProvider(
// create: (context) => UpdateUserInfoBloc(
// userRepository: context.read<AuthenticationBloc>().userRepository,
// ),
// )
// ],
// child:
BlocListener<UpdateUserInfoBloc, UpdateUserInfoState>(
listener: (context, state) {
if (state is UploadPictureSuccess) {
setState(() {
context.read<MyUserBloc>().state.user!.picture = state.userImage;
});
}
},
child: Scaffold(
appBar: PopAppbar(
onPressed: () {
Navigator.pop(context);
},
label: 'Perfil',
),
body: BlocBuilder<MyUserBloc, MyUserState>(builder: (context, state) {
if (state.status == MyUserStatus.success) {
return Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
GestureDetector(
onTap: () async {
final ImagePicker picker = ImagePicker();
final XFile? image = await picker.pickImage(
source: ImageSource.gallery,
maxHeight: 500,
maxWidth: 500,
imageQuality: 40,
);
if (image != null) {
context.read<UpdateUserInfoBloc>().add(
UploadPicture(image.path, state.user!.id),
);
}
},
child: state.user!.picture == ""
? Container(
width: 120,
height: 120,
decoration: BoxDecoration(
color: Colors.grey.shade300,
shape: BoxShape.circle,
),
child: Icon(
CupertinoIcons.person,
color: Colors.grey.shade400,
size: 40,
),
)
: Container(
width: 120,
height: 120,
decoration: BoxDecoration(
color: Colors.grey,
shape: BoxShape.circle,
image: DecorationImage(
image: NetworkImage(
state.user!.picture!,
),
fit: BoxFit.cover,
),
),
),
const SizedBox(height: 20.0),
TextFormField(
initialValue: state.user?.name,
decoration: const InputDecoration(
labelText: 'Nombre',
prefixIcon: Icon(Icons.person),
hintText: 'Nombre (obligatorio)',
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(25.0),
)),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.red),
),
focusedErrorBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Colors.red, width: 2.0),
),
),
),
const SizedBox(height: 20.0),
TextFormField(
initialValue: state.user?.name,
decoration: const InputDecoration(
labelText: 'Nombre',
prefixIcon: Icon(Icons.person),
hintText: 'Nombre (obligatorio)',
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(25.0),
)),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.red),
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Por favor, ingrese su nombre';
}
return null;
},
),
const SizedBox(height: 20.0),
TextFormField(
initialValue: state.user?.email,
decoration: const InputDecoration(
labelText: 'Nombre',
prefixIcon: Icon(Icons.person),
hintText: 'Nombre (obligatorio)',
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(25.0),
)),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.red),
),
focusedErrorBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Colors.red, width: 2.0),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.red, width: 2.0),
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Por favor, ingrese su nombre';
}
return null;
},
),
ElevatedButton(
onPressed: () {},
child: const Text('Guardar'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Por favor, ingrese su nombre';
}
return null;
},
),
const SizedBox(height: 20.0),
TextFormField(
initialValue: state.user?.email,
decoration: const InputDecoration(
labelText: 'Nombre',
prefixIcon: Icon(Icons.person),
hintText: 'Nombre (obligatorio)',
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(25.0),
)),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.red),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.red, width: 2.0),
),
),
],
),
);
} else {
return const Center(child: CircularProgressIndicator());
}
})),
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Por favor, ingrese su nombre';
}
return null;
},
),
ElevatedButton(
onPressed: () {},
child: const Text('Guardar'),
),
],
),
);
} else {
return const Center(child: CircularProgressIndicator());
}
})),
// ),
);
}
}
@@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:developer';
import 'dart:io';
@@ -9,21 +10,46 @@ import 'entities/entities.dart';
import 'user_repo.dart';
class FirebaseUserRepository implements UserRepository {
FirebaseUserRepository({
FirebaseAuth? firebaseAuth,
}) : _firebaseAuth = firebaseAuth ?? FirebaseAuth.instance;
final FirebaseAuth _firebaseAuth;
final usersCollection = FirebaseFirestore.instance.collection('users');
final StreamController<MyUser?> _userStreamController =
StreamController<MyUser?>.broadcast();
@override
Stream<User?> get user {
return _firebaseAuth.authStateChanges().map((firebaseUser) {
final user = firebaseUser;
return user;
FirebaseUserRepository(this._firebaseAuth) {
_firebaseAuth.userChanges().listen((user) async {
if (user != null) {
try {
final myUser = await getMyUser(user.uid);
_userStreamController.add(myUser);
} catch (e) {
log('Error en FirebaseUserRepository ${e.toString()}');
_userStreamController.add(null);
}
} else {
_userStreamController.add(null);
}
});
this.streamUser().listen((event) {
log('xd - : ${event}');
});
}
// Stream<MyUser?> get user => _userStreamController.stream;
@override
Stream<MyUser?> streamUser() {
return _userStreamController.stream;
}
// @override
// Stream<User?> get user {
// return _firebaseAuth.authStateChanges().map((firebaseUser) {
// final user = firebaseUser;
// return user;
// });
// }
// Sign up
@override
Future<MyUser> signUp(MyUser myUser, String password) async {
@@ -3,7 +3,8 @@ import 'package:firebase_auth/firebase_auth.dart';
import '../user_repository.dart';
abstract class UserRepository {
Stream<User?> get user;
// Stream<User?> get user;
Stream<MyUser?> streamUser();
Future<void> signIn(String email, String password);
+8
View File
@@ -741,6 +741,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.2.1+1"
injector:
dependency: "direct main"
description:
name: injector
sha256: ed389bed5b48a699d5b9561c985023d0d5cc88dd5ff2237aadcce5a5ab433e4e
url: "https://pub.dev"
source: hosted
version: "3.0.0"
intl:
dependency: "direct main"
description:
+1 -1
View File
@@ -39,6 +39,7 @@ dependencies:
google_sign_in: ^6.1.4
http: ^1.1.0
image_picker: ^1.0.7
injector: ^3.0.0
intl: any
intl_phone_field: null
location: ^5.0.3
@@ -60,7 +61,6 @@ dev_dependencies:
sdk: flutter
flutter:
uses-material-design: true
assets: