-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
331 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
import 'package:flutter/widgets.dart'; | ||
|
||
/// A key for accessing and modifying associated values from the [BuildContext]. | ||
/// | ||
/// [EnvironmentKey]s are an alternative to using [InheritedWidget]s for passing | ||
/// values down the widget tree. | ||
/// | ||
/// An [EnvironmentKey] is less verbose to define than an [InheritedWidget] | ||
/// since it inherits the [of] and [maybeOf] methods instead of having to define | ||
/// the equivalent static accessors. | ||
/// | ||
/// It further incorporates the concept of a [defaultValue] which is used when | ||
/// no value is provided through the [BuildContext]. | ||
/// | ||
/// # Example | ||
/// | ||
/// The following example shows how to define a [EnvironmentKey], as well as a | ||
/// extension method that is typically provided to make it easier to use. | ||
/// | ||
/// ```dart multi_begin | ||
/// import 'package:flutter/widgets.dart'; | ||
/// | ||
/// final class _DefaultPaddingKey | ||
/// extends EnvironmentKey<double, _DefaultPaddingKey> { | ||
/// const _DefaultPaddingKey(); | ||
/// | ||
/// @override | ||
/// double defaultValue(BuildContext context) => 8; | ||
/// } | ||
/// | ||
/// const defaultPadding = _DefaultPaddingKey(); | ||
/// | ||
/// extension WidgetModifiers on Widget { | ||
/// @widgetFactory | ||
/// Widget defaultPadding(double amount) => | ||
/// const _DefaultPaddingKey().update(value: amount, child: this); | ||
/// } | ||
/// ``` | ||
/// | ||
/// To access the value of an [EnvironmentKey] from the [BuildContext], use the | ||
/// [of] method: | ||
/// | ||
/// ```dart multi_end | ||
/// Widget build(BuildContext context) { | ||
/// return Padding( | ||
/// padding: EdgeInsets.all(defaultPadding.of(context)), | ||
/// child: Container(), | ||
/// ); | ||
/// } | ||
/// ``` | ||
abstract base class EnvironmentKey<T, K extends EnvironmentKey<T, K>> { | ||
/// Constructor for subclasses. | ||
const EnvironmentKey(); | ||
|
||
/// Returns the default value for this key, when no value is provided through | ||
/// the [BuildContext]. | ||
T defaultValue(BuildContext context); | ||
|
||
/// Returns the value of this key form the given [BuildContext] or the | ||
/// [defaultValue] if no value is provided. | ||
T of(BuildContext context) => maybeOf(context) ?? defaultValue(context); | ||
|
||
/// Returns the value of this key based on the given [BuildContext] or `null` | ||
/// if no value is provided. | ||
T? maybeOf(BuildContext context) => context | ||
.dependOnInheritedWidgetOfExactType<_EnvironmentValue<T, K>>() | ||
?.value; | ||
} | ||
|
||
/// Methods on [EnvironmentKey] for modifying the value of the key. | ||
extension EnvironmentValueModifiers<T, K extends EnvironmentKey<T, K>> | ||
on EnvironmentKey<T, K> { | ||
/// Returns a widget that provides the given [value] for this key to its | ||
/// descendants. | ||
@widgetFactory | ||
Widget update({required T value, required Widget child}) { | ||
return _EnvironmentValue<T, K>( | ||
value: value, | ||
child: child, | ||
); | ||
} | ||
|
||
/// Returns a widget that provides the result of [transform] applied to the | ||
/// value of this key to its descendants. | ||
@widgetFactory | ||
Widget transform({ | ||
required T Function(T value) transform, | ||
required Widget child, | ||
}) { | ||
return _EnvironmentValueTransformer( | ||
environmentKey: this, | ||
transform: transform, | ||
child: child, | ||
); | ||
} | ||
} | ||
|
||
final class _EnvironmentValue<T, K extends EnvironmentKey<T, K>> | ||
extends InheritedWidget { | ||
const _EnvironmentValue({ | ||
required this.value, | ||
required super.child, | ||
}); | ||
|
||
final T value; | ||
|
||
@override | ||
bool updateShouldNotify(covariant _EnvironmentValue<T, K> oldWidget) => | ||
value != oldWidget.value; | ||
} | ||
|
||
final class _EnvironmentValueTransformer<T, K extends EnvironmentKey<T, K>> | ||
extends StatelessWidget { | ||
const _EnvironmentValueTransformer({ | ||
required this.environmentKey, | ||
required this.transform, | ||
required this.child, | ||
}); | ||
|
||
final K environmentKey; | ||
final T Function(T value) transform; | ||
final Widget child; | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return environmentKey.update( | ||
value: transform(environmentKey.of(context)), | ||
child: child, | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
// ignore_for_file: library_private_types_in_public_api | ||
|
||
import 'package:flutter/rendering.dart'; | ||
import 'package:flutter/widgets.dart'; | ||
|
||
import '../animatable_render_object_widget.dart'; | ||
import '../environment.dart'; | ||
import '../parameter.dart'; | ||
|
||
/// An edge of a rectangle. | ||
enum Edge { | ||
/// The beginning edge in the reading direction. | ||
start, | ||
|
||
/// The ending edge in the reading direction. | ||
end, | ||
|
||
/// The top edge. | ||
top, | ||
|
||
/// The bottom edge. | ||
bottom; | ||
} | ||
|
||
/// Combinations of [Edge]s. | ||
abstract final class Edges { | ||
/// Set of all edges. | ||
static const all = {Edge.top, Edge.bottom, Edge.start, Edge.end}; | ||
|
||
/// Set of all edges along the vertical axis. | ||
static const vertical = {Edge.top, Edge.bottom}; | ||
|
||
/// Set of all edges along the horizontal axis. | ||
static const horizontal = {Edge.start, Edge.end}; | ||
|
||
/// Set that contains only the [Edge.start] edge. | ||
static const start = {Edge.start}; | ||
|
||
/// Set that contains only the [Edge.end] edge. | ||
static const end = {Edge.end}; | ||
|
||
/// Set that contains only the [Edge.top] edge. | ||
static const top = {Edge.top}; | ||
|
||
/// Set that contains only the [Edge.bottom] edge. | ||
static const bottom = {Edge.bottom}; | ||
} | ||
|
||
extension on Set<Edge> { | ||
EdgeInsetsGeometry uniformEdgeInsets(double amount) { | ||
return EdgeInsetsDirectional.only( | ||
top: contains(Edge.top) ? amount : 0, | ||
bottom: contains(Edge.bottom) ? amount : 0, | ||
start: contains(Edge.start) ? amount : 0, | ||
end: contains(Edge.end) ? amount : 0, | ||
); | ||
} | ||
} | ||
|
||
final class _DefaultUniformPaddingKey | ||
extends EnvironmentKey<double, _DefaultUniformPaddingKey> { | ||
const _DefaultUniformPaddingKey(); | ||
|
||
@override | ||
double defaultValue(BuildContext context) => 8; | ||
} | ||
|
||
/// [EnvironmentKey] for the default amount of padding to use in | ||
/// [UniformPadding]. | ||
/// | ||
/// {@template fleet.defaultUniformPadding} | ||
/// [defaultUniformPadding] is used by [UniformPadding] to determine the amount | ||
/// of padding to add when [UniformPadding.amount] is `null`. | ||
/// | ||
/// The default value is `8`. | ||
/// {@endtemplate} | ||
const defaultUniformPadding = _DefaultUniformPaddingKey(); | ||
|
||
typedef _UniformPaddingAnimatableParameters = ({ | ||
AnimatableEdgeInsetsGeometry padding | ||
}); | ||
|
||
/// Adds an equal [amount] of padding to specific [edges] around [child]. | ||
final class UniformPadding extends SingleChildRenderObjectWidget | ||
with | ||
AnimatableSingleChildRenderObjectWidgetMixin< | ||
_UniformPaddingAnimatableParameters> { | ||
/// Creates an [UniformPadding] widget. | ||
const UniformPadding({ | ||
super.key, | ||
this.edges = Edges.all, | ||
this.amount, | ||
super.child, | ||
}); | ||
|
||
/// The edges to add padding to. | ||
final Set<Edge> edges; | ||
|
||
/// The amount of padding to add. | ||
final double? amount; | ||
|
||
EdgeInsetsGeometry _resolvePadding(BuildContext context) => | ||
edges.uniformEdgeInsets(amount ?? defaultUniformPadding.of(context)); | ||
|
||
@override | ||
RenderObject createRenderObject(BuildContext context) { | ||
return RenderPadding( | ||
padding: _resolvePadding(context), | ||
textDirection: Directionality.of(context), | ||
); | ||
} | ||
|
||
@override | ||
void updateRenderObject( | ||
BuildContext context, | ||
covariant RenderPadding renderObject, | ||
) { | ||
renderObject | ||
..padding = _resolvePadding(context) | ||
..textDirection = Directionality.of(context); | ||
} | ||
|
||
@override | ||
_UniformPaddingAnimatableParameters createAnimatableParameters( | ||
covariant RenderPadding renderObject, | ||
AnimatableParameterHost host, | ||
) { | ||
return ( | ||
padding: AnimatableEdgeInsetsGeometry( | ||
renderObject.padding, | ||
host: host, | ||
) | ||
); | ||
} | ||
|
||
@override | ||
void updateAnimatableParameters( | ||
BuildContext context, | ||
_UniformPaddingAnimatableParameters parameters, | ||
) { | ||
parameters.padding.value = _resolvePadding(context); | ||
} | ||
|
||
@override | ||
void updateRenderObjectWithAnimatableParameters( | ||
BuildContext context, | ||
covariant RenderPadding renderObject, | ||
_UniformPaddingAnimatableParameters parameters, | ||
) { | ||
renderObject.padding = parameters.padding.animatedValue; | ||
} | ||
} | ||
|
||
/// Extension-based API for [UniformPadding]. | ||
extension UniformPaddingModifiers on Widget { | ||
/// Sets the [defaultUniformPadding] to [amount] for this widget and its | ||
/// descendants. | ||
/// | ||
/// {@macro fleet.defaultUniformPadding} | ||
@widgetFactory | ||
Widget defaultUniformPadding(double amount) => | ||
const _DefaultUniformPaddingKey().update(value: amount, child: this); | ||
|
||
/// Adds an equal [amount] of padding to specific [edges] of this widget. | ||
@widgetFactory | ||
Widget uniformPadding([Set<Edge> edges = Edges.all, double? amount]) { | ||
return UniformPadding( | ||
edges: edges, | ||
amount: amount, | ||
child: this, | ||
); | ||
} | ||
} |