Nikolas Rimikis
1 year ago
29 changed files with 180 additions and 97 deletions
@ -0,0 +1,103 @@ |
|||||||
|
import 'package:flutter/widgets.dart'; |
||||||
|
import 'package:neon/src/models/disposable.dart'; |
||||||
|
import 'package:provider/provider.dart'; |
||||||
|
import 'package:provider/single_child_widget.dart'; |
||||||
|
|
||||||
|
/// A [Provider] that manages the lifecycle of a [Disposable] value it provides |
||||||
|
/// by delegating [Create] and calling [Disposable.dispose]. |
||||||
|
class NeonProvider<T extends Disposable> extends SingleChildStatelessWidget { |
||||||
|
/// Creates a value, stores it, and exposes it to its descendants. |
||||||
|
const NeonProvider({ |
||||||
|
required final Create<T> create, |
||||||
|
super.key, |
||||||
|
this.child, |
||||||
|
this.lazy = true, |
||||||
|
}) : _create = create, |
||||||
|
_value = null, |
||||||
|
super(child: child); |
||||||
|
|
||||||
|
/// Expose an existing value without disposing it. |
||||||
|
/// |
||||||
|
/// {@macro provider.updateshouldnotify} |
||||||
|
const NeonProvider.value({ |
||||||
|
required final T value, |
||||||
|
super.key, |
||||||
|
this.child, |
||||||
|
}) : _value = value, |
||||||
|
_create = null, |
||||||
|
lazy = true, |
||||||
|
super(child: child); |
||||||
|
|
||||||
|
/// Optional widget below this widget in the tree having access to the value. |
||||||
|
/// |
||||||
|
/// {@macro flutter.widgets.ProxyWidget.child} |
||||||
|
final Widget? child; |
||||||
|
|
||||||
|
/// Whether the value should be created lazily. |
||||||
|
/// Defaults to `true`. |
||||||
|
final bool lazy; |
||||||
|
|
||||||
|
final Create<T>? _create; |
||||||
|
|
||||||
|
final T? _value; |
||||||
|
|
||||||
|
/// Method that allows widgets to access the value as long as their |
||||||
|
/// `BuildContext` contains a [NeonProvider] or [Provider] instance of the |
||||||
|
/// specified type. |
||||||
|
/// |
||||||
|
/// Calling this method is equivalent to calling: |
||||||
|
/// |
||||||
|
/// ```dart |
||||||
|
/// Provider.of(context, listen: false); |
||||||
|
/// ``` |
||||||
|
/// |
||||||
|
/// If we want to access an instance of `DisposableA` which was provided higher up |
||||||
|
/// in the widget tree we can do so via: |
||||||
|
/// |
||||||
|
/// ```dart |
||||||
|
/// NeonProvider.of<DisposableA>(context); |
||||||
|
/// ``` |
||||||
|
static T of<T>( |
||||||
|
final BuildContext context, { |
||||||
|
final bool listen = false, |
||||||
|
}) { |
||||||
|
try { |
||||||
|
return Provider.of<T>(context, listen: listen); |
||||||
|
} on ProviderNotFoundException catch (e) { |
||||||
|
if (e.valueType != T) { |
||||||
|
rethrow; |
||||||
|
} |
||||||
|
throw FlutterError( |
||||||
|
''' |
||||||
|
NeonProvider.of() called with a context that does not contain a $T. |
||||||
|
No ancestor could be found starting from the context that was passed to NeonProvider.of<$T>(). |
||||||
|
|
||||||
|
This can happen if the context you used comes from a widget above the NeonProvider. |
||||||
|
|
||||||
|
The context used was: $context |
||||||
|
''', |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
Widget buildWithChild(final BuildContext context, final Widget? child) { |
||||||
|
assert( |
||||||
|
child != null, |
||||||
|
'$runtimeType used outside of MultiBlocProvider must specify a child', |
||||||
|
); |
||||||
|
final value = _value; |
||||||
|
return value != null |
||||||
|
? InheritedProvider<T>.value( |
||||||
|
value: value, |
||||||
|
lazy: lazy, |
||||||
|
child: child, |
||||||
|
) |
||||||
|
: InheritedProvider<T>( |
||||||
|
create: _create, |
||||||
|
dispose: (final _, final value) => value.dispose(), |
||||||
|
lazy: lazy, |
||||||
|
child: child, |
||||||
|
); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue