Skip to content

Commit

Permalink
[adaptive_style] implemented AdaptiveStack
Browse files Browse the repository at this point in the history
  • Loading branch information
Francesco Iapicca committed Apr 30, 2024
1 parent b46a866 commit 77d9bf6
Show file tree
Hide file tree
Showing 18 changed files with 450 additions and 276 deletions.
42 changes: 24 additions & 18 deletions examples/adaptive_style_example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ class MyApplication extends StatelessWidget {
const MyApplication({super.key});

@override
Widget build(context) => const SizeRefProvider(
deviceSizes: [DeviceSize.iphoneSE],
child: MaterialApp(
Widget build(context) => ScaleRefProvider(
deviceSizes: const [DeviceSize.iphoneSE],
builder: (context) => const MaterialApp(
home: MyHomePage(),
),
);
Expand All @@ -19,21 +19,27 @@ class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});

@override
Widget build(context) => SizeRefBuilder(builder: (context, sizeRef) {
return switch (sizeRef.size) {
(DeviceSize.iphoneSE) => Scaffold(
backgroundColor: Colors.black,
body: Center(
child: FlutterLogo(
size: 100 * sizeRef.scale.min,
),
Widget build(context) => Material(
child: AdaptiveStackBuilder(
builder: (context, scaleRef, parentSize) => [
AdaptiveEdgePositioned(
parentSize: parentSize,
padding: const EdgeInsets.all(10),
dimension: 100,
edge: Edge.bottom,
builder: (context, scaleRef, parentSize) => const ColoredBox(
color: Colors.red,
),
),
_ => const Scaffold(
body: Center(
child: FlutterLogo(size: 100),
),
),
};
});
],
),
// child: AdaptiveEdgePositioned(
// padding: const EdgeInsets.all(10),
// dimension: 100,
// edge: Edge.bottom,
// builder: (context, scaleRef, _) => const ColoredBox(
// color: Colors.red,
// ),
// ),
);
}
12 changes: 9 additions & 3 deletions packages/adaptive_style/lib/adaptive_style.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
library adaptive_style;

export 'src/adaptive_size_builder.dart';
export 'src/adaptive_size_provider.dart';
export 'src/adaptive_edge_positioned.dart';
export 'src/adaptive_mediaquery_widget.dart';
export 'src/adaptive_stack.dart';
export 'src/adaptive_widget_builder.dart';
export 'src/adaptive_widget.dart';
export 'src/device_size.dart';
export 'src/extension.dart';
export 'src/inherited_adaptive_size.dart';
export 'src/inherited_scale_ref.dart';
export 'src/scale_ref_provider.dart';
export 'src/scale_ref.dart';
export 'src/size_scale.dart';
106 changes: 106 additions & 0 deletions packages/adaptive_style/lib/src/adaptive_edge_positioned.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import 'package:flutter/widgets.dart';

import 'adaptive_widget.dart';
import 'adaptive_widget_builder.dart';

enum Edge { top, bottom, left, right }

class AdaptiveEdgePositioned extends AdaptiveWidget {
final EdgeInsets padding;
final double dimension;
final AdaptiveWidgetBuilder _builder;
final Edge edge;
const AdaptiveEdgePositioned({
super.key,
this.padding = EdgeInsets.zero,
required AdaptiveWidgetBuilder builder,
required this.dimension,
required this.edge,
required this.parentSize,
}) : _builder = builder;

@override
Widget builder(context, scaleRef, parentSize) =>

/// TODO should calculate parent data
ScalableEdgePositioned(
edge: edge,
dimension: dimension,
scale: scaleRef.scale.min,
child: _builder(context, scaleRef, parentSize),
);

@override
final Size parentSize;
}

class ScalableEdgePositioned extends Positioned {
final EdgeInsets padding;
final double dimension;
final double scale;
final Edge edge;
const ScalableEdgePositioned({
required this.edge,
required super.child,
required this.dimension,
this.padding = EdgeInsets.zero,
required this.scale,
super.key,
});

@override
@protected
@visibleForTesting
double? get left {
return switch (edge) {
(Edge.right) => null,
_ => padding.left * scale,
};
}

@override
@protected
@visibleForTesting
double? get right {
return switch (edge) {
(Edge.left) => null,
_ => padding.right * scale,
};
}

@override
@protected
@visibleForTesting
double? get bottom {
return switch (edge) {
(Edge.top) => null,
_ => padding.bottom * scale,
};
}

@override
@protected
@visibleForTesting
double? get top {
return switch (edge) {
(Edge.bottom) => null,
_ => padding.top * scale,
};
}

@override
double? get height {
return switch (edge) {
(Edge.bottom || Edge.top) => (dimension - padding.vertical) * scale,
_ => null,
};
}

@override
double? get width {
return switch (edge) {
(Edge.left || Edge.right) => (dimension - padding.horizontal) * scale,
_ => null,
};
}
}
26 changes: 26 additions & 0 deletions packages/adaptive_style/lib/src/adaptive_mediaquery_widget.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import 'package:flutter/widgets.dart';
import 'package:yak_flutter/yak_flutter.dart';

class AdaptiveMediaQueryWidget extends MediaQueryWidget {
final double scale;
final WidgetBuilder builder;
const AdaptiveMediaQueryWidget({
required this.builder,
required this.scale,
super.key,
});

@override
Widget build(context) => key == null
? Builder(builder: builder)
: KeyedSubtree(
key: key,
child: Builder(builder: builder),
);

@override
MediaQueryData mediaQueryFrom(MediaQueryData mediaQuery) =>
mediaQuery.copyWith(
textScaler: TextScaler.linear(scale),
);
}
27 changes: 0 additions & 27 deletions packages/adaptive_style/lib/src/adaptive_size_builder.dart

This file was deleted.

87 changes: 87 additions & 0 deletions packages/adaptive_style/lib/src/adaptive_stack.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import 'package:flutter/widgets.dart';
import 'package:meta/meta.dart';

import 'adaptive_widget.dart';
import 'adaptive_widget_builder.dart';
import 'scale_ref.dart';

class AdaptiveStack extends AdaptiveWidget {
final AlignmentDirectional alignment;
final AdaptiveChildrenBuilder _builder;
final Clip clipBehavior;
final StackFit fit;
final TextDirection? textDirection;

const AdaptiveStack({
required AdaptiveChildrenBuilder builder,
required this.parentSize,
this.alignment = AlignmentDirectional.topStart,
this.clipBehavior = Clip.hardEdge,
this.fit = StackFit.loose,
this.textDirection,
super.key,
}) : _builder = builder;

@override
Widget builder(context, scaleRef, parentSize) => SizedBox.fromSize(
size: parentSize,
child: AdaptiveStackLayout(
parentSize: parentSize,
scaleRef: scaleRef,
context: context,
builder: _builder,
alignment: alignment,
textDirection: textDirection,
fit: fit,
clipBehavior: clipBehavior,
),
);

@override
final Size parentSize;
}

class AdaptiveStackLayout extends Stack {
final AdaptiveChildrenBuilder builder;
final Size parentSize;
final ScaleRef scaleRef;
final BuildContext context;
const AdaptiveStackLayout({
super.key,
super.alignment = AlignmentDirectional.topStart,
super.textDirection,
super.fit = StackFit.loose,
super.clipBehavior = Clip.hardEdge,
required this.builder,
required this.parentSize,
required this.context,
required this.scaleRef,
});

@override
@nonVirtual
List<Widget> get children => builder(context, scaleRef, parentSize);
}

class AdaptiveStackBuilder extends LayoutBuilder {
final AlignmentDirectional alignment;
final Clip clipBehavior;
final StackFit fit;
final TextDirection? textDirection;
AdaptiveStackBuilder({
required AdaptiveChildrenBuilder builder,
this.alignment = AlignmentDirectional.topStart,
this.clipBehavior = Clip.hardEdge,
this.fit = StackFit.loose,
this.textDirection,
super.key,
}) : super(
builder: (context, contraints) => AdaptiveStack(
alignment: alignment,
builder: builder,
clipBehavior: clipBehavior,
fit: fit,
parentSize: contraints.biggest,
textDirection: textDirection,
));
}
28 changes: 28 additions & 0 deletions packages/adaptive_style/lib/src/adaptive_widget.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';

import 'inherited_scale_ref.dart';
import 'scale_ref.dart';

abstract class AdaptiveWidget extends Widget implements StatelessWidget {
const AdaptiveWidget({super.key});

@override
StatelessElement createElement() => StatelessElement(this);

@override
@protected
@nonVirtual
Widget build(BuildContext context) {
final maybeScaleRef = InheritedScaleRef.maybeOf(context);
if (maybeScaleRef == null) {
throw Exception('ScaleRef not found in context,'
' make sure to have "ScaleRefProvider" in your Widget Tree');
}
return builder(context, maybeScaleRef, parentSize);
}

Size get parentSize;

Widget builder(BuildContext context, ScaleRef scaleRef, Size parentSize);
}
33 changes: 33 additions & 0 deletions packages/adaptive_style/lib/src/adaptive_widget_builder.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import 'package:flutter/widgets.dart';

import 'scale_ref.dart';

/// a function that return a `Widget` from a
/// `BuildContext` a `ScaleRef` and the `Size` of the parent Widget
typedef AdaptiveWidgetBuilder = Widget Function(
BuildContext context,
ScaleRef scaleRef,
Size parentSize,
);

mixin AdaptiveWidgetBuilderMixin on Widget {
Widget builder(
BuildContext context,
ScaleRef scaleRef,
Size parentSize,
);
}

typedef AdaptiveChildrenBuilder = List<Widget> Function(
BuildContext context,
ScaleRef scaleRef,
Size parentSize,
);

mixin AdaptiveChildrenBuilderrMixin on Widget {
List<Widget> builder(
BuildContext context,
ScaleRef scaleRef,
Size parentSize,
);
}
Loading

0 comments on commit 77d9bf6

Please sign in to comment.