Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add UniformPadding #46

Merged
merged 7 commits into from
May 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
);
}
}
Loading