Skip to content

Commit

Permalink
feat: add UniformPadding (#46)
Browse files Browse the repository at this point in the history
  • Loading branch information
blaugold committed May 29, 2023
1 parent 677060d commit a33f4d8
Show file tree
Hide file tree
Showing 7 changed files with 331 additions and 4 deletions.
4 changes: 4 additions & 0 deletions packages/fleet/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ for animating with Fleet:
- ASliverPadding
- ATransform

The following provided widgets are specific to Fleet:

- UniformPadding

---

**Gabriel Terwesten** • **GitHub**
Expand Down
5 changes: 4 additions & 1 deletion packages/fleet/example/lib/simple_declarative_animation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,13 @@ class _MyHomePageState extends State<MyHomePage> {
style: TextButton.styleFrom(foregroundColor: Colors.white),
child: const Text('Toggle'),
)
.uniformPadding(Edges.all, _expanded ? null : 32)
.animation(Curves.easeInOutCubic.animation(1.s))
.boxColor(Colors.orange)
.center()
.boxColor(_expanded ? Colors.green : Colors.blue)
.sizeWith(_expanded ? const Size.square(400) : const Size.square(200))
.animation(Curves.ease.animation(1.s), value: _expanded)
.animation(Curves.ease.animation(1.s))
.center(),
);
}
Expand Down
8 changes: 8 additions & 0 deletions packages/fleet/lib/fleet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export 'src/animate.dart' show Animated, withAnimation, AnimatingStateMixin;
export 'src/animation.dart' show AnimationSpec, AnimationFromCurveExtension;
export 'src/common.dart' show Block;
export 'src/duration.dart' show DurationFromIntExtension;
export 'src/environment.dart' show EnvironmentKey, EnvironmentValueModifiers;
export 'src/parameter.dart'
show
AnimatableAlignmentGeometry,
Expand Down Expand Up @@ -50,3 +51,10 @@ export 'src/parameter.dart'
AnimatableParameterHostMixin,
AnimatableParameterHost;
export 'src/widget_extension.dart' show FleetWidgetExtension;
export 'src/widgets/uniform_padding.dart'
show
Edge,
Edges,
UniformPadding,
defaultUniformPadding,
UniformPaddingModifiers;
12 changes: 10 additions & 2 deletions packages/fleet/lib/src/animate.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import 'package:flutter/widgets.dart' hide Animation;

import 'animatable_flutter_widgets.dart';
import 'animatable_render_object_widget.dart';
import 'animatable_stateless_widget.dart';
import 'animatable_widget_state.dart';
import 'animation.dart';
import 'common.dart';
import 'transaction.dart';
import 'widgets/uniform_padding.dart';

/// Applies an [animation] to the state changes caused by calling [block].
///
Expand Down Expand Up @@ -140,8 +143,9 @@ mixin AnimatingStateMixin<T extends StatefulWidget> on State<T> {
/// {@template fleet.Animated.widgets}
///
/// Only widgets that support animating with Fleet will animate changes. To
/// implement support for this in your own widgets use [AnimatableStateMixin] or
/// [AnimatableState].
/// implement support for this in your own widgets use [AnimatableStateMixin],
/// [AnimatableState], [AnimatableStatelessWidget] or
/// [AnimatableSingleChildRenderObjectWidgetMixin].
///
/// The following provided widgets support animating with Fleet:
///
Expand All @@ -157,6 +161,10 @@ mixin AnimatingStateMixin<T extends StatefulWidget> on State<T> {
/// - [ASliverPadding]
/// - [ATransform]
///
/// The following provided widgets are specific to Fleet:
///
/// - [UniformPadding]
///
/// {@endtemplate}
///
/// State changes are only animated if they happen at the same time that [value]
Expand Down
131 changes: 131 additions & 0 deletions packages/fleet/lib/src/environment.dart
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,
);
}
}
2 changes: 1 addition & 1 deletion packages/fleet/lib/src/widget_extension.dart
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ extension FleetWidgetExtension on Widget {

/// Adds [padding] around this widget.
@widgetFactory
Widget padding(EdgeInsets padding) {
Widget padding(EdgeInsetsGeometry padding) {
return APadding(
padding: padding,
child: this,
Expand Down
173 changes: 173 additions & 0 deletions packages/fleet/lib/src/widgets/uniform_padding.dart
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,
);
}
}

0 comments on commit a33f4d8

Please sign in to comment.