Skip to content

Commit

Permalink
[yak_flutter] add ScalebleWidget & co.
Browse files Browse the repository at this point in the history
  • Loading branch information
Francesco Iapicca committed Apr 22, 2024
1 parent a5a48dc commit f841e83
Show file tree
Hide file tree
Showing 5 changed files with 327 additions and 3 deletions.
4 changes: 2 additions & 2 deletions packages/yak_flutter/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
### 3.0.1
- add `EdgePositioned`
### 3.0.2
- add `EdgePositioned`, `ScalebleWidget`, `MediaQueryWidget` and `ScalableEdgePositioned`

### 3.0.0
- rework due to yak_result v3
Expand Down
34 changes: 34 additions & 0 deletions packages/yak_flutter/lib/src/widgets/media_query_widget.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import 'package:flutter/widgets.dart';

abstract class MediaQueryWidget extends Widget {
const MediaQueryWidget({super.key});

@override
ComponentElement createElement() => MediaQueryElement(this);

MediaQueryData mediaQueryFrom(MediaQueryData mediaQuery);

Widget build(BuildContext context);
}

class MediaQueryElement extends ComponentElement {
MediaQueryElement(MediaQueryWidget super.widget);

@override
Widget build() {
final mediaQueryWidget = widget as MediaQueryWidget;
return MediaQuery(
data: mediaQueryWidget.mediaQueryFrom(MediaQuery.of(this)),
child: Builder(
builder: mediaQueryWidget.build,
),
);
}

@override
void update(MediaQueryWidget newWidget) {
super.update(newWidget);
assert(widget == newWidget);
rebuild(force: true);
}
}
134 changes: 134 additions & 0 deletions packages/yak_flutter/lib/src/widgets/scalable_edge_positioned.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import 'package:flutter/widgets.dart';

import 'scalable_widget.dart';

@immutable
abstract class ScalableEdgePositioned extends Positioned {
final EdgeInsets padding;
final double dimension;
final double scale;
ScalableEdgePositioned({
required child,
required this.dimension,
required this.padding,
required this.scale,
super.key,
}) : super(
child: ScalebleWidget(
scale: scale,
child: child,
),
);

factory ScalableEdgePositioned.top({
required Widget child,
double dimension,
double scale,
EdgeInsets padding,
Key key,
}) = _EdgePositioneTop;

factory ScalableEdgePositioned.bottom({
required Widget child,
double dimension,
double scale,
EdgeInsets padding,
Key key,
}) = _EdgePositioneBottom;

factory ScalableEdgePositioned.left({
required Widget child,
double dimension,
double scale,
EdgeInsets padding,
Key key,
}) = _EdgePositioneLeft;

factory ScalableEdgePositioned.right({
required Widget child,
double dimension,
double scale,
EdgeInsets padding,
Key key,
}) = _EdgePositioneRight;
}

@immutable
class _EdgePositioneBottom extends ScalableEdgePositioned {
_EdgePositioneBottom({
required super.child,
super.dimension = 0,
super.scale = 1,
super.padding = EdgeInsets.zero,
super.key,
});

@override
double get left => padding.left * scale;
@override
double get right => padding.right * scale;
@override
double get bottom => padding.bottom * scale;
@override
double get height => (dimension - padding.vertical) * scale;
}

@immutable
class _EdgePositioneTop extends ScalableEdgePositioned {
_EdgePositioneTop({
required super.child,
super.dimension = 0,
super.scale = 1,
super.padding = EdgeInsets.zero,
super.key,
});

@override
double get left => padding.left * scale;
@override
double get right => padding.right * scale;
@override
double get top => padding.top * scale;
@override
double get height => (dimension - padding.vertical) * scale;
}

@immutable
class _EdgePositioneLeft extends ScalableEdgePositioned {
_EdgePositioneLeft({
required super.child,
super.dimension = 0,
super.scale = 1,
super.padding = EdgeInsets.zero,
super.key,
});

@override
double get left => padding.left * scale;
@override
double get top => padding.top * scale;
@override
double get bottom => padding.bottom * scale;
@override
double get width => (dimension - padding.horizontal) * scale;
}

