step-26
This commit is contained in:
parent
dada50bb3c
commit
cd3aaa46af
|
@ -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;
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
});
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue