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/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:loader_overlay/loader_overlay.dart';
import '../application/auth/auth_bloc.dart'; import '../application/auth/auth_bloc.dart';
import '../application/language/language_bloc.dart'; import '../application/language/language_bloc.dart';
@ -7,6 +8,7 @@ import '../common/theme/theme.dart';
import '../common/constant/app_constant.dart'; import '../common/constant/app_constant.dart';
import '../injection.dart'; import '../injection.dart';
import '../l10n/app_localizations.dart'; import '../l10n/app_localizations.dart';
import 'components/loading/loading_overlay.dart';
import 'router/app_router.dart'; import 'router/app_router.dart';
import 'router/app_router_observer.dart'; import 'router/app_router_observer.dart';
@ -27,6 +29,10 @@ class _AppWidgetState extends State<AppWidget> {
BlocProvider(create: (context) => getIt<LanguageBloc>()), BlocProvider(create: (context) => getIt<LanguageBloc>()),
BlocProvider(create: (context) => getIt<AuthBloc>()), BlocProvider(create: (context) => getIt<AuthBloc>()),
], ],
child: GlobalLoaderOverlay(
useDefaultLoading: false,
overlayWidgetBuilder: (progress) => LoadingOverlay(),
overlayColor: AppColor.black.withOpacity(0.35),
child: BlocBuilder<LanguageBloc, LanguageState>( child: BlocBuilder<LanguageBloc, LanguageState>(
builder: (context, state) { builder: (context, state) {
return MaterialApp.router( return MaterialApp.router(
@ -37,11 +43,14 @@ class _AppWidgetState extends State<AppWidget> {
localizationsDelegates: AppLocalizations.localizationsDelegates, localizationsDelegates: AppLocalizations.localizationsDelegates,
theme: ThemeApp.theme, theme: ThemeApp.theme,
routerConfig: _appRouter.config( routerConfig: _appRouter.config(
navigatorObservers: () => <NavigatorObserver>[AppRouteObserver()], 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/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:line_icons/line_icons.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 '../../../application/auth/logout_form/logout_form_bloc.dart';
import '../../../common/theme/theme.dart'; import '../../../common/theme/theme.dart';
@ -23,7 +24,9 @@ class ProfilePage extends StatelessWidget implements AutoRouteWrapper {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocListener<LogoutFormBloc, LogoutFormState>( return MultiBlocListener(
listeners: [
BlocListener<LogoutFormBloc, LogoutFormState>(
listener: (context, state) { listener: (context, state) {
state.failureOrAuthOption.fold( state.failureOrAuthOption.fold(
() => null, () => null,
@ -33,6 +36,19 @@ class ProfilePage extends StatelessWidget implements AutoRouteWrapper {
), ),
); );
}, },
),
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( child: Scaffold(
backgroundColor: AppColor.background, backgroundColor: AppColor.background,
body: CustomScrollView( body: CustomScrollView(

View File

@ -73,6 +73,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.0" 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: bloc:
dependency: transitive dependency: transitive
description: description:
@ -741,6 +749,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.1.1" 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: logging:
dependency: transitive dependency: transitive
description: description:

View File

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