feat: global loading overlay

This commit is contained in:
efrilm 2025-08-16 19:47:40 +07:00
parent f138e1dcc9
commit 5387d7b7a6
5 changed files with 89 additions and 24 deletions

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:loader_overlay/loader_overlay.dart';
import '../application/auth/auth_bloc.dart';
import '../application/language/language_bloc.dart';
@ -7,6 +8,7 @@ import '../common/theme/theme.dart';
import '../common/constant/app_constant.dart';
import '../injection.dart';
import '../l10n/app_localizations.dart';
import 'components/loading/loading_overlay.dart';
import 'router/app_router.dart';
import 'router/app_router_observer.dart';
@ -27,20 +29,27 @@ class _AppWidgetState extends State<AppWidget> {
BlocProvider(create: (context) => getIt<LanguageBloc>()),
BlocProvider(create: (context) => getIt<AuthBloc>()),
],
child: BlocBuilder<LanguageBloc, LanguageState>(
builder: (context, state) {
return MaterialApp.router(
debugShowCheckedModeBanner: false,
title: AppConstant.appName,
locale: state.language.locale,
supportedLocales: AppLocalizations.supportedLocales,
localizationsDelegates: AppLocalizations.localizationsDelegates,
theme: ThemeApp.theme,
routerConfig: _appRouter.config(
navigatorObservers: () => <NavigatorObserver>[AppRouteObserver()],
),
);
},
child: GlobalLoaderOverlay(
useDefaultLoading: false,
overlayWidgetBuilder: (progress) => LoadingOverlay(),
overlayColor: AppColor.black.withOpacity(0.35),
child: BlocBuilder<LanguageBloc, LanguageState>(
builder: (context, state) {
return MaterialApp.router(
debugShowCheckedModeBanner: false,
title: AppConstant.appName,
locale: state.language.locale,
supportedLocales: AppLocalizations.supportedLocales,
localizationsDelegates: AppLocalizations.localizationsDelegates,
theme: ThemeApp.theme,
routerConfig: _appRouter.config(
navigatorObservers: () => <NavigatorObserver>[
AppRouteObserver(),
],
),
);
},
),
),
);
}

View File

@ -0,0 +1,23 @@
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import '../../../common/theme/theme.dart';
class LoadingOverlay extends StatelessWidget {
const LoadingOverlay({super.key});
@override
Widget build(BuildContext context) {
return Center(
child: Container(
width: 64,
height: 64,
decoration: BoxDecoration(
color: AppColor.white,
borderRadius: BorderRadius.circular(AppValue.radius),
),
child: SpinKitCircle(color: AppColor.primary, size: 32.0),
),
);
}
}

View File

@ -2,6 +2,7 @@ import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:line_icons/line_icons.dart';
import 'package:loader_overlay/loader_overlay.dart';
import '../../../application/auth/logout_form/logout_form_bloc.dart';
import '../../../common/theme/theme.dart';
@ -23,16 +24,31 @@ class ProfilePage extends StatelessWidget implements AutoRouteWrapper {
@override
Widget build(BuildContext context) {
return BlocListener<LogoutFormBloc, LogoutFormState>(
listener: (context, state) {
state.failureOrAuthOption.fold(
() => null,
(either) => either.fold(
(f) => AppFlushbar.showAuthFailureToast(context, f),
(_) => context.router.replace(const LoginRoute()),
),
);
},
return MultiBlocListener(
listeners: [
BlocListener<LogoutFormBloc, LogoutFormState>(
listener: (context, state) {
state.failureOrAuthOption.fold(
() => null,
(either) => either.fold(
(f) => AppFlushbar.showAuthFailureToast(context, f),
(_) => context.router.replace(const LoginRoute()),
),
);
},
),
BlocListener<LogoutFormBloc, LogoutFormState>(
listenWhen: (previous, current) =>
previous.isSubmitting != current.isSubmitting,
listener: (context, state) {
if (state.isSubmitting) {
context.loaderOverlay.show();
} else {
context.loaderOverlay.hide();
}
},
),
],
child: Scaffold(
backgroundColor: AppColor.background,
body: CustomScrollView(

View File

@ -73,6 +73,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.3.0"
back_button_interceptor:
dependency: transitive
description:
name: back_button_interceptor
sha256: b85977faabf4aeb95164b3b8bf81784bed4c54ea1aef90a036ab6927ecf80c5a
url: "https://pub.dev"
source: hosted
version: "8.0.4"
bloc:
dependency: transitive
description:
@ -741,6 +749,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.1.1"
loader_overlay:
dependency: "direct main"
description:
name: loader_overlay
sha256: "285c9ccab9a42a392ba948bd0b14376fd0ee9ddd7b63e3018bcd54460fd3e021"
url: "https://pub.dev"
source: hosted
version: "5.0.0"
logging:
dependency: transitive
description:

View File

@ -39,6 +39,7 @@ dependencies:
image_picker: ^1.1.2
table_calendar: ^3.2.0
package_info_plus: ^8.3.1
loader_overlay: ^5.0.0
dev_dependencies:
flutter_test: