This commit is contained in:
Vandad Nahavandipoor 2022-01-08 07:33:31 +01:00
parent 094ca0a6eb
commit b4cac7331a
6 changed files with 139 additions and 190 deletions

View File

@ -1,8 +1,10 @@
import 'package:bloc/bloc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:mynotes/constants/routes.dart';
import 'package:mynotes/services/auth/auth_service.dart';
import 'package:mynotes/services/auth/bloc/auth_bloc.dart';
import 'package:mynotes/services/auth/bloc/auth_event.dart';
import 'package:mynotes/services/auth/bloc/auth_state.dart';
import 'package:mynotes/services/auth/firebase_auth_provider.dart';
import 'package:mynotes/views/login_view.dart';
import 'package:mynotes/views/notes/create_update_note_view.dart';
import 'package:mynotes/views/notes/notes_view.dart';
@ -17,7 +19,10 @@ void main() {
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const HomePage(),
home: BlocProvider<AuthBloc>(
create: (context) => AuthBloc(FirebaseAuthProvider()),
child: const HomePage(),
),
routes: {
loginRoute: (context) => const LoginView(),
registerRoute: (context) => const RegisterView(),
@ -29,173 +34,26 @@ void main() {
);
}
// class HomePage extends StatelessWidget {
// const HomePage({Key? key}) : super(key: key);
// @override
// Widget build(BuildContext context) {
// return FutureBuilder(
// future: AuthService.firebase().initialize(),
// builder: (context, snapshot) {
// switch (snapshot.connectionState) {
// case ConnectionState.done:
// final user = AuthService.firebase().currentUser;
// if (user != null) {
// if (user.isEmailVerified) {
// return const NotesView();
// } else {
// return const VerifyEmailView();
// }
// } else {
// return const LoginView();
// }
// default:
// return const CircularProgressIndicator();
// }
// },
// );
// }
// }
class HomePage extends StatefulWidget {
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
late final TextEditingController _controller;
@override
void initState() {
_controller = TextEditingController();
super.initState();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => CounterBloc(),
child: Scaffold(
appBar: AppBar(
title: const Text('Testing bloc'),
),
body: BlocConsumer<CounterBloc, CounterState>(
listener: (context, state) {
_controller.clear();
},
builder: (context, state) {
final invalidValue =
(state is CounterStateInvalidNumber) ? state.invalidValue : '';
return Column(
children: [
Text('Current value => ${state.value}'),
Visibility(
child: Text('Invalid input: $invalidValue'),
visible: state is CounterStateInvalidNumber,
),
TextField(
controller: _controller,
decoration: const InputDecoration(
hintText: 'Enter a number here',
),
keyboardType: TextInputType.number,
),
Row(
children: [
TextButton(
onPressed: () {
context
.read<CounterBloc>()
.add(DecrementEvent(_controller.text));
},
child: const Text('-'),
),
TextButton(
onPressed: () {
context
.read<CounterBloc>()
.add(IncrementEvent(_controller.text));
},
child: const Text('+'),
),
],
)
],
);
},
),
),
context.read<AuthBloc>().add(const AuthEventInitialize());
return BlocBuilder<AuthBloc, AuthState>(
builder: (context, state) {
if (state is AuthStateLoggedIn) {
return const NotesView();
} else if (state is AuthStateNeedsVerification) {
return const VerifyEmailView();
} else if (state is AuthStateLoggedOut) {
return const LoginView();
} else {
return const Scaffold(
body: CircularProgressIndicator(),
);
}
},
);
}
}
@immutable
abstract class CounterState {
final int value;
const CounterState(this.value);
}
class CounterStateValid extends CounterState {
const CounterStateValid(int value) : super(value);
}
class CounterStateInvalidNumber extends CounterState {
final String invalidValue;
const CounterStateInvalidNumber({
required this.invalidValue,
required int previousValue,
}) : super(previousValue);
}
@immutable
abstract class CounterEvent {
final String value;
const CounterEvent(this.value);
}
class IncrementEvent extends CounterEvent {
const IncrementEvent(String value) : super(value);
}
class DecrementEvent extends CounterEvent {
const DecrementEvent(String value) : super(value);
}
class CounterBloc extends Bloc<CounterEvent, CounterState> {
CounterBloc() : super(const CounterStateValid(0)) {
on<IncrementEvent>((event, emit) {
final integer = int.tryParse(event.value);
if (integer == null) {
emit(
CounterStateInvalidNumber(
invalidValue: event.value,
previousValue: state.value,
),
);
} else {
emit(CounterStateValid(state.value + integer));
}
});
on<DecrementEvent>((event, emit) {
final integer = int.tryParse(event.value);
if (integer == null) {
emit(
CounterStateInvalidNumber(
invalidValue: event.value,
previousValue: state.value,
),
);
} else {
emit(CounterStateValid(state.value - integer));
}
});
}
}

View File

@ -0,0 +1,46 @@
import 'package:bloc/bloc.dart';
import 'package:mynotes/services/auth/auth_provider.dart';
import 'package:mynotes/services/auth/bloc/auth_event.dart';
import 'package:mynotes/services/auth/bloc/auth_state.dart';
class AuthBloc extends Bloc<AuthEvent, AuthState> {
AuthBloc(AuthProvider provider) : super(const AuthStateLoading()) {
// initialize
on<AuthEventInitialize>((event, emit) async {
await provider.initialize();
final user = provider.currentUser;
if (user == null) {
emit(const AuthStateLoggedOut());
} else if (!user.isEmailVerified) {
emit(const AuthStateNeedsVerification());
} else {
emit(AuthStateLoggedIn(user));
}
});
// log in
on<AuthEventLogIn>((event, emit) async {
emit(const AuthStateLoading());
final email = event.email;
final password = event.password;
try {
final user = await provider.logIn(
email: email,
password: password,
);
emit(AuthStateLoggedIn(user));
} on Exception catch (e) {
emit(AuthStateLoginFailure(e));
}
});
// log out
on<AuthEventLogOut>((event, emit) async {
try {
emit(const AuthStateLoading());
await provider.logOut();
emit(const AuthStateLoggedOut());
} on Exception catch (e) {
emit(AuthStateLogoutFailure(e));
}
});
}
}

View File

@ -0,0 +1,20 @@
import 'package:flutter/foundation.dart' show immutable;
@immutable
abstract class AuthEvent {
const AuthEvent();
}
class AuthEventInitialize extends AuthEvent {
const AuthEventInitialize();
}
class AuthEventLogIn extends AuthEvent {
final String email;
final String password;
const AuthEventLogIn(this.email, this.password);
}
class AuthEventLogOut extends AuthEvent {
const AuthEventLogOut();
}

View File

@ -0,0 +1,34 @@
import 'package:flutter/foundation.dart' show immutable;
import 'package:mynotes/services/auth/auth_user.dart';
@immutable
abstract class AuthState {
const AuthState();
}
class AuthStateLoading extends AuthState {
const AuthStateLoading();
}
class AuthStateLoggedIn extends AuthState {
final AuthUser user;
const AuthStateLoggedIn(this.user);
}
class AuthStateLoginFailure extends AuthState {
final Exception exception;
const AuthStateLoginFailure(this.exception);
}
class AuthStateNeedsVerification extends AuthState {
const AuthStateNeedsVerification();
}
class AuthStateLoggedOut extends AuthState {
const AuthStateLoggedOut();
}
class AuthStateLogoutFailure extends AuthState {
final Exception exception;
const AuthStateLogoutFailure(this.exception);
}

View File

@ -1,8 +1,10 @@
import 'package:flutter/material.dart';
import 'package:mynotes/constants/routes.dart';
import 'package:mynotes/services/auth/auth_exceptions.dart';
import 'package:mynotes/services/auth/auth_service.dart';
import 'package:mynotes/services/auth/bloc/auth_bloc.dart';
import 'package:mynotes/services/auth/bloc/auth_event.dart';
import 'package:mynotes/utilities/dialogs/error_dialog.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class LoginView extends StatefulWidget {
const LoginView({Key? key}) : super(key: key);
@ -60,24 +62,12 @@ class _LoginViewState extends State<LoginView> {
final email = _email.text;
final password = _password.text;
try {
await AuthService.firebase().logIn(
email: email,
password: password,
);
final user = AuthService.firebase().currentUser;
if (user?.isEmailVerified ?? false) {
// user's email is verified
Navigator.of(context).pushNamedAndRemoveUntil(
notesRoute,
(route) => false,
);
} else {
// user's email is NOT verified
Navigator.of(context).pushNamedAndRemoveUntil(
verifyEmailRoute,
(route) => false,
);
}
context.read<AuthBloc>().add(
AuthEventLogIn(
email,
password,
),
);
} on UserNotFoundAuthException {
await showErrorDialog(
context,

View File

@ -2,10 +2,13 @@ import 'package:flutter/material.dart';
import 'package:mynotes/constants/routes.dart';
import 'package:mynotes/enums/menu_action.dart';
import 'package:mynotes/services/auth/auth_service.dart';
import 'package:mynotes/services/auth/bloc/auth_bloc.dart';
import 'package:mynotes/services/auth/bloc/auth_event.dart';
import 'package:mynotes/services/cloud/cloud_note.dart';
import 'package:mynotes/services/cloud/firebase_cloud_storage.dart';
import 'package:mynotes/utilities/dialogs/logout_dialog.dart';
import 'package:mynotes/views/notes/notes_list_view.dart';
import 'package:flutter_bloc/flutter_bloc.dart' show ReadContext;
class NotesView extends StatefulWidget {
const NotesView({Key? key}) : super(key: key);
@ -42,11 +45,9 @@ class _NotesViewState extends State<NotesView> {
case MenuAction.logout:
final shouldLogout = await showLogOutDialog(context);
if (shouldLogout) {
await AuthService.firebase().logOut();
Navigator.of(context).pushNamedAndRemoveUntil(
loginRoute,
(_) => false,
);
context.read<AuthBloc>().add(
const AuthEventLogOut(),
);
}
}
},