This commit is contained in:
Vandad Nahavandipoor 2022-01-10 07:22:45 +01:00
parent dada50bb3c
commit cd3aaa46af
6 changed files with 173 additions and 28 deletions

View File

@ -0,0 +1,104 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:mynotes/helpers/loading/loading_screen_controller.dart';
class LoadingScreen {
factory LoadingScreen() => _shared;
static final LoadingScreen _shared = LoadingScreen._sharedInstance();
LoadingScreen._sharedInstance();
LoadingScreenController? controller;
void show({
required BuildContext context,
required String text,
}) {
if (controller?.update(text) ?? false) {
return;
} else {
controller = showOverlay(
context: context,
text: text,
);
}
}
void hide() {
controller?.close();
controller = null;
}
LoadingScreenController showOverlay({
required BuildContext context,
required String text,
}) {
final _text = StreamController<String>();
_text.add(text);
final state = Overlay.of(context);
final renderBox = context.findRenderObject() as RenderBox;
final size = renderBox.size;
final overlay = OverlayEntry(
builder: (context) {
return Material(
color: Colors.black.withAlpha(150),
child: Center(
child: Container(
constraints: BoxConstraints(
maxWidth: size.width * 0.8,
maxHeight: size.height * 0.8,
minWidth: size.width * 0.5,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10.0),
),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(height: 10),
const CircularProgressIndicator(),
const SizedBox(height: 20),
StreamBuilder(
stream: _text.stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(
snapshot.data as String,
textAlign: TextAlign.center,
);
} else {
return Container();
}
},
),
],
),
),
)),
),
);
},
);
state?.insert(overlay);
return LoadingScreenController(
close: () {
_text.close();
overlay.remove();
return true;
},
update: (text) {
_text.add(text);
return true;
},
);
}
}

View File

@ -0,0 +1,15 @@
import 'package:flutter/foundation.dart' show immutable;
typedef CloseLoadingScreen = bool Function();
typedef UpdateLoadingScreen = bool Function(String text);
@immutable
class LoadingScreenController {
final CloseLoadingScreen close;
final UpdateLoadingScreen update;
const LoadingScreenController({
required this.close,
required this.update,
});
}

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:mynotes/constants/routes.dart';
import 'package:mynotes/helpers/loading/loading_screen.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';
@ -36,7 +37,17 @@ class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
context.read<AuthBloc>().add(const AuthEventInitialize());
return BlocBuilder<AuthBloc, AuthState>(
return BlocConsumer<AuthBloc, AuthState>(
listener: (context, state) {
if (state.isLoading) {
LoadingScreen().show(
context: context,
text: state.loadingText ?? 'Please wait a moment',
);
} else {
LoadingScreen().hide();
}
},
builder: (context, state) {
if (state is AuthStateLoggedIn) {
return const NotesView();

View File

@ -4,7 +4,8 @@ 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 AuthStateUninitialized()) {
AuthBloc(AuthProvider provider)
: super(const AuthStateUninitialized(isLoading: true)) {
// send email verification
on<AuthEventSendEmailVerification>((event, emit) async {
await provider.sendEmailVerification();
@ -19,9 +20,12 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
password: password,
);
await provider.sendEmailVerification();
emit(const AuthStateNeedsVerification());
emit(const AuthStateNeedsVerification(isLoading: false));
} on Exception catch (e) {
emit(AuthStateRegistering(e));
emit(AuthStateRegistering(
exception: e,
isLoading: false,
));
}
});
// initialize
@ -36,9 +40,12 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
),
);
} else if (!user.isEmailVerified) {
emit(const AuthStateNeedsVerification());
emit(const AuthStateNeedsVerification(isLoading: false));
} else {
emit(AuthStateLoggedIn(user));
emit(AuthStateLoggedIn(
user: user,
isLoading: false,
));
}
});
// log in
@ -47,6 +54,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
const AuthStateLoggedOut(
exception: null,
isLoading: true,
loadingText: 'Please wait while I log you in',
),
);
final email = event.email;
@ -64,7 +72,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
isLoading: false,
),
);
emit(const AuthStateNeedsVerification());
emit(const AuthStateNeedsVerification(isLoading: false));
} else {
emit(
const AuthStateLoggedOut(
@ -72,7 +80,10 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
isLoading: false,
),
);
emit(AuthStateLoggedIn(user));
emit(AuthStateLoggedIn(
user: user,
isLoading: false,
));
}
} on Exception catch (e) {
emit(

View File

@ -4,34 +4,50 @@ import 'package:equatable/equatable.dart';
@immutable
abstract class AuthState {
const AuthState();
final bool isLoading;
final String? loadingText;
const AuthState({
required this.isLoading,
this.loadingText = 'Please wait a moment',
});
}
class AuthStateUninitialized extends AuthState {
const AuthStateUninitialized();
const AuthStateUninitialized({required bool isLoading})
: super(isLoading: isLoading);
}
class AuthStateRegistering extends AuthState {
final Exception? exception;
const AuthStateRegistering(this.exception);
const AuthStateRegistering({
required this.exception,
required isLoading,
}) : super(isLoading: isLoading);
}
class AuthStateLoggedIn extends AuthState {
final AuthUser user;
const AuthStateLoggedIn(this.user);
const AuthStateLoggedIn({
required this.user,
required bool isLoading,
}) : super(isLoading: isLoading);
}
class AuthStateNeedsVerification extends AuthState {
const AuthStateNeedsVerification();
const AuthStateNeedsVerification({required bool isLoading})
: super(isLoading: isLoading);
}
class AuthStateLoggedOut extends AuthState with EquatableMixin {
final Exception? exception;
final bool isLoading;
const AuthStateLoggedOut({
required this.exception,
required this.isLoading,
});
required bool isLoading,
String? loadingText,
}) : super(
isLoading: isLoading,
loadingText: loadingText,
);
@override
List<Object?> get props => [exception, isLoading];

View File

@ -18,7 +18,6 @@ class LoginView extends StatefulWidget {
class _LoginViewState extends State<LoginView> {
late final TextEditingController _email;
late final TextEditingController _password;
CloseDialog? _closeDialogHandle;
@override
void initState() {
@ -39,17 +38,6 @@ class _LoginViewState extends State<LoginView> {
return BlocListener<AuthBloc, AuthState>(
listener: (context, state) async {
if (state is AuthStateLoggedOut) {
final closeDialog = _closeDialogHandle;
if (!state.isLoading && closeDialog != null) {
closeDialog();
_closeDialogHandle = null;
} else if (state.isLoading && closeDialog == null) {
_closeDialogHandle = showLoadingDialog(
context: context,
text: 'Loading...',
);
}
if (state.exception is UserNotFoundAuthException) {
await showErrorDialog(context, 'User not found');
} else if (state.exception is WrongPasswordAuthException) {