feat(bloc): add init function and multi provider

This commit is contained in:
Hugo Pointcheval 2022-10-17 19:56:23 -04:00
parent b99664856d
commit 2807582a16
Signed by: hugo
GPG Key ID: A9E8E9615379254F
6 changed files with 145 additions and 15 deletions

View File

@ -28,7 +28,7 @@ import 'package:wyatt_bloc_helper/src/utils/smart_provider.dart';
/// It automatically handles closing the instance when used with [create].
/// By default, [create] is called only when the instance is accessed.
/// To override this behavior, set [lazy] to `false`.
///
///
/// By default, it provide already provided instance found in the tree.
/// To override this behavior, set [smart] to `false`.
/// {@endtemplate}
@ -47,13 +47,21 @@ abstract class BlocBaseProviderScreen<Bloc extends BlocBase<State>,
final bool lazy;
/// Whether this uses [SmartProvider].
/// Defaults to `true`. But if you want to provide new [Bloc] or [Cubit]
/// Defaults to `true`. But if you want to provide new [Bloc] or [Cubit]
/// of a same type in a sub-tree you may have to disable this.
final bool smart;
/// Creates the [Bloc] or [Cubit] to be used.
Bloc create(BuildContext context);
/// Initialize the [Bloc] or [Cubit].
///
/// This function is useful when using with [SmartProvider], because
/// if you want to pass an initial event to your bloc you can pass it in
/// `create` function but if you re-use the bloc below in the tree this event
/// will never be re-pass.
Bloc init(BuildContext context, Bloc bloc) => bloc;
/// Creates the child [Widget] to be used.
Widget builder(BuildContext context);
@ -63,6 +71,7 @@ abstract class BlocBaseProviderScreen<Bloc extends BlocBase<State>,
lazy: lazy,
enable: smart,
create: (_) => create(context),
init: (_, bloc) => init(context, bloc),
child: Builder(builder: builder),
);
}

View File

@ -40,7 +40,6 @@ abstract class BlocBaseScreen<Bloc extends BlocBase<State>,
/// accessed the first time, not when provided.
final bool lazy;
/// Whether this uses [SmartProvider].
/// Defaults to `true`. But if you want to provide new Bloc of a same type,
/// in a sub-tree you may have to disable this.
@ -49,12 +48,21 @@ abstract class BlocBaseScreen<Bloc extends BlocBase<State>,
/// Creates the [Cubit] or [Bloc] to be used.
Bloc create(BuildContext context);
/// Initialize the [Bloc] or [Cubit].
///
/// This function is useful when using with [SmartProvider], because
/// if you want to pass an initial event to your bloc you can pass it in
/// `create` function but if you re-use the bloc below in the tree this event
/// will never be re-pass.
Bloc init(BuildContext context, Bloc bloc) => bloc;
@override
Widget build(BuildContext context) => SmartProvider.bloc<Bloc, State>(
context,
lazy: lazy,
enable: smart,
create: (_) => create(context),
child: super.build(context),
);
context,
lazy: lazy,
enable: smart,
create: (_) => create(context),
init: (_, bloc) => init(context, bloc),
child: super.build(context),
);
}

View File

@ -27,7 +27,7 @@ import 'package:wyatt_bloc_helper/src/utils/smart_provider.dart';
/// It automatically handles closing the instance when used with [create].
/// By default, [create] is called only when the instance is accessed.
/// To override this behavior, set [lazy] to `false`.
///
///
/// By default, it provide already provided instance found in the tree.
/// To override this behavior, set [smart] to `false`.
/// {@endtemplate}
@ -46,13 +46,21 @@ abstract class RepositoryBaseProviderScreen<Repository>
final bool lazy;
/// Whether this uses [SmartProvider].
/// Defaults to `true`. But if you want to provide new [Repository] of a
/// Defaults to `true`. But if you want to provide new [Repository] of a
/// same type in a sub-tree you may have to disable this.
final bool smart;
/// Creates the [Repository] to be used.
Repository create(BuildContext context);
/// Initialize the [Repository].
///
/// This function is useful when using with [SmartProvider], because
/// if you want to pass an initial call on your repository you can
/// call it in `create` function but if you re-provide the repo below in the
/// tree this action will never be call again.
Repository init(BuildContext context, Repository repository) => repository;
/// Creates the child [Widget] to be used.
Widget builder(BuildContext context);
@ -62,6 +70,7 @@ abstract class RepositoryBaseProviderScreen<Repository>
lazy: lazy,
enable: smart,
create: (_) => create(context),
init: (_, repository) => init(context, repository),
child: Builder(builder: builder),
);
}