@immutable
class _EdgePositioneRight extends ScalableEdgePositioned {
_EdgePositioneRight({
required super.child,
super.dimension = 0,
super.scale = 1,
super.padding = EdgeInsets.zero,
super.key,
});

@override
double get right => padding.right * scale;
@override
double get top => padding.top * scale;
@override
double get bottom => padding.bottom * scale;
@override
double get width => (dimension - padding.horizontal) * scale;
}
156 changes: 156 additions & 0 deletions packages/yak_flutter/lib/src/widgets/scalable_widget.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import 'dart:ui' as ui;

import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/rendering.dart';

import 'media_query_widget.dart';

class ScalebleWidget extends SingleChildRenderObjectWidget {
final double scale;

ScalebleWidget({
super.key,
required this.scale,
required Widget child,
}) : super(
child: ScalableMediaQueryWidget(
scale: scale,
child: child,
),
);

@override
ScaleTransform createRenderObject(context) => ScaleTransform(
scale: scale,
textDirection: Directionality.maybeOf(context),
);

@override
void updateRenderObject(context, ScaleTransform renderObject) =>
renderObject.scale(scale);
}

class ScaleTransform extends RenderProxyBox {
ScaleTransform({
TextDirection? textDirection,
required double scale,
}) : _scale = scale,
_transform = _scaleToMatrix(scale);

@override
bool get alwaysNeedsCompositing => child != null;

static Matrix4 _scaleToMatrix(double scale) =>
Matrix4.diagonal3Values(scale, scale, 1.0);

Matrix4 _transform;
double _scale;
void scale(double value) {
if (_scale == value) {
return;
}
_scale = value;
_transform = _scaleToMatrix(value);
markNeedsPaint();
markNeedsSemanticsUpdate();
}

@override
void paint(PaintingContext context, Offset offset) {
if (child == null) {
return;
}
final transform = _effectiveTransform;

final Offset? childOffset = MatrixUtils.getAsTranslation(transform);
if (childOffset != null) {
super.paint(context, offset + childOffset);
layer = null;
return;
}

final determinant = transform.determinant();
if (determinant == 0 || !determinant.isFinite) {
layer = null;
return;
}
layer = context.pushTransform(
needsCompositing,
offset,
transform,
super.paint,
oldLayer: layer is TransformLayer ? layer as TransformLayer? : null,
);
}

void setIdentity() {
_transform.setIdentity();
markNeedsPaint();
markNeedsSemanticsUpdate();
}

Matrix4 get _effectiveTransform => Matrix4.identity()..multiply(_transform);

@override
bool hitTest(BoxHitTestResult result, {required Offset position}) {
return hitTestChildren(result, position: position);
}

@override
bool hitTestChildren(result, {required Offset position}) =>
result.addWithPaintTransform(
transform: _effectiveTransform,
position: position,
hitTest: (result, position) => super.hitTestChildren(
result,
position: position,
),
);

@override
void applyPaintTransform(child, transform) =>
transform.multiply(_effectiveTransform);

@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DoubleProperty('scale', _scale));
}
}

class ScalableMediaQueryWidget extends MediaQueryWidget {
final double scale;
final Widget child;

const ScalableMediaQueryWidget({
required this.child,
required this.scale,
super.key,
});

@override
Widget build(context) => child;

@override
@nonVirtual
MediaQueryData mediaQueryFrom(mediaQuery) => mediaQuery.copyWith(
size: mediaQuery.size * scale,
viewInsets: mediaQuery.viewInsets * scale,
systemGestureInsets: mediaQuery.systemGestureInsets * scale,
viewPadding: mediaQuery.viewPadding * scale,
padding: mediaQuery.padding * scale,
devicePixelRatio: mediaQuery.devicePixelRatio * scale,
displayFeatures: [
for (final feature in mediaQuery.displayFeatures)
ui.DisplayFeature(
type: feature.type,
state: feature.state,
bounds: Rect.fromPoints(
feature.bounds.topLeft * scale,
feature.bounds.bottomRight * scale,
),
),
],
);
}
2 changes: 1 addition & 1 deletion packages/yak_flutter/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: yak_flutter
description: A collection of tools, widgets and extensions for Flutter framework.
version: 3.0.1
version: 3.0.2
homepage: https://github.com/yakforward-ou/yak_packages

environment:
Expand Down

0 comments on commit f841e83

Please sign in to comment.