Line data Source code
1 : import 'package:bloc/bloc.dart';
2 : import 'package:flutter/widgets.dart';
3 : import 'package:provider/provider.dart';
4 : import 'package:provider/single_child_widget.dart';
5 :
6 : /// Mixin which allows `MultiBlocProvider` to infer the types
7 : /// of multiple [BlocProvider]s.
8 : mixin BlocProviderSingleChildWidget on SingleChildWidget {}
9 :
10 : /// {@template bloc_provider}
11 : /// Takes a [Create] function that is responsible for
12 : /// creating the [Bloc] or [Cubit] and a [child] which will have access
13 : /// to the instance via `BlocProvider.of(context)`.
14 : /// It is used as a dependency injection (DI) widget so that a single instance
15 : /// of a [Bloc] or [Cubit] can be provided to multiple widgets within a subtree.
16 : ///
17 : /// ```dart
18 : /// BlocProvider(
19 : /// create: (BuildContext context) => BlocA(),
20 : /// child: ChildA(),
21 : /// );
22 : /// ```
23 : ///
24 : /// It automatically handles closing the instance when used with [Create].
25 : /// By default, [Create] is called only when the instance is accessed.
26 : /// To override this behavior, set [lazy] to `false`.
27 : ///
28 : /// ```dart
29 : /// BlocProvider(
30 : /// lazy: false,
31 : /// create: (BuildContext context) => BlocA(),
32 : /// child: ChildA(),
33 : /// );
34 : /// ```
35 : ///
36 : /// {@endtemplate}
37 : class BlocProvider<T extends BlocBase<Object?>>
38 : extends SingleChildStatelessWidget with BlocProviderSingleChildWidget {
39 : /// {@macro bloc_provider}
40 2 : BlocProvider({
41 : Key? key,
42 : required Create<T> create,
43 : this.child,
44 : this.lazy,
45 : }) : _create = create,
46 : _value = null,
47 2 : super(key: key, child: child);
48 :
49 : /// Takes a [value] and a [child] which will have access to the [value] via
50 : /// `BlocProvider.of(context)`.
51 : /// When `BlocProvider.value` is used, the [Bloc] or [Cubit]
52 : /// will not be automatically closed.
53 : /// As a result, `BlocProvider.value` should only be used for providing
54 : /// existing instances to new subtrees.
55 : ///
56 : /// A new [Bloc] or [Cubit] should not be created in `BlocProvider.value`.
57 : /// New instances should always be created using the
58 : /// default constructor within the [Create] function.
59 : ///
60 : /// ```dart
61 : /// BlocProvider.value(
62 : /// value: BlocProvider.of<BlocA>(context),
63 : /// child: ScreenA(),
64 : /// );
65 : /// ```
66 6 : BlocProvider.value({
67 : Key? key,
68 : required T value,
69 : this.child,
70 : }) : _value = value,
71 : _create = null,
72 : lazy = null,
73 6 : super(key: key, child: child);
74 :
75 : /// Widget which will have access to the [Bloc] or [Cubit].
76 : final Widget? child;
77 :
78 : /// Whether the [Bloc] or [Cubit] should be created lazily.
79 : /// Defaults to `true`.
80 : final bool? lazy;
81 :
82 : final Create<T>? _create;
83 :
84 : final T? _value;
85 :
86 : /// Method that allows widgets to access a [Bloc] or [Cubit] instance
87 : /// as long as their `BuildContext` contains a [BlocProvider] instance.
88 : ///
89 : /// If we want to access an instance of `BlocA` which was provided higher up
90 : /// in the widget tree we can do so via:
91 : ///
92 : /// ```dart
93 : /// BlocProvider.of<BlocA>(context);
94 : /// ```
95 2 : static T of<T extends BlocBase<Object?>>(
96 : BuildContext context, {
97 : bool listen = false,
98 : }) {
99 : try {
100 2 : return Provider.of<T>(context, listen: listen);
101 1 : } on ProviderNotFoundException catch (e) {
102 2 : if (e.valueType != T) rethrow;
103 1 : throw FlutterError(
104 : '''
105 : BlocProvider.of() called with a context that does not contain a $T.
106 : No ancestor could be found starting from the context that was passed to BlocProvider.of<$T>().
107 :
108 : This can happen if the context you used comes from a widget above the BlocProvider.
109 :
110 : The context used was: $context
111 1 : ''',
112 : );
113 : }
114 : }
115 :
116 6 : @override
117 : Widget buildWithChild(BuildContext context, Widget? child) {
118 6 : final value = _value;
119 : return value != null
120 6 : ? InheritedProvider<T>.value(
121 : value: value,
122 : startListening: _startListening,
123 6 : lazy: lazy,
124 : child: child,
125 : )
126 2 : : InheritedProvider<T>(
127 2 : create: _create,
128 4 : dispose: (_, bloc) => bloc.close(),
129 : startListening: _startListening,
130 : child: child,
131 2 : lazy: lazy,
132 : );
133 : }
134 :
135 6 : static VoidCallback _startListening(
136 : InheritedContext<BlocBase?> e,
137 : BlocBase value,
138 : ) {
139 12 : final subscription = value.stream.listen(
140 12 : (dynamic _) => e.markNeedsNotifyDependents(),
141 : );
142 6 : return subscription.cancel;
143 : }
144 : }
|