View File

@ -22,6 +22,7 @@ abstract class SmartProvider {
bloc<Bloc extends BlocBase<State>, State extends Object>(
BuildContext context, {
required Bloc Function(BuildContext) create,
required Bloc Function(BuildContext, Bloc) init,
Widget? child,
bool lazy = true,
bool enable = true,
@ -29,8 +30,9 @@ abstract class SmartProvider {
if (enable) {
final bloc = context.read<Bloc?>();
if (bloc != null) {
final b = bloc;
return BlocProvider<Bloc>.value(
value: bloc,
value: init(context, b),
child: child,
);
}
@ -38,7 +40,7 @@ abstract class SmartProvider {
return BlocProvider<Bloc>(
lazy: lazy,
create: (_) => create(context),
create: (_) => init(context, create(context)),
child: child,
);
}
@ -46,6 +48,7 @@ abstract class SmartProvider {
static RepositoryProvider<Repository> repo<Repository>(
BuildContext context, {
required Repository Function(BuildContext) create,
required Repository Function(BuildContext, Repository) init,
Widget? child,
bool lazy = true,
bool enable = true,
@ -53,8 +56,9 @@ abstract class SmartProvider {
if (enable) {
final repo = context.read<Repository?>();
if (repo != null) {
final r = repo;
return RepositoryProvider<Repository>.value(
value: repo,
value: init(context, r),
child: child,
);
}
@ -62,7 +66,7 @@ abstract class SmartProvider {
return RepositoryProvider<Repository>(
lazy: lazy,
create: (_) => create(context),
create: (_) => init(context, create(context)),
child: child,
);
}

View File

@ -0,0 +1,98 @@
// Copyright (C) 2022 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
/// {@template multi_provider}
/// Merges [MultiRepositoryProvider] and [MultiBlocProvider] widgets into
/// one widget tree.
///
/// [MultiProvider] improves the readability and eliminates the need
/// to nest multiple providers.
///
/// By using [MultiProvider] we can go from:
///
/// ```dart
/// MultiRepositoryProvider(
/// providers: [
/// RepositoryProvider<RepositoryA>(create: (context) => RepositoryA()),
/// RepositoryProvider<RepositoryB>(create: (context) => RepositoryB()),
/// RepositoryProvider<RepositoryC>(create: (context) => RepositoryC()),
/// ],
/// child:
/// MultiBlocProvider(
/// providers: [
/// BlocProvider<BlocA>(
/// create: (BuildContext context) => BlocA(),
/// ),
/// BlocProvider<BlocB>(
/// create: (BuildContext context) => BlocB(),
/// ),
/// BlocProvider<BlocC>(
/// create: (BuildContext context) => BlocC(),
/// ),
/// ],
/// child: ChildA(),
/// ),
/// )
/// ```
///
/// to:
///
/// ```dart
/// MultiRepositoryProvider(
/// repositoryProviders: [
/// RepositoryProvider<RepositoryA>(create: (context) => RepositoryA()),
/// RepositoryProvider<RepositoryB>(create: (context) => RepositoryB()),
/// RepositoryProvider<RepositoryC>(create: (context) => RepositoryC()),
/// ],
/// providers: [
/// BlocProvider<BlocA>(create: (context) => BlocA()),
/// BlocProvider<BlocB>(create: (context) => BlocB()),
/// BlocProvider<BlocC>(create: (context) => BlocC()),
/// ],
/// child: ChildA(),
/// )
/// ```
///
/// [MultiProvider] converts the [RepositoryProvider] and [BlocProvider] lists
/// into a tree of nested provider widgets.
/// As a result, the only advantage of using [MultiProvider] is
/// improved readability due to the reduction in nesting and boilerplate.
/// {@endtemplate}
class MultiProvider extends StatelessWidget {
/// {@macro multi_provider}
const MultiProvider({
required this.repositoryProviders,
required this.blocProviders,
required this.child,
super.key,
});
final List<RepositoryProvider<dynamic>> repositoryProviders;
final List<BlocProvider> blocProviders;
final Widget child;
@override
Widget build(BuildContext context) => MultiRepositoryProvider(
providers: repositoryProviders,
child: MultiBlocProvider(
providers: blocProviders,
child: child,
),
);
}

View File

@ -14,8 +14,10 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
/// Your best friend for BLoC in Flutter
library wyatt_bloc_helper;
export 'src/bloc.dart';
export 'src/cubit.dart';
export 'src/repo.dart';
export 'src/widgets/multi_provider.dart';